]> git.lizzy.rs Git - rust.git/commitdiff
Fix the conversion between bit representations and i128 representations
authorOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Thu, 22 Mar 2018 11:38:40 +0000 (12:38 +0100)
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Thu, 22 Mar 2018 11:38:40 +0000 (12:38 +0100)
src/librustc/ty/layout.rs
src/librustc/ty/mod.rs
src/librustc/ty/util.rs
src/test/run-pass/ctfe/signed_enum_discr.rs [new file with mode: 0644]

index 3a3f10cb87db4c6d5d74b56423fecf919079ff5e..029dd6f1fb466662046c0cd0a2e1ec052771023b 100644 (file)
@@ -1544,11 +1544,17 @@ enum StructKind {
                 }
 
                 let (mut min, mut max) = (i128::max_value(), i128::min_value());
+                let discr_type = def.repr.discr_type();
+                let bits = Integer::from_attr(tcx, discr_type).size().bits();
                 for (i, discr) in def.discriminants(tcx).enumerate() {
                     if variants[i].iter().any(|f| f.abi == Abi::Uninhabited) {
                         continue;
                     }
-                    let x = discr.val as i128;
+                    let mut x = discr.val as i128;
+                    if discr_type.is_signed() {
+                        // sign extend the raw representation to be an i128
+                        x = (x << (128 - bits)) >> (128 - bits);
+                    }
                     if x < min { min = x; }
                     if x > max { max = x; }
                 }
index c915022351925f835a8afc49de54dd2b082425f7..9ffdccefae58569bfcc0c1acb9ee1aa06ba2e848 100644 (file)
@@ -1886,7 +1886,6 @@ pub fn eval_explicit_discr(
     ) -> Option<Discr<'tcx>> {
         let param_env = ParamEnv::empty();
         let repr_type = self.repr.discr_type();
-        let bit_size = layout::Integer::from_attr(tcx, repr_type).size().bits();
         let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
         let instance = ty::Instance::new(expr_did, substs);
         let cid = GlobalId {
@@ -1896,25 +1895,13 @@ pub fn eval_explicit_discr(
         match tcx.const_eval(param_env.and(cid)) {
             Ok(&ty::Const {
                 val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
-                ..
+                ty,
             }) => {
                 trace!("discriminants: {} ({:?})", b, repr_type);
-                let ty = repr_type.to_ty(tcx);
-                if repr_type.is_signed() {
-                    let val = b as i128;
-                    // sign extend to i128
-                    let amt = 128 - bit_size;
-                    let val = (val << amt) >> amt;
-                    Some(Discr {
-                        val: val as u128,
-                        ty,
-                    })
-                } else {
-                    Some(Discr {
-                        val: b,
-                        ty,
-                    })
-                }
+                Some(Discr {
+                    val: b,
+                    ty,
+                })
             },
             Ok(&ty::Const {
                 val: ConstVal::Value(other),
index 91d460a96f785725eea068e89dce00f6bbbe1567..afe977d10baac333ff9c8b3ed3ebe500d1633062 100644 (file)
 
 #[derive(Copy, Clone, Debug)]
 pub struct Discr<'tcx> {
+    /// bit representation of the discriminant, so `-128i8` is `0xFF_u128`
     pub val: u128,
     pub ty: Ty<'tcx>
 }
 
 impl<'tcx> fmt::Display for Discr<'tcx> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        if self.ty.is_signed() {
-            write!(fmt, "{}", self.val as i128)
-        } else {
-            write!(fmt, "{}", self.val)
+        match self.ty.sty {
+            ty::TyInt(ity) => {
+                let bits = ty::tls::with(|tcx| {
+                    Integer::from_attr(tcx, SignedInt(ity)).size().bits()
+                });
+                let x = self.val as i128;
+                // sign extend the raw representation to be an i128
+                let x = (x << (128 - bits)) >> (128 - bits);
+                write!(fmt, "{}", x)
+            },
+            _ => write!(fmt, "{}", self.val),
         }
     }
 }
@@ -64,15 +72,18 @@ pub fn checked_add<'a, 'gcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, n: u128) -> (Sel
             TyUint(uty) => (Integer::from_attr(tcx, UnsignedInt(uty)), false),
             _ => bug!("non integer discriminant"),
         };
+
+        let bit_size = int.size().bits();
+        let amt = 128 - bit_size;
         if signed {
-            let (min, max) = match int {
-                Integer::I8 => (i8::min_value() as i128, i8::max_value() as i128),
-                Integer::I16 => (i16::min_value() as i128, i16::max_value() as i128),
-                Integer::I32 => (i32::min_value() as i128, i32::max_value() as i128),
-                Integer::I64 => (i64::min_value() as i128, i64::max_value() as i128),
-                Integer::I128 => (i128::min_value(), i128::max_value()),
+            let sext = |u| {
+                let i = u as i128;
+                (i << amt) >> amt
             };
-            let val = self.val as i128;
+            let min = sext(1_u128 << (bit_size - 1));
+            let max = i128::max_value() >> amt;
+            let val = sext(self.val);
+            assert!(n < (i128::max_value() as u128));
             let n = n as i128;
             let oflo = val > max - n;
             let val = if oflo {
@@ -80,22 +91,19 @@ pub fn checked_add<'a, 'gcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, n: u128) -> (Sel
             } else {
                 val + n
             };
+            // zero the upper bits
+            let val = val as u128;
+            let val = (val << amt) >> amt;
             (Self {
                 val: val as u128,
                 ty: self.ty,
             }, oflo)
         } else {
-            let (min, max) = match int {
-                Integer::I8 => (u8::min_value() as u128, u8::max_value() as u128),
-                Integer::I16 => (u16::min_value() as u128, u16::max_value() as u128),
-                Integer::I32 => (u32::min_value() as u128, u32::max_value() as u128),
-                Integer::I64 => (u64::min_value() as u128, u64::max_value() as u128),
-                Integer::I128 => (u128::min_value(), u128::max_value()),
-            };
+            let max = u128::max_value() >> amt;
             let val = self.val;
             let oflo = val > max - n;
             let val = if oflo {
-                min + (n - (max - val) - 1)
+                n - (max - val) - 1
             } else {
                 val + n
             };
diff --git a/src/test/run-pass/ctfe/signed_enum_discr.rs b/src/test/run-pass/ctfe/signed_enum_discr.rs
new file mode 100644 (file)
index 0000000..7049d28
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// https://github.com/rust-lang/rust/issues/49181
+
+#[derive(Eq, PartialEq)]
+#[repr(i8)]
+pub enum A {
+    B = -1,
+    C = 1,
+}
+
+pub const D: A = A::B;
+
+fn main() {
+    match A::C {
+        D => {},
+        _ => {}
+    }
+}