Skip to content
Closed
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
1 change: 1 addition & 0 deletions compiler/rustc_borrowck/src/borrow_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
mir::BorrowKind::Shallow => "shallow ",
mir::BorrowKind::Unique => "uniq ",
mir::BorrowKind::Mut { .. } => "mut ",
mir::BorrowKind::DerefMut => "deref mut",
};
write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place)
}
Expand Down
19 changes: 13 additions & 6 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -919,7 +919,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// FIXME: supply non-"" `opt_via` when appropriate
let first_borrow_desc;
let mut err = match (gen_borrow_kind, issued_borrow.kind) {
(BorrowKind::Shared, BorrowKind::Mut { .. }) => {
(BorrowKind::Shared, BorrowKind::Mut { .. } | BorrowKind::DerefMut) => {
first_borrow_desc = "mutable ";
self.cannot_reborrow_already_borrowed(
span,
Expand All @@ -933,7 +933,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None,
)
}
(BorrowKind::Mut { .. }, BorrowKind::Shared) => {
(BorrowKind::Mut { .. } | BorrowKind::DerefMut, BorrowKind::Shared) => {
first_borrow_desc = "immutable ";
let mut err = self.cannot_reborrow_already_borrowed(
span,
Expand All @@ -954,7 +954,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err
}

(BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
(
BorrowKind::Mut { .. } | BorrowKind::DerefMut,
BorrowKind::Mut { .. } | BorrowKind::DerefMut,
) => {
first_borrow_desc = "first ";
let mut err = self.cannot_mutably_borrow_multiply(
span,
Expand All @@ -977,7 +980,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
}

(BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => {
(
BorrowKind::Mut { .. } | BorrowKind::Unique | BorrowKind::DerefMut,
BorrowKind::Shallow,
) => {
if let Some(immutable_section_description) =
self.classify_immutable_section(issued_borrow.assigned_place)
{
Expand Down Expand Up @@ -1044,7 +1050,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
)
}

(BorrowKind::Mut { .. }, BorrowKind::Unique) => {
(BorrowKind::Mut { .. } | BorrowKind::DerefMut, BorrowKind::Unique) => {
first_borrow_desc = "first ";
self.cannot_reborrow_already_uniquely_borrowed(
span,
Expand All @@ -1065,7 +1071,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
BorrowKind::Mut { .. }
| BorrowKind::Unique
| BorrowKind::Shared
| BorrowKind::Shallow,
| BorrowKind::Shallow
| BorrowKind::DerefMut,
) => unreachable!(),
};

Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_borrowck/src/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,17 +645,18 @@ impl UseSpans<'_> {
f: impl Fn(Option<GeneratorKind>, Span) -> crate::session_diagnostics::CaptureVarCause,
) {
use crate::session_diagnostics::CaptureVarKind::*;
use rustc_middle::mir::BorrowKind;

if let UseSpans::ClosureUse { generator_kind, capture_kind_span, path_span, .. } = self {
if capture_kind_span != path_span {
err.subdiagnostic(match kind {
Some(kd) => match kd {
rustc_middle::mir::BorrowKind::Shared
| rustc_middle::mir::BorrowKind::Shallow
| rustc_middle::mir::BorrowKind::Unique => {
BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => {
Immute { kind_span: capture_kind_span }
}

rustc_middle::mir::BorrowKind::Mut { .. } => {
rustc_middle::mir::BorrowKind::Mut { .. }
| rustc_middle::mir::BorrowKind::DerefMut => {
Mut { kind_span: capture_kind_span }
}
},
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_borrowck/src/invalidation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
}
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
BorrowKind::Unique | BorrowKind::Mut { .. } => {
BorrowKind::Unique | BorrowKind::Mut { .. } | BorrowKind::DerefMut => {
let wk = WriteKind::MutableBorrow(bk);
if allow_two_phase_borrow(bk) {
(Deep, Reservation(wk))
Expand Down Expand Up @@ -381,7 +381,10 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
// Reads don't invalidate shared or shallow borrows
}

(Read(_), BorrowKind::Unique | BorrowKind::Mut { .. }) => {
(
Read(_),
BorrowKind::Unique | BorrowKind::Mut { .. } | BorrowKind::DerefMut,
) => {
// Reading from mere reservations of mutable-borrows is OK.
if !is_active(&this.dominators, borrow, location) {
// If the borrow isn't active yet, reads don't invalidate it
Expand Down Expand Up @@ -422,7 +425,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {

// only mutable borrows should be 2-phase
assert!(match borrow.kind {
BorrowKind::Shared | BorrowKind::Shallow => false,
BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::DerefMut => false,
BorrowKind::Unique | BorrowKind::Mut { .. } => true,
});

Expand Down
19 changes: 15 additions & 4 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
Control::Break
}
(_, BorrowKind::DerefMut) => bug!(
"should never encounter BorrowKind::DerefMut when checking for place accesses"
),
},
);

Expand All @@ -1201,6 +1204,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}

#[instrument(skip(self, flow_state), level = "debug")]
fn consume_rvalue(
&mut self,
location: Location,
Expand All @@ -1214,7 +1218,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
}
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
BorrowKind::Unique | BorrowKind::Mut { .. } => {
BorrowKind::Unique | BorrowKind::Mut { .. } | BorrowKind::DerefMut => {
let wk = WriteKind::MutableBorrow(bk);
if allow_two_phase_borrow(bk) {
(Deep, Reservation(wk))
Expand Down Expand Up @@ -1584,7 +1588,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {

// only mutable borrows should be 2-phase
assert!(match borrow.kind {
BorrowKind::Shared | BorrowKind::Shallow => false,
BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::DerefMut => false,
BorrowKind::Unique | BorrowKind::Mut { .. } => true,
});

Expand Down Expand Up @@ -1962,6 +1966,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// Checks the permissions for the given place and read or write kind
///
/// Returns `true` if an error is reported.
#[instrument(skip(self, flow_state), level = "debug")]
fn check_access_permissions(
&mut self,
(place, span): (Place<'tcx>, Span),
Expand All @@ -1979,14 +1984,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let the_place_err;

match kind {
Reservation(WriteKind::MutableBorrow(BorrowKind::DerefMut))
| Read(ReadKind::Borrow(BorrowKind::DerefMut)) => {
bug!(
"should never encounter BorrowKind::DerefMut with Reservation or Read when checking access permissions"
);
}
Reservation(WriteKind::MutableBorrow(
borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }),
))
| Write(WriteKind::MutableBorrow(
borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }),
borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. } | BorrowKind::DerefMut),
)) => {
let is_local_mutation_allowed = match borrow_kind {
BorrowKind::Unique => LocalMutationIsAllowed::Yes,
BorrowKind::Unique | BorrowKind::DerefMut => LocalMutationIsAllowed::Yes,
BorrowKind::Mut { .. } => is_local_mutation_allowed,
BorrowKind::Shared | BorrowKind::Shallow => unreachable!(),
};
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
BorrowKind::Unique => {
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow)
}
BorrowKind::Mut { .. } => {
BorrowKind::Mut { .. } | BorrowKind::DerefMut => {
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
}
};
Expand Down Expand Up @@ -459,7 +459,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
}

Rvalue::Ref(_, kind @ (BorrowKind::Mut { .. } | BorrowKind::Unique), place) => {
Rvalue::Ref(_, kind @ (BorrowKind::Mut { .. } | BorrowKind::Unique | BorrowKind::DerefMut), place) => {
let ty = place.ty(self.body, self.tcx).ty;
let is_allowed = match ty.kind() {
// Inside a `static mut`, `&mut [...]` is allowed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ where

fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
match kind {
mir::BorrowKind::Mut { .. } => true,
mir::BorrowKind::Mut { .. } | mir::BorrowKind::DerefMut => true,
mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
self.shared_borrow_allows_mutation(place)
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ impl<'tcx> Validator<'_, 'tcx> {
}
}

BorrowKind::Mut { .. } => {
BorrowKind::Mut { .. } | BorrowKind::DerefMut => {
let ty = place.ty(self.body, self.tcx).ty;

// In theory, any zero-sized value could be borrowed
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1993,7 +1993,10 @@ impl<'tcx> Rvalue<'tcx> {
impl BorrowKind {
pub fn allows_two_phase_borrow(&self) -> bool {
match *self {
BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false,
BorrowKind::Shared
| BorrowKind::Shallow
| BorrowKind::Unique
| BorrowKind::DerefMut => false,
BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow,
}
}
Expand All @@ -2002,7 +2005,7 @@ impl BorrowKind {
pub fn describe_mutability(&self) -> &str {
match *self {
BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => "immutable",
BorrowKind::Mut { .. } => "mutable",
BorrowKind::Mut { .. } | BorrowKind::DerefMut => "mutable",
}
}
}
Expand Down Expand Up @@ -2036,6 +2039,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
Ref(region, borrow_kind, ref place) => {
let kind_str = match borrow_kind {
BorrowKind::Shared => "",
BorrowKind::DerefMut => "deref mut ",
BorrowKind::Shallow => "shallow ",
BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ",
};
Expand Down
17 changes: 17 additions & 0 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,23 @@ pub enum BorrowKind {
/// (i.e., `adjustment::Adjust::Borrow`).
allow_two_phase_borrow: bool,
},

/// Corresponds to the borrow of the receiver in `DerefMut::deref_mut`. We don't want
/// to require the `mut` keyword for deref assignments on variables that implement
/// `DerefMut` to be more consistent with how we handle `&mut` in that case. More specifically
/// we want to allow the following to compile:
///
/// ```ignore (rust)
/// fn bar_mut(y: RefMut<'_, u32>) {
/// *y = 3;
/// }
/// ```
///
/// given that the `mut` on mutable references is implicit too.
///
/// `BorrowKind::DerefMut` is necessary in order to allow the borrow checker to let
/// this pass without `y` being `mut`.
DerefMut,
}

///////////////////////////////////////////////////////////////////////////
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ impl<'tcx> BinOp {
impl BorrowKind {
pub fn to_mutbl_lossy(self) -> hir::Mutability {
match self {
BorrowKind::Mut { .. } => hir::Mutability::Mut,
BorrowKind::Mut { .. } | BorrowKind::DerefMut => hir::Mutability::Mut,
BorrowKind::Shared => hir::Mutability::Not,

// We have no type corresponding to a unique imm borrow, so
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ macro_rules! make_mir_visitor {
BorrowKind::Unique => PlaceContext::NonMutatingUse(
NonMutatingUseContext::UniqueBorrow
),
BorrowKind::Mut { .. } =>
BorrowKind::Mut { .. } | BorrowKind::DerefMut =>
PlaceContext::MutatingUse(MutatingUseContext::Borrow),
};
self.visit_place(path, ctx, location);
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,11 @@ pub enum ExprKind<'tcx> {
Yield {
value: ExprId,
},
/// The argument to a `Call` of `DerefMut::deref_mut`. This is used to allow us to
/// adjust the `Mutability` of local variables that are deref'd.
DerefMutArg {
arg: ExprId,
},
}

/// Represents the association of a field identifier and an expression.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/thir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
}
}
Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
DerefMutArg { arg } => visitor.visit_expr(&visitor.thir()[arg]),
Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
visitor.visit_expr(&visitor.thir()[lhs]);
visitor.visit_expr(&visitor.thir()[rhs]);
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_mir_build/src/build/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
mutability: Mutability,
fake_borrow_temps: Option<&mut Vec<Local>>,
) -> BlockAnd<PlaceBuilder<'tcx>> {
debug!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability);

let this = self;
let expr_span = expr.span;
let source_info = this.source_info(expr_span);
Expand Down Expand Up @@ -437,6 +435,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
block.and(place_builder.deref())
}
ExprKind::DerefMutArg { .. } => {
bug!("encountered ExprKind::DerefMutArg in `expr_as_place`")
}
ExprKind::Index { lhs, index } => this.lower_index_expression(
block,
&this.thir[lhs],
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
block.and(Rvalue::Use(operand))
}
ExprKind::DerefMutArg { .. } => bug!("encountered DerefMutArg as Rvalue"),
}
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_mir_build/src/build/expr/category.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ impl Category {
| ExprKind::AddressOf { .. }
| ExprKind::Yield { .. }
| ExprKind::Call { .. }
| ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::Into)),
| ExprKind::InlineAsm { .. }
| ExprKind::DerefMutArg { .. } => Some(Category::Rvalue(RvalueFunc::Into)),

ExprKind::Array { .. }
| ExprKind::Tuple { .. }
Expand Down
Loading