about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/transform/const_prop.rs53
-rw-r--r--src/test/mir-opt/const_prop/cast.rs49
-rw-r--r--src/test/ui/consts/const-prop-overflowing-casts.rs9
-rw-r--r--src/test/ui/consts/const-prop-overflowing-casts.stderr22
-rw-r--r--src/test/ui/simd/simd-intrinsic-generic-cast.rs1
5 files changed, 127 insertions, 7 deletions
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index c36f7935115..8de85aab6e3 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -12,10 +12,10 @@ use rustc::mir::visit::{
     MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
 };
 use rustc::mir::{
-    read_only, AggregateKind, BasicBlock, BinOp, Body, BodyAndCache, ClearCrossCrate, Constant,
-    Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, ReadOnlyBodyAndCache, Rvalue,
-    SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind,
-    UnOp, RETURN_PLACE,
+    read_only, AggregateKind, BasicBlock, BinOp, Body, BodyAndCache, CastKind, ClearCrossCrate,
+    Constant, Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase,
+    ReadOnlyBodyAndCache, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement,
+    StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE,
 };
 use rustc::ty::layout::{
     HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout,
@@ -29,9 +29,9 @@ use syntax_pos::{Span, DUMMY_SP};
 
 use crate::const_eval::error_to_const_error;
 use crate::interpret::{
-    self, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx,
-    LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
-    ScalarMaybeUndef, StackPopCleanup,
+    self, intern_const_alloc_recursive, truncate, AllocId, Allocation, Frame, ImmTy, Immediate,
+    InterpCx, LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy,
+    Pointer, ScalarMaybeUndef, StackPopCleanup,
 };
 use crate::rustc::ty::subst::Subst;
 use crate::transform::{MirPass, MirSource};
@@ -584,6 +584,45 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                 }
             }
 
+            Rvalue::Cast(CastKind::Misc, op, ty) => {
+                trace!("checking Cast(Misc, {:?}, {:?})", op, ty);
+
+                if ty.is_integral() && op.ty(&self.local_decls, self.tcx).is_integral() {
+                    let value = self.use_ecx(source_info, |this| {
+                        this.ecx.read_immediate(this.ecx.eval_operand(op, None)?)
+                    })?;
+
+                    // Do not try to read bits for ZSTs
+                    if !value.layout.is_zst() {
+                        let value_size = value.layout.size;
+                        let value_bits = value.to_scalar().and_then(|r| r.to_bits(value_size));
+                        if let Ok(value_bits) = value_bits {
+                            let truncated = truncate(value_bits, place_layout.size);
+                            if truncated != value_bits {
+                                let scope = source_info.scope;
+                                let lint_root = match &self.source_scopes[scope].local_data {
+                                    ClearCrossCrate::Set(data) => data.lint_root,
+                                    ClearCrossCrate::Clear => return None,
+                                };
+                                self.tcx.lint_hir(
+                                    ::rustc::lint::builtin::CONST_ERR,
+                                    lint_root,
+                                    span,
+                                    &format!(
+                                        "truncating cast: the value {} requires {} bits but \
+                                              the target type is only {} bits",
+                                        value_bits,
+                                        value_size.bits(),
+                                        place_layout.size.bits()
+                                    ),
+                                );
+                                return None;
+                            }
+                        }
+                    }
+                }
+            }
+
             _ => {}
         }
 
diff --git a/src/test/mir-opt/const_prop/cast.rs b/src/test/mir-opt/const_prop/cast.rs
new file mode 100644
index 00000000000..9cfbfebdcc3
--- /dev/null
+++ b/src/test/mir-opt/const_prop/cast.rs
@@ -0,0 +1,49 @@
+fn main() {
+    let x = 42u8 as u32;
+
+    let y = 42u32 as u8;
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// let mut _0: ();
+// let _1: u32;
+// scope 1 {
+//   debug x => _1;
+//   let _2: u8;
+//   scope 2 {
+//     debug y => _2;
+//   }
+// }
+// bb0: {
+//   StorageLive(_1);
+//   _1 = const 42u8 as u32 (Misc);
+//   StorageLive(_2);
+//   _2 = const 42u32 as u8 (Misc);
+//   _0 = ();
+//   StorageDead(_2);
+//   StorageDead(_1);
+//   return;
+// }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// let mut _0: ();
+// let _1: u32;
+// scope 1 {
+//   debug x => _1;
+//   let _2: u8;
+//   scope 2 {
+//     debug y => _2;
+//   }
+// }
+// bb0: {
+//   StorageLive(_1);
+//   _1 = const 42u32;
+//   StorageLive(_2);
+//   _2 = const 42u8;
+//   _0 = ();
+//   StorageDead(_2);
+//   StorageDead(_1);
+//   return;
+// }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/ui/consts/const-prop-overflowing-casts.rs b/src/test/ui/consts/const-prop-overflowing-casts.rs
new file mode 100644
index 00000000000..11a04611487
--- /dev/null
+++ b/src/test/ui/consts/const-prop-overflowing-casts.rs
@@ -0,0 +1,9 @@
+// build-fail
+// ignore-tidy-linelength
+
+fn main() {
+    let _ = 0u8 as u32;
+    let _ = (1u32 << 31) as u16; //~ ERROR truncating cast: the value 2147483648 requires 32 bits but the target type is only 16 bits
+    let _ = (1u16 << 15) as u8; //~ ERROR truncating cast: the value 32768 requires 16 bits but the target type is only 8 bits
+    let _ = (!0u16) as u8; //~ ERROR truncating cast: the value 65535 requires 16 bits but the target type is only 8 bits
+}
diff --git a/src/test/ui/consts/const-prop-overflowing-casts.stderr b/src/test/ui/consts/const-prop-overflowing-casts.stderr
new file mode 100644
index 00000000000..af4e2c7005a
--- /dev/null
+++ b/src/test/ui/consts/const-prop-overflowing-casts.stderr
@@ -0,0 +1,22 @@
+error: truncating cast: the value 2147483648 requires 32 bits but the target type is only 16 bits
+  --> $DIR/const-prop-overflowing-casts.rs:6:13
+   |
+LL |     let _ = (1u32 << 31) as u16;
+   |             ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[deny(const_err)]` on by default
+
+error: truncating cast: the value 32768 requires 16 bits but the target type is only 8 bits
+  --> $DIR/const-prop-overflowing-casts.rs:7:13
+   |
+LL |     let _ = (1u16 << 15) as u8;
+   |             ^^^^^^^^^^^^^^^^^^
+
+error: truncating cast: the value 65535 requires 16 bits but the target type is only 8 bits
+  --> $DIR/const-prop-overflowing-casts.rs:8:13
+   |
+LL |     let _ = (!0u16) as u8;
+   |             ^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/simd/simd-intrinsic-generic-cast.rs b/src/test/ui/simd/simd-intrinsic-generic-cast.rs
index 15f232e2c0f..b81a76851d3 100644
--- a/src/test/ui/simd/simd-intrinsic-generic-cast.rs
+++ b/src/test/ui/simd/simd-intrinsic-generic-cast.rs
@@ -4,6 +4,7 @@
 
 #![feature(repr_simd, platform_intrinsics, concat_idents, test)]
 #![allow(non_camel_case_types)]
+#![allow(const_err)] // the test macro casts i32s to i8 and u8 which causes lots of warnings
 
 extern crate test;