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:
parent
4f93357d3b
commit
c00266b7ac
@ -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]
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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 |
|
||||
|
@ -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)),
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 };
|
||||
|
@ -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,
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
Loading…
Reference in New Issue
Block a user