Skip to content

Commit de6bc12

Browse files
authored
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.~~
2 parents 9ab654c + 459e37b commit de6bc12

File tree

6 files changed

+136
-30
lines changed

6 files changed

+136
-30
lines changed

src/librustc_mir/interpret/place.rs

+17
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,23 @@ where
663663
Ok(())
664664
}
665665

666+
/// Write an `Immediate` to memory.
667+
#[inline(always)]
668+
pub fn write_immediate_to_mplace(
669+
&mut self,
670+
src: Immediate<M::PointerTag>,
671+
dest: MPlaceTy<'tcx, M::PointerTag>,
672+
) -> EvalResult<'tcx> {
673+
self.write_immediate_to_mplace_no_validate(src, dest)?;
674+
675+
if M::enforce_validity(self) {
676+
// Data got changed, better make sure it matches the type!
677+
self.validate_operand(dest.into(), vec![], None, /*const_mode*/ false)?;
678+
}
679+
680+
Ok(())
681+
}
682+
666683
/// Write an immediate to a place.
667684
/// If you use this you are responsible for validating that things got copied at the
668685
/// right type.

src/librustc_mir/transform/const_prop.rs

+39-12
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ use syntax_pos::{Span, DUMMY_SP};
1717
use rustc::ty::subst::InternalSubsts;
1818
use rustc_data_structures::indexed_vec::IndexVec;
1919
use rustc::ty::layout::{
20-
LayoutOf, TyLayout, LayoutError,
21-
HasTyCtxt, TargetDataLayout, HasDataLayout,
20+
LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, Size,
2221
};
2322

2423
use crate::interpret::{
@@ -333,6 +332,12 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
333332
this.ecx.operand_field(eval, field.index() as u64)
334333
})?;
335334
},
335+
ProjectionElem::Deref => {
336+
trace!("processing deref");
337+
eval = self.use_ecx(source_info, |this| {
338+
this.ecx.deref_operand(eval)
339+
})?.into();
340+
}
336341
// We could get more projections by using e.g., `operand_projection`,
337342
// but we do not even have the stack frame set up properly so
338343
// an `Index` projection would throw us off-track.
@@ -363,8 +368,12 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
363368
Rvalue::Use(ref op) => {
364369
self.eval_operand(op, source_info)
365370
},
371+
Rvalue::Ref(_, _, ref place) => {
372+
let src = self.eval_place(place, source_info)?;
373+
let mplace = src.try_as_mplace().ok()?;
374+
Some(ImmTy::from_scalar(mplace.ptr.into(), place_layout).into())
375+
},
366376
Rvalue::Repeat(..) |
367-
Rvalue::Ref(..) |
368377
Rvalue::Aggregate(..) |
369378
Rvalue::NullaryOp(NullOp::Box, _) |
370379
Rvalue::Discriminant(..) => None,
@@ -376,10 +385,30 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
376385
this.ecx.cast(op, kind, dest.into())?;
377386
Ok(dest.into())
378387
})
379-
}
388+
},
389+
Rvalue::Len(ref place) => {
390+
let place = self.eval_place(&place, source_info)?;
391+
let mplace = place.try_as_mplace().ok()?;
392+
393+
if let ty::Slice(_) = mplace.layout.ty.sty {
394+
let len = mplace.meta.unwrap().to_usize(&self.ecx).unwrap();
380395

381-
// FIXME(oli-obk): evaluate static/constant slice lengths
382-
Rvalue::Len(_) => None,
396+
Some(ImmTy {
397+
imm: Immediate::Scalar(
398+
Scalar::from_uint(
399+
len,
400+
Size::from_bits(
401+
self.tcx.sess.target.usize_ty.bit_width().unwrap() as u64
402+
)
403+
).into(),
404+
),
405+
layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
406+
}.into())
407+
} else {
408+
trace!("not slice: {:?}", mplace.layout.ty.sty);
409+
None
410+
}
411+
},
383412
Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
384413
type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some(
385414
ImmTy {
@@ -525,12 +554,10 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
525554
source_info: SourceInfo,
526555
) {
527556
trace!("attepting to replace {:?} with {:?}", rval, value);
528-
self.ecx.validate_operand(
529-
value,
530-
vec![],
531-
None,
532-
true,
533-
).expect("value should already be a valid const");
557+
if let Err(e) = self.ecx.validate_operand(value, vec![], None, true) {
558+
trace!("validation error, attempt failed: {:?}", e);
559+
return;
560+
}
534561

535562
// FIXME> figure out what tho do when try_read_immediate fails
536563
let imm = self.use_ecx(source_info, |this| {
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
fn main() {
2+
*(&4);
3+
}
4+
5+
// END RUST SOURCE
6+
// START rustc.main.ConstProp.before.mir
7+
// bb0: {
8+
// ...
9+
// _2 = &(promoted[0]: i32);
10+
// _1 = (*_2);
11+
// ...
12+
//}
13+
// END rustc.main.ConstProp.before.mir
14+
// START rustc.main.ConstProp.after.mir
15+
// bb0: {
16+
// ...
17+
// _2 = const Scalar(AllocId(0).0x0) : &i32;
18+
// _1 = const 4i32;
19+
// ...
20+
// }
21+
// END rustc.main.ConstProp.after.mir
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
fn main() {
2+
let _ = main as usize as *const fn();
3+
}
4+
5+
// END RUST SOURCE
6+
// START rustc.main.ConstProp.before.mir
7+
// bb0: {
8+
// ...
9+
// _3 = const main as fn() (Pointer(ReifyFnPointer));
10+
// _2 = move _3 as usize (Misc);
11+
// ...
12+
// _1 = move _2 as *const fn() (Misc);
13+
// ...
14+
// }
15+
// END rustc.main.ConstProp.before.mir
16+
// START rustc.main.ConstProp.after.mir
17+
// bb0: {
18+
// ...
19+
// _3 = const Scalar(AllocId(1).0x0) : fn();
20+
// _2 = move _3 as usize (Misc);
21+
// ...
22+
// _1 = const Scalar(AllocId(1).0x0) : *const fn();
23+
// ...
24+
// }
25+
// END rustc.main.ConstProp.after.mir

src/test/mir-opt/const_prop/slice_len.rs

+22-18
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,40 @@
1-
fn test() -> &'static [u32] {
2-
&[1, 2]
3-
}
4-
51
fn main() {
6-
let x = test()[0];
2+
(&[1u32, 2, 3] as &[u32])[1];
73
}
84

95
// END RUST SOURCE
106
// START rustc.main.ConstProp.before.mir
11-
// bb1: {
7+
// bb0: {
128
// ...
13-
// _3 = const 0usize;
14-
// _4 = Len((*_2));
15-
// _5 = Lt(_3, _4);
16-
// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2;
9+
// _4 = &(promoted[0]: [u32; 3]);
10+
// _3 = _4;
11+
// _2 = move _3 as &[u32] (Pointer(Unsize));
12+
// ...
13+
// _6 = const 1usize;
14+
// _7 = Len((*_2));
15+
// _8 = Lt(_6, _7);
16+
// assert(move _8, "index out of bounds: the len is move _7 but the index is _6") -> bb1;
1717
// }
18-
// bb2: {
19-
// _1 = (*_2)[_3];
18+
// bb1: {
19+
// _1 = (*_2)[_6];
2020
// ...
2121
// return;
2222
// }
2323
// END rustc.main.ConstProp.before.mir
2424
// START rustc.main.ConstProp.after.mir
2525
// bb0: {
2626
// ...
27-
// _3 = const 0usize;
28-
// _4 = Len((*_2));
29-
// _5 = Lt(_3, _4);
30-
// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2;
27+
// _4 = const Scalar(AllocId(0).0x0) : &[u32; 3];
28+
// _3 = const Scalar(AllocId(0).0x0) : &[u32; 3];
29+
// _2 = move _3 as &[u32] (Pointer(Unsize));
30+
// ...
31+
// _6 = const 1usize;
32+
// _7 = const 3usize;
33+
// _8 = const true;
34+
// assert(const true, "index out of bounds: the len is move _7 but the index is _6") -> bb1;
3135
// }
32-
// bb2: {
33-
// _1 = (*_2)[_3];
36+
// bb1: {
37+
// _1 = (*_2)[_6];
3438
// ...
3539
// return;
3640
// }

src/test/ui/consts/const-eval/promoted_errors.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ warning: attempt to divide by zero
1616
LL | println!("{}", 1/(1-1));
1717
| ^^^^^^^
1818

19+
warning: this expression will panic at runtime
20+
--> $DIR/promoted_errors.rs:9:20
21+
|
22+
LL | println!("{}", 1/(1-1));
23+
| ^^^^^^^ attempt to divide by zero
24+
1925
warning: attempt to divide by zero
2026
--> $DIR/promoted_errors.rs:11:14
2127
|
@@ -34,6 +40,12 @@ warning: attempt to divide by zero
3440
LL | println!("{}", 1/(false as u32));
3541
| ^^^^^^^^^^^^^^^^
3642

43+
warning: this expression will panic at runtime
44+
--> $DIR/promoted_errors.rs:14:20
45+
|
46+
LL | println!("{}", 1/(false as u32));
47+
| ^^^^^^^^^^^^^^^^ attempt to divide by zero
48+
3749
warning: attempt to divide by zero
3850
--> $DIR/promoted_errors.rs:16:14
3951
|

0 commit comments

Comments
 (0)