From bc17936c8a466e56d472b811e0aca0cf8ffdf9a1 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Tue, 3 Sep 2019 21:56:15 -0400 Subject: [PATCH] [const-prop] Replace `eval_place()` with use of `InterpCx` --- src/librustc/mir/interpret/error.rs | 12 ++++ src/librustc_mir/interpret/eval_context.rs | 3 +- src/librustc_mir/interpret/operand.rs | 2 +- src/librustc_mir/interpret/place.rs | 9 +++ src/librustc_mir/transform/const_prop.rs | 56 ++----------------- src/test/mir-opt/const_prop/slice_len.rs | 2 +- src/test/ui/consts/const-eval/issue-50814.rs | 1 + .../ui/consts/const-eval/issue-50814.stderr | 12 +++- src/test/ui/issues/issue-52060.stderr | 3 +- 9 files changed, 43 insertions(+), 57 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index ac99ccd45eaf..0328f93859bb 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -389,6 +389,14 @@ pub enum UnsupportedOpInfo<'tcx> { /// Free-form case. Only for errors that are never caught! Unsupported(String), + /// Error used by the `ConstProp` pass when an attempt is made + /// to read an uninitialized local. + UninitializedLocal, + + /// Error used by the `ConstProp` pass to prevent reading statics + /// while evaluating `const` items. + ReadOfStaticInConst, + // -- Everything below is not categorized yet -- FunctionAbiMismatch(Abi, Abi), FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>), @@ -511,6 +519,8 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { addresses, e.g., comparing pointers into different allocations"), DeadLocal => write!(f, "tried to access a dead local variable"), + UninitializedLocal => + write!(f, "tried to access an uninitialized local variable"), DerefFunctionPointer => write!(f, "tried to dereference a function pointer"), ExecuteMemory => @@ -552,6 +562,8 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { not a power of two"), Unsupported(ref msg) => write!(f, "{}", msg), + ReadOfStaticInConst => + write!(f, "tried to read from a static during const evaluation"), } } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index fdf85260c3d9..7ca14b51740a 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -134,8 +134,7 @@ impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { pub fn access(&self) -> InterpResult<'tcx, Operand> { match self.value { LocalValue::Dead => throw_unsup!(DeadLocal), - LocalValue::Uninitialized => - bug!("The type checker should prevent reading from a never-written local"), + LocalValue::Uninitialized => throw_unsup!(UninitializedLocal), LocalValue::Live(val) => Ok(val), } } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index f5d1ec3eb755..89af0031bfd2 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -481,7 +481,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Evaluate a place with the goal of reading from it. This lets us sometimes // avoid allocations. - pub(super) fn eval_place_to_op( + pub fn eval_place_to_op( &self, place: &mir::Place<'tcx>, layout: Option>, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 2f1b35757fe9..f9ba1452d64f 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -597,6 +597,15 @@ where } StaticKind::Static => { + //if the first frame on the stack isn't a static item, then we shouldn't + //eval any static places (unless -Z unleash-the-miri-inside-of-you is on) + if let ty::InstanceDef::Item(item_def_id) = self.stack[0].instance.def { + if !self.tcx.is_static(item_def_id) && + !self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { + trace!("eval_static_to_mplace: can't eval static in constant"); + throw_unsup!(ReadOfStaticInConst); + } + } let ty = place_static.ty; assert!(!ty.needs_subst()); let layout = self.layout_of(ty)?; diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 857757ada53b..ff1a7c2c48fd 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -6,14 +6,14 @@ use std::cell::Cell; use rustc::hir::def::DefKind; use rustc::mir::{ AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, - Local, NullOp, UnOp, StatementKind, Statement, LocalKind, Static, StaticKind, - TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem, + Local, NullOp, UnOp, StatementKind, Statement, LocalKind, + TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, SourceScope, SourceScopeLocalData, LocalDecl, }; use rustc::mir::visit::{ Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext, }; -use rustc::mir::interpret::{Scalar, GlobalId, InterpResult, PanicInfo}; +use rustc::mir::interpret::{Scalar, InterpResult, PanicInfo}; use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; use syntax_pos::{Span, DUMMY_SP}; use rustc::ty::subst::InternalSubsts; @@ -282,53 +282,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option> { trace!("eval_place(place={:?})", place); - let mut eval = match place.base { - PlaceBase::Local(loc) => self.get_const(loc).clone()?, - PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => { - let generics = self.tcx.generics_of(self.source.def_id()); - if generics.requires_monomorphization(self.tcx) { - // FIXME: can't handle code with generics - return None; - } - let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id()); - let instance = Instance::new(self.source.def_id(), substs); - let cid = GlobalId { - instance, - promoted: Some(promoted), - }; - let res = self.use_ecx(source_info, |this| { - this.ecx.const_eval_raw(cid) - })?; - trace!("evaluated promoted {:?} to {:?}", promoted, res); - res.into() - } - _ => return None, - }; - - for (i, elem) in place.projection.iter().enumerate() { - let proj_base = &place.projection[..i]; - - match elem { - ProjectionElem::Field(field, _) => { - trace!("field proj on {:?}", proj_base); - eval = self.use_ecx(source_info, |this| { - 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. - _ => return None, - } - } - - Some(eval) + self.use_ecx(source_info, |this| { + this.ecx.eval_place_to_op(place, None) + }) } fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option> { diff --git a/src/test/mir-opt/const_prop/slice_len.rs b/src/test/mir-opt/const_prop/slice_len.rs index 5babeb195a82..05595ce147c9 100644 --- a/src/test/mir-opt/const_prop/slice_len.rs +++ b/src/test/mir-opt/const_prop/slice_len.rs @@ -34,7 +34,7 @@ fn main() { // assert(const true, "index out of bounds: the len is move _7 but the index is _6") -> bb1; // } // bb1: { -// _1 = (*_2)[_6]; +// _1 = const 2u32; // ... // return; // } diff --git a/src/test/ui/consts/const-eval/issue-50814.rs b/src/test/ui/consts/const-eval/issue-50814.rs index b85cecda16e9..274967ef60de 100644 --- a/src/test/ui/consts/const-eval/issue-50814.rs +++ b/src/test/ui/consts/const-eval/issue-50814.rs @@ -11,6 +11,7 @@ struct Sum(A,B); impl Unsigned for Sum { const MAX: u8 = A::MAX + B::MAX; //~ ERROR any use of this value will cause an error + //~| ERROR any use of this value will cause an error } fn foo(_: T) -> &'static u8 { diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr index 707dfee7cd5b..de3459c72dd2 100644 --- a/src/test/ui/consts/const-eval/issue-50814.stderr +++ b/src/test/ui/consts/const-eval/issue-50814.stderr @@ -9,13 +9,21 @@ LL | const MAX: u8 = A::MAX + B::MAX; = note: `#[deny(const_err)]` on by default error[E0080]: evaluation of constant expression failed - --> $DIR/issue-50814.rs:17:5 + --> $DIR/issue-50814.rs:18:5 | LL | &Sum::::MAX | ^----------------- | | | referenced constant has errors -error: aborting due to 2 previous errors +error: any use of this value will cause an error + --> $DIR/issue-50814.rs:13:21 + | +LL | const MAX: u8 = A::MAX + B::MAX; + | ----------------^^^^^^^^^^^^^^^- + | | + | attempt to add with overflow + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/issues/issue-52060.stderr b/src/test/ui/issues/issue-52060.stderr index 2f90f7f9e035..6fbc1ed52c47 100644 --- a/src/test/ui/issues/issue-52060.stderr +++ b/src/test/ui/issues/issue-52060.stderr @@ -6,4 +6,5 @@ LL | static B: [u32; 1] = [0; A.len()]; error: aborting due to previous error -For more information about this error, try `rustc --explain E0013`. +Some errors have detailed explanations: E0013, E0080. +For more information about an error, try `rustc --explain E0013`.