t: T,
) -> InterpResult<'tcx, T> {
match self.stack.last() {
- Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)),
+ Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)?),
None => if t.needs_subst() {
err!(TooGeneric).into()
} else {
&self,
t: T,
substs: SubstsRef<'tcx>
- ) -> T {
+ ) -> InterpResult<'tcx, T> {
// miri doesn't care about lifetimes, and will choke on some crazy ones
// let's simply get rid of them
let substituted = t.subst(*self.tcx, substs);
- self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted)
+
+ if substituted.needs_subst() {
+ return err!(TooGeneric);
+ }
+
+ Ok(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted))
}
pub fn layout_of_local(
None => {
let layout = crate::interpret::operand::from_known_layout(layout, || {
let local_ty = frame.body.local_decls[local].ty;
- let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs);
+ let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs)?;
self.layout_of(local_ty)
})?;
// Layouts of locals are requested a lot, so we cache them.
//! Propagates constants for early reporting of statically known
//! assertion failures
+use std::cell::Cell;
+
use rustc::hir::def::DefKind;
use rustc::mir::{
AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue,
};
use crate::interpret::{
- self, InterpretCx, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind,
+ self, InterpretCx, ScalarMaybeUndef, Immediate, OpTy,
+ ImmTy, MemoryKind, StackPopCleanup, LocalValue, LocalState,
};
use crate::const_eval::{
CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx,
trace!("ConstProp starting for {:?}", source.def_id());
+ // steal some data we need from `body`
+ let source_scope_local_data = std::mem::replace(
+ &mut body.source_scope_local_data,
+ ClearCrossCrate::Clear
+ );
+ let promoted = std::mem::replace(
+ &mut body.promoted,
+ IndexVec::new()
+ );
+
+ let dummy_body =
+ &Body::new(
+ body.basic_blocks().clone(),
+ Default::default(),
+ ClearCrossCrate::Clear,
+ Default::default(),
+ None,
+ body.local_decls.clone(),
+ Default::default(),
+ body.arg_count,
+ Default::default(),
+ tcx.def_span(source.def_id()),
+ Default::default(),
+ );
+
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
// constants, instead of just checking for const-folding succeeding.
// That would require an uniform one-def no-mutation analysis
// and RPO (or recursing when needing the value of a local).
- let mut optimization_finder = ConstPropagator::new(body, tcx, source);
+ let mut optimization_finder = ConstPropagator::new(
+ body,
+ dummy_body,
+ source_scope_local_data,
+ promoted,
+ tcx,
+ source
+ );
optimization_finder.visit_body(body);
// put back the data we stole from `mir`
+ let (source_scope_local_data, promoted) = optimization_finder.release_stolen_data();
std::mem::replace(
&mut body.source_scope_local_data,
- optimization_finder.source_scope_local_data
+ source_scope_local_data
);
std::mem::replace(
&mut body.promoted,
- optimization_finder.promoted
+ promoted
);
trace!("ConstProp done for {:?}", source.def_id());
ecx: InterpretCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
tcx: TyCtxt<'tcx>,
source: MirSource<'tcx>,
- places: IndexVec<Local, Option<Const<'tcx>>>,
can_const_prop: IndexVec<Local, bool>,
param_env: ParamEnv<'tcx>,
source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>,
impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
fn new(
- body: &mut Body<'tcx>,
+ body: &Body<'tcx>,
+ dummy_body: &'mir Body<'tcx>,
+ source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>,
+ promoted: IndexVec<Promoted, Body<'tcx>>,
tcx: TyCtxt<'tcx>,
source: MirSource<'tcx>,
) -> ConstPropagator<'mir, 'tcx> {
- let param_env = tcx.param_env(source.def_id());
- let ecx = mk_eval_cx(tcx, tcx.def_span(source.def_id()), param_env);
+ let def_id = source.def_id();
+ let param_env = tcx.param_env(def_id);
+ let span = tcx.def_span(def_id);
+ let mut ecx = mk_eval_cx(tcx, span, param_env);
let can_const_prop = CanConstProp::check(body);
- let source_scope_local_data = std::mem::replace(
- &mut body.source_scope_local_data,
- ClearCrossCrate::Clear
- );
- let promoted = std::mem::replace(
- &mut body.promoted,
- IndexVec::new()
- );
+
+ ecx.push_stack_frame(
+ Instance::new(def_id, &InternalSubsts::identity_for_item(tcx, def_id)),
+ span,
+ dummy_body,
+ None,
+ StackPopCleanup::None {
+ cleanup: false,
+ },
+ ).expect("failed to push initial stack frame");
ConstPropagator {
ecx,
source,
param_env,
can_const_prop,
- places: IndexVec::from_elem(None, &body.local_decls),
source_scope_local_data,
//FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
local_decls: body.local_decls.clone(),
}
}
+ fn release_stolen_data(self) ->
+ (ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>,
+ IndexVec<Promoted, Body<'tcx>>)
+ {
+ (self.source_scope_local_data, self.promoted)
+ }
+
fn get_const(&self, local: Local) -> Option<Const<'tcx>> {
- self.places[local]
+ let l = &self.ecx.frame().locals[local];
+ if l.value == LocalValue::Uninitialized || l.value == LocalValue::Dead {
+ return None;
+ }
+
+ self.ecx.access_local(self.ecx.frame(), local, None).ok()
}
fn set_const(&mut self, local: Local, c: Option<Const<'tcx>>) {
- self.places[local] = c;
+ self.ecx.frame_mut().locals[local] =
+ match c {
+ Some(op_ty) => LocalState {
+ value: LocalValue::Live(*op_ty),
+ layout: Cell::new(Some(op_ty.layout)),
+ },
+ None => LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) },
+ };
}
fn use_ecx<F, T>(