Skip to content

Commit 566c23d

Browse files
committed
THIR patterns: Explicitly distinguish &pin from plain &/&mut
1 parent 63f4513 commit 566c23d

File tree

11 files changed

+71
-24
lines changed

11 files changed

+71
-24
lines changed

compiler/rustc_middle/src/thir.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -807,12 +807,22 @@ pub enum PatKind<'tcx> {
807807
subpatterns: Vec<FieldPat<'tcx>>,
808808
},
809809

810-
/// `box P`, `&P`, `&mut P`, etc.
810+
/// Explicit or implicit `&P` or `&mut P`, for some subpattern `P`.
811+
///
812+
/// Implicit `&`/`&mut` patterns can be inserted by match-ergonomics.
813+
///
814+
/// With `feature(pin_ergonomics)`, this can also be `&pin const P` or
815+
/// `&pin mut P`, as indicated by the `pin` field.
811816
Deref {
817+
#[type_visitable(ignore)]
818+
pin: hir::Pinnedness,
812819
subpattern: Box<Pat<'tcx>>,
813820
},
814821

815-
/// Deref pattern, written `box P` for now.
822+
/// Explicit or implicit `deref!(..)` pattern, under `feature(deref_patterns)`.
823+
/// Represents a call to `Deref` or `DerefMut`, or a deref-move of `Box`.
824+
///
825+
/// `box P` patterns also lower to this, under `feature(box_patterns)`.
816826
DerefPattern {
817827
subpattern: Box<Pat<'tcx>>,
818828
/// Whether the pattern scrutinee needs to be borrowed in order to call `Deref::deref` or

compiler/rustc_middle/src/thir/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
268268
| PatKind::Error(_) => {}
269269

270270
PatKind::Binding { subpattern: Some(subpattern), .. }
271-
| PatKind::Deref { subpattern }
271+
| PatKind::Deref { subpattern, .. }
272272
| PatKind::DerefPattern { subpattern, .. } => callback(subpattern),
273273

274274
PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => {

compiler/rustc_mir_build/src/builder/matches/match_pair.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::sync::Arc;
22

33
use rustc_abi::FieldIdx;
44
use rustc_middle::mir::*;
5+
use rustc_middle::span_bug;
56
use rustc_middle::thir::*;
67
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
78

@@ -314,23 +315,24 @@ impl<'tcx> MatchPairTree<'tcx> {
314315
None
315316
}
316317

317-
// FIXME: Pin-patterns should probably have their own pattern kind,
318-
// instead of overloading `PatKind::Deref` via the pattern type.
319-
PatKind::Deref { ref subpattern }
320-
if let Some(ref_ty) = pattern.ty.pinned_ty()
321-
&& ref_ty.is_ref() =>
322-
{
318+
PatKind::Deref { pin: Pinnedness::Pinned, ref subpattern } => {
319+
let pinned_ref_ty = match pattern.ty.pinned_ty() {
320+
Some(p_ty) if p_ty.is_ref() => p_ty,
321+
_ => span_bug!(pattern.span, "bad type for pinned deref: {:?}", pattern.ty),
322+
};
323323
MatchPairTree::for_pattern(
324-
place_builder.field(FieldIdx::ZERO, ref_ty).deref(),
324+
// Project into the `Pin(_)` struct, then deref the inner `&` or `&mut`.
325+
place_builder.field(FieldIdx::ZERO, pinned_ref_ty).deref(),
325326
subpattern,
326327
cx,
327328
&mut subpairs,
328329
extra_data,
329330
);
331+
330332
None
331333
}
332334

333-
PatKind::Deref { ref subpattern }
335+
PatKind::Deref { pin: Pinnedness::Not, ref subpattern }
334336
| PatKind::DerefPattern { ref subpattern, borrow: DerefPatBorrowMode::Box } => {
335337
MatchPairTree::for_pattern(
336338
place_builder.deref(),

compiler/rustc_mir_build/src/builder/matches/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::mem;
1010
use std::sync::Arc;
1111

1212
use itertools::{Itertools, Position};
13-
use rustc_abi::{FIRST_VARIANT, VariantIdx};
13+
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
1414
use rustc_data_structures::debug_assert_matches;
1515
use rustc_data_structures::fx::FxIndexMap;
1616
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -909,7 +909,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
909909
| PatKind::Never
910910
| PatKind::Error(_) => {}
911911

912-
PatKind::Deref { ref subpattern } => {
912+
PatKind::Deref { pin: Pinnedness::Pinned, ref subpattern } => {
913+
// Project into the `Pin(_)` struct, then deref the inner `&` or `&mut`.
914+
visit_subpat(self, subpattern, &user_tys.leaf(FieldIdx::ZERO).deref(), f);
915+
}
916+
PatKind::Deref { pin: Pinnedness::Not, ref subpattern } => {
913917
visit_subpat(self, subpattern, &user_tys.deref(), f);
914918
}
915919

compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,12 @@ impl<'tcx> ConstToPat<'tcx> {
294294
|| pointee_ty.is_slice()
295295
|| pointee_ty.is_sized(tcx, self.typing_env)
296296
{
297-
// References have the same valtree representation as their pointee.
298297
PatKind::Deref {
298+
// This node has type `ty::Ref`, so it's not a pin-deref.
299+
pin: hir::Pinnedness::Not,
300+
// Lower the valtree to a pattern as the pointee type.
301+
// This works because references have the same valtree
302+
// representation as their pointee.
299303
subpattern: self.valtree_to_pat(ty::Value { ty: *pointee_ty, valtree }),
300304
}
301305
} else {

compiler/rustc_mir_build/src/thir/pattern/mod.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,16 @@ impl<'tcx> PatCtxt<'tcx> {
132132
debug!("{:?}: wrapping pattern with adjustment {:?}", thir_pat, adjust);
133133
let span = thir_pat.span;
134134
let kind = match adjust.kind {
135-
PatAdjust::BuiltinDeref => PatKind::Deref { subpattern: thir_pat },
135+
PatAdjust::BuiltinDeref => {
136+
PatKind::Deref { pin: hir::Pinnedness::Not, subpattern: thir_pat }
137+
}
136138
PatAdjust::OverloadedDeref => {
137139
let borrow = self.typeck_results.deref_pat_borrow_mode(adjust.source, pat);
138140
PatKind::DerefPattern { subpattern: thir_pat, borrow }
139141
}
140-
PatAdjust::PinDeref => PatKind::Deref { subpattern: thir_pat },
142+
PatAdjust::PinDeref => {
143+
PatKind::Deref { pin: hir::Pinnedness::Pinned, subpattern: thir_pat }
144+
}
141145
};
142146
Box::new(Pat { span, ty: adjust.source, kind, extra: None })
143147
});
@@ -334,15 +338,15 @@ impl<'tcx> PatCtxt<'tcx> {
334338
let borrow = self.typeck_results.deref_pat_borrow_mode(ty, subpattern);
335339
PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), borrow }
336340
}
337-
hir::PatKind::Ref(subpattern, _, _) => {
341+
hir::PatKind::Ref(subpattern, pin, _) => {
338342
// Track the default binding mode for the Rust 2024 migration suggestion.
339343
let opt_old_mode_span =
340344
self.rust_2024_migration.as_mut().and_then(|s| s.visit_explicit_deref());
341345
let subpattern = self.lower_pattern(subpattern);
342346
if let Some(s) = &mut self.rust_2024_migration {
343347
s.leave_ref(opt_old_mode_span);
344348
}
345-
PatKind::Deref { subpattern }
349+
PatKind::Deref { pin, subpattern }
346350
}
347351
hir::PatKind::Box(subpattern) => PatKind::DerefPattern {
348352
subpattern: self.lower_pattern(subpattern),

compiler/rustc_mir_build/src/thir/print.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -774,8 +774,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
774774
print_indented!(self, "]", depth_lvl + 2);
775775
print_indented!(self, "}", depth_lvl + 1);
776776
}
777-
PatKind::Deref { subpattern } => {
777+
PatKind::Deref { pin, subpattern } => {
778778
print_indented!(self, "Deref { ", depth_lvl + 1);
779+
print_indented!(self, format_args!("pin: {pin:?}"), depth_lvl + 2);
779780
print_indented!(self, "subpattern:", depth_lvl + 2);
780781
self.print_pat(subpattern, depth_lvl + 2);
781782
print_indented!(self, "}", depth_lvl + 1);

compiler/rustc_pattern_analysis/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
// tidy-alphabetical-start
66
#![allow(unused_crate_dependencies)]
7+
#![cfg_attr(feature = "rustc", feature(if_let_guard))]
78
// tidy-alphabetical-end
89

910
pub(crate) mod checks;

compiler/rustc_pattern_analysis/src/rustc.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use std::iter::once;
44

55
use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx};
66
use rustc_arena::DroplessArena;
7-
use rustc_hir::HirId;
87
use rustc_hir::def_id::DefId;
8+
use rustc_hir::{self as hir, HirId};
99
use rustc_index::{Idx, IndexVec};
1010
use rustc_middle::middle::stability::EvalResult;
1111
use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary};
@@ -468,12 +468,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
468468
fields = vec![];
469469
arity = 0;
470470
}
471-
PatKind::Deref { subpattern } => {
471+
PatKind::Deref { pin, subpattern } => {
472472
fields = vec![self.lower_pat(subpattern).at_index(0)];
473473
arity = 1;
474-
ctor = match ty.pinned_ref() {
475-
None if ty.is_ref() => Ref,
476-
Some((inner_ty, _)) => {
474+
ctor = match pin {
475+
hir::Pinnedness::Not if ty.is_ref() => Ref,
476+
hir::Pinnedness::Pinned if let Some((inner_ty, _)) = ty.pinned_ref() => {
477477
self.internal_state.has_lowered_deref_pat.set(true);
478478
DerefPattern(RevealedTy(inner_ty))
479479
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![crate_type = "rlib"]
2+
#![feature(pin_ergonomics)]
3+
#![expect(incomplete_features)]
4+
//@ edition: 2024
5+
//@ check-pass
6+
7+
// Test that we don't ICE when projecting user-type-annotations through a `&pin` pattern.
8+
//
9+
// Historically, this could occur when the code handling those projections did not know
10+
// about `&pin` patterns, and incorrectly treated them as plain `&`/`&mut` patterns instead.
11+
12+
struct Data {
13+
x: u32
14+
}
15+
16+
pub fn project_user_type_through_pin() -> u32 {
17+
let &pin const Data { x }: &pin const Data = &pin const Data { x: 30 };
18+
x
19+
}

0 commit comments

Comments
 (0)