|
3 | 3 | use crate::hir::map::DefPathData;
|
4 | 4 | use crate::ich::NodeIdHashingMode;
|
5 | 5 | use crate::mir::interpret::{sign_extend, truncate};
|
6 |
| -use crate::ty::layout::{Integer, IntegerExt}; |
| 6 | +use crate::ty::layout::{Integer, IntegerExt, Size}; |
7 | 7 | use crate::ty::query::TyCtxtAt;
|
8 | 8 | use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef};
|
9 | 9 | use crate::ty::TyKind::*;
|
10 | 10 | use crate::ty::{self, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable};
|
11 | 11 | use crate::util::common::ErrorReported;
|
| 12 | +use rustc_apfloat::Float as _; |
| 13 | +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
| 14 | +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; |
12 | 15 | use rustc_hir as hir;
|
13 | 16 | use rustc_hir::def::DefKind;
|
14 | 17 | use rustc_hir::def_id::DefId;
|
15 |
| - |
16 |
| -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
17 |
| -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; |
18 | 18 | use rustc_macros::HashStable;
|
19 | 19 | use rustc_span::Span;
|
20 | 20 | use std::{cmp, fmt};
|
@@ -43,41 +43,54 @@ impl<'tcx> fmt::Display for Discr<'tcx> {
|
43 | 43 | }
|
44 | 44 | }
|
45 | 45 |
|
| 46 | +fn signed_min(size: Size) -> i128 { |
| 47 | + sign_extend(1_u128 << (size.bits() - 1), size) as i128 |
| 48 | +} |
| 49 | + |
| 50 | +fn signed_max(size: Size) -> i128 { |
| 51 | + i128::max_value() >> (128 - size.bits()) |
| 52 | +} |
| 53 | + |
| 54 | +fn unsigned_max(size: Size) -> u128 { |
| 55 | + u128::max_value() >> (128 - size.bits()) |
| 56 | +} |
| 57 | + |
| 58 | +fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) { |
| 59 | + let (int, signed) = match ty.kind { |
| 60 | + Int(ity) => (Integer::from_attr(&tcx, SignedInt(ity)), true), |
| 61 | + Uint(uty) => (Integer::from_attr(&tcx, UnsignedInt(uty)), false), |
| 62 | + _ => bug!("non integer discriminant"), |
| 63 | + }; |
| 64 | + (int.size(), signed) |
| 65 | +} |
| 66 | + |
46 | 67 | impl<'tcx> Discr<'tcx> {
|
47 | 68 | /// Adds `1` to the value and wraps around if the maximum for the type is reached.
|
48 | 69 | pub fn wrap_incr(self, tcx: TyCtxt<'tcx>) -> Self {
|
49 | 70 | self.checked_add(tcx, 1).0
|
50 | 71 | }
|
51 | 72 | pub fn checked_add(self, tcx: TyCtxt<'tcx>, n: u128) -> (Self, bool) {
|
52 |
| - let (int, signed) = match self.ty.kind { |
53 |
| - Int(ity) => (Integer::from_attr(&tcx, SignedInt(ity)), true), |
54 |
| - Uint(uty) => (Integer::from_attr(&tcx, UnsignedInt(uty)), false), |
55 |
| - _ => bug!("non integer discriminant"), |
56 |
| - }; |
57 |
| - |
58 |
| - let size = int.size(); |
59 |
| - let bit_size = int.size().bits(); |
60 |
| - let shift = 128 - bit_size; |
61 |
| - if signed { |
62 |
| - let sext = |u| sign_extend(u, size) as i128; |
63 |
| - let min = sext(1_u128 << (bit_size - 1)); |
64 |
| - let max = i128::max_value() >> shift; |
65 |
| - let val = sext(self.val); |
| 73 | + let (size, signed) = int_size_and_signed(tcx, self.ty); |
| 74 | + let (val, oflo) = if signed { |
| 75 | + let min = signed_min(size); |
| 76 | + let max = signed_max(size); |
| 77 | + let val = sign_extend(self.val, size) as i128; |
66 | 78 | assert!(n < (i128::max_value() as u128));
|
67 | 79 | let n = n as i128;
|
68 | 80 | let oflo = val > max - n;
|
69 | 81 | let val = if oflo { min + (n - (max - val) - 1) } else { val + n };
|
70 | 82 | // zero the upper bits
|
71 | 83 | let val = val as u128;
|
72 | 84 | let val = truncate(val, size);
|
73 |
| - (Self { val: val as u128, ty: self.ty }, oflo) |
| 85 | + (val, oflo) |
74 | 86 | } else {
|
75 |
| - let max = u128::max_value() >> shift; |
| 87 | + let max = unsigned_max(size); |
76 | 88 | let val = self.val;
|
77 | 89 | let oflo = val > max - n;
|
78 | 90 | let val = if oflo { n - (max - val) - 1 } else { val + n };
|
79 |
| - (Self { val: val, ty: self.ty }, oflo) |
80 |
| - } |
| 91 | + (val, oflo) |
| 92 | + }; |
| 93 | + (Self { val, ty: self.ty }, oflo) |
81 | 94 | }
|
82 | 95 | }
|
83 | 96 |
|
@@ -621,6 +634,44 @@ impl<'tcx> TyCtxt<'tcx> {
|
621 | 634 | }
|
622 | 635 |
|
623 | 636 | impl<'tcx> ty::TyS<'tcx> {
|
| 637 | + /// Returns the maximum value for the given numeric type (including `char`s) |
| 638 | + /// or returns `None` if the type is not numeric. |
| 639 | + pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> { |
| 640 | + let val = match self.kind { |
| 641 | + ty::Int(_) | ty::Uint(_) => { |
| 642 | + let (size, signed) = int_size_and_signed(tcx, self); |
| 643 | + let val = if signed { signed_max(size) as u128 } else { unsigned_max(size) }; |
| 644 | + Some(val) |
| 645 | + } |
| 646 | + ty::Char => Some(std::char::MAX as u128), |
| 647 | + ty::Float(fty) => Some(match fty { |
| 648 | + ast::FloatTy::F32 => ::rustc_apfloat::ieee::Single::INFINITY.to_bits(), |
| 649 | + ast::FloatTy::F64 => ::rustc_apfloat::ieee::Double::INFINITY.to_bits(), |
| 650 | + }), |
| 651 | + _ => None, |
| 652 | + }; |
| 653 | + val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) |
| 654 | + } |
| 655 | + |
| 656 | + /// Returns the minimum value for the given numeric type (including `char`s) |
| 657 | + /// or returns `None` if the type is not numeric. |
| 658 | + pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> { |
| 659 | + let val = match self.kind { |
| 660 | + ty::Int(_) | ty::Uint(_) => { |
| 661 | + let (size, signed) = int_size_and_signed(tcx, self); |
| 662 | + let val = if signed { truncate(signed_min(size) as u128, size) } else { 0 }; |
| 663 | + Some(val) |
| 664 | + } |
| 665 | + ty::Char => Some(0), |
| 666 | + ty::Float(fty) => Some(match fty { |
| 667 | + ast::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(), |
| 668 | + ast::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(), |
| 669 | + }), |
| 670 | + _ => None, |
| 671 | + }; |
| 672 | + val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) |
| 673 | + } |
| 674 | + |
624 | 675 | /// Checks whether values of this type `T` are *moved* or *copied*
|
625 | 676 | /// when referenced -- this amounts to a check for whether `T:
|
626 | 677 | /// Copy`, but note that we **don't** consider lifetimes when
|
|
0 commit comments