]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/transform/const_prop.rs
[const-prop] Replace `Cast` handling with use of `InterpCx`
[rust.git] / src / librustc_mir / transform / const_prop.rs
index 857757ada53b7dda66c70aa2daa89d51722fedee..e1a2d1693199885fdd9446aae73b9312913fb55b 100644 (file)
@@ -6,14 +6,14 @@
 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;
@@ -24,7 +24,7 @@
 
 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,
@@ -282,53 +282,9 @@ fn eval_constant(
 
     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>> {
@@ -344,11 +300,17 @@ fn const_prop(
         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)?;
@@ -360,30 +322,6 @@ fn const_prop(
             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(
@@ -670,15 +608,15 @@ fn visit_statement(
                 .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() {
@@ -692,6 +630,18 @@ fn visit_statement(
                     }
                 }
             }
+        } 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);
     }