Encode (in MIR) whether borrows are explicit in source or arise due to autoref.

This is foundation for issue 46747 (limit two-phase borrows to method-call autorefs).
This commit is contained in:
Felix S. Klock II 2018-01-15 12:47:26 +01:00
parent 4f93357d3b
commit c00266b7ac
14 changed files with 67 additions and 35 deletions

View File

@ -20,7 +20,6 @@ use std::mem;
impl_stable_hash_for!(struct mir::GeneratorLayout<'tcx> { fields });
impl_stable_hash_for!(struct mir::SourceInfo { span, scope });
impl_stable_hash_for!(enum mir::Mutability { Mut, Not });
impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut });
impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer });
impl_stable_hash_for!(struct mir::LocalDecl<'tcx> {
mutability,
@ -36,6 +35,25 @@ impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator,
impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, kind });
impl_stable_hash_for!(struct mir::UnsafetyCheckResult { violations, unsafe_blocks });
impl<'gcx> HashStable<StableHashingContext<'gcx>>
for mir::BorrowKind {
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
mir::BorrowKind::Shared |
mir::BorrowKind::Unique => {}
mir::BorrowKind::Mut { allow_two_phase_borrow } => {
allow_two_phase_borrow.hash_stable(hcx, hasher);
}
}
}
}
impl<'gcx> HashStable<StableHashingContext<'gcx>>
for mir::UnsafetyViolationKind {
#[inline]

View File

@ -413,7 +413,11 @@ pub enum BorrowKind {
Unique,
/// Data is mutable and not aliasable.
Mut,
Mut {
/// True if this borrow arose from method-call auto-ref
/// (i.e. `adjustment::Adjust::Borrow`)
allow_two_phase_borrow: bool
}
}
///////////////////////////////////////////////////////////////////////////
@ -1611,7 +1615,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
Ref(region, borrow_kind, ref place) => {
let kind_str = match borrow_kind {
BorrowKind::Shared => "",
BorrowKind::Mut | BorrowKind::Unique => "mut ",
BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ",
};
// When printing regions, add trailing space if necessary.

View File

@ -264,7 +264,7 @@ impl<'tcx> BinOp {
impl BorrowKind {
pub fn to_mutbl_lossy(self) -> hir::Mutability {
match self {
BorrowKind::Mut => hir::MutMutable,
BorrowKind::Mut { .. } => hir::MutMutable,
BorrowKind::Shared => hir::MutImmutable,
// We have no type corresponding to a unique imm borrow, so

View File

@ -951,9 +951,10 @@ impl<'tcx> PlaceContext<'tcx> {
pub fn is_mutating_use(&self) -> bool {
match *self {
PlaceContext::Store | PlaceContext::AsmOutput | PlaceContext::Call |
PlaceContext::Borrow { kind: BorrowKind::Mut, .. } |
PlaceContext::Borrow { kind: BorrowKind::Mut { .. }, .. } |
PlaceContext::Projection(Mutability::Mut) |
PlaceContext::Drop => true,
PlaceContext::Inspect |
PlaceContext::Borrow { kind: BorrowKind::Shared, .. } |
PlaceContext::Borrow { kind: BorrowKind::Unique, .. } |
@ -971,7 +972,8 @@ impl<'tcx> PlaceContext<'tcx> {
PlaceContext::Borrow { kind: BorrowKind::Unique, .. } |
PlaceContext::Projection(Mutability::Not) |
PlaceContext::Copy | PlaceContext::Move => true,
PlaceContext::Borrow { kind: BorrowKind::Mut, .. } | PlaceContext::Store |
PlaceContext::Borrow { kind: BorrowKind::Mut { .. }, .. } | PlaceContext::Store |
PlaceContext::AsmOutput |
PlaceContext::Call | PlaceContext::Projection(Mutability::Mut) |
PlaceContext::Drop | PlaceContext::StorageLive | PlaceContext::StorageDead |

View File

@ -134,7 +134,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
BindingMode::ByValue => mutability == Mutability::Mut,
BindingMode::ByRef(_, bk) => {
write!(f, "ref ")?;
bk == BorrowKind::Mut
match bk { BorrowKind::Mut { .. } => true, _ => false }
}
};
if is_mut {
@ -429,7 +429,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
(Mutability::Not, BindingMode::ByValue),
ty::BindByReference(hir::MutMutable) =>
(Mutability::Not, BindingMode::ByRef(
region.unwrap(), BorrowKind::Mut)),
region.unwrap(), BorrowKind::Mut { allow_two_phase_borrow: false })),
ty::BindByReference(hir::MutImmutable) =>
(Mutability::Not, BindingMode::ByRef(
region.unwrap(), BorrowKind::Shared)),

View File

@ -256,8 +256,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
"immutable",
"mutable",
) {
(BorrowKind::Shared, lft, _, BorrowKind::Mut, _, rgt) |
(BorrowKind::Mut, _, lft, BorrowKind::Shared, rgt, _) => self.tcx
(BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) |
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => self.tcx
.cannot_reborrow_already_borrowed(
span,
&desc_place,
@ -271,7 +271,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Origin::Mir,
),
(BorrowKind::Mut, _, _, BorrowKind::Mut, _, _) => self.tcx
(BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => self.tcx
.cannot_mutably_borrow_multiply(
span,
&desc_place,
@ -314,7 +314,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Origin::Mir,
),
(BorrowKind::Mut, _, lft, BorrowKind::Unique, _, _) => self.tcx
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => self.tcx
.cannot_reborrow_already_uniquely_borrowed(
span,
&desc_place,

View File

@ -797,7 +797,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Control::Continue
}
(Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut) => {
(Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => {
// Reading from mere reservations of mutable-borrows is OK.
if this.tcx.sess.two_phase_borrows() && index.is_reservation()
{
@ -828,7 +828,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}
(Reservation(kind), BorrowKind::Unique)
| (Reservation(kind), BorrowKind::Mut)
| (Reservation(kind), BorrowKind::Mut { .. })
| (Activation(kind, _), _)
| (Write(kind), _) => {
match rw {
@ -945,7 +945,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Rvalue::Ref(_ /*rgn*/, bk, ref place) => {
let access_kind = match bk {
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
BorrowKind::Unique | BorrowKind::Mut => {
BorrowKind::Unique | BorrowKind::Mut { .. } => {
let wk = WriteKind::MutableBorrow(bk);
if self.tcx.sess.two_phase_borrows() {
(Deep, Reservation(wk))
@ -1196,7 +1196,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// mutable borrow before we check it.
match borrow.kind {
BorrowKind::Shared => return,
BorrowKind::Unique | BorrowKind::Mut => {}
BorrowKind::Unique | BorrowKind::Mut { .. } => {}
}
self.access_place(
@ -1467,8 +1467,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
span_bug!(span, "&unique borrow for {:?} should not fail", place);
}
}
Reservation(WriteKind::MutableBorrow(BorrowKind::Mut))
| Write(WriteKind::MutableBorrow(BorrowKind::Mut)) => if let Err(place_err) =
Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { .. }))
| Write(WriteKind::MutableBorrow(BorrowKind::Mut { .. })) => if let Err(place_err) =
self.is_mutable(place, is_local_mutation_allowed)
{
error_reported = true;
@ -1532,7 +1532,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Activation(..) => {} // permission checks are done at Reservation point.
Read(ReadKind::Borrow(BorrowKind::Unique))
| Read(ReadKind::Borrow(BorrowKind::Mut))
| Read(ReadKind::Borrow(BorrowKind::Mut { .. }))
| Read(ReadKind::Borrow(BorrowKind::Shared))
| Read(ReadKind::Copy) => {} // Access authorized
}

View File

@ -122,7 +122,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
let kind = match self.kind {
mir::BorrowKind::Shared => "",
mir::BorrowKind::Unique => "uniq ",
mir::BorrowKind::Mut => "mut ",
mir::BorrowKind::Mut { .. } => "mut ",
};
let region = format!("{}", self.region);
let region = if region.len() > 0 { format!("{} ", region) } else { region };

View File

@ -21,6 +21,7 @@ use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
use rustc::ty::cast::CastKind as TyCastKind;
use rustc::hir;
use rustc::hir::def_id::LocalDefId;
use rustc::mir::{BorrowKind};
impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
type Output = Expr<'tcx>;
@ -111,7 +112,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
span,
kind: ExprKind::Borrow {
region: deref.region,
borrow_kind: to_borrow_kind(deref.mutbl),
borrow_kind: to_borrow_kind(deref.mutbl, true),
arg: expr.to_ref(),
},
};
@ -121,7 +122,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
Adjust::Borrow(AutoBorrow::Ref(r, m)) => {
ExprKind::Borrow {
region: r,
borrow_kind: to_borrow_kind(m),
borrow_kind: to_borrow_kind(m, true),
arg: expr.to_ref(),
}
}
@ -141,7 +142,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
span,
kind: ExprKind::Borrow {
region,
borrow_kind: to_borrow_kind(m),
borrow_kind: to_borrow_kind(m, true),
arg: expr.to_ref(),
},
};
@ -287,7 +288,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
};
ExprKind::Borrow {
region,
borrow_kind: to_borrow_kind(mutbl),
borrow_kind: to_borrow_kind(mutbl, false),
arg: expr.to_ref(),
}
}
@ -642,9 +643,9 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
}
}
fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
fn to_borrow_kind(m: hir::Mutability, allow_two_phase_borrow: bool) -> BorrowKind {
match m {
hir::MutMutable => BorrowKind::Mut,
hir::MutMutable => BorrowKind::Mut { allow_two_phase_borrow },
hir::MutImmutable => BorrowKind::Shared,
}
}
@ -947,7 +948,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
let borrow_kind = match upvar_borrow.kind {
ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique,
ty::BorrowKind::MutBorrow => BorrowKind::Mut,
ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false }
};
Expr {
temp_lifetime,

View File

@ -716,11 +716,14 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}),
span
));
let borrow_kind = BorrowKind::Mut {
allow_two_phase_borrow: false,
};
statements.push(Statement {
source_info,
kind: StatementKind::Assign(
Place::Local(ref_rcvr),
Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, rcvr_l)
Rvalue::Ref(tcx.types.re_erased, borrow_kind, rcvr_l)
)
});
Operand::Move(Place::Local(ref_rcvr))

View File

@ -426,7 +426,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
debug!("Creating temp for return destination");
let dest = Rvalue::Ref(
self.tcx.types.re_erased,
BorrowKind::Mut,
BorrowKind::Mut { allow_two_phase_borrow: false },
destination.0);
let ty = dest.ty(caller_mir, self.tcx);
@ -511,7 +511,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Local {
let arg = Rvalue::Ref(
self.tcx.types.re_erased,
BorrowKind::Mut,
BorrowKind::Mut { allow_two_phase_borrow: false },
arg.deref());
let ty = arg.ty(caller_mir, self.tcx);

View File

@ -600,7 +600,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
}
let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx);
if kind == BorrowKind::Mut {
if let BorrowKind::Mut { .. } = kind {
// In theory, any zero-sized value could be borrowed
// mutably without consequences. However, only &mut []
// is allowed right now, and only in functions.

View File

@ -531,7 +531,9 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
let result = BasicBlockData {
statements: vec![self.assign(
&Place::Local(ref_place),
Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, self.place.clone())
Rvalue::Ref(tcx.types.re_erased,
BorrowKind::Mut { allow_two_phase_borrow: false },
self.place.clone())
)],
terminator: Some(Terminator {
kind: TerminatorKind::Call {
@ -591,7 +593,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
} else {
(Rvalue::Ref(
tcx.types.re_erased,
BorrowKind::Mut,
BorrowKind::Mut { allow_two_phase_borrow: false },
self.place.clone().index(cur)),
Rvalue::BinaryOp(BinOp::Add, copy(&Place::Local(cur)), one))
};
@ -735,7 +737,9 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
// cur = tmp as *mut T;
// end = Offset(cur, len);
drop_block_stmts.push(self.assign(&tmp, Rvalue::Ref(
tcx.types.re_erased, BorrowKind::Mut, self.place.clone()
tcx.types.re_erased,
BorrowKind::Mut { allow_two_phase_borrow: false },
self.place.clone()
)));
drop_block_stmts.push(self.assign(&cur, Rvalue::Cast(
CastKind::Misc, Operand::Move(tmp.clone()), iter_ty

View File

@ -870,7 +870,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
} else {
self.cx.tcx.data_layout.pointer_align
};
if bk == mir::BorrowKind::Mut {
if let mir::BorrowKind::Mut { .. } = bk {
consts::addr_of_mut(self.cx, llval, align, "ref_mut")
} else {
consts::addr_of(self.cx, llval, align, "ref")