Skip to content

Commit

Permalink
treat ref-to-raw cast like a reborrow: do a special kind of retag
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Dec 18, 2018
1 parent c9bb68f commit c1160a8
Show file tree
Hide file tree
Showing 22 changed files with 76 additions and 128 deletions.
4 changes: 2 additions & 2 deletions src/librustc/ich/impls_mir.rs
Expand Up @@ -200,13 +200,13 @@ impl_stable_hash_for!(impl<'gcx> for enum mir::StatementKind<'gcx> [ mir::Statem
SetDiscriminant { place, variant_index },
StorageLive(place),
StorageDead(place),
EscapeToRaw(place),
Retag { fn_entry, two_phase, place },
Retag(retag_kind, place),
AscribeUserType(place, variance, c_ty),
Nop,
InlineAsm { asm, outputs, inputs },
});

impl_stable_hash_for!(enum mir::RetagKind { FnEntry, TwoPhase, Raw, Default });
impl_stable_hash_for!(enum mir::FakeReadCause { ForMatchGuard, ForMatchedPlace, ForLet });

impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Place<'gcx> {
Expand Down
48 changes: 24 additions & 24 deletions src/librustc/mir/mod.rs
Expand Up @@ -1774,23 +1774,7 @@ pub enum StatementKind<'tcx> {
/// by miri and only generated when "-Z mir-emit-retag" is passed.
/// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/>
/// for more details.
Retag {
/// `fn_entry` indicates whether this is the initial retag that happens in the
/// function prolog.
fn_entry: bool,
/// `two_phase` indicates whether this is just the reservation action of
/// a two-phase borrow.
two_phase: bool,
/// The place to retag
place: Place<'tcx>,
},

/// Escape the given reference to a raw pointer, so that it can be accessed
/// without precise provenance tracking. These statements are currently only interpreted
/// by miri and only generated when "-Z mir-emit-retag" is passed.
/// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/>
/// for more details.
EscapeToRaw(Operand<'tcx>),
Retag(RetagKind, Place<'tcx>),

/// Encodes a user's type ascription. These need to be preserved
/// intact so that NLL can respect them. For example:
Expand All @@ -1810,6 +1794,19 @@ pub enum StatementKind<'tcx> {
Nop,
}

/// `RetagKind` describes what kind of retag is to be performed.
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq)]
pub enum RetagKind {
/// The initial retag when entering a function
FnEntry,
/// Retag preparing for a two-phase borrow
TwoPhase,
/// Retagging raw pointers
Raw,
/// A "normal" retag
Default,
}

/// The `FakeReadCause` describes the type of pattern why a `FakeRead` statement exists.
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
pub enum FakeReadCause {
Expand Down Expand Up @@ -1845,13 +1842,16 @@ impl<'tcx> Debug for Statement<'tcx> {
match self.kind {
Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv),
FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place),
Retag { fn_entry, two_phase, ref place } =>
write!(fmt, "Retag({}{}{:?})",
if fn_entry { "[fn entry] " } else { "" },
if two_phase { "[2phase] " } else { "" },
Retag(ref kind, ref place) =>
write!(fmt, "Retag({}{:?})",
match kind {
RetagKind::FnEntry => "[fn entry] ",
RetagKind::TwoPhase => "[2phase] ",
RetagKind::Raw => "[raw] ",
RetagKind::Default => "",
},
place,
),
EscapeToRaw(ref place) => write!(fmt, "EscapeToRaw({:?})", place),
StorageLive(ref place) => write!(fmt, "StorageLive({:?})", place),
StorageDead(ref place) => write!(fmt, "StorageDead({:?})", place),
SetDiscriminant {
Expand Down Expand Up @@ -2965,6 +2965,7 @@ CloneTypeFoldableAndLiftImpls! {
SourceInfo,
UpvarDecl,
FakeReadCause,
RetagKind,
SourceScope,
SourceScopeData,
SourceScopeLocalData,
Expand Down Expand Up @@ -3031,8 +3032,7 @@ EnumTypeFoldableImpl! {
(StatementKind::StorageLive)(a),
(StatementKind::StorageDead)(a),
(StatementKind::InlineAsm) { asm, outputs, inputs },
(StatementKind::Retag) { fn_entry, two_phase, place },
(StatementKind::EscapeToRaw)(place),
(StatementKind::Retag)(kind, place),
(StatementKind::AscribeUserType)(a, v, b),
(StatementKind::Nop),
}
Expand Down
18 changes: 6 additions & 12 deletions src/librustc/mir/visit.rs
Expand Up @@ -153,11 +153,10 @@ macro_rules! make_mir_visitor {
}

fn visit_retag(&mut self,
fn_entry: & $($mutability)* bool,
two_phase: & $($mutability)* bool,
kind: & $($mutability)* RetagKind,
place: & $($mutability)* Place<'tcx>,
location: Location) {
self.super_retag(fn_entry, two_phase, place, location);
self.super_retag(kind, place, location);
}

fn visit_place(&mut self,
Expand Down Expand Up @@ -385,9 +384,6 @@ macro_rules! make_mir_visitor {
location
);
}
StatementKind::EscapeToRaw(ref $($mutability)* op) => {
self.visit_operand(op, location);
}
StatementKind::StorageLive(ref $($mutability)* local) => {
self.visit_local(
local,
Expand Down Expand Up @@ -417,10 +413,9 @@ macro_rules! make_mir_visitor {
self.visit_operand(input, location);
}
}
StatementKind::Retag { ref $($mutability)* fn_entry,
ref $($mutability)* two_phase,
ref $($mutability)* place } => {
self.visit_retag(fn_entry, two_phase, place, location);
StatementKind::Retag ( ref $($mutability)* kind,
ref $($mutability)* place ) => {
self.visit_retag(kind, place, location);
}
StatementKind::AscribeUserType(
ref $($mutability)* place,
Expand Down Expand Up @@ -725,8 +720,7 @@ macro_rules! make_mir_visitor {
}

fn super_retag(&mut self,
_fn_entry: & $($mutability)* bool,
_two_phase: & $($mutability)* bool,
_kind: & $($mutability)* RetagKind,
place: & $($mutability)* Place<'tcx>,
location: Location) {
self.visit_place(
Expand Down
1 change: 0 additions & 1 deletion src/librustc_codegen_ssa/mir/statement.rs
Expand Up @@ -106,7 +106,6 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
mir::StatementKind::FakeRead(..) |
mir::StatementKind::Retag { .. } |
mir::StatementKind::EscapeToRaw { .. } |
mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => bx,
}
Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir/borrow_check/mod.rs
Expand Up @@ -590,7 +590,6 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
StatementKind::Nop
| StatementKind::AscribeUserType(..)
| StatementKind::Retag { .. }
| StatementKind::EscapeToRaw { .. }
| StatementKind::StorageLive(..) => {
// `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
// to borrow check.
Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir/borrow_check/nll/invalidation.rs
Expand Up @@ -135,7 +135,6 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
StatementKind::Nop |
StatementKind::AscribeUserType(..) |
StatementKind::Retag { .. } |
StatementKind::EscapeToRaw { .. } |
StatementKind::StorageLive(..) => {
// `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
// to borrow check.
Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir/borrow_check/nll/type_check/mod.rs
Expand Up @@ -1316,7 +1316,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
| StatementKind::StorageDead(..)
| StatementKind::InlineAsm { .. }
| StatementKind::Retag { .. }
| StatementKind::EscapeToRaw { .. }
| StatementKind::Nop => {}
}
}
Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir/dataflow/impls/borrows.rs
Expand Up @@ -300,7 +300,6 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
mir::StatementKind::SetDiscriminant { .. } |
mir::StatementKind::StorageLive(..) |
mir::StatementKind::Retag { .. } |
mir::StatementKind::EscapeToRaw { .. } |
mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => {}

Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir/dataflow/move_paths/builder.rs
Expand Up @@ -302,7 +302,6 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
"SetDiscriminant should not exist during borrowck");
}
StatementKind::Retag { .. } |
StatementKind::EscapeToRaw { .. } |
StatementKind::AscribeUserType(..) |
StatementKind::Nop => {}
}
Expand Down
20 changes: 7 additions & 13 deletions src/librustc_mir/interpret/cast.rs
Expand Up @@ -44,34 +44,28 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
}

Misc => {
let src_layout = src.layout;
let src = self.read_immediate(src)?;

// There are no casts to references
assert!(!dest.layout.ty.is_region_ptr());
// Hence we make all casts erase the tag
let src = src.erase_tag().with_default_tag();

if self.type_is_fat_ptr(src_layout.ty) {
match (src, self.type_is_fat_ptr(dest.layout.ty)) {
if self.type_is_fat_ptr(src.layout.ty) {
match (*src, self.type_is_fat_ptr(dest.layout.ty)) {
// pointers to extern types
(Immediate::Scalar(_),_) |
// slices and trait objects to other slices/trait objects
(Immediate::ScalarPair(..), true) => {
// No change to immediate
self.write_immediate(src, dest)?;
self.write_immediate(*src, dest)?;
}
// slices and trait objects to thin pointers (dropping the metadata)
(Immediate::ScalarPair(data, _), false) => {
self.write_scalar(data, dest)?;
}
}
} else {
match src_layout.variants {
match src.layout.variants {
layout::Variants::Single { index } => {
if let Some(def) = src_layout.ty.ty_adt_def() {
if let Some(def) = src.layout.ty.ty_adt_def() {
// Cast from a univariant enum
assert!(src_layout.is_zst());
assert!(src.layout.is_zst());
let discr_val = def
.discriminant_for_variant(*self.tcx, index)
.val;
Expand All @@ -84,7 +78,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
layout::Variants::NicheFilling { .. } => {},
}

let dest_val = self.cast_scalar(src.to_scalar()?, src_layout, dest.layout)?;
let dest_val = self.cast_scalar(src.to_scalar()?, src.layout, dest.layout)?;
self.write_scalar(dest_val, dest)?;
}
}
Expand Down
12 changes: 1 addition & 11 deletions src/librustc_mir/interpret/machine.rs
Expand Up @@ -203,22 +203,12 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
#[inline]
fn retag(
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
_fn_entry: bool,
_two_phase: bool,
_kind: mir::RetagKind,
_place: PlaceTy<'tcx, Self::PointerTag>,
) -> EvalResult<'tcx> {
Ok(())
}

/// Execute an escape-to-raw operation
#[inline]
fn escape_to_raw(
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
_ptr: OpTy<'tcx, Self::PointerTag>,
) -> EvalResult<'tcx> {
Ok(())
}

/// Called immediately before a new stack frame got pushed
fn stack_push(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
Expand Down
8 changes: 2 additions & 6 deletions src/librustc_mir/interpret/step.rs
Expand Up @@ -119,13 +119,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
FakeRead(..) => {}

// Stacked Borrows.
Retag { fn_entry, two_phase, ref place } => {
Retag(kind, ref place) => {
let dest = self.eval_place(place)?;
M::retag(self, fn_entry, two_phase, dest)?;
}
EscapeToRaw(ref op) => {
let op = self.eval_operand(op, None)?;
M::escape_to_raw(self, op)?;
M::retag(self, kind, dest)?;
}

// Statements we do not track.
Expand Down
13 changes: 2 additions & 11 deletions src/librustc_mir/shim.rs
Expand Up @@ -226,20 +226,11 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// The first argument (index 0), but add 1 for the return value.
let dropee_ptr = Place::Local(Local::new(1+0));
if tcx.sess.opts.debugging_opts.mir_emit_retag {
// Function arguments should be retagged
// Function arguments should be retagged, and we make this one raw.
mir.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
source_info,
kind: StatementKind::Retag {
fn_entry: true,
two_phase: false,
place: dropee_ptr.clone(),
},
kind: StatementKind::Retag(RetagKind::Raw, dropee_ptr.clone()),
});
// We use raw ptr operations, better prepare the alias tracking for that
mir.basic_blocks_mut()[START_BLOCK].statements.insert(1, Statement {
source_info,
kind: StatementKind::EscapeToRaw(Operand::Copy(dropee_ptr.clone())),
})
}
let patch = {
let param_env = tcx.param_env(def_id).with_reveal_all();
Expand Down

0 comments on commit c1160a8

Please sign in to comment.