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));
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())
}
};
use syntax::source_map::{self, Span};
-use syntax::ast::Mutability;
use super::{
Value, Operand, MemPlace, MPlaceTy, Place, PlaceExtra,
#[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<mir::BasicBlock>),
- /// 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
"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 {
/// 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,
// 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(())
}
}
}
- self.memory.mark_static_initialized(
+ self.memory.intern_static(
vtable.alloc_id,
Mutability::Immutable,
)?;