From 772c5761b1cbbb9667bf9b6f2bf8f960c5a0b8d3 Mon Sep 17 00:00:00 2001 From: Frank King Date: Sat, 8 Feb 2025 09:20:56 +0800 Subject: [PATCH 1/2] parse `pin`ned local variable declarations --- compiler/rustc_ast/src/ast.rs | 33 ++++-- compiler/rustc_ast_ir/src/lib.rs | 9 ++ compiler/rustc_ast_lowering/src/item.rs | 4 +- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 5 +- .../src/diagnostics/mutability_errors.rs | 10 +- .../src/deriving/generic/mod.rs | 8 +- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_hir/src/pat_util.rs | 2 +- .../rustc_hir_analysis/src/check/region.rs | 4 +- compiler/rustc_hir_pretty/src/lib.rs | 5 +- compiler/rustc_hir_typeck/src/pat.rs | 20 ++-- compiler/rustc_hir_typeck/src/upvar.rs | 5 +- compiler/rustc_middle/src/mir/mod.rs | 4 +- compiler/rustc_middle/src/thir.rs | 2 +- .../rustc_middle/src/ty/typeck_results.rs | 2 +- .../src/builder/matches/mod.rs | 8 +- compiler/rustc_mir_build/src/builder/mod.rs | 4 +- .../rustc_mir_build/src/check_unsafety.rs | 2 +- .../src/thir/pattern/check_match.rs | 2 +- compiler/rustc_parse/messages.ftl | 7 ++ compiler/rustc_parse/src/errors.rs | 21 ++++ compiler/rustc_parse/src/parser/pat.rs | 105 +++++++++++++++--- .../clippy_lints/src/index_refutable_slice.rs | 2 +- .../clippy/clippy_lints/src/let_if_seq.rs | 2 +- .../clippy_lints/src/loops/same_item_push.rs | 2 +- .../clippy_lints/src/matches/match_as_ref.rs | 2 +- .../src/matches/needless_match.rs | 2 +- .../clippy_lints/src/methods/clone_on_copy.rs | 2 +- .../clippy_lints/src/methods/filter_next.rs | 2 +- .../src/methods/iter_overeager_cloned.rs | 2 +- .../src/methods/manual_inspect.rs | 2 +- src/tools/clippy/clippy_lints/src/misc.rs | 4 +- .../src/needless_arbitrary_self_type.rs | 2 +- .../src/needless_pass_by_value.rs | 2 +- .../clippy/clippy_lints/src/question_mark.rs | 2 +- .../clippy_lints/src/redundant_locals.rs | 4 +- .../clippy/clippy_lints/src/utils/author.rs | 5 +- .../clippy/clippy_utils/src/hir_utils.rs | 3 +- src/tools/rustfmt/src/patterns.rs | 49 ++++++-- src/tools/rustfmt/src/utils.rs | 13 +++ src/tools/rustfmt/tests/source/pin_sugar.rs | 33 ++++++ src/tools/rustfmt/tests/target/pin_sugar.rs | 14 +++ .../pin-ergonomics/pinned-local-no-const.rs | 13 +++ .../pinned-local-no-const.stderr | 14 +++ .../pin-ergonomics/pinned-local.rs | 19 ++++ .../pin-ergonomics/pinned-local.stderr | 35 ++++++ .../feature-gate-pin_ergonomics.rs | 7 ++ .../feature-gate-pin_ergonomics.stderr | 38 ++++++- tests/ui/thir-print/thir-tree-match.stdout | 2 +- 50 files changed, 450 insertions(+), 93 deletions(-) create mode 100644 tests/ui/async-await/pin-ergonomics/pinned-local-no-const.rs create mode 100644 tests/ui/async-await/pin-ergonomics/pinned-local-no-const.stderr create mode 100644 tests/ui/async-await/pin-ergonomics/pinned-local.rs create mode 100644 tests/ui/async-await/pin-ergonomics/pinned-local.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 29c1d34a125a4..853a8ccb6f824 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -720,18 +720,22 @@ impl ByRef { /// Used for both the explicit binding annotations given in the HIR for a binding /// and the final binding mode that we infer after type inference/match ergonomics. /// `.0` is the by-reference mode (`ref`, `ref mut`, or by value), -/// `.1` is the mutability of the binding. +/// `.1` is the pinnedness of the binding, +/// `.2` is the mutability of the binding. #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Encodable, Decodable, HashStable_Generic)] -pub struct BindingMode(pub ByRef, pub Mutability); +pub struct BindingMode(pub ByRef, pub Pinnedness, pub Mutability); impl BindingMode { - pub const NONE: Self = Self(ByRef::No, Mutability::Not); - pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Not); - pub const MUT: Self = Self(ByRef::No, Mutability::Mut); - pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Not); - pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Mut); - pub const MUT_REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Mut); + pub const NONE: Self = Self(ByRef::No, Pinnedness::Not, Mutability::Not); + pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Pinnedness::Not, Mutability::Not); + pub const MUT: Self = Self(ByRef::No, Pinnedness::Not, Mutability::Mut); + pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Pinnedness::Not, Mutability::Not); + pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Pinnedness::Not, Mutability::Mut); + pub const MUT_REF_MUT: Self = + Self(ByRef::Yes(Mutability::Mut), Pinnedness::Not, Mutability::Mut); + pub const PIN_CONST: Self = Self(ByRef::No, Pinnedness::Pinned, Mutability::Not); + pub const PIN_MUT: Self = Self(ByRef::No, Pinnedness::Pinned, Mutability::Mut); pub fn prefix_str(self) -> &'static str { match self { @@ -741,6 +745,9 @@ impl BindingMode { Self::REF_MUT => "ref mut ", Self::MUT_REF => "mut ref ", Self::MUT_REF_MUT => "mut ref mut ", + Self::PIN_CONST => "pin const ", + Self::PIN_MUT => "pin mut ", + Self(_, Pinnedness::Pinned, _) => panic!("unsupported pinned binding mode"), } } } @@ -2604,7 +2611,9 @@ pub type ExplicitSelf = Spanned; impl Param { /// Attempts to cast parameter to `ExplicitSelf`. pub fn to_self(&self) -> Option { - if let PatKind::Ident(BindingMode(ByRef::No, mutbl), ident, _) = self.pat.kind { + if let PatKind::Ident(BindingMode(ByRef::No, Pinnedness::Not, mutbl), ident, _) = + self.pat.kind + { if ident.name == kw::SelfLower { return match self.ty.kind { TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))), @@ -2659,7 +2668,11 @@ impl Param { attrs, pat: P(Pat { id: DUMMY_NODE_ID, - kind: PatKind::Ident(BindingMode(ByRef::No, mutbl), eself_ident, None), + kind: PatKind::Ident( + BindingMode(ByRef::No, Pinnedness::Not, mutbl), + eself_ident, + None, + ), span, tokens: None, }), diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs index 9884e191ea7bd..c929c40a8511d 100644 --- a/compiler/rustc_ast_ir/src/lib.rs +++ b/compiler/rustc_ast_ir/src/lib.rs @@ -93,3 +93,12 @@ pub enum Pinnedness { Not, Pinned, } + +impl Pinnedness { + pub fn is_pin(self) -> bool { + matches!(self, Self::Pinned) + } + pub fn is_not(self) -> bool { + matches!(self, Self::Not) + } +} diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 1d3db64b47ed9..e4f1606c14cab 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1283,7 +1283,9 @@ impl<'hir> LoweringContext<'_, 'hir> { // Check if this is a binding pattern, if so, we can optimize and avoid adding a // `let = __argN;` statement. In this case, we do not rename the parameter. let (ident, is_simple_parameter) = match parameter.pat.kind { - hir::PatKind::Binding(hir::BindingMode(ByRef::No, _), _, ident, _) => (ident, true), + hir::PatKind::Binding(hir::BindingMode(ByRef::No, _, _), _, ident, _) => { + (ident, true) + } // For `ref mut` or wildcard arguments, we can't reuse the binding, but // we can keep the same name for the parameter. // This lets rustdoc render it correctly in documentation. diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b865cbedbbb78..b6bb3f5a96726 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1628,7 +1628,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| { let is_mutable_pat = matches!( arg.pat.kind, - PatKind::Ident(hir::BindingMode(_, Mutability::Mut), ..) + PatKind::Ident(hir::BindingMode(_, _, Mutability::Mut), ..) ); match &arg.ty.kind { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 44e956dc37f3e..dc8c2452c3998 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1620,7 +1620,10 @@ impl<'a> State<'a> { match &pat.kind { PatKind::Wild => self.word("_"), PatKind::Never => self.word("!"), - PatKind::Ident(BindingMode(by_ref, mutbl), ident, sub) => { + PatKind::Ident(BindingMode(by_ref, pin, mutbl), ident, sub) => { + if pin.is_pin() { + self.word_nbsp("pin"); + } if mutbl.is_mut() { self.word_nbsp("mut"); } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index be4a7736b1c20..b521db80cbe29 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -305,7 +305,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { { match *decl.local_info() { LocalInfo::User(BindingForm::Var(mir::VarBindingForm { - binding_mode: BindingMode(ByRef::No, Mutability::Not), + binding_mode: BindingMode(ByRef::No, _, Mutability::Not), opt_ty_info: Some(sp), opt_match_place: _, pat_span: _, @@ -732,7 +732,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { debug!("local_decl: {:?}", local_decl); let pat_span = match *local_decl.local_info() { LocalInfo::User(BindingForm::Var(mir::VarBindingForm { - binding_mode: BindingMode(ByRef::No, Mutability::Not), + binding_mode: BindingMode(ByRef::No, _, Mutability::Not), opt_ty_info: _, opt_match_place: _, pat_span, @@ -1144,7 +1144,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: BindingMode(ByRef::No, _), + binding_mode: BindingMode(ByRef::No, _, _), opt_ty_info, .. })) => { @@ -1223,7 +1223,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: BindingMode(ByRef::Yes(_), _), + binding_mode: BindingMode(ByRef::Yes(_), _, _), .. })) => { let pattern_span: Span = local_decl.source_info.span; @@ -1438,7 +1438,7 @@ fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)), LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 234ec8582165b..e1b24f892b8e1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -183,7 +183,7 @@ pub(crate) use SubstructureFields::*; use rustc_ast::ptr::P; use rustc_ast::{ self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, - Generics, Mutability, PatKind, VariantData, + Generics, Mutability, PatKind, Pinnedness, VariantData, }; use rustc_attr_parsing as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; @@ -1470,7 +1470,11 @@ impl<'a> TraitDef<'a> { struct_field.ident, cx.pat( path.span, - PatKind::Ident(BindingMode(by_ref, Mutability::Not), path, None), + PatKind::Ident( + BindingMode(by_ref, Pinnedness::Not, Mutability::Not), + path, + None, + ), ), ) }); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 61f64e62058fc..10827f98dc914 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -11,7 +11,7 @@ use rustc_ast::{ }; pub use rustc_ast::{ BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, - ImplPolarity, IsAuto, Movability, Mutability, UnOp, UnsafeBinderCastKind, + ImplPolarity, IsAuto, Movability, Mutability, Pinnedness, UnOp, UnsafeBinderCastKind, }; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index 8dd1e4e829274..6551ef2c3df50 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -95,7 +95,7 @@ impl hir::Pat<'_> { pub fn simple_ident(&self) -> Option { match self.kind { - PatKind::Binding(BindingMode(ByRef::No, _), _, ident, None) => Some(ident), + PatKind::Binding(BindingMode(ByRef::No, _, _), _, ident, None) => Some(ident), _ => None, } } diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 255f5fee52a80..4209ae8e1a723 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -681,7 +681,7 @@ fn resolve_local<'tcx>( // & expression, and its lifetime would be extended to the end of the block (due // to a different rule, not the below code). match pat.kind { - PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(_), _), ..) => true, + PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(_), _, _), ..) => true, PatKind::Struct(_, field_pats, _) => field_pats.iter().any(|fp| is_binding_pat(fp.pat)), @@ -700,7 +700,7 @@ fn resolve_local<'tcx>( } PatKind::Ref(_, _) - | PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..) + | PatKind::Binding(hir::BindingMode(hir::ByRef::No, _, _), ..) | PatKind::Wild | PatKind::Never | PatKind::Expr(_) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 167bed5f65029..93e4cbe9cfe20 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1914,7 +1914,10 @@ impl<'a> State<'a> { match pat.kind { PatKind::Wild => self.word("_"), PatKind::Never => self.word("!"), - PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => { + PatKind::Binding(BindingMode(by_ref, pin, mutbl), _, ident, sub) => { + if pin.is_pin() { + self.word_nbsp("pin"); + } if mutbl.is_mut() { self.word_nbsp("mut"); } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index bd0848b991661..9a023b0570dd7 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -12,7 +12,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{ self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatExpr, - PatExprKind, PatKind, expr_needs_parens, + PatExprKind, PatKind, Pinnedness, expr_needs_parens, }; use rustc_infer::infer; use rustc_middle::traits::PatternOriginExpr; @@ -824,7 +824,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Determine the binding mode... let bm = match user_bind_annot { - BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(def_br_mutbl) = def_br => { + BindingMode(ByRef::No, pin, Mutability::Mut) + if let ByRef::Yes(def_br_mutbl) = def_br => + { // Only mention the experimental `mut_ref` feature if if we're in edition 2024 and // using other experimental matching features compatible with it. if pat.span.at_least_rust_2024() @@ -841,7 +843,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .emit(); } - BindingMode(def_br, Mutability::Mut) + BindingMode(def_br, pin, Mutability::Mut) } else { // `mut` resets the binding mode on edition <= 2021 self.add_rust_2024_migration_desugared_pat( @@ -850,11 +852,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 't', // last char of `mut` def_br_mutbl, ); - BindingMode(ByRef::No, Mutability::Mut) + BindingMode(ByRef::No, pin, Mutability::Mut) } } - BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl), - BindingMode(ByRef::Yes(user_br_mutbl), _) => { + BindingMode(ByRef::No, pin, mutbl) => BindingMode(def_br, pin, mutbl), + BindingMode(ByRef::Yes(user_br_mutbl), _, _) => { if let ByRef::Yes(def_br_mutbl) = def_br { // `ref`/`ref mut` overrides the binding mode on edition <= 2021 self.add_rust_2024_migration_desugared_pat( @@ -1079,7 +1081,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let PatKind::Ref(the_ref, _) = i.kind && let PatKind::Binding(mt, _, ident, _) = the_ref.kind { - let BindingMode(_, mtblty) = mt; + let BindingMode(_, _, mtblty) = mt; err.span_suggestion_verbose( i.span, format!("consider removing `&{mutability}` from the pattern"), @@ -2872,8 +2874,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the user-provided binding modifier doesn't match the default binding mode, we'll // need to suggest reference patterns, which can affect other bindings. // For simplicity, we opt to suggest making the pattern fully explicit. - info.suggest_eliding_modes &= - user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not); + info.suggest_eliding_modes &= user_bind_annot + == BindingMode(ByRef::Yes(def_br_mutbl), Pinnedness::Not, Mutability::Not); "binding modifier" } else { info.bad_ref_pats = true; diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 9a0b22470585f..178a1b65f1191 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -276,7 +276,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { else { bug!(); }; - let hir::PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), _, _, _) = pat.kind + let hir::PatKind::Binding(hir::BindingMode(hir::ByRef::No, _, _), _, _, _) = + pat.kind else { // Complex pattern, skip the non-upvar local. continue; @@ -1802,7 +1803,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let bm = *typeck_results.pat_binding_modes().get(var_hir_id).expect("missing binding mode"); - let mut is_mutbl = bm.1; + let mut is_mutbl = bm.2; for pointer_ty in place.deref_tys() { match self.structurally_resolve_type(self.tcx.hir().span(var_hir_id), pointer_ty).kind() diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index cf90df1b198b8..ea5b9b3a8cc40 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1094,7 +1094,7 @@ impl<'tcx> LocalDecl<'tcx> { self.local_info(), LocalInfo::User( BindingForm::Var(VarBindingForm { - binding_mode: BindingMode(ByRef::No, _), + binding_mode: BindingMode(ByRef::No, _, _), opt_ty_info: _, opt_match_place: _, pat_span: _, @@ -1111,7 +1111,7 @@ impl<'tcx> LocalDecl<'tcx> { self.local_info(), LocalInfo::User( BindingForm::Var(VarBindingForm { - binding_mode: BindingMode(ByRef::No, _), + binding_mode: BindingMode(ByRef::No, _, _), opt_ty_info: _, opt_match_place: _, pat_span: _, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index e5592de81cd78..103a1d3e46f02 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -633,7 +633,7 @@ impl<'tcx> Pat<'tcx> { pub fn simple_ident(&self) -> Option { match self.kind { PatKind::Binding { - name, mode: BindingMode(ByRef::No, _), subpattern: None, .. + name, mode: BindingMode(ByRef::No, _, _), subpattern: None, .. } => Some(name), _ => None, } diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index d4484a16fea4d..6bf8a59c44f4a 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -454,7 +454,7 @@ impl<'tcx> TypeckResults<'tcx> { let mut has_ref_mut = false; pat.walk(|pat| { if let hir::PatKind::Binding(_, id, _, _) = pat.kind - && let Some(BindingMode(ByRef::Yes(Mutability::Mut), _)) = + && let Some(BindingMode(ByRef::Yes(Mutability::Mut), _, _)) = self.pat_binding_modes().get(id) { has_ref_mut = true; diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index d05d5b151ff48..f14a449f1a079 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -594,7 +594,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> BlockAnd<()> { match irrefutable_pat.kind { // Optimize the case of `let x = ...` to write directly into `x` - PatKind::Binding { mode: BindingMode(ByRef::No, _), var, subpattern: None, .. } => { + PatKind::Binding { + mode: BindingMode(ByRef::No, _, _), var, subpattern: None, .. + } => { let place = self.storage_live_binding( block, var, @@ -618,7 +620,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ref subpattern, ascription: thir::Ascription { ref annotation, variance: _ }, } if let PatKind::Binding { - mode: BindingMode(ByRef::No, _), + mode: BindingMode(ByRef::No, _, _), var, subpattern: None, .. @@ -2772,7 +2774,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.tcx; let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope }; let local = LocalDecl { - mutability: mode.1, + mutability: mode.2, ty: var_ty, user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) }, source_info, diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 949559549345f..1d61fcde4a399 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -953,7 +953,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Don't introduce extra copies for simple bindings PatKind::Binding { var, - mode: BindingMode(ByRef::No, mutability), + mode: BindingMode(ByRef::No, pin, mutability), subpattern: None, .. } => { @@ -963,7 +963,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(kind) = param.self_kind { LocalInfo::User(BindingForm::ImplicitSelf(kind)) } else { - let binding_mode = BindingMode(ByRef::No, mutability); + let binding_mode = BindingMode(ByRef::No, pin, mutability); LocalInfo::User(BindingForm::Var(VarBindingForm { binding_mode, opt_ty_info: param.ty_span, diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index c2eafd0a74e65..6f333d86f2df8 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -374,7 +374,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } visit::walk_pat(self, pat); } - PatKind::Binding { mode: BindingMode(ByRef::Yes(rm), _), ty, .. } => { + PatKind::Binding { mode: BindingMode(ByRef::Yes(rm), _, _), ty, .. } => { if self.inside_adt { let ty::Ref(_, ty, _) = ty.kind() else { span_bug!( diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index d60ae6484afb2..2368e1c5eaa75 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -871,7 +871,7 @@ fn check_for_bindings_named_same_as_variants( ) { if let PatKind::Binding { name, - mode: BindingMode(ByRef::No, Mutability::Not), + mode: BindingMode(ByRef::No, _, Mutability::Not), subpattern: None, ty, .. diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 563081c7240c4..b3f893eddc682 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -663,6 +663,8 @@ parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||` +parse_note_pin_pattern_usage = `pin mut` or `pin const` may be followed by `variable` and `variable @ pattern` + parse_nul_in_c_str = null characters in C string literals are not supported 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 `@` .label_binding = binding on the right, should be on the left .suggestion = switch the order +parse_pin_on_nested_ident_pattern = `pin {$mutbl}` must be attached to each individual binding + .suggestion = add `pin {$mutbl}` to each binding +parse_pin_on_non_ident_pattern = `pin {$mutbl}` must be followed by a named binding + .suggestion = remove the `pin {$mutbl}` prefix + parse_question_mark_in_type = invalid `?` in type .label = `?` is only allowed on expressions, not types .suggestion = if you meant to express that the type might not contain a value, use the `Option` wrapper type diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index dc03d6f9521d4..b8f12f6d7bfe3 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2628,6 +2628,27 @@ pub(crate) enum InvalidMutInPattern { }, } +#[derive(Diagnostic)] +pub(crate) enum InvalidPinInPattern { + #[diag(parse_pin_on_nested_ident_pattern)] + #[note(parse_note_pin_pattern_usage)] + NestedIdent { + #[primary_span] + #[suggestion(code = "{pat}", applicability = "machine-applicable", style = "verbose")] + span: Span, + mutbl: &'static str, + pat: String, + }, + #[diag(parse_pin_on_non_ident_pattern)] + #[note(parse_note_pin_pattern_usage)] + NonIdent { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] + span: Span, + mutbl: &'static str, + }, +} + #[derive(Diagnostic)] #[diag(parse_repeated_mut_in_pattern)] pub(crate) struct RepeatedMutInPattern { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 8ce749ec81417..35fa3cb147033 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -7,7 +7,8 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{ self as ast, Arm, AttrVec, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall, Mutability, - Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt, StmtKind, + Pat, PatField, PatFieldsRest, PatKind, Path, Pinnedness, QSelf, RangeEnd, RangeSyntax, Stmt, + StmtKind, }; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey}; @@ -22,12 +23,12 @@ use crate::errors::{ DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, - InclusiveRangeNoEnd, InvalidMutInPattern, ParenRangeSuggestion, PatternOnWrongSideOfAt, - RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, - TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, UnexpectedExpressionInPattern, - UnexpectedExpressionInPatternSugg, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, - UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, - UnexpectedVertVertInPattern, WrapInParens, + InclusiveRangeNoEnd, InvalidMutInPattern, InvalidPinInPattern, ParenRangeSuggestion, + PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, + TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, + UnexpectedExpressionInPattern, UnexpectedExpressionInPatternSugg, UnexpectedLifetimeInPattern, + UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, + UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens, }; use crate::parser::expr::{DestructuredFloat, could_be_unclosed_char_literal}; use crate::{exp, maybe_recover_from_interpolated_ty_qpath, maybe_whole}; @@ -745,6 +746,8 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(exp!(Underscore)) { // Parse `_` PatKind::Wild + } else if let Some((pinned, mutability)) = self.parse_pin_and_mut() { + self.parse_pat_ident_pin(pinned, mutability, lo.to(self.prev_token.span))? } else if self.eat_keyword(exp!(Mut)) { self.parse_pat_ident_mut()? } else if self.eat_keyword(exp!(Ref)) { @@ -756,7 +759,10 @@ impl<'a> Parser<'a> { } // Parse ref ident @ pat / ref mut ident @ pat let mutbl = self.parse_mutability(); - self.parse_pat_ident(BindingMode(ByRef::Yes(mutbl), Mutability::Not), syntax_loc)? + self.parse_pat_ident( + BindingMode(ByRef::Yes(mutbl), Pinnedness::Not, Mutability::Not), + syntax_loc, + )? } else if self.eat_keyword(exp!(Box)) { self.parse_pat_box()? } else if self.check_inline_const(0) { @@ -1032,6 +1038,38 @@ impl<'a> Parser<'a> { }) } + /// Parse a pinned binding with the `pin mut` or `pin const` token already eaten. + fn parse_pat_ident_pin( + &mut self, + pin: Pinnedness, + mutbl: Mutability, + // span of `pin mut` or `pin const` + span: Span, + ) -> PResult<'a, PatKind> { + // Parse the pattern we hope to be an identifier. + let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier), None)?; + + // If we don't have `pin mut $ident (@ pat)?`, error. + if let PatKind::Ident( + BindingMode(ByRef::No, p @ Pinnedness::Not, m @ Mutability::Not), + .., + ) = &mut pat.kind + { + *p = pin; + *m = mutbl; + } else { + // Add `pin` to any binding in the parsed pattern. + let mut changed_any_binding = Self::make_all_value_bindings_pinned(&mut pat); + if let Mutability::Mut = mutbl { + // Add `mut` to any binding in the parsed pattern. + changed_any_binding |= Self::make_all_value_bindings_mutable(&mut pat); + } + self.ban_pin_general_pat(span, &pat, mutbl, changed_any_binding); + } + + Ok(pat.into_inner().kind) + } + /// Parse a mutable binding with the `mut` token already eaten. fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> { let mut_span = self.prev_token.span; @@ -1053,7 +1091,8 @@ impl<'a> Parser<'a> { let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier), None)?; // If we don't have `mut $ident (@ pat)?`, error. - if let PatKind::Ident(BindingMode(br @ ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind + if let PatKind::Ident(BindingMode(br @ ByRef::No, _, m @ Mutability::Not), ..) = + &mut pat.kind { // Don't recurse into the subpattern. // `mut` on the outer binding doesn't affect the inner bindings. @@ -1065,19 +1104,40 @@ impl<'a> Parser<'a> { self.ban_mut_general_pat(mut_span, &pat, changed_any_binding); } - if matches!(pat.kind, PatKind::Ident(BindingMode(ByRef::Yes(_), Mutability::Mut), ..)) { + if matches!(pat.kind, PatKind::Ident(BindingMode(ByRef::Yes(_), _, Mutability::Mut), ..)) { self.psess.gated_spans.gate(sym::mut_ref, pat.span); } Ok(pat.into_inner().kind) } - /// Turn all by-value immutable bindings in a pattern into mutable bindings. + /// Turn all by-value immutable bindings in a pattern into pinned bindings. + /// Returns `true` if any change was made. + fn make_all_value_bindings_pinned(pat: &mut P) -> bool { + struct AddPin(bool); + impl MutVisitor for AddPin { + fn visit_pat(&mut self, pat: &mut P) { + if let PatKind::Ident(BindingMode(ByRef::No, p @ Pinnedness::Not, _), ..) = + &mut pat.kind + { + self.0 = true; + *p = Pinnedness::Pinned; + } + mut_visit::walk_pat(self, pat); + } + } + + let mut add_pin = AddPin(false); + add_pin.visit_pat(pat); + add_pin.0 + } + + /// Turn all by-value immutable bindings in a pattern into mutable bindings if specified. /// Returns `true` if any change was made. fn make_all_value_bindings_mutable(pat: &mut P) -> bool { struct AddMut(bool); impl MutVisitor for AddMut { fn visit_pat(&mut self, pat: &mut P) { - if let PatKind::Ident(BindingMode(ByRef::No, m @ Mutability::Not), ..) = + if let PatKind::Ident(BindingMode(ByRef::No, _, m @ Mutability::Not), ..) = &mut pat.kind { self.0 = true; @@ -1092,6 +1152,25 @@ impl<'a> Parser<'a> { add_mut.0 } + /// Error on `pin mut $pat` or `pin const $pat` where `$pat` is not an ident. + fn ban_pin_general_pat( + &self, + lo: Span, + pat: &Pat, + mutbl: Mutability, + changed_any_binding: bool, + ) { + self.dcx().emit_err(if changed_any_binding { + InvalidPinInPattern::NestedIdent { + span: lo.to(pat.span), + mutbl: mutbl.ptr_str(), + pat: pprust::pat_to_string(pat), + } + } else { + InvalidPinInPattern::NonIdent { span: lo.until(pat.span), mutbl: mutbl.ptr_str() } + }); + } + /// Error on `mut $pat` where `$pat` is not an ident. fn ban_mut_general_pat(&self, lo: Span, pat: &Pat, changed_any_binding: bool) { self.dcx().emit_err(if changed_any_binding { @@ -1714,7 +1793,7 @@ impl<'a> Parser<'a> { let fieldname = self.parse_field_name()?; hi = self.prev_token.span; - let ann = BindingMode(by_ref, mutability); + let ann = BindingMode(by_ref, Pinnedness::Not, mutability); let fieldpat = self.mk_pat_ident(boxed_span.to(hi), ann, fieldname); let subpat = if is_box { self.mk_pat(lo.to(hi), PatKind::Box(fieldpat)) } else { fieldpat }; diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index deac51ab4c493..e29c189f1eaf7 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -94,7 +94,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap = FxIndexMap::default(); pat.walk_always(|pat| { // We'll just ignore mut and ref mut for simplicity sake right now - if let hir::PatKind::Binding(hir::BindingMode(by_ref, hir::Mutability::Not), value_hir_id, ident, sub_pat) = + if let hir::PatKind::Binding(hir::BindingMode(by_ref, _, hir::Mutability::Not), value_hir_id, ident, sub_pat) = pat.kind && by_ref != hir::ByRef::Yes(hir::Mutability::Mut) { diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs index 5db28e9ae9b84..d0a272679db57 100644 --- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs +++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs @@ -104,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { }; let mutability = match mode { - BindingMode(_, Mutability::Mut) => " ", + BindingMode(_, _, Mutability::Mut) => " ", _ => "", }; diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index c27e930c99a5e..86c550af329e9 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -73,7 +73,7 @@ pub(super) fn check<'tcx>( let node = cx.tcx.hir_node(hir_id); if let Node::Pat(pat) = node && let PatKind::Binding(bind_ann, ..) = pat.kind - && !matches!(bind_ann, BindingMode(_, Mutability::Mut)) + && !matches!(bind_ann, BindingMode(_, _, Mutability::Mut)) && let Node::LetStmt(parent_let_expr) = cx.tcx.parent_hir_node(hir_id) && let Some(init) = parent_let_expr.init { diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs index 1cb4b512a30e5..407b90e78a1e6 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs @@ -59,7 +59,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome) - && let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., ident, _) = first_pat.kind + && let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _, _), .., ident, _) = first_pat.kind && let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind && is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome) && let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs index 7e65d586110e5..3ef383f7f5d07 100644 --- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs @@ -182,7 +182,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool { }, )), ) => { - return !matches!(annot, BindingMode(ByRef::Yes(_), _)) && pat_ident.name == first_seg.ident.name; + return !matches!(annot, BindingMode(ByRef::Yes(_), _, _)) && pat_ident.name == first_seg.ident.name; }, // Example: `Custom::TypeA => Custom::TypeB`, or `None => None` ( diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index 1ee27d90d0545..74677bbf34eae 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -69,7 +69,7 @@ pub(super) fn check( _ => false, }, // local binding capturing a reference - Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..)) => { + Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingMode(ByRef::Yes(_), _, _), ..)) => { return; }, _ => false, diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs index 6c1a14fc88299..463ad496f88f9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs @@ -46,7 +46,7 @@ pub(super) fn check<'tcx>( span_lint_and_then(cx, FILTER_NEXT, expr.span, msg, |diag| { let (applicability, pat) = if let Some(id) = path_to_local(recv) && let hir::Node::Pat(pat) = cx.tcx.hir_node(id) - && let hir::PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind + && let hir::PatKind::Binding(BindingMode(_, _, Mutability::Not), _, ident, _) = pat.kind { (Applicability::Unspecified, Some((pat.span, ident))) } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index a80977459f21d..963656be0698c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -82,7 +82,7 @@ pub(super) fn check<'tcx>( } match it.kind { - PatKind::Binding(BindingMode(_, Mutability::Mut), _, _, _) | PatKind::Ref(_, Mutability::Mut) => { + PatKind::Binding(BindingMode(_, _, Mutability::Mut), _, _, _) | PatKind::Ref(_, Mutability::Mut) => { to_be_discarded = true; false }, diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs index 09ccb386a20bc..739279767c823 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs @@ -24,7 +24,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: && (is_diag_item_method(cx, fn_id, sym::Option) || is_diag_item_method(cx, fn_id, sym::Result)))) && let body = cx.tcx.hir_body(c.body) && let [param] = body.params - && let PatKind::Binding(BindingMode(ByRef::No, Mutability::Not), arg_id, _, None) = param.pat.kind + && let PatKind::Binding(BindingMode(ByRef::No, _, Mutability::Not), arg_id, _, None) = param.pat.kind && let arg_ty = typeck.node_type(arg_id) && let ExprKind::Block(block, _) = body.value.kind && let Some(final_expr) = block.expr diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index fca416d9e64c7..7e2a802b0f9d7 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -159,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { ) { if !matches!(k, FnKind::Closure) { for arg in iter_input_pats(decl, body) { - if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind + if let PatKind::Binding(BindingMode(ByRef::Yes(_), _, _), ..) = arg.pat.kind && is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) && !arg.span.in_external_macro(cx.tcx.sess.source_map()) { @@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if let StmtKind::Let(local) = stmt.kind - && let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind + && let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _, _), .., name, None) = local.pat.kind && let Some(init) = local.init // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id) diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs index 5f7fde30f03f6..9bc8c5aacd9f5 100644 --- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs @@ -120,7 +120,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { match &p.ty.kind { TyKind::Path(None, path) => { - if let PatKind::Ident(BindingMode(ByRef::No, mutbl), _, _) = p.pat.kind { + if let PatKind::Ident(BindingMode(ByRef::No, _, mutbl), _, _) = p.pat.kind { check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl); } }, diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 40c65d1ef9e86..64c9685263b40 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -192,7 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { }) && !implements_borrow_trait && !all_borrowable_trait - && let PatKind::Binding(BindingMode(_, Mutability::Not), canonical_id, ..) = arg.pat.kind + && let PatKind::Binding(BindingMode(_, _, Mutability::Not), canonical_id, ..) = arg.pat.kind && !moved_vars.contains(&canonical_id) { // Dereference suggestion diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index ffc3b86c502e3..7dd0de8b02ec3 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -415,7 +415,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: && !is_else_clause(cx.tcx, expr) && let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind && ddpos.as_opt_usize().is_none() - && let PatKind::Binding(BindingMode(by_ref, _), bind_id, ident, None) = field.kind + && let PatKind::Binding(BindingMode(by_ref, _, _), bind_id, ident, None) = field.kind && let caller_ty = cx.typeck_results().expr_ty(let_expr) && let if_block = IfBlockType::IfLet( cx.qpath_res(path1, let_pat.hir_id), diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs index f3ccc9e38f4d8..c522b290887cd 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { if !local.span.is_desugaring(DesugaringKind::Async) // the pattern is a single by-value binding - && let PatKind::Binding(BindingMode(ByRef::No, mutability), _, ident, None) = local.pat.kind + && let PatKind::Binding(BindingMode(ByRef::No, _, mutability), _, ident, None) = local.pat.kind // the binding is not type-ascribed && local.ty.is_none() // the expression is a resolved path @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals { && let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id) && let Node::Pat(binding_pat) = cx.tcx.hir_node(binding_id) // the previous binding has the same mutability - && find_binding(binding_pat, ident).is_some_and(|bind| bind.1 == mutability) + && find_binding(binding_pat, ident).is_some_and(|bind| bind.2 == mutability) // the local does not change the effect of assignments to the binding. see #11290 && !affects_assignments(cx, mutability, binding_id, local.hir_id) // the local does not affect the code's drop behavior diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 5fc166438e84a..091e19cbb5f72 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -1,6 +1,6 @@ use clippy_utils::{get_attr, higher}; use rustc_ast::LitIntType; -use rustc_ast::ast::{LitFloatType, LitKind}; +use rustc_ast::ast::{LitFloatType, LitKind, Pinnedness}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{ self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind, @@ -682,6 +682,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { BindingMode::REF_MUT => "REF_MUT", BindingMode::MUT_REF => "MUT_REF", BindingMode::MUT_REF_MUT => "MUT_REF_MUT", + BindingMode::PIN_CONST => "PIN_CONST ", + BindingMode::PIN_MUT => "PIN_MUT", + BindingMode(_, Pinnedness::Pinned, _) => panic!("unsupported pinned binding mode"), }; kind!("Binding(BindingMode::{ann}, _, {name}, {sub})"); self.ident(name); diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 0ac675345ae0c..98301092c2821 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1124,8 +1124,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_pat(&mut self, pat: &Pat<'_>) { std::mem::discriminant(&pat.kind).hash(&mut self.s); match pat.kind { - PatKind::Binding(BindingMode(by_ref, mutability), _, _, pat) => { + PatKind::Binding(BindingMode(by_ref, pinnedness, mutability), _, _, pat) => { std::mem::discriminant(&by_ref).hash(&mut self.s); + std::mem::discriminant(&pinnedness).hash(&mut self.s); std::mem::discriminant(&mutability).hash(&mut self.s); if let Some(pat) = pat { self.hash_pat(pat); diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index bafed41e39f42..a3c5701604bd4 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -18,7 +18,9 @@ use crate::shape::Shape; use crate::source_map::SpanUtils; use crate::spanned::Spanned; use crate::types::{PathContext, rewrite_path}; -use crate::utils::{format_mutability, mk_sp, mk_sp_lo_plus_one, rewrite_ident}; +use crate::utils::{ + format_mutability, format_pin_and_mut, mk_sp, mk_sp_lo_plus_one, rewrite_ident, +}; /// Returns `true` if the given pattern is "short". /// A short pattern is defined by the following grammar: @@ -129,8 +131,9 @@ impl Rewrite for Pat { write_list(&items, &fmt) } PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, shape), - PatKind::Ident(BindingMode(by_ref, mutability), ident, ref sub_pat) => { - let mut_prefix = format_mutability(mutability).trim(); + PatKind::Ident(BindingMode(by_ref, pinnedness, mutability), ident, ref sub_pat) => { + let (pin_prefix, mut_prefix) = format_pin_and_mut(pinnedness, mutability); + let (pin_prefix, mut_prefix) = (pin_prefix.trim(), mut_prefix.trim()); let (ref_kw, mut_infix) = match by_ref { ByRef::Yes(rmutbl) => ("ref", format_mutability(rmutbl).trim()), @@ -143,7 +146,8 @@ impl Rewrite for Pat { let width = shape .width .checked_sub( - mut_prefix.len() + pin_prefix.len() + + mut_prefix.len() + ref_kw.len() + mut_infix.len() + id_str.len() @@ -163,27 +167,48 @@ impl Rewrite for Pat { None => "".to_owned(), }; - // combine prefix and ref - let (first_lo, first) = match (mut_prefix.is_empty(), ref_kw.is_empty()) { + // combine pin and mut + let (pin_mut_lo, pin_mut) = match (pin_prefix.is_empty(), mut_prefix.is_empty()) { (false, false) => { - let lo = context.snippet_provider.span_after(self.span, "mut"); - let hi = context.snippet_provider.span_before(self.span, "ref"); + let lo = context.snippet_provider.span_after(self.span, "pin"); + let hi = context.snippet_provider.span_before(self.span, mut_prefix); ( - context.snippet_provider.span_after(self.span, "ref"), + context.snippet_provider.span_after(self.span, mut_prefix), combine_strs_with_missing_comments( context, + pin_prefix, mut_prefix, - ref_kw, mk_sp(lo, hi), shape, true, )?, ) } - (false, true) => ( - context.snippet_provider.span_after(self.span, "mut"), + (false, true) => unreachable!("mut_prefix necessarily follows a pin_prefix"), + (true, false) => ( + context.snippet_provider.span_after(self.span, mut_prefix), mut_prefix.to_owned(), ), + (true, true) => (self.span.lo(), "".to_owned()), + }; + + // combine prefix and ref + let (first_lo, first) = match (pin_mut.is_empty(), ref_kw.is_empty()) { + (false, false) => { + let hi = context.snippet_provider.span_before(self.span, "ref"); + ( + context.snippet_provider.span_after(self.span, "ref"), + combine_strs_with_missing_comments( + context, + &pin_mut, + ref_kw, + mk_sp(pin_mut_lo, hi), + shape, + true, + )?, + ) + } + (false, true) => (pin_mut_lo, pin_mut), (true, false) => ( context.snippet_provider.span_after(self.span, "ref"), ref_kw.to_owned(), diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index ba4a4c045f1c2..2301b813b7b0c 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -132,6 +132,19 @@ pub(crate) fn format_mutability(mutability: ast::Mutability) -> &'static str { } } +#[inline] +pub(crate) fn format_pin_and_mut( + pinnedness: ast::Pinnedness, + mutability: ast::Mutability, +) -> (&'static str, &'static str) { + match (pinnedness, mutability) { + (ast::Pinnedness::Not, ast::Mutability::Mut) => ("", "mut "), + (ast::Pinnedness::Not, ast::Mutability::Not) => ("", ""), + (ast::Pinnedness::Pinned, ast::Mutability::Mut) => ("pin ", "mut "), + (ast::Pinnedness::Pinned, ast::Mutability::Not) => ("pin ", "const "), + } +} + #[inline] pub(crate) fn format_extern(ext: ast::Extern, explicit_abi: bool) -> Cow<'static, str> { match ext { diff --git a/src/tools/rustfmt/tests/source/pin_sugar.rs b/src/tools/rustfmt/tests/source/pin_sugar.rs index 0eb3c0770c482..694056b5f0874 100644 --- a/src/tools/rustfmt/tests/source/pin_sugar.rs +++ b/src/tools/rustfmt/tests/source/pin_sugar.rs @@ -8,3 +8,36 @@ fn g<'a>(x: & 'a pin const i32) {} fn h<'a>(x: & 'a pin mut i32) {} fn i(x: &pin mut i32) {} + +fn pinned_locals() { + let pin mut +x = 0_i32; + let pin /* comment */ mut +x = 0_i32; + let pin mut /* comment */ +x = 0_i32; + let pin +const +y = 0_i32; + let pin +/* comment */ const +y = 0_i32; + let pin +const /* comment */ +y = 0_i32; +let ( + pin + const x, + pin mut y +) = (0_i32, 0_i32); +let ( + pin /* comment */ + const x, + pin /* comment */ mut y +) = (0_i32, 0_i32); +let ( + pin + const /* comment */ x, + pin mut /* comment */ y +) = (0_i32, 0_i32); +} \ No newline at end of file diff --git a/src/tools/rustfmt/tests/target/pin_sugar.rs b/src/tools/rustfmt/tests/target/pin_sugar.rs index c9fa883e238fd..36ddfeeea0172 100644 --- a/src/tools/rustfmt/tests/target/pin_sugar.rs +++ b/src/tools/rustfmt/tests/target/pin_sugar.rs @@ -7,3 +7,17 @@ fn f(x: &pin const i32) {} fn g<'a>(x: &'a pin const i32) {} fn h<'a>(x: &'a pin mut i32) {} fn i(x: &pin mut i32) {} + +fn pinned_locals() { + let pin mut x = 0_i32; + let pin /* comment */ mut x = 0_i32; + let pin mut /* comment */ x = 0_i32; + let pin const y = 0_i32; + let pin + /* comment */ + const y = 0_i32; + let pin const /* comment */ y = 0_i32; + let (pin const x, pin mut y) = (0_i32, 0_i32); + let (pin /* comment */ const x, pin /* comment */ mut y) = (0_i32, 0_i32); + let (pin const /* comment */ x, pin mut /* comment */ y) = (0_i32, 0_i32); +} diff --git a/tests/ui/async-await/pin-ergonomics/pinned-local-no-const.rs b/tests/ui/async-await/pin-ergonomics/pinned-local-no-const.rs new file mode 100644 index 0000000000000..e226399ca0646 --- /dev/null +++ b/tests/ui/async-await/pin-ergonomics/pinned-local-no-const.rs @@ -0,0 +1,13 @@ +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +// Makes sure we reject `pin pat`. + +struct Foo; + +fn foo() { + let pin x = Foo; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `x` + x = Foo; +} + +fn main() {} diff --git a/tests/ui/async-await/pin-ergonomics/pinned-local-no-const.stderr b/tests/ui/async-await/pin-ergonomics/pinned-local-no-const.stderr new file mode 100644 index 0000000000000..784c24537ca30 --- /dev/null +++ b/tests/ui/async-await/pin-ergonomics/pinned-local-no-const.stderr @@ -0,0 +1,14 @@ +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `x` + --> $DIR/pinned-local-no-const.rs:9:13 + | +LL | let pin x = Foo; + | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | +help: there is a keyword `in` with a similar name + | +LL - let pin x = Foo; +LL + let in x = Foo; + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/pin-ergonomics/pinned-local.rs b/tests/ui/async-await/pin-ergonomics/pinned-local.rs new file mode 100644 index 0000000000000..2c75fd841a571 --- /dev/null +++ b/tests/ui/async-await/pin-ergonomics/pinned-local.rs @@ -0,0 +1,19 @@ +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +// Makes sure we can handle `pin mut pat` and `pin const pat`. + +struct Foo; + +fn foo() { + let pin mut x = Foo; + let pin const y = Foo; + x = Foo; // FIXME: this should be an error + y = Foo; //~ ERROR cannot assign twice to immutable variable `y` + + let (pin mut x, pin const y) = (Foo, Foo); + x = Foo; // FIXME: this should be an error + y = Foo; //~ ERROR cannot assign twice to immutable variable `y` +} + +fn main() {} diff --git a/tests/ui/async-await/pin-ergonomics/pinned-local.stderr b/tests/ui/async-await/pin-ergonomics/pinned-local.stderr new file mode 100644 index 0000000000000..903229844757b --- /dev/null +++ b/tests/ui/async-await/pin-ergonomics/pinned-local.stderr @@ -0,0 +1,35 @@ +error[E0384]: cannot assign twice to immutable variable `y` + --> $DIR/pinned-local.rs:12:5 + | +LL | let pin const y = Foo; + | ----------- first assignment to `y` +LL | x = Foo; // FIXME: this should be an error +LL | y = Foo; + | ^^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut pin const y = Foo; + | +++ + +error[E0384]: cannot assign twice to immutable variable `y` + --> $DIR/pinned-local.rs:16:5 + | +LL | let (pin mut x, pin const y) = (Foo, Foo); + | ----------- first assignment to `y` +LL | x = Foo; // FIXME: this should be an error +LL | y = Foo; + | ^^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let (pin mut x, mut pin const y) = (Foo, Foo); + | +++ +help: to modify the original value, take a borrow instead + | +LL | let (pin mut x, ref mut pin const y) = (Foo, Foo); + | +++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0384`. diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs index 4624faf1e53cf..ba34616f4facc 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -27,4 +27,11 @@ fn baz(mut x: Pin<&mut Foo>) { fn baz_sugar(_: &pin const Foo) {} //~ ERROR pinned reference syntax is experimental +fn pinned_locals() { + let pin mut x = Foo; //~ ERROR pinned reference syntax is experimental + let pin const y = Foo; //~ ERROR pinned reference syntax is experimental + x = Foo; // FIXME: this should be an error + y = Foo; //~ ERROR cannot assign twice to immutable variable `y` +} + fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr index dd93a7be1ada1..ea0470e3edda5 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr @@ -28,6 +28,26 @@ LL | fn baz_sugar(_: &pin const Foo) {} = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:31:9 + | +LL | let pin mut x = Foo; + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:32:9 + | +LL | let pin const y = Foo; + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0382]: use of moved value: `x` --> $DIR/feature-gate-pin_ergonomics.rs:20:9 | @@ -66,7 +86,21 @@ help: consider reborrowing the `Pin` instead of moving it LL | x.as_mut().foo(); | +++++++++ -error: aborting due to 5 previous errors +error[E0384]: cannot assign twice to immutable variable `y` + --> $DIR/feature-gate-pin_ergonomics.rs:34:5 + | +LL | let pin const y = Foo; + | ----------- first assignment to `y` +LL | x = Foo; // FIXME: this should be an error +LL | y = Foo; + | ^^^^^^^ cannot assign twice to immutable variable + | +help: consider making this binding mutable + | +LL | let mut pin const y = Foo; + | +++ + +error: aborting due to 8 previous errors -Some errors have detailed explanations: E0382, E0658. +Some errors have detailed explanations: E0382, E0384, E0658. For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 910582ae4d9e9..cbddc688009e3 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -12,7 +12,7 @@ params: [ kind: PatKind { Binding { name: "foo" - mode: BindingMode(No, Not) + mode: BindingMode(No, Not, Not) var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).2)) ty: Foo is_primary: true From 70032221f1a2151f5e15ff682640c3a715c1e103 Mon Sep 17 00:00:00 2001 From: Frank King Date: Thu, 13 Feb 2025 11:32:41 +0800 Subject: [PATCH 2/2] Remove suggestions of making `pin const` mutable --- compiler/rustc_middle/src/mir/mod.rs | 4 +++- .../async-await/pin-ergonomics/pinned-local.stderr | 14 -------------- .../feature-gate-pin_ergonomics.stderr | 5 ----- 3 files changed, 3 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index ea5b9b3a8cc40..36ece2ecec16f 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -19,6 +19,7 @@ use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_hir::{ self as hir, BindingMode, ByRef, CoroutineDesugaring, CoroutineKind, HirId, ImplicitSelfKind, + Pinnedness, }; use rustc_index::bit_set::DenseBitSet; use rustc_index::{Idx, IndexSlice, IndexVec}; @@ -1094,7 +1095,8 @@ impl<'tcx> LocalDecl<'tcx> { self.local_info(), LocalInfo::User( BindingForm::Var(VarBindingForm { - binding_mode: BindingMode(ByRef::No, _, _), + // FIXME(pin_ergonomics): `pin const` can also be made mutable, but needs special handling. + binding_mode: BindingMode(ByRef::No, Pinnedness::Not, _), opt_ty_info: _, opt_match_place: _, pat_span: _, diff --git a/tests/ui/async-await/pin-ergonomics/pinned-local.stderr b/tests/ui/async-await/pin-ergonomics/pinned-local.stderr index 903229844757b..97c7e70388992 100644 --- a/tests/ui/async-await/pin-ergonomics/pinned-local.stderr +++ b/tests/ui/async-await/pin-ergonomics/pinned-local.stderr @@ -6,11 +6,6 @@ LL | let pin const y = Foo; LL | x = Foo; // FIXME: this should be an error LL | y = Foo; | ^^^^^^^ cannot assign twice to immutable variable - | -help: consider making this binding mutable - | -LL | let mut pin const y = Foo; - | +++ error[E0384]: cannot assign twice to immutable variable `y` --> $DIR/pinned-local.rs:16:5 @@ -20,15 +15,6 @@ LL | let (pin mut x, pin const y) = (Foo, Foo); LL | x = Foo; // FIXME: this should be an error LL | y = Foo; | ^^^^^^^ cannot assign twice to immutable variable - | -help: consider making this binding mutable - | -LL | let (pin mut x, mut pin const y) = (Foo, Foo); - | +++ -help: to modify the original value, take a borrow instead - | -LL | let (pin mut x, ref mut pin const y) = (Foo, Foo); - | +++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr index ea0470e3edda5..92273640b4604 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr @@ -94,11 +94,6 @@ LL | let pin const y = Foo; LL | x = Foo; // FIXME: this should be an error LL | y = Foo; | ^^^^^^^ cannot assign twice to immutable variable - | -help: consider making this binding mutable - | -LL | let mut pin const y = Foo; - | +++ error: aborting due to 8 previous errors