diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 693fc9ba2f327..0d389b31f9075 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::{ @@ -386,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 { diff --git a/src/test/mir-opt/const_prop/slice_len.rs b/src/test/mir-opt/const_prop/slice_len.rs index 3435ca07f4cd8..5babeb195a826 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; // }