Auto merge of #103957 - JakobDegen:drop-retag, r=RalfJung
Retag as FnEntry on `drop_in_place` This commit changes the mir drop shim to always retag its argument as if it were a `&mut`. cc rust-lang/unsafe-code-guidelines#373
This commit is contained in:
commit
cca80b9a81
10 changed files with 199 additions and 15 deletions
|
@ -119,11 +119,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
|
||||
Drop { place, target, unwind } => {
|
||||
let place = self.eval_place(place)?;
|
||||
let ty = place.layout.ty;
|
||||
trace!("TerminatorKind::drop: {:?}, type {}", place, ty);
|
||||
|
||||
let frame = self.frame();
|
||||
let ty = place.ty(&frame.body.local_decls, *self.tcx).ty;
|
||||
let ty = self.subst_from_frame_and_normalize_erasing_regions(frame, ty)?;
|
||||
let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
|
||||
if let ty::InstanceDef::DropGlue(_, None) = instance.def {
|
||||
// This is the branch we enter if and only if the dropped type has no drop glue
|
||||
// whatsoever. This can happen as a result of monomorphizing a drop of a
|
||||
// generic. In order to make sure that generic and non-generic code behaves
|
||||
// roughly the same (and in keeping with Mir semantics) we do nothing here.
|
||||
self.go_to_block(target);
|
||||
return Ok(());
|
||||
}
|
||||
let place = self.eval_place(place)?;
|
||||
trace!("TerminatorKind::drop: {:?}, type {}", place, ty);
|
||||
self.drop_in_place(&place, instance, target, unwind)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -564,14 +564,13 @@ pub enum TerminatorKind<'tcx> {
|
|||
Unreachable,
|
||||
|
||||
/// The behavior of this statement differs significantly before and after drop elaboration.
|
||||
/// After drop elaboration, `Drop` executes the drop glue for the specified place, after which
|
||||
/// it continues execution/unwinds at the given basic blocks. It is possible that executing drop
|
||||
/// glue is special - this would be part of Rust's memory model. (**FIXME**: due we have an
|
||||
/// issue tracking if drop glue has any interesting semantics in addition to those of a function
|
||||
/// call?)
|
||||
///
|
||||
/// `Drop` before drop elaboration is a *conditional* execution of the drop glue. Specifically, the
|
||||
/// `Drop` will be executed if...
|
||||
/// After drop elaboration: `Drop` terminators are a complete nop for types that have no drop
|
||||
/// glue. For other types, `Drop` terminators behave exactly like a call to
|
||||
/// `core::mem::drop_in_place` with a pointer to the given place.
|
||||
///
|
||||
/// `Drop` before drop elaboration is a *conditional* execution of the drop glue. Specifically,
|
||||
/// the `Drop` will be executed if...
|
||||
///
|
||||
/// **Needs clarification**: End of that sentence. This in effect should document the exact
|
||||
/// behavior of drop elaboration. The following sounds vaguely right, but I'm not quite sure:
|
||||
|
|
|
@ -174,9 +174,36 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
|
|||
let mut body =
|
||||
new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
|
||||
|
||||
// The first argument (index 0), but add 1 for the return value.
|
||||
let mut dropee_ptr = Place::from(Local::new(1 + 0));
|
||||
if tcx.sess.opts.unstable_opts.mir_emit_retag {
|
||||
// We want to treat the function argument as if it was passed by `&mut`. As such, we
|
||||
// generate
|
||||
// ```
|
||||
// temp = &mut *arg;
|
||||
// Retag(temp, FnEntry)
|
||||
// ```
|
||||
// It's important that we do this first, before anything that depends on `dropee_ptr`
|
||||
// has been put into the body.
|
||||
let reborrow = Rvalue::Ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
tcx.mk_place_deref(dropee_ptr),
|
||||
);
|
||||
let ref_ty = reborrow.ty(body.local_decls(), tcx);
|
||||
dropee_ptr = body.local_decls.push(LocalDecl::new(ref_ty, span)).into();
|
||||
let new_statements = [
|
||||
StatementKind::Assign(Box::new((dropee_ptr, reborrow))),
|
||||
StatementKind::Retag(RetagKind::FnEntry, Box::new(dropee_ptr)),
|
||||
];
|
||||
for s in new_statements {
|
||||
body.basic_blocks_mut()[START_BLOCK]
|
||||
.statements
|
||||
.push(Statement { source_info, kind: s });
|
||||
}
|
||||
}
|
||||
|
||||
if ty.is_some() {
|
||||
// The first argument (index 0), but add 1 for the return value.
|
||||
let dropee_ptr = Place::from(Local::new(1 + 0));
|
||||
let patch = {
|
||||
let param_env = tcx.param_env_reveal_all_normalized(def_id);
|
||||
let mut elaborator =
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue