|
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