Skip to content

Commit 332cac2

Browse files
authored
Rollup merge of #122598 - Nadrieril:full-derefpats, r=matthewjasper
deref patterns: lower deref patterns to MIR This lowers deref patterns to MIR. This is a bit tricky because this is the first kind of pattern that requires storing a value in a temporary. Thanks to #123324 false edges are no longer a problem. The thing I'm not confident about is the handling of fake borrows. This PR ignores any fake borrows inside a deref pattern. We are guaranteed to at least fake borrow the place of the first pointer value, which could be enough, but I'm not certain.
2 parents 68939f7 + 726fb55 commit 332cac2

File tree

51 files changed

+764
-301
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+764
-301
lines changed

compiler/rustc_borrowck/src/borrow_set.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
6969
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
7070
let kind = match self.kind {
7171
mir::BorrowKind::Shared => "",
72-
mir::BorrowKind::Fake => "fake ",
72+
mir::BorrowKind::Fake(mir::FakeBorrowKind::Deep) => "fake ",
73+
mir::BorrowKind::Fake(mir::FakeBorrowKind::Shallow) => "fake shallow ",
7374
mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ",
7475
// FIXME: differentiate `TwoPhaseBorrow`
7576
mir::BorrowKind::Mut {

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+19-10
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ use rustc_middle::hir::nested_filter::OnlyBodies;
1717
use rustc_middle::mir::tcx::PlaceTy;
1818
use rustc_middle::mir::{
1919
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
20-
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, Operand, Place,
21-
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
22-
VarBindingForm,
20+
FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
21+
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
22+
TerminatorKind, VarBindingForm,
2323
};
2424
use rustc_middle::ty::{
2525
self, suggest_constraining_type_params, PredicateKind, ToPredicate, Ty, TyCtxt,
@@ -1486,7 +1486,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
14861486
let first_borrow_desc;
14871487
let mut err = match (gen_borrow_kind, issued_borrow.kind) {
14881488
(
1489-
BorrowKind::Shared,
1489+
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
14901490
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
14911491
) => {
14921492
first_borrow_desc = "mutable ";
@@ -1504,7 +1504,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15041504
}
15051505
(
15061506
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
1507-
BorrowKind::Shared,
1507+
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
15081508
) => {
15091509
first_borrow_desc = "immutable ";
15101510
let mut err = self.cannot_reborrow_already_borrowed(
@@ -1566,7 +1566,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15661566
self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
15671567
}
15681568

1569-
(BorrowKind::Mut { .. }, BorrowKind::Fake) => {
1569+
(BorrowKind::Mut { .. }, BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
15701570
if let Some(immutable_section_description) =
15711571
self.classify_immutable_section(issued_borrow.assigned_place)
15721572
{
@@ -1629,7 +1629,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
16291629
)
16301630
}
16311631

1632-
(BorrowKind::Shared, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => {
1632+
(
1633+
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
1634+
BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },
1635+
) => {
16331636
first_borrow_desc = "first ";
16341637
self.cannot_reborrow_already_uniquely_borrowed(
16351638
span,
@@ -1659,8 +1662,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
16591662
)
16601663
}
16611664

1662-
(BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Fake)
1663-
| (BorrowKind::Fake, BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake) => {
1665+
(
1666+
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),
1667+
BorrowKind::Shared | BorrowKind::Fake(_),
1668+
)
1669+
| (
1670+
BorrowKind::Fake(FakeBorrowKind::Shallow),
1671+
BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_),
1672+
) => {
16641673
unreachable!()
16651674
}
16661675
};
@@ -3572,7 +3581,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
35723581
let loan_span = loan_spans.args_or_use();
35733582

35743583
let descr_place = self.describe_any_place(place.as_ref());
3575-
if loan.kind == BorrowKind::Fake {
3584+
if let BorrowKind::Fake(_) = loan.kind {
35763585
if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
35773586
let mut err = self.cannot_mutate_in_immutable_section(
35783587
span,

compiler/rustc_borrowck/src/diagnostics/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,7 @@ impl UseSpans<'_> {
654654
match kind {
655655
Some(kd) => match kd {
656656
rustc_middle::mir::BorrowKind::Shared
657-
| rustc_middle::mir::BorrowKind::Fake => {
657+
| rustc_middle::mir::BorrowKind::Fake(_) => {
658658
CaptureVarKind::Immut { kind_span: capture_kind_span }
659659
}
660660

compiler/rustc_borrowck/src/lib.rs

+16-13
Original file line numberDiff line numberDiff line change
@@ -1056,18 +1056,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
10561056
Control::Continue
10571057
}
10581058

1059-
(Read(_), BorrowKind::Shared | BorrowKind::Fake)
1060-
| (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
1061-
Control::Continue
1062-
}
1059+
(Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
1060+
| (
1061+
Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
1062+
BorrowKind::Mut { .. },
1063+
) => Control::Continue,
10631064

1064-
(Reservation(_), BorrowKind::Fake | BorrowKind::Shared) => {
1065+
(Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => {
10651066
// This used to be a future compatibility warning (to be
10661067
// disallowed on NLL). See rust-lang/rust#56254
10671068
Control::Continue
10681069
}
10691070

1070-
(Write(WriteKind::Move), BorrowKind::Fake) => {
1071+
(Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
10711072
// Handled by initialization checks.
10721073
Control::Continue
10731074
}
@@ -1175,10 +1176,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
11751176
match rvalue {
11761177
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
11771178
let access_kind = match bk {
1178-
BorrowKind::Fake => {
1179+
BorrowKind::Fake(FakeBorrowKind::Shallow) => {
11791180
(Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
11801181
}
1181-
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
1182+
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
1183+
(Deep, Read(ReadKind::Borrow(bk)))
1184+
}
11821185
BorrowKind::Mut { .. } => {
11831186
let wk = WriteKind::MutableBorrow(bk);
11841187
if allow_two_phase_borrow(bk) {
@@ -1197,7 +1200,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
11971200
flow_state,
11981201
);
11991202

1200-
let action = if bk == BorrowKind::Fake {
1203+
let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) {
12011204
InitializationRequiringAction::MatchOn
12021205
} else {
12031206
InitializationRequiringAction::Borrow
@@ -1557,7 +1560,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15571560

15581561
// only mutable borrows should be 2-phase
15591562
assert!(match borrow.kind {
1560-
BorrowKind::Shared | BorrowKind::Fake => false,
1563+
BorrowKind::Shared | BorrowKind::Fake(_) => false,
15611564
BorrowKind::Mut { .. } => true,
15621565
});
15631566

@@ -2122,14 +2125,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
21222125
| WriteKind::Replace
21232126
| WriteKind::StorageDeadOrDrop
21242127
| WriteKind::MutableBorrow(BorrowKind::Shared)
2125-
| WriteKind::MutableBorrow(BorrowKind::Fake),
2128+
| WriteKind::MutableBorrow(BorrowKind::Fake(_)),
21262129
)
21272130
| Write(
21282131
WriteKind::Move
21292132
| WriteKind::Replace
21302133
| WriteKind::StorageDeadOrDrop
21312134
| WriteKind::MutableBorrow(BorrowKind::Shared)
2132-
| WriteKind::MutableBorrow(BorrowKind::Fake),
2135+
| WriteKind::MutableBorrow(BorrowKind::Fake(_)),
21332136
) => {
21342137
if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
21352138
&& !self.has_buffered_diags()
@@ -2153,7 +2156,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
21532156
return false;
21542157
}
21552158
Read(
2156-
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake)
2159+
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_))
21572160
| ReadKind::Copy,
21582161
) => {
21592162
// Access authorized

compiler/rustc_borrowck/src/places_conflict.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use crate::Overlap;
5555
use crate::{AccessDepth, Deep, Shallow};
5656
use rustc_hir as hir;
5757
use rustc_middle::mir::{
58-
Body, BorrowKind, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem,
58+
Body, BorrowKind, FakeBorrowKind, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem,
5959
};
6060
use rustc_middle::ty::{self, TyCtxt};
6161
use std::cmp::max;
@@ -271,10 +271,10 @@ fn place_components_conflict<'tcx>(
271271
// If the second example, where we did, then we still know
272272
// that the borrow can access a *part* of our place that
273273
// our access cares about, so we still have a conflict.
274-
if borrow_kind == BorrowKind::Fake
274+
if borrow_kind == BorrowKind::Fake(FakeBorrowKind::Shallow)
275275
&& borrow_place.projection.len() < access_place.projection.len()
276276
{
277-
debug!("borrow_conflicts_with_place: fake borrow");
277+
debug!("borrow_conflicts_with_place: shallow borrow");
278278
false
279279
} else {
280280
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");

compiler/rustc_borrowck/src/polonius/loan_invalidations.rs

+13-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use rustc_data_structures::graph::dominators::Dominators;
22
use rustc_middle::mir::visit::Visitor;
3-
use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue};
3+
use rustc_middle::mir::{
4+
self, BasicBlock, Body, FakeBorrowKind, Location, NonDivergingIntrinsic, Place, Rvalue,
5+
};
46
use rustc_middle::mir::{BorrowKind, Mutability, Operand};
57
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
68
use rustc_middle::mir::{Statement, StatementKind};
@@ -239,10 +241,12 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
239241
match rvalue {
240242
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
241243
let access_kind = match bk {
242-
BorrowKind::Fake => {
244+
BorrowKind::Fake(FakeBorrowKind::Shallow) => {
243245
(Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
244246
}
245-
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
247+
BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
248+
(Deep, Read(ReadKind::Borrow(bk)))
249+
}
246250
BorrowKind::Mut { .. } => {
247251
let wk = WriteKind::MutableBorrow(bk);
248252
if allow_two_phase_borrow(bk) {
@@ -357,8 +361,11 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
357361
// have already taken the reservation
358362
}
359363

360-
(Read(_), BorrowKind::Fake | BorrowKind::Shared)
361-
| (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
364+
(Read(_), BorrowKind::Fake(_) | BorrowKind::Shared)
365+
| (
366+
Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
367+
BorrowKind::Mut { .. },
368+
) => {
362369
// Reads don't invalidate shared or shallow borrows
363370
}
364371

@@ -403,7 +410,7 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
403410

404411
// only mutable borrows should be 2-phase
405412
assert!(match borrow.kind {
406-
BorrowKind::Shared | BorrowKind::Fake => false,
413+
BorrowKind::Shared | BorrowKind::Fake(_) => false,
407414
BorrowKind::Mut { .. } => true,
408415
});
409416

compiler/rustc_const_eval/src/transform/check_consts/check.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
414414
BorrowKind::Shared => {
415415
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
416416
}
417-
BorrowKind::Fake => {
417+
BorrowKind::Fake(_) => {
418418
PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow)
419419
}
420420
BorrowKind::Mut { .. } => {
@@ -487,7 +487,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
487487
}
488488
}
489489

490-
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake, place)
490+
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake(_), place)
491491
| Rvalue::AddressOf(Mutability::Not, place) => {
492492
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
493493
self.ccx,

compiler/rustc_const_eval/src/transform/check_consts/resolver.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ where
105105
fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
106106
match kind {
107107
mir::BorrowKind::Mut { .. } => true,
108-
mir::BorrowKind::Shared | mir::BorrowKind::Fake => {
108+
mir::BorrowKind::Shared | mir::BorrowKind::Fake(_) => {
109109
self.shared_borrow_allows_mutation(place)
110110
}
111111
}

compiler/rustc_const_eval/src/transform/validate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -965,7 +965,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
965965
}
966966
}
967967
},
968-
Rvalue::Ref(_, BorrowKind::Fake, _) => {
968+
Rvalue::Ref(_, BorrowKind::Fake(_), _) => {
969969
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
970970
self.fail(
971971
location,

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

+9
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
750750
}
751751
}
752752
}
753+
} else if let PatKind::Deref(subpattern) = pat.kind {
754+
// A deref pattern is a bit special: the binding mode of its inner bindings
755+
// determines whether to borrow *at the level of the deref pattern* rather than
756+
// borrowing the bound place (since that inner place is inside the temporary that
757+
// stores the result of calling `deref()`/`deref_mut()` so can't be captured).
758+
let mutable = mc.typeck_results.pat_has_ref_mut_binding(subpattern);
759+
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
760+
let bk = ty::BorrowKind::from_mutbl(mutability);
761+
delegate.borrow(place, discr_place.hir_id, bk);
753762
}
754763
}));
755764
}

compiler/rustc_hir_typeck/src/mem_categorization.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -711,13 +711,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
711711
self.cat_pattern_(place_with_id, subpat, op)?;
712712
}
713713

714-
PatKind::Box(subpat) | PatKind::Ref(subpat, _) | PatKind::Deref(subpat) => {
714+
PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
715715
// box p1, &p1, &mut p1. we can ignore the mutability of
716716
// PatKind::Ref since that information is already contained
717717
// in the type.
718718
let subplace = self.cat_deref(pat, place_with_id)?;
719719
self.cat_pattern_(subplace, subpat, op)?;
720720
}
721+
PatKind::Deref(subpat) => {
722+
let mutable = self.typeck_results.pat_has_ref_mut_binding(subpat);
723+
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
724+
let re_erased = self.tcx().lifetimes.re_erased;
725+
let ty = self.pat_ty_adjusted(subpat)?;
726+
let ty = Ty::new_ref(self.tcx(), re_erased, ty, mutability);
727+
// A deref pattern generates a temporary.
728+
let place = self.cat_rvalue(pat.hir_id, ty);
729+
self.cat_pattern_(place, subpat, op)?;
730+
}
721731

722732
PatKind::Slice(before, ref slice, after) => {
723733
let Some(element_ty) = place_with_id.place.ty().builtin_index() else {

compiler/rustc_middle/src/mir/pretty.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,8 @@ impl<'tcx> Debug for Rvalue<'tcx> {
985985
Ref(region, borrow_kind, ref place) => {
986986
let kind_str = match borrow_kind {
987987
BorrowKind::Shared => "",
988-
BorrowKind::Fake => "fake ",
988+
BorrowKind::Fake(FakeBorrowKind::Deep) => "fake ",
989+
BorrowKind::Fake(FakeBorrowKind::Shallow) => "fake shallow ",
989990
BorrowKind::Mut { .. } => "mut ",
990991
};
991992

compiler/rustc_middle/src/mir/statement.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@ impl<'tcx> PlaceRef<'tcx> {
236236
}
237237
}
238238

239+
#[inline]
240+
pub fn to_place(&self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
241+
Place { local: self.local, projection: tcx.mk_place_elems(self.projection) }
242+
}
243+
239244
#[inline]
240245
pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
241246
if let &[ref proj_base @ .., elem] = self.projection {
@@ -446,15 +451,15 @@ impl<'tcx> Rvalue<'tcx> {
446451
impl BorrowKind {
447452
pub fn mutability(&self) -> Mutability {
448453
match *self {
449-
BorrowKind::Shared | BorrowKind::Fake => Mutability::Not,
454+
BorrowKind::Shared | BorrowKind::Fake(_) => Mutability::Not,
450455
BorrowKind::Mut { .. } => Mutability::Mut,
451456
}
452457
}
453458

454459
pub fn allows_two_phase_borrow(&self) -> bool {
455460
match *self {
456461
BorrowKind::Shared
457-
| BorrowKind::Fake
462+
| BorrowKind::Fake(_)
458463
| BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => {
459464
false
460465
}

0 commit comments

Comments
 (0)