Skip to content

Commit

Permalink
Rollup merge of rust-lang#61532 - wesleywiser:const_prop_more, r=oli-obk
Browse files Browse the repository at this point in the history
[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.~~
  • Loading branch information
Centril committed Jun 7, 2019
2 parents d3fa451 + 459e37b commit a56a2dd
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 30 deletions.
17 changes: 17 additions & 0 deletions src/librustc_mir/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
51 changes: 39 additions & 12 deletions src/librustc_mir/transform/const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand Down Expand Up @@ -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| {
Expand Down
21 changes: 21 additions & 0 deletions src/test/mir-opt/const_prop/ref_deref.rs
Original file line number Diff line number Diff line change
@@ -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
25 changes: 25 additions & 0 deletions src/test/mir-opt/const_prop/reify_fn_ptr.rs
Original file line number Diff line number Diff line change
@@ -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
40 changes: 22 additions & 18 deletions src/test/mir-opt/const_prop/slice_len.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,40 @@
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;
// }
// END rustc.main.ConstProp.before.mir
// 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;
// }
Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/consts/const-eval/promoted_errors.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand All @@ -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
|
Expand Down

0 comments on commit a56a2dd

Please sign in to comment.