/// Temporary allocations introduced to save stackframes
/// This is pure interpreter magic and has nothing to do with how rustc does it
/// An example is calling an FnMut closure that has been converted to a FnOnce closure
- /// The memory will be freed when the stackframe finishes
- pub interpreter_temporaries: Vec<Pointer>,
+ /// The value's destructor will be called and the memory freed when the stackframe finishes
+ pub interpreter_temporaries: Vec<(Pointer, Ty<'tcx>)>,
////////////////////////////////////////////////////////////////////////////////
// Current position within the function
substs: &'tcx Substs<'tcx>,
return_lvalue: Lvalue<'tcx>,
return_to_block: StackPopCleanup,
- temporaries: Vec<Pointer>,
+ temporaries: Vec<(Pointer, Ty<'tcx>)>,
) -> EvalResult<'tcx> {
::log_settings::settings().indentation += 1;
}
}
}
- // deallocate all temporary allocations
- for ptr in frame.interpreter_temporaries {
- trace!("deallocating temporary allocation");
- self.memory.dump_alloc(ptr.alloc_id);
- self.memory.deallocate(ptr)?;
+ // drop and deallocate all temporary allocations
+ for (ptr, ty) in frame.interpreter_temporaries {
+ trace!("dropping temporary allocation");
+ let mut drops = Vec::new();
+ self.drop(Lvalue::from_ptr(ptr), ty, &mut drops)?;
+ self.eval_drop_impls(drops, frame.span)?;
}
Ok(())
}
def_id: DefId,
substs: &'tcx Substs<'tcx>,
args: &mut Vec<(Value, Ty<'tcx>)>,
- ) -> EvalResult<'tcx, (DefId, &'tcx Substs<'tcx>, Vec<Pointer>)> {
+ ) -> EvalResult<'tcx, (DefId, &'tcx Substs<'tcx>, Vec<(Pointer, Ty<'tcx>)>)> {
let trait_ref = ty::TraitRef::from_method(self.tcx, trait_id, substs);
let trait_ref = self.tcx.normalize_associated_type(&ty::Binder(trait_ref));
let ptr = self.alloc_ptr(args[0].1)?;
let size = self.type_size(args[0].1)?.expect("closures are sized");
self.memory.write_primval(ptr, primval, size)?;
- temporaries.push(ptr);
ptr
},
Value::ByValPair(a, b) => {
let ptr = self.alloc_ptr(args[0].1)?;
self.write_pair_to_ptr(a, b, ptr, args[0].1)?;
- temporaries.push(ptr);
ptr
},
};
+ temporaries.push((ptr, args[0].1));
args[0].0 = Value::ByVal(PrimVal::Ptr(ptr));
args[0].1 = self.tcx.mk_mut_ptr(args[0].1);
}
--- /dev/null
+struct Foo<'a>(&'a mut bool);
+
+impl<'a> Drop for Foo<'a> {
+ fn drop(&mut self) {
+ *self.0 = true;
+ }
+}
+
+fn f<T: FnOnce()>(t: T) {
+ t()
+}
+
+fn main() {
+ let mut ran_drop = false;
+ {
+ let x = Foo(&mut ran_drop);
+ // this closure never by val uses its captures
+ // so it's basically a fn(&self)
+ // the shim used to not drop the `x`
+ let x = move || { let _ = x; };
+ f(x);
+ }
+ assert!(ran_drop);
+}