[const-prop] Replace eval_place() with use of InterpCx

This commit is contained in:
Wesley Wiser 2019-09-03 21:56:15 -04:00
parent 59367b074f
commit bc17936c8a
9 changed files with 43 additions and 57 deletions

View file

@ -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"),
}
}
}

View file

@ -134,8 +134,7 @@ impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> {
pub fn access(&self) -> InterpResult<'tcx, Operand<Tag>> {
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),
}
}

View file

@ -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<TyLayout<'tcx>>,

View file

@ -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)?;

View file

@ -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<Const<'tcx>> {
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<Const<'tcx>> {

View file

@ -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;
// }

View file

@ -11,6 +11,7 @@ struct Sum<A,B>(A,B);
impl<A: Unsigned, B: Unsigned> Unsigned for Sum<A,B> {
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>(_: T) -> &'static u8 {

View file

@ -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::<U8,U8>::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`.

View file

@ -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`.