diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 7c1ce21d8f5..3f0ab3b8f7c 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -157,14 +157,6 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>( let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ret = ecx.allocate(layout, MemoryKind::Stack)?; - let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); - let is_static = tcx.is_static(cid.instance.def_id()); - let mutability = if is_static == Some(hir::Mutability::MutMutable) || internally_mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }; - let cleanup = StackPopCleanup::FinishStatic(mutability); let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); @@ -175,12 +167,22 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>( mir.span, mir, Place::Ptr(*ret), - cleanup, + StackPopCleanup::None { cleanup: false }, )?; // The main interpreter loop. ecx.run()?; + // Intern the result + let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); + let is_static = tcx.is_static(cid.instance.def_id()); + let mutability = if is_static == Some(hir::Mutability::MutMutable) || internally_mutable { + Mutability::Mutable + } else { + Mutability::Immutable + }; + ecx.memory.intern_static(ret.ptr.to_ptr()?.alloc_id, mutability)?; + debug!("eval_body_using_ecx done: {:?}", *ret); Ok(ret.into()) } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 49027683d87..dd908acec71 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -32,7 +32,6 @@ use rustc::mir::interpret::{ }; use syntax::source_map::{self, Span}; -use syntax::ast::Mutability; use super::{ Value, Operand, MemPlace, MPlaceTy, Place, PlaceExtra, @@ -159,15 +158,14 @@ impl<'mir, 'tcx: 'mir> Hash for Frame<'mir, 'tcx> { #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum StackPopCleanup { - /// The stackframe existed to compute the initial value of a static/constant. - /// Call `M::intern_static` on the return value and all allocations it references - /// when this is done. Must have a valid pointer as return place. - FinishStatic(Mutability), /// Jump to the next block in the caller, or cause UB if None (that's a function /// that may never return). Goto(Option), - /// Just do nohing: Used by Main and for the box_alloc hook in miri - None, + /// Just do nohing: Used by Main and for the box_alloc hook in miri. + /// `cleanup` says whether locals are deallocated. Static computation + /// wants them leaked to intern what they need (and just throw away + /// the entire `ecx` when it is done). + None { cleanup: bool }, } // State of a local variable @@ -631,18 +629,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M "tried to pop a stack frame, but there were none", ); match frame.return_to_block { - StackPopCleanup::FinishStatic(mutability) => { - let mplace = frame.return_place.to_mem_place(); - // to_ptr should be okay here; it is the responsibility of whoever pushed - // this frame to make sure that this works. - let ptr = mplace.ptr.to_ptr()?; - assert_eq!(ptr.offset.bytes(), 0); - self.memory.mark_static_initialized(ptr.alloc_id, mutability)?; - } StackPopCleanup::Goto(block) => { self.goto_block(block)?; } - StackPopCleanup::None => { } + StackPopCleanup::None { cleanup } => { + if !cleanup { + // Leak the locals + return Ok(()); + } + } } // deallocate all locals that are backed by an allocation for local in frame.locals { diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index e570468a467..85c1ab4edcb 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -570,22 +570,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { /// Reading and writing impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { - /// mark an allocation pointed to by a static as static and initialized - fn mark_inner_allocation_initialized( - &mut self, - alloc: AllocId, - mutability: Mutability, - ) -> EvalResult<'tcx> { - match self.alloc_map.contains_key(&alloc) { - // already interned - false => Ok(()), - // this still needs work - true => self.mark_static_initialized(alloc, mutability), - } - } - /// mark an allocation as static and initialized, either mutable or not - pub fn mark_static_initialized( + pub fn intern_static( &mut self, alloc_id: AllocId, mutability: Mutability, @@ -613,7 +599,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // at references. So whenever we follow a reference, we should likely // assume immutability -- and we should make sure that the compiler // does not permit code that would break this! - self.mark_inner_allocation_initialized(alloc, mutability)?; + if self.alloc_map.contains_key(&alloc) { + // Not yet interned, so proceed recursively + self.intern_static(alloc, mutability)?; + } } Ok(()) } diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 4ce0563749a..6aea68907ec 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -68,7 +68,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { } } - self.memory.mark_static_initialized( + self.memory.intern_static( vtable.alloc_id, Mutability::Immutable, )?;