Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add escape-to-raw MIR statement #55716

Merged
merged 6 commits into from
Nov 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/librustc/ich/impls_mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,9 @@ for mir::StatementKind<'gcx> {
mir::StatementKind::EndRegion(ref region_scope) => {
region_scope.hash_stable(hcx, hasher);
}
mir::StatementKind::EscapeToRaw(ref place) => {
place.hash_stable(hcx, hasher);
}
mir::StatementKind::Retag { fn_entry, ref place } => {
fn_entry.hash_stable(hcx, hasher);
place.hash_stable(hcx, hasher);
Expand Down
9 changes: 9 additions & 0 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1766,6 +1766,13 @@ pub enum StatementKind<'tcx> {
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>),

/// Mark one terminating point of a region scope (i.e. static region).
/// (The starting point(s) arise implicitly from borrows.)
EndRegion(region::Scope),
Expand Down Expand Up @@ -1827,6 +1834,7 @@ impl<'tcx> Debug for Statement<'tcx> {
EndRegion(ref ce) => write!(fmt, "EndRegion({})", ty::ReScope(*ce)),
Retag { fn_entry, ref place } =>
write!(fmt, "Retag({}{:?})", if fn_entry { "[fn entry] " } else { "" }, 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 @@ -2968,6 +2976,7 @@ EnumTypeFoldableImpl! {
(StatementKind::StorageDead)(a),
(StatementKind::InlineAsm) { asm, outputs, inputs },
(StatementKind::Retag) { fn_entry, place },
(StatementKind::EscapeToRaw)(place),
(StatementKind::EndRegion)(a),
(StatementKind::AscribeUserType)(a, v, b),
(StatementKind::Nop),
Expand Down
5 changes: 4 additions & 1 deletion src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,9 @@ 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 @@ -1022,7 +1025,7 @@ pub enum MutatingUseContext<'tcx> {
/// f(&mut x.y);
///
Projection,
/// Retagging (updating the "Stacked Borrows" tag)
/// Retagging, a "Stacked Borrows" shadow state operation
Retag,
}

Expand Down
3 changes: 2 additions & 1 deletion src/librustc_codegen_llvm/mir/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,9 @@ impl FunctionCx<'a, 'll, 'tcx> {
bx
}
mir::StatementKind::FakeRead(..) |
mir::StatementKind::EndRegion(_) |
mir::StatementKind::EndRegion(..) |
mir::StatementKind::Retag { .. } |
mir::StatementKind::EscapeToRaw { .. } |
mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => bx,
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/borrow_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ 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: 1 addition & 0 deletions src/librustc_mir/borrow_check/nll/invalidation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ 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
5 changes: 3 additions & 2 deletions src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1290,11 +1290,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
}
StatementKind::FakeRead(..)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
| StatementKind::InlineAsm { .. }
| StatementKind::EndRegion(_)
| StatementKind::Retag { .. }
| StatementKind::EscapeToRaw { .. }
| StatementKind::Nop => {}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_mir/build/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// region_scope=None so place indexes live forever. They are scalars so they
// do not need storage annotations, and they are often copied between
// places.
// Making this a *fresh* temporary also means we do not have to worry about
// the index changing later: Nothing will ever change this temporary.
// The "retagging" transformation (for Stacked Borrows) relies on this.
let idx = unpack!(block = this.as_temp(block, None, index, Mutability::Mut));

// bounds check:
Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,6 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>;

const STATIC_KIND: Option<!> = None; // no copying of statics allowed
const ENABLE_PTR_TRACKING_HOOKS: bool = false; // we don't have no provenance

#[inline(always)]
fn enforce_validity(_ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/dataflow/impls/borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ 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
3 changes: 2 additions & 1 deletion src/librustc_mir/dataflow/move_paths/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,9 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
span_bug!(stmt.source_info.span,
"SetDiscriminant should not exist during borrowck");
}
StatementKind::EndRegion(_) |
StatementKind::EndRegion(..) |
StatementKind::Retag { .. } |
StatementKind::EscapeToRaw { .. } |
StatementKind::AscribeUserType(..) |
StatementKind::Nop => {}
}
Expand Down
27 changes: 7 additions & 20 deletions src/librustc_mir/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,40 +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)?;

let src = if M::ENABLE_PTR_TRACKING_HOOKS && src_layout.ty.is_region_ptr() {
// The only `Misc` casts on references are those creating raw pointers.
assert!(dest.layout.ty.is_unsafe_ptr());
// For the purpose of the "ptr tag hooks", treat this as creating
// a new, raw reference.
let place = self.ref_to_mplace(src)?;
self.create_ref(place, None)?
} else {
*src
};

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 @@ -90,8 +78,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
layout::Variants::NicheFilling { .. } => {},
}

let src = src.to_scalar()?;
let dest_val = self.cast_scalar(src, 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
14 changes: 6 additions & 8 deletions src/librustc_mir/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,18 +183,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
} else if Some(def_id) == self.tcx.lang_items().panic_fn() {
assert!(args.len() == 1);
// &(&'static str, &'static str, u32, u32)
let ptr = self.read_immediate(args[0])?;
let place = self.ref_to_mplace(ptr)?;
let place = self.deref_operand(args[0])?;
let (msg, file, line, col) = (
self.mplace_field(place, 0)?,
self.mplace_field(place, 1)?,
self.mplace_field(place, 2)?,
self.mplace_field(place, 3)?,
);

let msg_place = self.ref_to_mplace(self.read_immediate(msg.into())?)?;
let msg_place = self.deref_operand(msg.into())?;
let msg = Symbol::intern(self.read_str(msg_place)?);
let file_place = self.ref_to_mplace(self.read_immediate(file.into())?)?;
let file_place = self.deref_operand(file.into())?;
let file = Symbol::intern(self.read_str(file_place)?);
let line = self.read_scalar(line.into())?.to_u32()?;
let col = self.read_scalar(col.into())?.to_u32()?;
Expand All @@ -203,17 +202,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
assert!(args.len() == 2);
// &'static str, &(&'static str, u32, u32)
let msg = args[0];
let ptr = self.read_immediate(args[1])?;
let place = self.ref_to_mplace(ptr)?;
let place = self.deref_operand(args[1])?;
let (file, line, col) = (
self.mplace_field(place, 0)?,
self.mplace_field(place, 1)?,
self.mplace_field(place, 2)?,
);

let msg_place = self.ref_to_mplace(self.read_immediate(msg.into())?)?;
let msg_place = self.deref_operand(msg.into())?;
let msg = Symbol::intern(self.read_str(msg_place)?);
let file_place = self.ref_to_mplace(self.read_immediate(file.into())?)?;
let file_place = self.deref_operand(file.into())?;
let file = Symbol::intern(self.read_str(file_place)?);
let line = self.read_scalar(line.into())?.to_u32()?;
let col = self.read_scalar(col.into())?.to_u32()?;
Expand Down
28 changes: 10 additions & 18 deletions src/librustc_mir/interpret/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,6 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
/// that is added to the memory so that the work is not done twice.
const STATIC_KIND: Option<Self::MemoryKinds>;

/// As an optimization, you can prevent the pointer tracking hooks from ever being
/// called. You should only do this if you do not care about provenance tracking.
/// This controls the `tag_reference` and `tag_dereference` hooks.
const ENABLE_PTR_TRACKING_HOOKS: bool;

/// Whether to enforce the validity invariant
fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool;

Expand Down Expand Up @@ -211,18 +206,6 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
kind: MemoryKind<Self::MemoryKinds>,
) -> EvalResult<'tcx, Pointer<Self::PointerTag>>;

/// Executed when evaluating the `&` operator: Creating a new reference.
/// This has the chance to adjust the tag. It should not change anything else!
/// `mutability` can be `None` in case a raw ptr is being created.
#[inline]
fn tag_reference(
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
place: MPlaceTy<'tcx, Self::PointerTag>,
_mutability: Option<hir::Mutability>,
) -> EvalResult<'tcx, Scalar<Self::PointerTag>> {
Ok(place.ptr)
}

/// Executed when evaluating the `*` operator: Following a reference.
/// This has the chance to adjust the tag. It should not change anything else!
/// `mutability` can be `None` in case a raw ptr is being dereferenced.
Expand All @@ -235,7 +218,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
Ok(place.ptr)
}

/// Execute a validation operation
/// Execute a retagging operation
#[inline]
fn retag(
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
Expand All @@ -244,4 +227,13 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
) -> 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(())
}
}
11 changes: 0 additions & 11 deletions src/librustc_mir/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,17 +555,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
})
}

// Take an operand, representing a pointer, and dereference it to a place -- that
// will always be a MemPlace.
pub(super) fn deref_operand(
&self,
src: OpTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let val = self.read_immediate(src)?;
trace!("deref to {} on {:?}", val.layout.ty, *val);
Ok(self.ref_to_mplace(val)?)
}

pub fn operand_projection(
&self,
base: OpTy<'tcx, M::PointerTag>,
Expand Down
Loading