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;
use crate::interpret::{
self, InterpCx, ScalarMaybeUndef, Immediate, OpTy,
- ImmTy, MemoryKind, StackPopCleanup, LocalValue, LocalState,
+ ImmTy, StackPopCleanup, LocalValue, LocalState,
};
use crate::const_eval::{
CompileTimeInterpreter, error_to_const_error, mk_eval_cx,
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>> {
rvalue: &Rvalue<'tcx>,
place_layout: TyLayout<'tcx>,
source_info: SourceInfo,
+ place: &Place<'tcx>,
) -> Option<Const<'tcx>> {
let span = source_info.span;
match *rvalue {
- Rvalue::Use(ref op) => {
- self.eval_operand(op, source_info)
+ Rvalue::Use(_) |
+ Rvalue::Len(_) |
+ Rvalue::Cast(..) => {
+ self.use_ecx(source_info, |this| {
+ this.ecx.eval_rvalue_into_place(rvalue, place)?;
+ this.ecx.eval_place_to_op(place, Some(place_layout))
+ })
},
Rvalue::Ref(_, _, ref place) => {
let src = self.eval_place(place, source_info)?;
Rvalue::NullaryOp(NullOp::Box, _) |
Rvalue::Discriminant(..) => None,
- Rvalue::Cast(kind, ref operand, _) => {
- let op = self.eval_operand(operand, source_info)?;
- self.use_ecx(source_info, |this| {
- let dest = this.ecx.allocate(place_layout, MemoryKind::Stack);
- 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.kind {
- let len = mplace.meta.unwrap().to_usize(&self.ecx).unwrap();
-
- Some(ImmTy::from_uint(
- len,
- self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
- ).into())
- } else {
- trace!("not slice: {:?}", mplace.layout.ty.kind);
- None
- }
- },
Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some(
ImmTy::from_uint(
.ty(&self.local_decls, self.tcx)
.ty;
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
- if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) {
- if let Place {
- base: PlaceBase::Local(local),
- projection: box [],
- } = *place {
+ if let Place {
+ base: PlaceBase::Local(local),
+ projection: box [],
+ } = *place {
+ if let Some(value) = self.const_prop(rval, place_layout, statement.source_info, place) {
trace!("checking whether {:?} can be stored to {:?}", value, local);
if self.can_const_prop[local] {
trace!("storing {:?} to {:?}", value, local);
- assert!(self.get_const(local).is_none());
+ assert!(self.get_const(local).is_none() || self.get_const(local) == Some(value));
self.set_const(local, value);
if self.should_const_prop() {
}
}
}
+ } else if let StatementKind::StorageLive(local) = statement.kind {
+ if self.can_const_prop[local] {
+ let frame = self.ecx.frame_mut();
+
+ frame.locals[local].value = LocalValue::Uninitialized;
+ }
+ } else if let StatementKind::StorageDead(local) = statement.kind {
+ if self.can_const_prop[local] {
+ let frame = self.ecx.frame_mut();
+
+ frame.locals[local].value = LocalValue::Dead;
+ }
}
self.super_statement(statement, location);
}