make retagging work even with 'unstable' places
This commit is contained in:
parent
c5351ad4dc
commit
9397ea1368
15 changed files with 135 additions and 128 deletions
|
@ -10,16 +10,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
|
|||
|
||||
pub struct AddRetag;
|
||||
|
||||
/// Determines whether this place is "stable": Whether, if we evaluate it again
|
||||
/// after the assignment, we can be sure to obtain the same place value.
|
||||
/// (Concurrent accesses by other threads are no problem as these are anyway non-atomic
|
||||
/// copies. Data races are UB.)
|
||||
fn is_stable(place: PlaceRef<'_>) -> bool {
|
||||
// Which place this evaluates to can change with any memory write,
|
||||
// so cannot assume deref to be stable.
|
||||
!place.has_deref()
|
||||
}
|
||||
|
||||
/// Determine whether this type may contain a reference (or box), and thus needs retagging.
|
||||
/// We will only recurse `depth` times into Tuples/ADTs to bound the cost of this.
|
||||
fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> bool {
|
||||
|
@ -69,22 +59,10 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
|||
let basic_blocks = body.basic_blocks.as_mut();
|
||||
let local_decls = &body.local_decls;
|
||||
let needs_retag = |place: &Place<'tcx>| {
|
||||
// FIXME: Instead of giving up for unstable places, we should introduce
|
||||
// a temporary and retag on that.
|
||||
is_stable(place.as_ref())
|
||||
!place.has_deref() // we're not eally interested in stores to "outside" locations, they are hard to keep track of anyway
|
||||
&& may_contain_reference(place.ty(&*local_decls, tcx).ty, /*depth*/ 3, tcx)
|
||||
&& !local_decls[place.local].is_deref_temp()
|
||||
};
|
||||
let place_base_raw = |place: &Place<'tcx>| {
|
||||
// If this is a `Deref`, get the type of what we are deref'ing.
|
||||
if place.has_deref() {
|
||||
let ty = &local_decls[place.local].ty;
|
||||
ty.is_unsafe_ptr()
|
||||
} else {
|
||||
// Not a deref, and thus not raw.
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
// PART 1
|
||||
// Retag arguments at the beginning of the start block.
|
||||
|
@ -108,7 +86,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
|||
}
|
||||
|
||||
// PART 2
|
||||
// Retag return values of functions. Also escape-to-raw the argument of `drop`.
|
||||
// Retag return values of functions.
|
||||
// We collect the return destinations because we cannot mutate while iterating.
|
||||
let returns = basic_blocks
|
||||
.iter_mut()
|
||||
|
@ -140,30 +118,25 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
|||
}
|
||||
|
||||
// PART 3
|
||||
// Add retag after assignment.
|
||||
// Add retag after assignments where data "enters" this function: the RHS is behind a deref and the LHS is not.
|
||||
for block_data in basic_blocks {
|
||||
// We want to insert statements as we iterate. To this end, we
|
||||
// iterate backwards using indices.
|
||||
for i in (0..block_data.statements.len()).rev() {
|
||||
let (retag_kind, place) = match block_data.statements[i].kind {
|
||||
// Retag-as-raw after escaping to a raw pointer, if the referent
|
||||
// is not already a raw pointer.
|
||||
StatementKind::Assign(box (lplace, Rvalue::AddressOf(_, ref rplace)))
|
||||
if !place_base_raw(rplace) =>
|
||||
{
|
||||
(RetagKind::Raw, lplace)
|
||||
}
|
||||
// Retag after assignments of reference type.
|
||||
StatementKind::Assign(box (ref place, ref rvalue)) if needs_retag(place) => {
|
||||
let kind = match rvalue {
|
||||
Rvalue::Ref(_, borrow_kind, _)
|
||||
if borrow_kind.allows_two_phase_borrow() =>
|
||||
{
|
||||
RetagKind::TwoPhase
|
||||
}
|
||||
_ => RetagKind::Default,
|
||||
let add_retag = match rvalue {
|
||||
// Ptr-creating operations already do their own internal retagging, no
|
||||
// need to also add a retag statement.
|
||||
Rvalue::Ref(..) | Rvalue::AddressOf(..) => false,
|
||||
_ => true,
|
||||
};
|
||||
(kind, *place)
|
||||
if add_retag {
|
||||
(RetagKind::Default, *place)
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Do nothing for the rest
|
||||
_ => continue,
|
||||
|
|
|
@ -985,16 +985,6 @@ fn create_generator_drop_shim<'tcx>(
|
|||
tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }),
|
||||
source_info,
|
||||
);
|
||||
if tcx.sess.opts.unstable_opts.mir_emit_retag {
|
||||
// Alias tracking must know we changed the type
|
||||
body.basic_blocks_mut()[START_BLOCK].statements.insert(
|
||||
0,
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Retag(RetagKind::Raw, Box::new(Place::from(SELF_ARG))),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Make sure we remove dead blocks to remove
|
||||
// unrelated code from the resume part of the function
|
||||
|
|
|
@ -177,16 +177,6 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
|
|||
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));
|
||||
if tcx.sess.opts.unstable_opts.mir_emit_retag {
|
||||
// Function arguments should be retagged, and we make this one raw.
|
||||
body.basic_blocks_mut()[START_BLOCK].statements.insert(
|
||||
0,
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Retag(RetagKind::Raw, Box::new(dropee_ptr)),
|
||||
},
|
||||
);
|
||||
}
|
||||
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