about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-06-07 16:48:03 +0200
committerGitHub <noreply@github.com>2019-06-07 16:48:03 +0200
commitde6bc12868569e32beecfe6ded4142aaf6a7434f (patch)
treec7cf97847b3ef628bfd0804ced08683070e4128a
parent9ab654c53e17c5d7a2efe25cf859472fd5b9e03c (diff)
parent459e37b304f62659b59215eed57da991873b3445 (diff)
downloadrust-de6bc12868569e32beecfe6ded4142aaf6a7434f.tar.gz
rust-de6bc12868569e32beecfe6ded4142aaf6a7434f.zip
Rollup merge of #61532 - wesleywiser:const_prop_more, r=oli-obk
[const-prop] Support Rvalue::{Ref,Len} and Deref

Also fixes an ICE I found in testing.

r? @oli-obk

~~The final commit is just for a perf run. I'll remove it after that is completed.~~
-rw-r--r--src/librustc_mir/interpret/place.rs17
-rw-r--r--src/librustc_mir/transform/const_prop.rs51
-rw-r--r--src/test/mir-opt/const_prop/ref_deref.rs21
-rw-r--r--src/test/mir-opt/const_prop/reify_fn_ptr.rs25
-rw-r--r--src/test/mir-opt/const_prop/slice_len.rs40
-rw-r--r--src/test/ui/consts/const-eval/promoted_errors.stderr12
6 files changed, 136 insertions, 30 deletions
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index fac9665d968..a3297666113 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -663,6 +663,23 @@ where
         Ok(())
     }
 
+    /// Write an `Immediate` to memory.
+    #[inline(always)]
+    pub fn write_immediate_to_mplace(
+        &mut self,
+        src: Immediate<M::PointerTag>,
+        dest: MPlaceTy<'tcx, M::PointerTag>,
+    ) -> EvalResult<'tcx> {
+        self.write_immediate_to_mplace_no_validate(src, dest)?;
+
+        if M::enforce_validity(self) {
+            // Data got changed, better make sure it matches the type!
+            self.validate_operand(dest.into(), vec![], None, /*const_mode*/ false)?;
+        }
+
+        Ok(())
+    }
+
     /// Write an immediate to a place.
     /// If you use this you are responsible for validating that things got copied at the
     /// right type.
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index dbaa4e557c6..0d389b31f90 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -17,8 +17,7 @@ use syntax_pos::{Span, DUMMY_SP};
 use rustc::ty::subst::InternalSubsts;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc::ty::layout::{
-    LayoutOf, TyLayout, LayoutError,
-    HasTyCtxt, TargetDataLayout, HasDataLayout,
+    LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, Size,
 };
 
 use crate::interpret::{
@@ -333,6 +332,12 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
                             this.ecx.operand_field(eval, field.index() as u64)
                         })?;
                     },
+                    ProjectionElem::Deref => {
+                        trace!("processing deref");
+                        eval = self.use_ecx(source_info, |this| {
+                            this.ecx.deref_operand(eval)
+                        })?.into();
+                    }
                     // We could get more projections by using e.g., `operand_projection`,
                     // but we do not even have the stack frame set up properly so
                     // an `Index` projection would throw us off-track.
@@ -363,8 +368,12 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
             Rvalue::Use(ref op) => {
                 self.eval_operand(op, source_info)
             },
+            Rvalue::Ref(_, _, ref place) => {
+                let src = self.eval_place(place, source_info)?;
+                let mplace = src.try_as_mplace().ok()?;
+                Some(ImmTy::from_scalar(mplace.ptr.into(), place_layout).into())
+            },
             Rvalue::Repeat(..) |
-            Rvalue::Ref(..) |
             Rvalue::Aggregate(..) |
             Rvalue::NullaryOp(NullOp::Box, _) |
             Rvalue::Discriminant(..) => None,
@@ -376,10 +385,30 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
                     this.ecx.cast(op, kind, dest.into())?;
                     Ok(dest.into())
                 })
-            }
+            },
+            Rvalue::Len(ref place) => {
+                let place = self.eval_place(&place, source_info)?;
+                let mplace = place.try_as_mplace().ok()?;
+
+                if let ty::Slice(_) = mplace.layout.ty.sty {
+                    let len = mplace.meta.unwrap().to_usize(&self.ecx).unwrap();
 
-            // FIXME(oli-obk): evaluate static/constant slice lengths
-            Rvalue::Len(_) => None,
+                    Some(ImmTy {
+                        imm: Immediate::Scalar(
+                            Scalar::from_uint(
+                                len,
+                                Size::from_bits(
+                                    self.tcx.sess.target.usize_ty.bit_width().unwrap() as u64
+                                )
+                            ).into(),
+                        ),
+                        layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
+                    }.into())
+                } else {
+                    trace!("not slice: {:?}", mplace.layout.ty.sty);
+                    None
+                }
+            },
             Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
                 type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some(
                     ImmTy {
@@ -525,12 +554,10 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
         source_info: SourceInfo,
     ) {
         trace!("attepting to replace {:?} with {:?}", rval, value);
-        self.ecx.validate_operand(
-            value,
-            vec![],
-            None,
-            true,
-        ).expect("value should already be a valid const");
+        if let Err(e) = self.ecx.validate_operand(value, vec![], None, true) {
+            trace!("validation error, attempt failed: {:?}", e);
+            return;
+        }
 
         // FIXME> figure out what tho do when try_read_immediate fails
         let imm = self.use_ecx(source_info, |this| {
diff --git a/src/test/mir-opt/const_prop/ref_deref.rs b/src/test/mir-opt/const_prop/ref_deref.rs
new file mode 100644
index 00000000000..2d04822c0e7
--- /dev/null
+++ b/src/test/mir-opt/const_prop/ref_deref.rs
@@ -0,0 +1,21 @@
+fn main() {
+    *(&4);
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+//     ...
+//     _2 = &(promoted[0]: i32);
+//     _1 = (*_2);
+//     ...
+//}
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+//     ...
+//     _2 = const Scalar(AllocId(0).0x0) : &i32;
+//     _1 = const 4i32;
+//     ...
+// }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.rs b/src/test/mir-opt/const_prop/reify_fn_ptr.rs
new file mode 100644
index 00000000000..809eb19ade8
--- /dev/null
+++ b/src/test/mir-opt/const_prop/reify_fn_ptr.rs
@@ -0,0 +1,25 @@
+fn main() {
+    let _ = main as usize as *const fn();
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+//  bb0: {
+//      ...
+//      _3 = const main as fn() (Pointer(ReifyFnPointer));
+//      _2 = move _3 as usize (Misc);
+//      ...
+//      _1 = move _2 as *const fn() (Misc);
+//      ...
+//  }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+//  bb0: {
+//      ...
+//      _3 = const Scalar(AllocId(1).0x0) : fn();
+//      _2 = move _3 as usize (Misc);
+//      ...
+//      _1 = const Scalar(AllocId(1).0x0) : *const fn();
+//      ...
+//  }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/slice_len.rs b/src/test/mir-opt/const_prop/slice_len.rs
index 3435ca07f4c..5babeb195a8 100644
--- a/src/test/mir-opt/const_prop/slice_len.rs
+++ b/src/test/mir-opt/const_prop/slice_len.rs
@@ -1,22 +1,22 @@
-fn test() -> &'static [u32] {
-    &[1, 2]
-}
-
 fn main() {
-    let x = test()[0];
+    (&[1u32, 2, 3] as &[u32])[1];
 }
 
 // END RUST SOURCE
 // START rustc.main.ConstProp.before.mir
-//  bb1: {
+//  bb0: {
 //      ...
-//      _3 = const 0usize;
-//      _4 = Len((*_2));
-//      _5 = Lt(_3, _4);
-//      assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2;
+//      _4 = &(promoted[0]: [u32; 3]);
+//      _3 = _4;
+//      _2 = move _3 as &[u32] (Pointer(Unsize));
+//      ...
+//      _6 = const 1usize;
+//      _7 = Len((*_2));
+//      _8 = Lt(_6, _7);
+//      assert(move _8, "index out of bounds: the len is move _7 but the index is _6") -> bb1;
 //  }
-//  bb2: {
-//      _1 = (*_2)[_3];
+//  bb1: {
+//      _1 = (*_2)[_6];
 //      ...
 //      return;
 //  }
@@ -24,13 +24,17 @@ fn main() {
 // START rustc.main.ConstProp.after.mir
 //  bb0: {
 //      ...
-//      _3 = const 0usize;
-//      _4 = Len((*_2));
-//      _5 = Lt(_3, _4);
-//      assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2;
+//      _4 = const Scalar(AllocId(0).0x0) : &[u32; 3];
+//      _3 = const Scalar(AllocId(0).0x0) : &[u32; 3];
+//      _2 = move _3 as &[u32] (Pointer(Unsize));
+//      ...
+//      _6 = const 1usize;
+//      _7 = const 3usize;
+//      _8 = const true;
+//      assert(const true, "index out of bounds: the len is move _7 but the index is _6") -> bb1;
 //  }
-//  bb2: {
-//      _1 = (*_2)[_3];
+//  bb1: {
+//      _1 = (*_2)[_6];
 //      ...
 //      return;
 //  }
diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr
index c9d5ede61ad..c9f3a7659f9 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.stderr
@@ -16,6 +16,12 @@ warning: attempt to divide by zero
 LL |     println!("{}", 1/(1-1));
    |                    ^^^^^^^
 
+warning: this expression will panic at runtime
+  --> $DIR/promoted_errors.rs:9:20
+   |
+LL |     println!("{}", 1/(1-1));
+   |                    ^^^^^^^ attempt to divide by zero
+
 warning: attempt to divide by zero
   --> $DIR/promoted_errors.rs:11:14
    |
@@ -34,6 +40,12 @@ warning: attempt to divide by zero
 LL |     println!("{}", 1/(false as u32));
    |                    ^^^^^^^^^^^^^^^^
 
+warning: this expression will panic at runtime
+  --> $DIR/promoted_errors.rs:14:20
+   |
+LL |     println!("{}", 1/(false as u32));
+   |                    ^^^^^^^^^^^^^^^^ attempt to divide by zero
+
 warning: attempt to divide by zero
   --> $DIR/promoted_errors.rs:16:14
    |