Skip to content

Commit cdf8fcf

Browse files
committed
parse pinned local variable declarations
1 parent ecda83b commit cdf8fcf

File tree

49 files changed

+390
-85
lines changed

Some content is hidden

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

49 files changed

+390
-85
lines changed

compiler/rustc_ast/src/ast.rs

+23-10
Original file line numberDiff line numberDiff line change
@@ -718,18 +718,22 @@ impl ByRef {
718718
/// Used for both the explicit binding annotations given in the HIR for a binding
719719
/// and the final binding mode that we infer after type inference/match ergonomics.
720720
/// `.0` is the by-reference mode (`ref`, `ref mut`, or by value),
721-
/// `.1` is the mutability of the binding.
721+
/// `.1` is the pinnedness of the binding,
722+
/// `.2` is the mutability of the binding.
722723
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
723724
#[derive(Encodable, Decodable, HashStable_Generic)]
724-
pub struct BindingMode(pub ByRef, pub Mutability);
725+
pub struct BindingMode(pub ByRef, pub Pinnedness, pub Mutability);
725726

726727
impl BindingMode {
727-
pub const NONE: Self = Self(ByRef::No, Mutability::Not);
728-
pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Not);
729-
pub const MUT: Self = Self(ByRef::No, Mutability::Mut);
730-
pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Not);
731-
pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Mut);
732-
pub const MUT_REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Mut);
728+
pub const NONE: Self = Self(ByRef::No, Pinnedness::Not, Mutability::Not);
729+
pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Pinnedness::Not, Mutability::Not);
730+
pub const MUT: Self = Self(ByRef::No, Pinnedness::Not, Mutability::Mut);
731+
pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Pinnedness::Not, Mutability::Not);
732+
pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Pinnedness::Not, Mutability::Mut);
733+
pub const MUT_REF_MUT: Self =
734+
Self(ByRef::Yes(Mutability::Mut), Pinnedness::Not, Mutability::Mut);
735+
pub const PIN_CONST: Self = Self(ByRef::No, Pinnedness::Pinned, Mutability::Not);
736+
pub const PIN_MUT: Self = Self(ByRef::No, Pinnedness::Pinned, Mutability::Mut);
733737

734738
pub fn prefix_str(self) -> &'static str {
735739
match self {
@@ -739,6 +743,9 @@ impl BindingMode {
739743
Self::REF_MUT => "ref mut ",
740744
Self::MUT_REF => "mut ref ",
741745
Self::MUT_REF_MUT => "mut ref mut ",
746+
Self::PIN_CONST => "pin const ",
747+
Self::PIN_MUT => "pin mut ",
748+
Self(_, Pinnedness::Pinned, _) => panic!("unsupported pinned binding mode"),
742749
}
743750
}
744751
}
@@ -2551,7 +2558,9 @@ pub type ExplicitSelf = Spanned<SelfKind>;
25512558
impl Param {
25522559
/// Attempts to cast parameter to `ExplicitSelf`.
25532560
pub fn to_self(&self) -> Option<ExplicitSelf> {
2554-
if let PatKind::Ident(BindingMode(ByRef::No, mutbl), ident, _) = self.pat.kind {
2561+
if let PatKind::Ident(BindingMode(ByRef::No, Pinnedness::Not, mutbl), ident, _) =
2562+
self.pat.kind
2563+
{
25552564
if ident.name == kw::SelfLower {
25562565
return match self.ty.kind {
25572566
TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
@@ -2606,7 +2615,11 @@ impl Param {
26062615
attrs,
26072616
pat: P(Pat {
26082617
id: DUMMY_NODE_ID,
2609-
kind: PatKind::Ident(BindingMode(ByRef::No, mutbl), eself_ident, None),
2618+
kind: PatKind::Ident(
2619+
BindingMode(ByRef::No, Pinnedness::Not, mutbl),
2620+
eself_ident,
2621+
None,
2622+
),
26102623
span,
26112624
tokens: None,
26122625
}),

compiler/rustc_ast_ir/src/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,12 @@ pub enum Pinnedness {
8686
Not,
8787
Pinned,
8888
}
89+
90+
impl Pinnedness {
91+
pub fn is_pin(self) -> bool {
92+
matches!(self, Self::Pinned)
93+
}
94+
pub fn is_not(self) -> bool {
95+
matches!(self, Self::Not)
96+
}
97+
}

compiler/rustc_ast_lowering/src/item.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1189,7 +1189,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
11891189
// Check if this is a binding pattern, if so, we can optimize and avoid adding a
11901190
// `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
11911191
let (ident, is_simple_parameter) = match parameter.pat.kind {
1192-
hir::PatKind::Binding(hir::BindingMode(ByRef::No, _), _, ident, _) => (ident, true),
1192+
hir::PatKind::Binding(hir::BindingMode(ByRef::No, _, _), _, ident, _) => {
1193+
(ident, true)
1194+
}
11931195
// For `ref mut` or wildcard arguments, we can't reuse the binding, but
11941196
// we can keep the same name for the parameter.
11951197
// This lets rustdoc render it correctly in documentation.

compiler/rustc_ast_lowering/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1607,7 +1607,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16071607
implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
16081608
let is_mutable_pat = matches!(
16091609
arg.pat.kind,
1610-
PatKind::Ident(hir::BindingMode(_, Mutability::Mut), ..)
1610+
PatKind::Ident(hir::BindingMode(_, _, Mutability::Mut), ..)
16111611
);
16121612

16131613
match &arg.ty.kind {

compiler/rustc_ast_pretty/src/pprust/state.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1594,7 +1594,10 @@ impl<'a> State<'a> {
15941594
match &pat.kind {
15951595
PatKind::Wild => self.word("_"),
15961596
PatKind::Never => self.word("!"),
1597-
PatKind::Ident(BindingMode(by_ref, mutbl), ident, sub) => {
1597+
PatKind::Ident(BindingMode(by_ref, pin, mutbl), ident, sub) => {
1598+
if pin.is_pin() {
1599+
self.word_nbsp("pin");
1600+
}
15981601
if mutbl.is_mut() {
15991602
self.word_nbsp("mut");
16001603
}

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
304304
{
305305
match *decl.local_info() {
306306
LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
307-
binding_mode: BindingMode(ByRef::No, Mutability::Not),
307+
binding_mode: BindingMode(ByRef::No, _, Mutability::Not),
308308
opt_ty_info: Some(sp),
309309
opt_match_place: _,
310310
pat_span: _,
@@ -732,7 +732,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
732732
debug!("local_decl: {:?}", local_decl);
733733
let pat_span = match *local_decl.local_info() {
734734
LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
735-
binding_mode: BindingMode(ByRef::No, Mutability::Not),
735+
binding_mode: BindingMode(ByRef::No, _, Mutability::Not),
736736
opt_ty_info: _,
737737
opt_match_place: _,
738738
pat_span,
@@ -1147,7 +1147,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
11471147
}
11481148

11491149
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1150-
binding_mode: BindingMode(ByRef::No, _),
1150+
binding_mode: BindingMode(ByRef::No, _, _),
11511151
opt_ty_info,
11521152
..
11531153
})) => {
@@ -1225,7 +1225,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
12251225
}
12261226

12271227
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1228-
binding_mode: BindingMode(ByRef::Yes(_), _),
1228+
binding_mode: BindingMode(ByRef::Yes(_), _, _),
12291229
..
12301230
})) => {
12311231
let pattern_span: Span = local_decl.source_info.span;
@@ -1440,7 +1440,7 @@ fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symb
14401440
match *local_decl.local_info() {
14411441
// Check if mutably borrowing a mutable reference.
14421442
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1443-
binding_mode: BindingMode(ByRef::No, Mutability::Not),
1443+
binding_mode: BindingMode(ByRef::No, _, Mutability::Not),
14441444
..
14451445
})) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)),
14461446
LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => {

compiler/rustc_builtin_macros/src/deriving/generic/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ pub(crate) use SubstructureFields::*;
183183
use rustc_ast::ptr::P;
184184
use rustc_ast::{
185185
self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind,
186-
Generics, Mutability, PatKind, VariantData,
186+
Generics, Mutability, PatKind, Pinnedness, VariantData,
187187
};
188188
use rustc_attr_parsing as attr;
189189
use rustc_expand::base::{Annotatable, ExtCtxt};
@@ -1477,7 +1477,11 @@ impl<'a> TraitDef<'a> {
14771477
struct_field.ident,
14781478
cx.pat(
14791479
path.span,
1480-
PatKind::Ident(BindingMode(by_ref, Mutability::Not), path, None),
1480+
PatKind::Ident(
1481+
BindingMode(by_ref, Pinnedness::Not, Mutability::Not),
1482+
path,
1483+
None,
1484+
),
14811485
),
14821486
)
14831487
});

compiler/rustc_hir/src/pat_util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl hir::Pat<'_> {
9595

9696
pub fn simple_ident(&self) -> Option<Ident> {
9797
match self.kind {
98-
PatKind::Binding(BindingMode(ByRef::No, _), _, ident, None) => Some(ident),
98+
PatKind::Binding(BindingMode(ByRef::No, _, _), _, ident, None) => Some(ident),
9999
_ => None,
100100
}
101101
}

compiler/rustc_hir_analysis/src/check/region.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ fn resolve_local<'tcx>(
681681
// & expression, and its lifetime would be extended to the end of the block (due
682682
// to a different rule, not the below code).
683683
match pat.kind {
684-
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(_), _), ..) => true,
684+
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(_), _, _), ..) => true,
685685

686686
PatKind::Struct(_, field_pats, _) => field_pats.iter().any(|fp| is_binding_pat(fp.pat)),
687687

@@ -700,7 +700,7 @@ fn resolve_local<'tcx>(
700700
}
701701

702702
PatKind::Ref(_, _)
703-
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
703+
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _, _), ..)
704704
| PatKind::Wild
705705
| PatKind::Never
706706
| PatKind::Path(_)

compiler/rustc_hir_pretty/src/lib.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1871,7 +1871,10 @@ impl<'a> State<'a> {
18711871
match pat.kind {
18721872
PatKind::Wild => self.word("_"),
18731873
PatKind::Never => self.word("!"),
1874-
PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => {
1874+
PatKind::Binding(BindingMode(by_ref, pin, mutbl), _, ident, sub) => {
1875+
if pin.is_pin() {
1876+
self.word_nbsp("pin");
1877+
}
18751878
if mutbl.is_mut() {
18761879
self.word_nbsp("mut");
18771880
}

compiler/rustc_hir_typeck/src/pat.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
790790

791791
// Determine the binding mode...
792792
let bm = match user_bind_annot {
793-
BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
793+
BindingMode(ByRef::No, pin, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
794794
// Only mention the experimental `mut_ref` feature if if we're in edition 2024 and
795795
// using other experimental matching features compatible with it.
796796
if pat.span.at_least_rust_2024()
@@ -807,7 +807,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
807807
.emit();
808808
}
809809

810-
BindingMode(def_br, Mutability::Mut)
810+
BindingMode(def_br, pin, Mutability::Mut)
811811
} else {
812812
// `mut` resets the binding mode on edition <= 2021
813813
self.add_rust_2024_migration_desugared_pat(
@@ -816,11 +816,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
816816
ident.span,
817817
"requires binding by-value, but the implicit default is by-reference",
818818
);
819-
BindingMode(ByRef::No, Mutability::Mut)
819+
BindingMode(ByRef::No, pin, Mutability::Mut)
820820
}
821821
}
822-
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
823-
BindingMode(ByRef::Yes(_), _) => {
822+
BindingMode(ByRef::No, pin, mutbl) => BindingMode(def_br, pin, mutbl),
823+
BindingMode(ByRef::Yes(_), _, _) => {
824824
if matches!(def_br, ByRef::Yes(_)) {
825825
// `ref`/`ref mut` overrides the binding mode on edition <= 2021
826826
self.add_rust_2024_migration_desugared_pat(
@@ -1043,7 +1043,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10431043
if let PatKind::Ref(the_ref, _) = i.kind
10441044
&& let PatKind::Binding(mt, _, ident, _) = the_ref.kind
10451045
{
1046-
let BindingMode(_, mtblty) = mt;
1046+
let BindingMode(_, _, mtblty) = mt;
10471047
err.span_suggestion_verbose(
10481048
i.span,
10491049
format!("consider removing `&{mutability}` from the pattern"),

compiler/rustc_hir_typeck/src/upvar.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
276276
else {
277277
bug!();
278278
};
279-
let hir::PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), _, _, _) = pat.kind
279+
let hir::PatKind::Binding(hir::BindingMode(hir::ByRef::No, _, _), _, _, _) =
280+
pat.kind
280281
else {
281282
// Complex pattern, skip the non-upvar local.
282283
continue;
@@ -1799,7 +1800,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17991800

18001801
let bm = *typeck_results.pat_binding_modes().get(var_hir_id).expect("missing binding mode");
18011802

1802-
let mut is_mutbl = bm.1;
1803+
let mut is_mutbl = bm.2;
18031804

18041805
for pointer_ty in place.deref_tys() {
18051806
match self.structurally_resolve_type(self.tcx.hir().span(var_hir_id), pointer_ty).kind()

compiler/rustc_middle/src/mir/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1122,7 +1122,7 @@ impl<'tcx> LocalDecl<'tcx> {
11221122
self.local_info(),
11231123
LocalInfo::User(
11241124
BindingForm::Var(VarBindingForm {
1125-
binding_mode: BindingMode(ByRef::No, _),
1125+
binding_mode: BindingMode(ByRef::No, _, _),
11261126
opt_ty_info: _,
11271127
opt_match_place: _,
11281128
pat_span: _,
@@ -1139,7 +1139,7 @@ impl<'tcx> LocalDecl<'tcx> {
11391139
self.local_info(),
11401140
LocalInfo::User(
11411141
BindingForm::Var(VarBindingForm {
1142-
binding_mode: BindingMode(ByRef::No, _),
1142+
binding_mode: BindingMode(ByRef::No, _, _),
11431143
opt_ty_info: _,
11441144
opt_match_place: _,
11451145
pat_span: _,

compiler/rustc_middle/src/thir.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ impl<'tcx> Pat<'tcx> {
629629
pub fn simple_ident(&self) -> Option<Symbol> {
630630
match self.kind {
631631
PatKind::Binding {
632-
name, mode: BindingMode(ByRef::No, _), subpattern: None, ..
632+
name, mode: BindingMode(ByRef::No, _, _), subpattern: None, ..
633633
} => Some(name),
634634
_ => None,
635635
}

compiler/rustc_middle/src/ty/typeck_results.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ impl<'tcx> TypeckResults<'tcx> {
456456
let mut has_ref_mut = false;
457457
pat.walk(|pat| {
458458
if let hir::PatKind::Binding(_, id, _, _) = pat.kind
459-
&& let Some(BindingMode(ByRef::Yes(Mutability::Mut), _)) =
459+
&& let Some(BindingMode(ByRef::Yes(Mutability::Mut), _, _)) =
460460
self.pat_binding_modes().get(id)
461461
{
462462
has_ref_mut = true;

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

+5-3
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
583583
) -> BlockAnd<()> {
584584
match irrefutable_pat.kind {
585585
// Optimize the case of `let x = ...` to write directly into `x`
586-
PatKind::Binding { mode: BindingMode(ByRef::No, _), var, subpattern: None, .. } => {
586+
PatKind::Binding {
587+
mode: BindingMode(ByRef::No, _, _), var, subpattern: None, ..
588+
} => {
587589
let place = self.storage_live_binding(
588590
block,
589591
var,
@@ -608,7 +610,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
608610
box Pat {
609611
kind:
610612
PatKind::Binding {
611-
mode: BindingMode(ByRef::No, _),
613+
mode: BindingMode(ByRef::No, _, _),
612614
var,
613615
subpattern: None,
614616
..
@@ -2758,7 +2760,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
27582760
let tcx = self.tcx;
27592761
let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
27602762
let local = LocalDecl {
2761-
mutability: mode.1,
2763+
mutability: mode.2,
27622764
ty: var_ty,
27632765
user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) },
27642766
source_info,

compiler/rustc_mir_build/src/builder/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -963,7 +963,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
963963
// Don't introduce extra copies for simple bindings
964964
PatKind::Binding {
965965
var,
966-
mode: BindingMode(ByRef::No, mutability),
966+
mode: BindingMode(ByRef::No, pin, mutability),
967967
subpattern: None,
968968
..
969969
} => {
@@ -973,7 +973,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
973973
if let Some(kind) = param.self_kind {
974974
LocalInfo::User(BindingForm::ImplicitSelf(kind))
975975
} else {
976-
let binding_mode = BindingMode(ByRef::No, mutability);
976+
let binding_mode = BindingMode(ByRef::No, pin, mutability);
977977
LocalInfo::User(BindingForm::Var(VarBindingForm {
978978
binding_mode,
979979
opt_ty_info: param.ty_span,

compiler/rustc_mir_build/src/check_unsafety.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
372372
}
373373
visit::walk_pat(self, pat);
374374
}
375-
PatKind::Binding { mode: BindingMode(ByRef::Yes(rm), _), ty, .. } => {
375+
PatKind::Binding { mode: BindingMode(ByRef::Yes(rm), _, _), ty, .. } => {
376376
if self.inside_adt {
377377
let ty::Ref(_, ty, _) = ty.kind() else {
378378
span_bug!(

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,7 @@ fn check_for_bindings_named_same_as_variants(
876876
) {
877877
if let PatKind::Binding {
878878
name,
879-
mode: BindingMode(ByRef::No, Mutability::Not),
879+
mode: BindingMode(ByRef::No, _, Mutability::Not),
880880
subpattern: None,
881881
ty,
882882
..

compiler/rustc_parse/messages.ftl

+7
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,8 @@ parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable
663663
664664
parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
665665
666+
parse_note_pin_pattern_usage = `pin mut` or `pin const` may be followed by `variable` and `variable @ pattern`
667+
666668
parse_nul_in_c_str = null characters in C string literals are not supported
667669
668670
parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
@@ -698,6 +700,11 @@ parse_pattern_on_wrong_side_of_at = pattern on wrong side of `@`
698700
.label_binding = binding on the right, should be on the left
699701
.suggestion = switch the order
700702
703+
parse_pin_on_nested_ident_pattern = `pin {$mutbl}` must be attached to each individual binding
704+
.suggestion = add `pin {$mutbl}` to each binding
705+
parse_pin_on_non_ident_pattern = `pin {$mutbl}` must be followed by a named binding
706+
.suggestion = remove the `pin {$mutbl}` prefix
707+
701708
parse_question_mark_in_type = invalid `?` in type
702709
.label = `?` is only allowed on expressions, not types
703710
.suggestion = if you meant to express that the type might not contain a value, use the `Option` wrapper type

0 commit comments

Comments
 (0)