Skip to content

Commit

Permalink
Auto merge of #55316 - RalfJung:retagging, r=oli-obk
Browse files Browse the repository at this point in the history
Add Retagging statements

This adds a `Retag` statement kind to MIR, used to perform the retagging operation from [Stacked Borrows](https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html). It also kills the old `Validate` statements that I added last year.

NOTE: This includes #55270. Only [these commits are new](RalfJung/rust@stacked-borrows-ng...RalfJung:retagging).
  • Loading branch information
bors committed Nov 2, 2018
2 parents d0c869c + d10304e commit 87a3c1e
Show file tree
Hide file tree
Showing 37 changed files with 450 additions and 922 deletions.
9 changes: 8 additions & 1 deletion src/bootstrap/bin/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,15 @@ fn main() {

// When running miri tests, we need to generate MIR for all libraries
if env::var("TEST_MIRI").ok().map_or(false, |val| val == "true") {
// The flags here should be kept in sync with `add_miri_default_args`
// in miri's `src/lib.rs`.
cmd.arg("-Zalways-encode-mir");
cmd.arg("-Zmir-emit-validate=1");
// These options are preferred by miri, to be able to perform better validation,
// but the bootstrap compiler might not understand them.
if stage != "0" {
cmd.arg("-Zmir-emit-retag");
cmd.arg("-Zmir-opt-level=0");
}
}

// Force all crates compiled by this compiler to (a) be unstable and (b)
Expand Down
23 changes: 3 additions & 20 deletions src/librustc/ich/impls_mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,9 @@ for mir::StatementKind<'gcx> {
mir::StatementKind::EndRegion(ref region_scope) => {
region_scope.hash_stable(hcx, hasher);
}
mir::StatementKind::Validate(ref op, ref places) => {
op.hash_stable(hcx, hasher);
places.hash_stable(hcx, hasher);
mir::StatementKind::Retag { fn_entry, ref place } => {
fn_entry.hash_stable(hcx, hasher);
place.hash_stable(hcx, hasher);
}
mir::StatementKind::AscribeUserType(ref place, ref variance, ref c_ty) => {
place.hash_stable(hcx, hasher);
Expand All @@ -278,23 +278,6 @@ for mir::StatementKind<'gcx> {

impl_stable_hash_for!(enum mir::FakeReadCause { ForMatchGuard, ForMatchedPlace, ForLet });

impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>>
for mir::ValidationOperand<'gcx, T>
where T: HashStable<StableHashingContext<'a>>
{
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>)
{
self.place.hash_stable(hcx, hasher);
self.ty.hash_stable(hcx, hasher);
self.re.hash_stable(hcx, hasher);
self.mutbl.hash_stable(hcx, hasher);
}
}

impl_stable_hash_for!(enum mir::ValidationOp { Acquire, Release, Suspend(region_scope) });

impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Place<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
Expand Down
78 changes: 14 additions & 64 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1754,10 +1754,17 @@ pub enum StatementKind<'tcx> {
inputs: Box<[Operand<'tcx>]>,
},

/// Assert the given places to be valid inhabitants of their type. These statements are
/// currently only interpreted by miri and only generated when "-Z mir-emit-validate" is passed.
/// See <https://internals.rust-lang.org/t/types-as-contracts/5562/73> for more details.
Validate(ValidationOp, Vec<ValidationOperand<'tcx, Place<'tcx>>>),
/// Retag references in the given place, ensuring they got fresh tags. This is
/// part of the Stacked Borrows model. 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.
Retag {
/// `fn_entry` indicates whether this is the initial retag that happens in the
/// function prolog.
fn_entry: bool,
place: Place<'tcx>,
},

/// Mark one terminating point of a region scope (i.e. static region).
/// (The starting point(s) arise implicitly from borrows.)
Expand Down Expand Up @@ -1810,57 +1817,6 @@ pub enum FakeReadCause {
ForLet,
}

/// The `ValidationOp` describes what happens with each of the operands of a
/// `Validate` statement.
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, PartialEq, Eq)]
pub enum ValidationOp {
/// Recursively traverse the place following the type and validate that all type
/// invariants are maintained. Furthermore, acquire exclusive/read-only access to the
/// memory reachable from the place.
Acquire,
/// Recursive traverse the *mutable* part of the type and relinquish all exclusive
/// access.
Release,
/// Recursive traverse the *mutable* part of the type and relinquish all exclusive
/// access *until* the given region ends. Then, access will be recovered.
Suspend(region::Scope),
}

impl Debug for ValidationOp {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
use self::ValidationOp::*;
match *self {
Acquire => write!(fmt, "Acquire"),
Release => write!(fmt, "Release"),
// (reuse lifetime rendering policy from ppaux.)
Suspend(ref ce) => write!(fmt, "Suspend({})", ty::ReScope(*ce)),
}
}
}

// This is generic so that it can be reused by miri
#[derive(Clone, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub struct ValidationOperand<'tcx, T> {
pub place: T,
pub ty: Ty<'tcx>,
pub re: Option<region::Scope>,
pub mutbl: hir::Mutability,
}

impl<'tcx, T: Debug> Debug for ValidationOperand<'tcx, T> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
write!(fmt, "{:?}: {:?}", self.place, self.ty)?;
if let Some(ce) = self.re {
// (reuse lifetime rendering policy from ppaux.)
write!(fmt, "/{}", ty::ReScope(ce))?;
}
if let hir::MutImmutable = self.mutbl {
write!(fmt, " (imm)")?;
}
Ok(())
}
}

impl<'tcx> Debug for Statement<'tcx> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
use self::StatementKind::*;
Expand All @@ -1869,7 +1825,8 @@ impl<'tcx> Debug for Statement<'tcx> {
FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place),
// (reuse lifetime rendering policy from ppaux.)
EndRegion(ref ce) => write!(fmt, "EndRegion({})", ty::ReScope(*ce)),
Validate(ref op, ref places) => write!(fmt, "Validate({:?}, {:?})", op, places),
Retag { fn_entry, ref place } =>
write!(fmt, "Retag({}{:?})", if fn_entry { "[fn entry] " } else { "" }, place),
StorageLive(ref place) => write!(fmt, "StorageLive({:?})", place),
StorageDead(ref place) => write!(fmt, "StorageDead({:?})", place),
SetDiscriminant {
Expand Down Expand Up @@ -2944,7 +2901,6 @@ CloneTypeFoldableAndLiftImpls! {
SourceInfo,
UpvarDecl,
FakeReadCause,
ValidationOp,
SourceScope,
SourceScopeData,
SourceScopeLocalData,
Expand Down Expand Up @@ -2997,12 +2953,6 @@ BraceStructTypeFoldableImpl! {
}
}

BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ValidationOperand<'tcx, Place<'tcx>> {
place, ty, re, mutbl
}
}

BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
source_info, kind
Expand All @@ -3017,7 +2967,7 @@ EnumTypeFoldableImpl! {
(StatementKind::StorageLive)(a),
(StatementKind::StorageDead)(a),
(StatementKind::InlineAsm) { asm, outputs, inputs },
(StatementKind::Validate)(a, b),
(StatementKind::Retag) { fn_entry, place },
(StatementKind::EndRegion)(a),
(StatementKind::AscribeUserType)(a, v, b),
(StatementKind::Nop),
Expand Down
37 changes: 24 additions & 13 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,13 @@ macro_rules! make_mir_visitor {
self.super_ascribe_user_ty(place, variance, user_ty, location);
}

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

fn visit_place(&mut self,
place: & $($mutability)* Place<'tcx>,
context: PlaceContext<'tcx>,
Expand Down Expand Up @@ -371,17 +378,6 @@ macro_rules! make_mir_visitor {
);
}
StatementKind::EndRegion(_) => {}
StatementKind::Validate(_, ref $($mutability)* places) => {
for operand in places {
self.visit_place(
& $($mutability)* operand.place,
PlaceContext::NonUse(NonUseContext::Validate),
location
);
self.visit_ty(& $($mutability)* operand.ty,
TyContext::Location(location));
}
}
StatementKind::SetDiscriminant{ ref $($mutability)* place, .. } => {
self.visit_place(
place,
Expand Down Expand Up @@ -417,6 +413,10 @@ macro_rules! make_mir_visitor {
self.visit_operand(input, location);
}
}
StatementKind::Retag { ref $($mutability)* fn_entry,
ref $($mutability)* place } => {
self.visit_retag(fn_entry, place, location);
}
StatementKind::AscribeUserType(
ref $($mutability)* place,
ref $($mutability)* variance,
Expand Down Expand Up @@ -719,6 +719,17 @@ macro_rules! make_mir_visitor {
self.visit_user_type_projection(user_ty);
}

fn super_retag(&mut self,
_fn_entry: & $($mutability)* bool,
place: & $($mutability)* Place<'tcx>,
location: Location) {
self.visit_place(
place,
PlaceContext::MutatingUse(MutatingUseContext::Retag),
location,
);
}

fn super_place(&mut self,
place: & $($mutability)* Place<'tcx>,
context: PlaceContext<'tcx>,
Expand Down Expand Up @@ -1010,6 +1021,8 @@ pub enum MutatingUseContext<'tcx> {
/// f(&mut x.y);
///
Projection,
/// Retagging (updating the "Stacked Borrows" tag)
Retag,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
Expand All @@ -1020,8 +1033,6 @@ pub enum NonUseContext {
StorageDead,
/// User type annotation assertions for NLL.
AscribeUserTy,
/// Validation command.
Validate,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
Expand Down
5 changes: 2 additions & 3 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1282,9 +1282,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"in addition to `.mir` files, create graphviz `.dot` files"),
dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
"if set, exclude the pass number when dumping MIR (used in tests)"),
mir_emit_validate: usize = (0, parse_uint, [TRACKED],
"emit Validate MIR statements, interpreted e.g. by miri (0: do not emit; 1: if function \
contains unsafe block, only validate arguments; 2: always emit full validation)"),
mir_emit_retag: bool = (false, parse_bool, [TRACKED],
"emit Retagging MIR statements, interpreted e.g. by miri; implies -Zmir-opt-level=0"),
perf_stats: bool = (false, parse_bool, [UNTRACKED],
"print some performance-related statistics"),
hir_stats: bool = (false, parse_bool, [UNTRACKED],
Expand Down
4 changes: 1 addition & 3 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1547,11 +1547,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}

/// Should we emit EndRegion MIR statements? These are consumed by
/// MIR borrowck, but not when NLL is used. They are also consumed
/// by the validation stuff.
/// MIR borrowck, but not when NLL is used.
pub fn emit_end_regions(self) -> bool {
self.sess.opts.debugging_opts.emit_end_regions ||
self.sess.opts.debugging_opts.mir_emit_validate > 0 ||
self.use_mir_borrowck()
}

Expand Down
3 changes: 2 additions & 1 deletion src/librustc_codegen_llvm/mir/analyze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
self.assign(local, location);
}

PlaceContext::NonUse(_) => {}
PlaceContext::NonUse(_) |
PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}

PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_codegen_llvm/mir/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
}
mir::StatementKind::FakeRead(..) |
mir::StatementKind::EndRegion(_) |
mir::StatementKind::Validate(..) |
mir::StatementKind::Retag { .. } |
mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => bx,
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/borrow_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,9 +600,9 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
}
StatementKind::Nop
| StatementKind::AscribeUserType(..)
| StatementKind::Validate(..)
| StatementKind::Retag { .. }
| StatementKind::StorageLive(..) => {
// `Nop`, `AscribeUserType`, `Validate`, and `StorageLive` are irrelevant
// `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
// to borrow check.
}
StatementKind::StorageDead(local) => {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/borrow_check/nll/invalidation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
StatementKind::EndRegion(..) |
StatementKind::Nop |
StatementKind::AscribeUserType(..) |
StatementKind::Validate(..) |
StatementKind::Retag { .. } |
StatementKind::StorageLive(..) => {
// `Nop`, `AscribeUserType`, `Validate`, and `StorageLive` are irrelevant
// `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
// to borrow check.
}
StatementKind::StorageDead(local) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1294,7 +1294,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
| StatementKind::StorageDead(_)
| StatementKind::InlineAsm { .. }
| StatementKind::EndRegion(_)
| StatementKind::Validate(..)
| StatementKind::Retag { .. }
| StatementKind::Nop => {}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/dataflow/impls/borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
mir::StatementKind::FakeRead(..) |
mir::StatementKind::SetDiscriminant { .. } |
mir::StatementKind::StorageLive(..) |
mir::StatementKind::Validate(..) |
mir::StatementKind::Retag { .. } |
mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => {}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/dataflow/move_paths/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
"SetDiscriminant should not exist during borrowck");
}
StatementKind::EndRegion(_) |
StatementKind::Validate(..) |
StatementKind::Retag { .. } |
StatementKind::AscribeUserType(..) |
StatementKind::Nop => {}
}
Expand Down
Loading

0 comments on commit 87a3c1e

Please sign in to comment.