diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e93351bcf7125..9f444670d91a1 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -789,14 +789,14 @@ pub struct PatField { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Encodable, Decodable, HashStable_Generic, Walkable)] pub enum ByRef { - Yes(Mutability), + Yes(Pinnedness, Mutability), No, } impl ByRef { #[must_use] pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self { - if let ByRef::Yes(old_mutbl) = &mut self { + if let ByRef::Yes(_, old_mutbl) = &mut self { *old_mutbl = cmp::min(*old_mutbl, mutbl); } self @@ -814,20 +814,33 @@ pub struct BindingMode(pub ByRef, 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 REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Not); + pub const REF_PIN: Self = + Self(ByRef::Yes(Pinnedness::Pinned, 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 REF_MUT: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Not); + pub const REF_PIN_MUT: Self = + Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Not); + pub const MUT_REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Mut); + pub const MUT_REF_PIN: Self = + Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Not), Mutability::Mut); + pub const MUT_REF_MUT: Self = + Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Mut); + pub const MUT_REF_PIN_MUT: Self = + Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Mut); pub fn prefix_str(self) -> &'static str { match self { Self::NONE => "", Self::REF => "ref ", + Self::REF_PIN => "ref pin const ", Self::MUT => "mut ", Self::REF_MUT => "ref mut ", + Self::REF_PIN_MUT => "ref pin mut ", Self::MUT_REF => "mut ref ", + Self::MUT_REF_PIN => "mut ref pin ", Self::MUT_REF_MUT => "mut ref mut ", + Self::MUT_REF_PIN_MUT => "mut ref pin mut ", } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 03e5a6edeece5..c60407c419c14 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -368,6 +368,7 @@ macro_rules! common_visitor_and_walkers { crate::tokenstream::TokenStream, Movability, Mutability, + Pinnedness, Result<(), rustc_span::ErrorGuaranteed>, rustc_data_structures::fx::FxHashMap, rustc_span::ErrorGuaranteed, diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs index 44837b1b49407..0f63fad157431 100644 --- a/compiler/rustc_ast_ir/src/lib.rs +++ b/compiler/rustc_ast_ir/src/lib.rs @@ -311,3 +311,10 @@ pub enum Pinnedness { Not, Pinned, } + +impl Pinnedness { + /// Return `true` if self is pinned + pub fn is_pinned(self) -> bool { + matches!(self, Self::Pinned) + } +} diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index a5e2bcaa3bd06..93f4e47342f14 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1712,10 +1712,15 @@ impl<'a> State<'a> { if mutbl.is_mut() { self.word_nbsp("mut"); } - if let ByRef::Yes(rmutbl) = by_ref { + if let ByRef::Yes(pinnedness, rmutbl) = by_ref { self.word_nbsp("ref"); + if pinnedness.is_pinned() { + self.word_nbsp("pin"); + } if rmutbl.is_mut() { self.word_nbsp("mut"); + } else if pinnedness.is_pinned() { + self.word_nbsp("const"); } } self.print_ident(*ident); diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 639c75d7c5e47..093969586596d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -48,6 +48,7 @@ pub(crate) mod must_use; pub(crate) mod no_implicit_prelude; pub(crate) mod non_exhaustive; pub(crate) mod path; +pub(crate) mod pin_v2; pub(crate) mod proc_macro_attrs; pub(crate) mod prototype; pub(crate) mod repr; diff --git a/compiler/rustc_attr_parsing/src/attributes/pin_v2.rs b/compiler/rustc_attr_parsing/src/attributes/pin_v2.rs new file mode 100644 index 0000000000000..597a9515b0048 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/pin_v2.rs @@ -0,0 +1,21 @@ +use rustc_hir::Target; +use rustc_hir::attrs::AttributeKind; +use rustc_span::{Span, Symbol, sym}; + +use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; +use crate::context::Stage; +use crate::target_checking::AllowedTargets; +use crate::target_checking::Policy::Allow; + +pub(crate) struct PinV2Parser; + +impl NoArgsAttributeParser for PinV2Parser { + const PATH: &[Symbol] = &[sym::pin_v2]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Enum), + Allow(Target::Struct), + Allow(Target::Union), + ]); + const CREATE: fn(Span) -> AttributeKind = AttributeKind::PinV2; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6694dac8bb25a..15904fd7d3348 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -47,6 +47,7 @@ use crate::attributes::must_use::MustUseParser; use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser; use crate::attributes::non_exhaustive::NonExhaustiveParser; use crate::attributes::path::PathParser as PathAttributeParser; +use crate::attributes::pin_v2::PinV2Parser; use crate::attributes::proc_macro_attrs::{ ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser, }; @@ -233,6 +234,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index b4990ffc7739c..e23c7eebeca1e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1188,7 +1188,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; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a57689a45b67b..0b098d1fafde3 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2584,6 +2584,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { _ => bug!("Deref of unexpected type: {:?}", base_ty), } } + // Check as the inner reference type if it is a field projection + // from the `&pin` pattern + ProjectionElem::Field(FieldIdx::ZERO, _) + if let Some(adt) = + place_base.ty(self.body(), self.infcx.tcx).ty.ty_adt_def() + && adt.is_pin() + && self.infcx.tcx.features().pin_ergonomics() => + { + self.is_mutable(place_base, is_local_mutation_allowed) + } // All other projections are owned by their base path, so mutable if // base path is mutable ProjectionElem::Field(..) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index a2acac8b3045d..2c472801aa044 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -893,6 +893,15 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::No, loop_match, experimental!(loop_match) ), + // The `#[pin_v2]` attribute is part of the `pin_ergonomics` experiment + // that allows structurally pinning, tracked in: + // + // - https://github.com/rust-lang/rust/issues/130494 + gated!( + pin_v2, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::Yes, pin_ergonomics, experimental!(pin_v2), + ), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 828c15cc391dd..1bb87673d52d2 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -637,6 +637,9 @@ pub enum AttributeKind { /// Represents `#[pattern_complexity_limit]` PatternComplexityLimit { attr_span: Span, limit_span: Span, limit: Limit }, + /// Represents `#[pin_v2]` + PinV2(Span), + /// Represents `#[pointee]` Pointee(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 362ab407aab35..11c54b0ac1da0 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -77,6 +77,7 @@ impl AttributeKind { PassByValue(..) => Yes, Path(..) => No, PatternComplexityLimit { .. } => No, + PinV2(..) => Yes, Pointee(..) => No, ProcMacro(..) => No, ProcMacroAttribute(..) => No, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d26e289bc0d28..cb0ae35c8ad46 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -13,7 +13,7 @@ use rustc_ast::{ pub use rustc_ast::{ AssignOp, AssignOpKind, AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, DelimArgs, ImplPolarity, IsAuto, - MetaItemInner, MetaItemLit, Movability, Mutability, UnOp, + MetaItemInner, MetaItemLit, Movability, Mutability, Pinnedness, UnOp, }; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index f99fefcf56ace..bac34454b3b7a 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -575,7 +575,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)), diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index f7bbc2e51f4cf..c0ce8e2051a5c 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1923,10 +1923,15 @@ impl<'a> State<'a> { if mutbl.is_mut() { self.word_nbsp("mut"); } - if let ByRef::Yes(rmutbl) = by_ref { + if let ByRef::Yes(pinnedness, rmutbl) = by_ref { self.word_nbsp("ref"); + if pinnedness.is_pinned() { + self.word_nbsp("pin"); + } if rmutbl.is_mut() { self.word_nbsp("mut"); + } else if pinnedness.is_pinned() { + self.word_nbsp("const"); } } self.print_ident(ident); diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 1ed0756fdd6a7..60303d5ee81e4 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -227,6 +227,10 @@ hir_typeck_pass_to_variadic_function = can't pass `{$ty}` to variadic function .suggestion = cast the value to `{$cast_ty}` .teach_help = certain types, like `{$ty}`, must be cast before passing them to a variadic function to match the implicit cast that a C compiler would perform as part of C's numeric promotion rules +hir_typeck_project_on_non_pin_project_type = cannot project on type that is not `#[pin_v2]` + .note = type defined here + .suggestion = add `#[pin_v2]` here + hir_typeck_ptr_cast_add_auto_to_object = cannot add {$traits_len -> [1] auto trait {$traits} *[other] auto traits {$traits} diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index d15d092b7d3da..615a8c95056d1 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -1156,3 +1156,14 @@ pub(crate) struct ConstContinueBadLabel { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_project_on_non_pin_project_type)] +pub(crate) struct ProjectOnNonPinProjectType { + #[primary_span] + pub span: Span, + #[note] + pub def_span: Option, + #[suggestion(code = "#[pin_v2]\n", applicability = "machine-applicable")] + pub sugg_span: Option, +} diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 2034131882820..b9f1463d8007d 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -986,7 +986,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // of the pattern, as this just looks confusing, instead use the span // of the discriminant. match bm.0 { - hir::ByRef::Yes(m) => { + hir::ByRef::Yes(_, m) => { let bk = ty::BorrowKind::from_mutbl(m); self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk); } @@ -1004,7 +1004,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // Deref patterns on boxes don't borrow, so we ignore them here. // HACK: this could be a fake pattern corresponding to a deref inserted by match // ergonomics, in which case `pat.hir_id` will be the id of the subpattern. - if let hir::ByRef::Yes(mutability) = + if let hir::ByRef::Yes(_, mutability) = self.cx.typeck_results().deref_pat_borrow_mode(place.place.ty(), subpattern) { let bk = ty::BorrowKind::from_mutbl(mutability); @@ -1256,7 +1256,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx .get(pat.hir_id) .expect("missing binding mode"); - if matches!(bm.0, hir::ByRef::Yes(_)) { + if let hir::ByRef::Yes(pinnedness, _) = bm.0 { + let base_ty = if pinnedness.is_pinned() { + base_ty.pinned_ty().ok_or_else(|| { + debug!("By-pin-ref binding of non-`Pin` type: {base_ty:?}"); + self.cx.report_bug(pat.span, "by-pin-ref binding of non-`Pin` type") + })? + } else { + base_ty + }; // a bind-by-ref means that the base_ty will be the type of the ident itself, // but what we want here is the type of the underlying value being borrowed. // So peel off one-level, turning the &T into T. @@ -1264,7 +1272,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx { Some(ty) => Ok(ty), None => { - debug!("By-ref binding of non-derefable type"); + debug!("By-ref binding of non-derefable type: {base_ty:?}"); Err(self .cx .report_bug(pat.span, "by-ref binding of non-derefable type")) @@ -1706,6 +1714,18 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx }; self.pat_deref_place(pat.hir_id, place_with_id, pat, target_ty)? } + adjustment::PatAdjust::PinDeref => { + debug!("`PinDeref` of non-pinned-reference type: {:?}", adjust.source); + let target_ty = adjust.source.pinned_ty().ok_or_else(|| { + self.cx.report_bug( + self.cx.tcx().hir_span(pat.hir_id), + "`PinDeref` of non-pinned-reference type", + ) + })?; + let kind = ProjectionKind::Field(FieldIdx::ZERO, FIRST_VARIANT); + place_with_id = self.cat_projection(pat.hir_id, place_with_id, target_ty, kind); + self.cat_deref(pat.hir_id, place_with_id)? + } }; } drop(typeck_results); // explicitly release borrow of typeck results, just in case. @@ -1877,7 +1897,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // Deref patterns on boxes are lowered using a built-in deref. hir::ByRef::No => self.cat_deref(hir_id, base_place), // For other types, we create a temporary to match on. - hir::ByRef::Yes(mutability) => { + hir::ByRef::Yes(_, mutability) => { let re_erased = self.cx.tcx().lifetimes.re_erased; let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability); // A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ... diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index d14463e44a03f..f27085d59c0ed 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -18,7 +18,7 @@ use rustc_hir::{ use rustc_hir_analysis::autoderef::report_autoderef_recursion_limit_error; use rustc_infer::infer::RegionVariableOrigin; use rustc_middle::traits::PatternOriginExpr; -use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, Pinnedness, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_session::parse::feature_err; @@ -403,7 +403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.check_pat_inner(pat, opt_path_res, adjust_mode, expected, pat_info); self.write_ty(pat.hir_id, ty); - // If we implicitly inserted overloaded dereferences before matching, check the pattern to + // If we implicitly inserted overloaded dereferences before matching check the pattern to // see if the dereferenced types need `DerefMut` bounds. if let Some(derefed_tys) = self.typeck_results.borrow().pat_adjustments().get(pat.hir_id) && derefed_tys.iter().any(|adjust| adjust.kind == PatAdjust::OverloadedDeref) @@ -413,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat, derefed_tys.iter().filter_map(|adjust| match adjust.kind { PatAdjust::OverloadedDeref => Some(adjust.source), - PatAdjust::BuiltinDeref => None, + PatAdjust::BuiltinDeref | PatAdjust::PinDeref => None, }), ); } @@ -471,7 +471,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { #[cfg(debug_assertions)] - if pat_info.binding_mode == ByRef::Yes(Mutability::Mut) + if matches!(pat_info.binding_mode, ByRef::Yes(_, Mutability::Mut)) && pat_info.max_ref_mutbl != MutblCap::Mut && self.downgrade_mut_inside_shared() { @@ -489,12 +489,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let old_pat_info = pat_info; let pat_info = PatInfo { current_depth: old_pat_info.current_depth + 1, ..old_pat_info }; + let adjust_binding_mode = |inner_pinnedness, inner_mutability| { + match pat_info.binding_mode { + // If default binding mode is by value, make it `ref`, `ref mut`, `ref pin const` + // or `ref pin mut` (depending on whether we observe `&`, `&mut`, `&pin const` or + // `&pin mut`). + ByRef::No => ByRef::Yes(inner_pinnedness, inner_mutability), + // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`). + // Pinnedness is preserved. + ByRef::Yes(pinnedness, Mutability::Mut) => ByRef::Yes(pinnedness, inner_mutability), + // Once a `ref`, always a `ref`. + // This is because a `& &mut` cannot mutate the underlying value. + // Pinnedness is preserved. + ByRef::Yes(pinnedness, Mutability::Not) => ByRef::Yes(pinnedness, Mutability::Not), + } + }; + match pat.kind { - // Peel off a `&` or `&mut` from the scrutinee type. See the examples in + // Peel off a `&` or `&mut`from the scrutinee type. See the examples in // `tests/ui/rfcs/rfc-2005-default-binding-mode`. _ if let AdjustMode::Peel { kind: peel_kind } = adjust_mode && pat.default_binding_modes - && let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() + && let &ty::Ref(_, inner_ty, inner_mutability) = expected.kind() && self.should_peel_ref(peel_kind, expected) => { debug!("inspecting {:?}", expected); @@ -508,22 +524,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .or_default() .push(PatAdjustment { kind: PatAdjust::BuiltinDeref, source: expected }); - let mut binding_mode = ByRef::Yes(match pat_info.binding_mode { - // If default binding mode is by value, make it `ref` or `ref mut` - // (depending on whether we observe `&` or `&mut`). - ByRef::No | - // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`). - ByRef::Yes(Mutability::Mut) => inner_mutability, - // Once a `ref`, always a `ref`. - // This is because a `& &mut` cannot mutate the underlying value. - ByRef::Yes(Mutability::Not) => Mutability::Not, - }); + let mut binding_mode = adjust_binding_mode(Pinnedness::Not, inner_mutability); let mut max_ref_mutbl = pat_info.max_ref_mutbl; if self.downgrade_mut_inside_shared() { binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl()); } - if binding_mode == ByRef::Yes(Mutability::Not) { + if matches!(binding_mode, ByRef::Yes(_, Mutability::Not)) { max_ref_mutbl = MutblCap::Not; } debug!("default binding mode is now {:?}", binding_mode); @@ -533,6 +540,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Recurse with the new expected type. self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info) } + // If `pin_ergonomics` is enabled, peel the `&pin` from the pinned reference type. See the + // examples in `tests/ui/async-await/pin-ergonomics/`. + _ if self.tcx.features().pin_ergonomics() + && let AdjustMode::Peel { kind: peel_kind } = adjust_mode + && pat.default_binding_modes + && self.should_peel_smart_pointer(peel_kind, expected) + && let Some(pinned_ty) = expected.pinned_ty() + // Currently, only pinned reference is specially handled, leaving other + // pinned types (e.g. `Pin>` to deref patterns) handled as a + // deref pattern. + && let &ty::Ref(_, inner_ty, inner_mutability) = pinned_ty.kind() => + { + debug!("scrutinee ty {expected:?} is a pinned reference, inserting pin deref"); + + // if the inner_ty is an ADT, make sure that it can be structurally pinned + // (i.e., it is `#[pin_v2]`). + if let Some(adt) = inner_ty.ty_adt_def() + && !adt.is_pin_project() + && !adt.is_pin() + { + let def_span: Option = self.tcx.hir_span_if_local(adt.did()); + let sugg_span = def_span.map(|span| span.shrink_to_lo()); + self.dcx().emit_err(crate::errors::ProjectOnNonPinProjectType { + span: pat.span, + def_span, + sugg_span, + }); + } + + let binding_mode = adjust_binding_mode(Pinnedness::Pinned, inner_mutability); + // If the pinnedness is `Not`, it means the pattern is unpinned + // and thus requires an `Unpin` bound. + if matches!(binding_mode, ByRef::Yes(Pinnedness::Not, _)) { + self.register_bound( + inner_ty, + self.tcx.require_lang_item(hir::LangItem::Unpin, pat.span), + self.misc(pat.span), + ) + } + debug!("default binding mode is now {:?}", binding_mode); + + // Use the old pat info to keep `current_depth` to its old value. + let new_pat_info = PatInfo { binding_mode, ..old_pat_info }; + + self.check_deref_pattern( + pat, + opt_path_res, + adjust_mode, + expected, + inner_ty, + PatAdjust::PinDeref, + new_pat_info, + ) + } // If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the // examples in `tests/ui/pattern/deref_patterns/`. _ if self.tcx.features().deref_patterns() @@ -540,35 +601,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && pat.default_binding_modes && self.should_peel_smart_pointer(peel_kind, expected) => { - debug!("scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref"); + debug!("scrutinee ty {expected:?} is a smart pointer, inserting pin deref"); + // The scrutinee is a smart pointer; implicitly dereference it. This adds a // requirement that `expected: DerefPure`. - let mut inner_ty = self.deref_pat_target(pat.span, expected); + let inner_ty = self.deref_pat_target(pat.span, expected); // Once we've checked `pat`, we'll add a `DerefMut` bound if it contains any // `ref mut` bindings. See `Self::register_deref_mut_bounds_if_needed`. - let mut typeck_results = self.typeck_results.borrow_mut(); - let mut pat_adjustments_table = typeck_results.pat_adjustments_mut(); - let pat_adjustments = pat_adjustments_table.entry(pat.hir_id).or_default(); - // We may reach the recursion limit if a user matches on a type `T` satisfying - // `T: Deref`; error gracefully in this case. - // FIXME(deref_patterns): If `deref_patterns` stabilizes, it may make sense to move - // this check out of this branch. Alternatively, this loop could be implemented with - // autoderef and this check removed. For now though, don't break code compiling on - // stable with lots of `&`s and a low recursion limit, if anyone's done that. - if self.tcx.recursion_limit().value_within_limit(pat_adjustments.len()) { - // Preserve the smart pointer type for THIR lowering and closure upvar analysis. - pat_adjustments - .push(PatAdjustment { kind: PatAdjust::OverloadedDeref, source: expected }); - } else { - let guar = report_autoderef_recursion_limit_error(self.tcx, pat.span, expected); - inner_ty = Ty::new_error(self.tcx, guar); - } - drop(typeck_results); - - // Recurse, using the old pat info to keep `current_depth` to its old value. - // Peeling smart pointers does not update the default binding mode. - self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, old_pat_info) + self.check_deref_pattern( + pat, + opt_path_res, + adjust_mode, + expected, + inner_ty, + PatAdjust::OverloadedDeref, + old_pat_info, + ) } PatKind::Missing | PatKind::Wild | PatKind::Err(_) => expected, // We allow any type here; we ensure that the type is uninhabited during match checking. @@ -647,6 +696,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn check_deref_pattern( + &self, + pat: &'tcx Pat<'tcx>, + opt_path_res: Option, ErrorGuaranteed>>, + adjust_mode: AdjustMode, + expected: Ty<'tcx>, + mut inner_ty: Ty<'tcx>, + pat_adjust_kind: PatAdjust, + pat_info: PatInfo<'tcx>, + ) -> Ty<'tcx> { + debug_assert!( + !matches!(pat_adjust_kind, PatAdjust::BuiltinDeref), + "unexpected deref pattern for builtin reference type {expected:?}", + ); + + let mut typeck_results = self.typeck_results.borrow_mut(); + let mut pat_adjustments_table = typeck_results.pat_adjustments_mut(); + let pat_adjustments = pat_adjustments_table.entry(pat.hir_id).or_default(); + // We may reach the recursion limit if a user matches on a type `T` satisfying + // `T: Deref`; error gracefully in this case. + // FIXME(deref_patterns): If `deref_patterns` stabilizes, it may make sense to move + // this check out of this branch. Alternatively, this loop could be implemented with + // autoderef and this check removed. For now though, don't break code compiling on + // stable with lots of `&`s and a low recursion limit, if anyone's done that. + if self.tcx.recursion_limit().value_within_limit(pat_adjustments.len()) { + // Preserve the smart pointer type for THIR lowering and closure upvar analysis. + pat_adjustments.push(PatAdjustment { kind: pat_adjust_kind, source: expected }); + } else { + let guar = report_autoderef_recursion_limit_error(self.tcx, pat.span, expected); + inner_ty = Ty::new_error(self.tcx, guar); + } + drop(typeck_results); + + // Recurse, using the old pat info to keep `current_depth` to its old value. + // Peeling smart pointers does not update the default binding mode. + self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, pat_info) + } + /// How should the binding mode and expected type be adjusted? /// /// When the pattern contains a path, `opt_path_res` must be `Some(path_res)`. @@ -1061,7 +1148,7 @@ 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, 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() @@ -1091,8 +1178,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl), - BindingMode(ByRef::Yes(user_br_mutbl), _) => { - if let ByRef::Yes(def_br_mutbl) = def_br { + 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( pat_info.top_info.hir_id, @@ -1108,7 +1195,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - if bm.0 == ByRef::Yes(Mutability::Mut) + if matches!(bm.0, ByRef::Yes(_, Mutability::Mut)) && let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl { let mut err = struct_span_code_err!( @@ -1136,7 +1223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let local_ty = self.local_ty(pat.span, pat.hir_id); let eq_ty = match bm.0 { - ByRef::Yes(mutbl) => { + ByRef::Yes(Pinnedness::Not, mutbl) => { // If the binding is like `ref x | ref mut x`, // then `x` is assigned a value of type `&M T` where M is the // mutability and T is the expected type. @@ -1146,6 +1233,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // See (note_1) for an explanation. self.new_ref_ty(pat.span, mutbl, expected) } + // Wrapping the type into `Pin` if the binding is like `ref pin const|mut x` + ByRef::Yes(Pinnedness::Pinned, mutbl) => Ty::new_adt( + self.tcx, + self.tcx.adt_def(self.tcx.require_lang_item(hir::LangItem::Pin, pat.span)), + self.tcx.mk_args(&[self.new_ref_ty(pat.span, mutbl, expected).into()]), + ), // Otherwise, the type of x is the expected type `T`. ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1). }; @@ -2605,7 +2698,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected = self.try_structurally_resolve_type(pat.span, expected); // Determine whether we're consuming an inherited reference and resetting the default // binding mode, based on edition and enabled experimental features. - if let ByRef::Yes(inh_mut) = pat_info.binding_mode { + if let ByRef::Yes(inh_pin, inh_mut) = pat_info.binding_mode + // FIXME(pin_ergonomics): since `&pin` pattern is supported, the condition here + // should be adjusted to `pat_pin == inh_pin` + && (!self.tcx.features().pin_ergonomics() || inh_pin == Pinnedness::Not) + { match self.ref_pat_matches_inherited_ref(pat.span.edition()) { InheritedRefMatchRule::EatOuter => { // ref pattern attempts to consume inherited reference @@ -3126,8 +3223,10 @@ 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 &= matches!( + user_bind_annot, + BindingMode(ByRef::Yes(_, mutbl), Mutability::Not) if mutbl == def_br_mutbl + ); if user_bind_annot == BindingMode(ByRef::No, Mutability::Mut) { info.bad_mut_modifiers = true; "`mut` binding modifier" diff --git a/compiler/rustc_lint/src/static_mut_refs.rs b/compiler/rustc_lint/src/static_mut_refs.rs index 16e1fb0192b32..1c0df1f4234a2 100644 --- a/compiler/rustc_lint/src/static_mut_refs.rs +++ b/compiler/rustc_lint/src/static_mut_refs.rs @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for StaticMutRefs { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'_>) { if let hir::StmtKind::Let(loc) = stmt.kind && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind - && let hir::ByRef::Yes(m) = ba.0 + && let hir::ByRef::Yes(_, m) = ba.0 && let Some(init) = loc.init && let Some(err_span) = path_is_static_mut(init, init.span) { diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 74573455f531a..2920c9cb42ab4 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -232,4 +232,7 @@ pub enum PatAdjust { /// An implicit call to `Deref(Mut)::deref(_mut)` before matching, such as when matching the /// pattern `[..]` against a scrutinee of type `Vec`. OverloadedDeref, + /// An implicit dereference before matching a `&pin` reference (under feature `pin_ergonomics`), + /// which will be lowered as a builtin deref of the private field `__pointer` in `Pin` + PinDeref, } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index df82c7a826be9..510c546f82a4e 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -55,6 +55,10 @@ bitflags::bitflags! { const IS_UNSAFE_CELL = 1 << 9; /// Indicates whether the type is `UnsafePinned`. const IS_UNSAFE_PINNED = 1 << 10; + /// Indicates whether the type is `Pin`. + const IS_PIN = 1 << 11; + /// Indicates whether the type is `#[pin_project]`. + const IS_PIN_PROJECT = 1 << 12; } } rustc_data_structures::external_bitflags_debug! { AdtFlags } @@ -284,6 +288,10 @@ impl AdtDefData { debug!("found non-exhaustive variant list for {:?}", did); flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE; } + if find_attr!(tcx.get_all_attrs(did), AttributeKind::PinV2(..)) { + debug!("found pin-project type {:?}", did); + flags |= AdtFlags::IS_PIN_PROJECT; + } flags |= match kind { AdtKind::Enum => AdtFlags::IS_ENUM, @@ -313,6 +321,9 @@ impl AdtDefData { if tcx.is_lang_item(did, LangItem::UnsafePinned) { flags |= AdtFlags::IS_UNSAFE_PINNED; } + if tcx.is_lang_item(did, LangItem::Pin) { + flags |= AdtFlags::IS_PIN; + } AdtDefData { did, variants, flags, repr } } @@ -428,6 +439,19 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_MANUALLY_DROP) } + /// Returns `true` if this is `Pin`. + #[inline] + pub fn is_pin(self) -> bool { + self.flags().contains(AdtFlags::IS_PIN) + } + + /// Returns `true` is this is `#[pin_v2]` for the purposes + /// of structural pinning. + #[inline] + pub fn is_pin_project(self) -> bool { + self.flags().contains(AdtFlags::IS_PIN_PROJECT) + } + /// Returns `true` if this type has a destructor. pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool { self.destructor(tcx).is_some() diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index ad8b1fd0693b0..953c806658aef 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1349,6 +1349,23 @@ impl<'tcx> Ty<'tcx> { } } + pub fn pinned_ty(self) -> Option> { + match self.kind() { + Adt(def, args) if def.is_pin() => Some(args.type_at(0)), + _ => None, + } + } + + pub fn pinned_ref(self) -> Option<(Ty<'tcx>, ty::Mutability)> { + if let Adt(def, args) = self.kind() + && def.is_pin() + && let &ty::Ref(_, ty, mutbl) = args.type_at(0).kind() + { + return Some((ty, mutbl)); + } + None + } + /// Panics if called on any type other than `Box`. pub fn expect_boxed_ty(self) -> Ty<'tcx> { self.boxed_ty() diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 20657ba8c726c..96f5697971a47 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -11,6 +11,7 @@ use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_hir::hir_id::OwnerId; use rustc_hir::{ self as hir, BindingMode, ByRef, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, Mutability, + Pinnedness, }; use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; @@ -479,7 +480,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; @@ -503,7 +504,7 @@ impl<'tcx> TypeckResults<'tcx> { ByRef::No } else { let mutable = self.pat_has_ref_mut_binding(inner); - ByRef::Yes(if mutable { Mutability::Mut } else { Mutability::Not }) + ByRef::Yes(Pinnedness::Not, if mutable { Mutability::Mut } else { Mutability::Not }) } } diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index c3028b9b5c4ea..af565ef636993 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -1,9 +1,10 @@ use std::sync::Arc; +use rustc_abi::FieldIdx; use rustc_hir::ByRef; use rustc_middle::mir::*; use rustc_middle::thir::*; -use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, Pinnedness, Ty, TypeVisitableExt}; use crate::builder::Builder; use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder}; @@ -299,7 +300,24 @@ impl<'tcx> MatchPairTree<'tcx> { None } - PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(mutability) } => { + PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(Pinnedness::Pinned, _) } => { + let Some(ref_ty) = pattern.ty.pinned_ty() else { + rustc_middle::bug!("RefPin pattern on non-`Pin` type {:?}", pattern.ty); + }; + MatchPairTree::for_pattern( + place_builder.field(FieldIdx::ZERO, ref_ty).deref(), + subpattern, + cx, + &mut subpairs, + extra_data, + ); + None + } + + PatKind::DerefPattern { + ref subpattern, + borrow: ByRef::Yes(Pinnedness::Not, mutability), + } => { // Create a new temporary for each deref pattern. // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls? let temp = cx.temp( diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 82f12a969bb1c..96c58dc14e8cb 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -5,20 +5,21 @@ //! This also includes code for pattern bindings in `let` statements and //! function parameters. +use std::assert_matches::debug_assert_matches; use std::borrow::Borrow; use std::mem; use std::sync::Arc; use itertools::{Itertools, Position}; -use rustc_abi::VariantIdx; +use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir::{BindingMode, ByRef, LetStmt, LocalSource, Node}; -use rustc_middle::bug; +use rustc_hir::{BindingMode, ByRef, LangItem, LetStmt, LocalSource, Node, Pinnedness}; use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::thir::{self, *}; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, ValTree, ValTreeKind}; +use rustc_middle::{bug, span_bug}; use rustc_pattern_analysis::constructor::RangeEnd; use rustc_pattern_analysis::rustc::{DeconstructedPat, RustcPatCtxt}; use rustc_span::{BytePos, Pos, Span, Symbol, sym}; @@ -917,6 +918,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { visit_subpat(self, subpattern, &user_tys.deref(), f); } + PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(Pinnedness::Pinned, _) } => { + visit_subpat(self, subpattern, &user_tys.leaf(FieldIdx::ZERO).deref(), f); + } + PatKind::DerefPattern { ref subpattern, .. } => { visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f); } @@ -2747,9 +2752,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source); self.cfg.push_assign(block, source_info, ref_for_guard, rvalue); } - ByRef::Yes(mutbl) => { - // The arm binding will be by reference, so eagerly create it now. Drops must - // be scheduled to emit `StorageDead` on the guard's failure/break branches. + ByRef::Yes(pinnedness, mutbl) => { + // The arm binding will be by reference, so eagerly create it now // be scheduled to emit `StorageDead` on the guard's failure/break branches. let value_for_arm = self.storage_live_binding( block, binding.var_id, @@ -2761,6 +2765,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rvalue = Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source); + let rvalue = match pinnedness { + ty::Pinnedness::Not => rvalue, + ty::Pinnedness::Pinned => { + self.pin_borrowed_local(block, value_for_arm.local, rvalue, source_info) + } + }; self.cfg.push_assign(block, source_info, value_for_arm, rvalue); // For the guard binding, take a shared reference to that reference. let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm); @@ -2797,14 +2807,59 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let rvalue = match binding.binding_mode.0 { ByRef::No => Rvalue::Use(self.consume_by_copy_or_move(binding.source)), - ByRef::Yes(mutbl) => { - Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source) + ByRef::Yes(pinnedness, mutbl) => { + let rvalue = + Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source); + match pinnedness { + ty::Pinnedness::Not => rvalue, + ty::Pinnedness::Pinned => { + self.pin_borrowed_local(block, local.local, rvalue, source_info) + } + } } }; self.cfg.push_assign(block, source_info, local, rvalue); } } + /// Given an rvalue `&[mut]borrow` and a local `local`, generate the pinned borrow for it: + /// ```ignore (illustrative) + /// pinned_temp = &borrow; + /// local = Pin { __pointer: move pinned_temp }; + /// ``` + fn pin_borrowed_local( + &mut self, + block: BasicBlock, + local: Local, + borrow: Rvalue<'tcx>, + source_info: SourceInfo, + ) -> Rvalue<'tcx> { + debug_assert_matches!(borrow, Rvalue::Ref(..)); + + let local_ty = self.local_decls[local].ty; + + let pinned_ty = local_ty.pinned_ty().unwrap_or_else(|| { + span_bug!( + source_info.span, + "expect type `Pin` for a pinned binding, found type {:?}", + local_ty + ) + }); + let pinned_temp = + Place::from(self.local_decls.push(LocalDecl::new(pinned_ty, source_info.span))); + self.cfg.push_assign(block, source_info, pinned_temp, borrow); + Rvalue::Aggregate( + Box::new(AggregateKind::Adt( + self.tcx.require_lang_item(LangItem::Pin, source_info.span), + FIRST_VARIANT, + self.tcx.mk_args(&[pinned_ty.into()]), + None, + None, + )), + std::iter::once(Operand::Move(pinned_temp)).collect(), + ) + } + /// Each binding (`ref mut var`/`ref var`/`mut var`/`var`, where the bound /// `var` has type `T` in the arm body) in a pattern maps to 2 locals. The /// first local is a binding for occurrences of `var` in the guard, which diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 195d45c2c4c49..18e9543407764 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -383,7 +383,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 3929a97eed8f2..2400d297c89cf 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -797,7 +797,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat: // We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`. let mut conflicts_ref = Vec::new(); sub.each_binding(|_, mode, _, span| { - if matches!(mode, ByRef::Yes(_)) { + if matches!(mode, ByRef::Yes(..)) { conflicts_ref.push(span) } }); @@ -813,7 +813,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat: return; } ByRef::No => return, - ByRef::Yes(m) => m, + ByRef::Yes(_, m) => m, }; // We now have `ref $mut_outer binding @ sub` (semantically). @@ -823,7 +823,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat: let mut conflicts_mut_ref = Vec::new(); sub.each_binding(|name, mode, ty, span| { match mode { - ByRef::Yes(mut_inner) => match (mut_outer, mut_inner) { + ByRef::Yes(_, mut_inner) => match (mut_outer, mut_inner) { // Both sides are `ref`. (Mutability::Not, Mutability::Not) => {} // 2x `ref mut`. diff --git a/compiler/rustc_mir_build/src/thir/pattern/migration.rs b/compiler/rustc_mir_build/src/thir/pattern/migration.rs index 8887308530506..095023a471b93 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/migration.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/migration.rs @@ -212,7 +212,7 @@ impl<'a> PatMigration<'a> { } if !self.info.suggest_eliding_modes && explicit_ba.0 == ByRef::No - && let ByRef::Yes(mutbl) = mode.0 + && let ByRef::Yes(_, mutbl) = mode.0 { // If we can't fix the pattern by eliding modifiers, we'll need to make the pattern // fully explicit. i.e. we'll need to suggest reference patterns for this. diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index dc6b958904497..404f410e22191 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -11,7 +11,7 @@ use rustc_abi::{FieldIdx, Integer}; use rustc_errors::codes::*; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; -use rustc_hir::{self as hir, LangItem, RangeEnd}; +use rustc_hir::{self as hir, ByRef, LangItem, Mutability, Pinnedness, RangeEnd}; use rustc_index::Idx; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::interpret::LitToConstInput; @@ -114,6 +114,16 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let borrow = self.typeck_results.deref_pat_borrow_mode(adjust.source, pat); PatKind::DerefPattern { subpattern: thir_pat, borrow } } + PatAdjust::PinDeref => { + let mutable = self.typeck_results.pat_has_ref_mut_binding(pat); + PatKind::DerefPattern { + subpattern: thir_pat, + borrow: ByRef::Yes( + Pinnedness::Pinned, + if mutable { Mutability::Mut } else { Mutability::Not }, + ), + } + } }; Box::new(Pat { span, ty: adjust.source, kind }) }); @@ -354,11 +364,22 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // A ref x pattern is the same node used for x, and as such it has // x's type, which is &T, where we want T (the type being matched). let var_ty = ty; - if let hir::ByRef::Yes(_) = mode.0 { - if let ty::Ref(_, rty, _) = ty.kind() { - ty = *rty; - } else { - bug!("`ref {}` has wrong type {}", ident, ty); + if let hir::ByRef::Yes(pinnedness, _) = mode.0 { + match pinnedness { + hir::Pinnedness::Pinned + if let Some(pty) = ty.pinned_ty() + && let &ty::Ref(_, rty, _) = pty.kind() => + { + debug_assert!( + self.tcx.features().pin_ergonomics(), + "`pin_ergonomics` must be enabled to have a by-pin-ref binding" + ); + ty = rty; + } + hir::Pinnedness::Not if let &ty::Ref(_, rty, _) = ty.kind() => { + ty = rty; + } + _ => bug!("`ref {}` has wrong type {}", ident, ty), } }; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index ed4069dae933c..30870c810942f 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -36,8 +36,8 @@ use rustc_ast::tokenstream::{ use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID, - DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, - Visibility, VisibilityKind, + DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Pinnedness, Recovered, + Safety, StrLit, Visibility, VisibilityKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; @@ -1317,7 +1317,12 @@ impl<'a> Parser<'a> { /// Parses reference binding mode (`ref`, `ref mut`, or nothing). fn parse_byref(&mut self) -> ByRef { - if self.eat_keyword(exp!(Ref)) { ByRef::Yes(self.parse_mutability()) } else { ByRef::No } + if self.eat_keyword(exp!(Ref)) { + // FIXME(pin_ergonomics): support `ref pin const|mut` bindings + ByRef::Yes(Pinnedness::Not, self.parse_mutability()) + } else { + ByRef::No + } } /// Possibly parses mutability (`const` or `mut`). diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 4f522d57e4140..f964ecb90326f 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}; @@ -778,7 +779,11 @@ 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( + // FIXME(pin_ergonomics): support `ref pin const|mut` bindings + BindingMode(ByRef::Yes(Pinnedness::Not, mutbl), Mutability::Not), + syntax_loc, + )? } else if self.eat_keyword(exp!(Box)) { self.parse_pat_box()? } else if self.check_inline_const(0) { @@ -1093,7 +1098,7 @@ 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.kind) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ef42c42f68b37..c214104d60670 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -283,7 +283,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::ObjcSelector { .. } | AttributeKind::RustcCoherenceIsCore(..) | AttributeKind::DebuggerVisualizer(..) - | AttributeKind::RustcMain, + | AttributeKind::RustcMain + | AttributeKind::PinV2(..), ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 877b5ad93bfca..6d34587684bb3 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -125,9 +125,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { ) => { self.check_def_id(def_id); } - _ if self.in_pat => {} Res::PrimTy(..) | Res::SelfCtor(..) | Res::Local(..) => {} Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => { + // Using a variant in patterns should not make the variant live, + // since we can just remove the match arm that matches the pattern + if self.in_pat { + return; + } let variant_id = self.tcx.parent(ctor_def_id); let enum_id = self.tcx.parent(variant_id); self.check_def_id(enum_id); @@ -136,6 +140,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } } Res::Def(DefKind::Variant, variant_id) => { + // Using a variant in patterns should not make the variant live, + // since we can just remove the match arm that matches the pattern + if self.in_pat { + return; + } let enum_id = self.tcx.parent(variant_id); self.check_def_id(enum_id); if !self.ignore_variant_stack.contains(&variant_id) { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c1c9fa57f85b2..9e8465d2da2e5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1668,6 +1668,7 @@ symbols! { pin, pin_ergonomics, pin_macro, + pin_v2, platform_intrinsics, plugin, plugin_registrar, diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 52915abca1504..e1b3ff92a07b8 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1965,6 +1965,9 @@ Please disable assertions with `rust.debug-assertions = false`. cmd.arg("--default-codegen-backend") .arg(builder.config.default_codegen_backend(test_compiler.host).name()); } + if builder.config.cmd.bypass_ignore_backends() { + cmd.arg("--bypass-ignore-backends"); + } if builder.build.config.llvm_enzyme { cmd.arg("--has-enzyme"); diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 9e408505933d3..bf089d25ffec8 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -422,6 +422,9 @@ pub enum Subcommand { #[arg(long)] /// Use a different codegen backend when running tests. test_codegen_backend: Option, + #[arg(long)] + /// Ignore `//@ ignore-backends` directives. + bypass_ignore_backends: bool, }, /// Build and run some test suites *in Miri* Miri { @@ -668,6 +671,13 @@ impl Subcommand { _ => None, } } + + pub fn bypass_ignore_backends(&self) -> bool { + match self { + Subcommand::Test { bypass_ignore_backends, .. } => *bypass_ignore_backends, + _ => false, + } + } } /// Returns the shell completion for a given shell, if the result differs from the current diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 12ceef0c928de..045c8c71f9cd2 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -207,7 +207,9 @@ settings: on `wasm32-unknown-unknown` target because the target does not support the `proc-macro` crate type. - `needs-target-std` — ignores if target platform does not have std support. -- `ignore-backends` — ignores the listed backends, separated by whitespace characters. +- `ignore-backends` — ignores the listed backends, separated by whitespace characters. Please note + that this directive can be overriden with the `--bypass-ignore-backends=[BACKEND]` command line + flag. - `needs-backends` — only runs the test if current codegen backend is listed. The following directives will check LLVM support: diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index 544f9b97237cb..a837be680dcdd 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -336,6 +336,7 @@ complete -c x -n "__fish_x_using_subcommand test" -l force-rerun -d 'rerun tests complete -c x -n "__fish_x_using_subcommand test" -l only-modified -d 'only run tests that result has been changed' complete -c x -n "__fish_x_using_subcommand test" -l rustfix-coverage -d 'enable this to generate a Rustfix coverage file, which is saved in `//rustfix_missing_coverage.txt`' complete -c x -n "__fish_x_using_subcommand test" -l no-capture -d 'don\'t capture stdout/stderr of tests' +complete -c x -n "__fish_x_using_subcommand test" -l bypass-ignore-backends -d 'Ignore `//@ ignore-backends` directives' complete -c x -n "__fish_x_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x -n "__fish_x_using_subcommand test" -s i -l incremental -d 'use incremental compilation' complete -c x -n "__fish_x_using_subcommand test" -l include-default-paths -d 'include default paths in addition to the provided ones' diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index b03acf930f70d..1a02adbddfea7 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -383,6 +383,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--only-modified', '--only-modified', [CompletionResultType]::ParameterName, 'only run tests that result has been changed') [CompletionResult]::new('--rustfix-coverage', '--rustfix-coverage', [CompletionResultType]::ParameterName, 'enable this to generate a Rustfix coverage file, which is saved in `//rustfix_missing_coverage.txt`') [CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests') + [CompletionResult]::new('--bypass-ignore-backends', '--bypass-ignore-backends', [CompletionResultType]::ParameterName, 'Ignore `//@ ignore-backends` directives') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 08e4cd26ce887..63b7987fb290e 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -336,6 +336,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -l force-rerun -d 'rerun complete -c x.py -n "__fish_x.py_using_subcommand test" -l only-modified -d 'only run tests that result has been changed' complete -c x.py -n "__fish_x.py_using_subcommand test" -l rustfix-coverage -d 'enable this to generate a Rustfix coverage file, which is saved in `//rustfix_missing_coverage.txt`' complete -c x.py -n "__fish_x.py_using_subcommand test" -l no-capture -d 'don\'t capture stdout/stderr of tests' +complete -c x.py -n "__fish_x.py_using_subcommand test" -l bypass-ignore-backends -d 'Ignore `//@ ignore-backends` directives' complete -c x.py -n "__fish_x.py_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_x.py_using_subcommand test" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_x.py_using_subcommand test" -l include-default-paths -d 'include default paths in addition to the provided ones' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index 3d95d88af4955..cac70f722098f 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -383,6 +383,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--only-modified', '--only-modified', [CompletionResultType]::ParameterName, 'only run tests that result has been changed') [CompletionResult]::new('--rustfix-coverage', '--rustfix-coverage', [CompletionResultType]::ParameterName, 'enable this to generate a Rustfix coverage file, which is saved in `//rustfix_missing_coverage.txt`') [CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests') + [CompletionResult]::new('--bypass-ignore-backends', '--bypass-ignore-backends', [CompletionResultType]::ParameterName, 'Ignore `//@ ignore-backends` directives') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 8ff0eaf35c89a..cff17f431d33d 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -3875,7 +3875,7 @@ _x.py() { return 0 ;; x.py__test) - opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 9d2d73e582ec6..47cdaf97befcc 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -383,6 +383,7 @@ _arguments "${_arguments_options[@]}" : \ '--only-modified[only run tests that result has been changed]' \ '--rustfix-coverage[enable this to generate a Rustfix coverage file, which is saved in \`//rustfix_missing_coverage.txt\`]' \ '--no-capture[don'\''t capture stdout/stderr of tests]' \ +'--bypass-ignore-backends[Ignore \`//@ ignore-backends\` directives]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh index c1b73fb7c9e34..700617bfeba0e 100644 --- a/src/etc/completions/x.sh +++ b/src/etc/completions/x.sh @@ -3875,7 +3875,7 @@ _x() { return 0 ;; x__test) - opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --bypass-ignore-backends --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index 29237ef9bf8fd..b960be4a1b10a 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -383,6 +383,7 @@ _arguments "${_arguments_options[@]}" : \ '--only-modified[only run tests that result has been changed]' \ '--rustfix-coverage[enable this to generate a Rustfix coverage file, which is saved in \`//rustfix_missing_coverage.txt\`]' \ '--no-capture[don'\''t capture stdout/stderr of tests]' \ +'--bypass-ignore-backends[Ignore \`//@ ignore-backends\` directives]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 6c280c0736b18..4b6d313d288ad 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -896,7 +896,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { // Register the loaded external files in the source map so they show up in depinfo. // We can't load them via the source map because it gets created after we process the options. for external_path in &loaded_paths { - let _ = sess.source_map().load_file(external_path); + let _ = sess.source_map().load_binary_file(external_path); } if sess.opts.describe_lints { diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 471e966e2c24b..1b3c96d82b410 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -273,6 +273,7 @@ pub(crate) fn run( bin_crate: bool, ) { let inner = move || -> Result<(), String> { + let emit_dep_info = renderopts.dep_info().is_some(); // Generates source files for examples renderopts.no_emit_shared = true; let (cx, _) = Context::init(krate, renderopts, cache, tcx, Default::default()) @@ -320,6 +321,10 @@ pub(crate) fn run( calls.encode(&mut encoder); encoder.finish().map_err(|(_path, e)| e.to_string())?; + if emit_dep_info { + rustc_interface::passes::write_dep_info(tcx); + } + Ok(()) }; 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 919702c5714ad..e95816353df61 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, arm: &Arm<'_>) -> Option { .qpath_res(qpath, arm.pat.hir_id) .ctor_parent(cx) .is_lang_item(cx, 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 && e.res(cx).ctor_parent(cx).is_lang_item(cx, 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 c9b6821ad98fd..9c6cf66019f01 100644 --- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs @@ -172,7 +172,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/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index d39e315cae1f2..7a1dd94567b14 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -176,7 +176,7 @@ fn get_pat_binding<'tcx>( if let PatKind::Binding(bind_annot, hir_id, ident, _) = pat.kind && hir_id == local { - if matches!(bind_annot.0, rustc_ast::ByRef::Yes(_)) { + if matches!(bind_annot.0, rustc_ast::ByRef::Yes(..)) { let _ = byref_ident.insert(ident); } // the second call of `replace()` returns a `Some(span)`, meaning a multi-binding pattern 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 8980a22ad6131..18087bd96debf 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 @@ -57,7 +57,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) _ => 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/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index 1a6165d0af835..14675015c35e0 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -150,7 +150,7 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { let init_expr_str = Sugg::hir_with_applicability(cx, init_expr, "..", &mut applicability).maybe_paren(); // Take care when binding is `ref` let sugg = if let PatKind::Binding( - BindingMode(ByRef::Yes(ref_mutability), binding_mutability), + BindingMode(ByRef::Yes(_,ref_mutability), binding_mutability), _hir_id, ident, subpattern, @@ -169,7 +169,7 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { // Handle subpattern (@ subpattern) let maybe_subpattern = match subpattern { Some(Pat { - kind: PatKind::Binding(BindingMode(ByRef::Yes(_), _), _, subident, None), + kind: PatKind::Binding(BindingMode(ByRef::Yes(..), _), _, subident, None), .. }) => { // avoid `&ref` @@ -504,8 +504,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); let requires_semi = matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(_)); let method_call_str = match by_ref { - ByRef::Yes(Mutability::Mut) => ".as_mut()", - ByRef::Yes(Mutability::Not) => ".as_ref()", + ByRef::Yes(_, Mutability::Mut) => ".as_mut()", + ByRef::Yes(_, Mutability::Not) => ".as_ref()", ByRef::No => "", }; let sugg = format!( diff --git a/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs b/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs index 074b79263d377..250c277ab5e1f 100644 --- a/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs +++ b/src/tools/clippy/clippy_lints/src/toplevel_ref_arg.rs @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for ToplevelRefArg { ) { 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()) { @@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for ToplevelRefArg { 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/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 222427cd3075f..129e8a45aa892 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -743,10 +743,14 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { let ann = match ann { BindingMode::NONE => "NONE", BindingMode::REF => "REF", + BindingMode::REF_PIN => "REF_PIN", BindingMode::MUT => "MUT", BindingMode::REF_MUT => "REF_MUT", + BindingMode::REF_PIN_MUT => "REF_PIN_MUT", BindingMode::MUT_REF => "MUT_REF", + BindingMode::MUT_REF_PIN => "MUT_REF_PIN", BindingMode::MUT_REF_MUT => "MUT_REF_MUT", + BindingMode::MUT_REF_PIN_MUT => "MUT_REF_PIN_MUT", }; kind!("Binding(BindingMode::{ann}, _, {name}, {sub})"); self.ident(name); diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 6f0e57bd3ab1c..2bdd5739a5579 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -211,7 +211,12 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS // Custom `Deref` impl might have side effects ExprKind::Unary(UnOp::Deref, e) - if self.cx.typeck_results().expr_ty(e).builtin_deref(true).is_none() => + if self + .cx + .typeck_results() + .expr_ty(e) + .builtin_deref(true) + .is_none() => { self.eagerness |= NoChange; }, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 11220a8c4c017..ce6cd3d5ce0e9 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -782,7 +782,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { ByRef::No if !is_copy(cx, cx.typeck_results().node_type(id)) => { capture = CaptureKind::Value; }, - ByRef::Yes(Mutability::Mut) if capture != CaptureKind::Value => { + ByRef::Yes(_, Mutability::Mut) if capture != CaptureKind::Value => { capture = CaptureKind::Ref(Mutability::Mut); }, _ => (), @@ -1830,7 +1830,7 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr< .typeck_results() .pat_binding_modes() .get(pat.hir_id) - .is_some_and(|mode| matches!(mode.0, ByRef::Yes(_))) + .is_some_and(|mode| matches!(mode.0, ByRef::Yes(..))) { // If the parameter is `(x, y)` of type `&(T, T)`, or `[x, y]` of type `&[T; 2]`, then // due to match ergonomics, the inner patterns become references. Don't consider this diff --git a/src/tools/clippy/tests/ui/explicit_write_in_test.stderr b/src/tools/clippy/tests/ui/explicit_write_in_test.stderr deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 8e47d51ee4dbd..1f893fecb54b0 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -710,6 +710,8 @@ pub struct Config { pub default_codegen_backend: CodegenBackend, /// Name/path of the backend to use instead of `default_codegen_backend`. pub override_codegen_backend: Option, + /// Whether to ignore `//@ ignore-backends`. + pub bypass_ignore_backends: bool, } impl Config { diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 0318ed2b3d119..5988f59fd92f7 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -1493,7 +1493,7 @@ fn ignore_backends(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision } } }) { - if config.default_codegen_backend == backend { + if !config.bypass_ignore_backends && config.default_codegen_backend == backend { return IgnoreDecision::Ignore { reason: format!("{} backend is marked as ignore", backend.as_str()), }; diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 11a462c3d44a6..b524017e4dadd 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -217,7 +217,8 @@ fn parse_config(args: Vec) -> Config { "override-codegen-backend", "the codegen backend to use instead of the default one", "CODEGEN BACKEND [NAME | PATH]", - ); + ) + .optflag("", "bypass-ignore-backends", "ignore `//@ ignore-backends` directives"); let (argv0, args_) = args.split_first().unwrap(); if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { @@ -484,6 +485,7 @@ fn parse_config(args: Vec) -> Config { default_codegen_backend, override_codegen_backend, + bypass_ignore_backends: matches.opt_present("bypass-ignore-backends"), } } diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index 4bd3531f4b433..60a7e6d47d2fb 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -138,5 +138,6 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { minicore_path: Default::default(), default_codegen_backend: CodegenBackend::Llvm, override_codegen_backend: None, + bypass_ignore_backends: Default::default(), } } diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index fa9a3e33914b6..03752c371ae11 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -134,7 +134,8 @@ impl Rewrite for Pat { let mut_prefix = format_mutability(mutability).trim(); let (ref_kw, mut_infix) = match by_ref { - ByRef::Yes(rmutbl) => ("ref", format_mutability(rmutbl).trim()), + // FIXME(pin_ergonomics): format the pinnedness + ByRef::Yes(_, rmutbl) => ("ref", format_mutability(rmutbl).trim()), ByRef::No => ("", ""), }; let id_str = rewrite_ident(context, ident); diff --git a/tests/run-make/rustdoc-scrape-examples-dep-info/examples/ex.rs b/tests/run-make/rustdoc-scrape-examples-dep-info/examples/ex.rs new file mode 100644 index 0000000000000..c37b8dd48853a --- /dev/null +++ b/tests/run-make/rustdoc-scrape-examples-dep-info/examples/ex.rs @@ -0,0 +1,6 @@ +fn main() {} + +#[test] +fn a_test() { + foobar::ok(); +} diff --git a/tests/run-make/rustdoc-scrape-examples-dep-info/rmake.rs b/tests/run-make/rustdoc-scrape-examples-dep-info/rmake.rs new file mode 100644 index 0000000000000..7dfa6584785ae --- /dev/null +++ b/tests/run-make/rustdoc-scrape-examples-dep-info/rmake.rs @@ -0,0 +1,19 @@ +//@ needs-target-std +use run_make_support::{assert_contains, rfs}; + +#[path = "../rustdoc-scrape-examples-remap/scrape.rs"] +mod scrape; + +fn main() { + scrape::scrape( + &["--scrape-tests", "--emit=dep-info"], + &["--emit=dep-info,invocation-specific"], + ); + + let content = rfs::read_to_string("foobar.d"); + assert_contains(&content, "lib.rs:"); + assert_contains(&content, "rustdoc/ex.calls:"); + + let content = rfs::read_to_string("ex.d"); + assert_contains(&content, "examples/ex.rs:"); +} diff --git a/tests/run-make/rustdoc-scrape-examples-dep-info/src/lib.rs b/tests/run-make/rustdoc-scrape-examples-dep-info/src/lib.rs new file mode 100644 index 0000000000000..93d56b7e972f8 --- /dev/null +++ b/tests/run-make/rustdoc-scrape-examples-dep-info/src/lib.rs @@ -0,0 +1,3 @@ +//@ has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' '' + +pub fn ok() {} diff --git a/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs b/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs index 8996ff184c900..38943b663c420 100644 --- a/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs +++ b/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs @@ -3,5 +3,5 @@ mod scrape; fn main() { - scrape::scrape(&[]); + scrape::scrape(&[], &[]); } diff --git a/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs b/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs index 8996ff184c900..38943b663c420 100644 --- a/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs +++ b/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs @@ -3,5 +3,5 @@ mod scrape; fn main() { - scrape::scrape(&[]); + scrape::scrape(&[], &[]); } diff --git a/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs b/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs index 8996ff184c900..38943b663c420 100644 --- a/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs +++ b/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs @@ -3,5 +3,5 @@ mod scrape; fn main() { - scrape::scrape(&[]); + scrape::scrape(&[], &[]); } diff --git a/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs b/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs index ead3920c76132..920a65d56f8e5 100644 --- a/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs +++ b/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs @@ -2,5 +2,5 @@ mod scrape; fn main() { - scrape::scrape(&[]); + scrape::scrape(&[], &[]); } diff --git a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs index c4d7814c3c831..668cb3797fb9e 100644 --- a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs +++ b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs @@ -2,7 +2,7 @@ use std::path::Path; use run_make_support::{htmldocck, rfs, rustc, rustdoc}; -pub fn scrape(extra_args: &[&str]) { +pub fn scrape(extra_args_scrape: &[&str], extra_args_doc: &[&str]) { let out_dir = Path::new("rustdoc"); let crate_name = "foobar"; let deps = rfs::read_dir("examples") @@ -27,7 +27,7 @@ pub fn scrape(extra_args: &[&str]) { .arg(&out_example) .arg("--scrape-examples-target-crate") .arg(crate_name) - .args(extra_args) + .args(extra_args_scrape) .run(); out_deps.push(out_example); } @@ -42,6 +42,7 @@ pub fn scrape(extra_args: &[&str]) { for dep in out_deps { rustdoc.arg("--with-examples").arg(dep); } + rustdoc.args(extra_args_doc); rustdoc.run(); htmldocck().arg(out_dir).arg("src/lib.rs").run(); diff --git a/tests/run-make/rustdoc-scrape-examples-test/rmake.rs b/tests/run-make/rustdoc-scrape-examples-test/rmake.rs index 0868507c4ae5b..c0c4df91d517d 100644 --- a/tests/run-make/rustdoc-scrape-examples-test/rmake.rs +++ b/tests/run-make/rustdoc-scrape-examples-test/rmake.rs @@ -3,5 +3,5 @@ mod scrape; fn main() { - scrape::scrape(&["--scrape-tests"]); + scrape::scrape(&["--scrape-tests"], &[]); } diff --git a/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs b/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs index 8996ff184c900..38943b663c420 100644 --- a/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs +++ b/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs @@ -3,5 +3,5 @@ mod scrape; fn main() { - scrape::scrape(&[]); + scrape::scrape(&[], &[]); } diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs index 7746654555dd8..07aba0d1d2815 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -2,11 +2,11 @@ use std::pin::Pin; +#[pin_v2] //~ ERROR the `#[pin_v2]` attribute is an experimental feature struct Foo; impl Foo { - fn foo(self: Pin<&mut Self>) { - } + fn foo(self: Pin<&mut Self>) {} fn foo_sugar(&pin mut self) {} //~ ERROR pinned reference syntax is experimental fn foo_sugar_const(&pin const self) {} //~ ERROR pinned reference syntax is experimental } @@ -51,11 +51,11 @@ fn borrows() { mod not_compiled { use std::pin::Pin; + #[pin_v2] struct Foo; impl Foo { - fn foo(self: Pin<&mut Self>) { - } + fn foo(self: Pin<&mut Self>) {} fn foo_sugar(&pin mut self) {} //~ ERROR pinned reference syntax is experimental fn foo_sugar_const(&pin const self) {} //~ ERROR pinned reference syntax is experimental } diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr index a8890254facea..cff564c01fc6b 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr @@ -148,6 +148,16 @@ LL | let x: Pin<&_> = &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]: the `#[pin_v2]` attribute is an experimental feature + --> $DIR/feature-gate-pin_ergonomics.rs:5:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = 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:28:9 | @@ -177,16 +187,16 @@ LL | x.foo(); | ^ value used here after move | note: `Foo::foo` takes ownership of the receiver `self`, which moves `x` - --> $DIR/feature-gate-pin_ergonomics.rs:8:12 + --> $DIR/feature-gate-pin_ergonomics.rs:9:12 | -LL | fn foo(self: Pin<&mut Self>) { +LL | fn foo(self: Pin<&mut Self>) {} | ^^^^ help: consider reborrowing the `Pin` instead of moving it | LL | x.as_mut().foo(); | +++++++++ -error: aborting due to 17 previous errors +error: aborting due to 18 previous errors Some errors have detailed explanations: E0382, E0658. For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/lint/dead-code/inferred-generic-arg.rs b/tests/ui/lint/dead-code/inferred-generic-arg.rs new file mode 100644 index 0000000000000..106d6e7763c8b --- /dev/null +++ b/tests/ui/lint/dead-code/inferred-generic-arg.rs @@ -0,0 +1,16 @@ +//@ check-pass + +#![deny(dead_code)] + +#[derive(Default)] +struct Test { + +} + +fn main() { + if let Some::(test) = magic::() { } +} + +fn magic() -> Option { + Some(T::default()) +} diff --git a/tests/ui/pin-ergonomics/pattern-matching-deref-pattern.normal.stderr b/tests/ui/pin-ergonomics/pattern-matching-deref-pattern.normal.stderr new file mode 100644 index 0000000000000..96bac039df723 --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching-deref-pattern.normal.stderr @@ -0,0 +1,155 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/pattern-matching-deref-pattern.rs:48:28 + | +LL | let Foo { x, y } = foo.as_mut(); + | - - ^^^^^^^^^^^^ + | | | + | | ...and here + | data moved here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider borrowing the pattern binding + | +LL | let Foo { ref x, y } = foo.as_mut(); + | +++ +help: consider borrowing the pattern binding + | +LL | let Foo { x, ref y } = foo.as_mut(); + | +++ + +error[E0507]: cannot move out of a shared reference + --> $DIR/pattern-matching-deref-pattern.rs:38:24 + | +LL | let Foo { x, y } = foo.as_mut(); + | - - ^^^^^^^^^^^^ + | | | + | | ...and here + | data moved here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider borrowing the pattern binding + | +LL | let Foo { ref x, y } = foo.as_mut(); + | +++ +help: consider borrowing the pattern binding + | +LL | let Foo { x, ref y } = foo.as_mut(); + | +++ + +error[E0507]: cannot move out of a shared reference + --> $DIR/pattern-matching-deref-pattern.rs:70:28 + | +LL | let Foo { x, y } = foo.as_ref(); + | - - ^^^^^^^^^^^^ + | | | + | | ...and here + | data moved here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider borrowing the pattern binding + | +LL | let Foo { ref x, y } = foo.as_ref(); + | +++ +help: consider borrowing the pattern binding + | +LL | let Foo { x, ref y } = foo.as_ref(); + | +++ + +error[E0507]: cannot move out of a shared reference + --> $DIR/pattern-matching-deref-pattern.rs:60:24 + | +LL | let Foo { x, y } = foo.as_ref(); + | - - ^^^^^^^^^^^^ + | | | + | | ...and here + | data moved here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider borrowing the pattern binding + | +LL | let Foo { ref x, y } = foo.as_ref(); + | +++ +help: consider borrowing the pattern binding + | +LL | let Foo { x, ref y } = foo.as_ref(); + | +++ + +error[E0507]: cannot move out of a shared reference + --> $DIR/pattern-matching-deref-pattern.rs:92:25 + | +LL | let Bar(x, y) = bar.as_mut(); + | - - ^^^^^^^^^^^^ + | | | + | | ...and here + | data moved here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider borrowing the pattern binding + | +LL | let Bar(ref x, y) = bar.as_mut(); + | +++ +help: consider borrowing the pattern binding + | +LL | let Bar(x, ref y) = bar.as_mut(); + | +++ + +error[E0507]: cannot move out of a shared reference + --> $DIR/pattern-matching-deref-pattern.rs:82:21 + | +LL | let Bar(x, y) = bar.as_mut(); + | - - ^^^^^^^^^^^^ + | | | + | | ...and here + | data moved here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider borrowing the pattern binding + | +LL | let Bar(ref x, y) = bar.as_mut(); + | +++ +help: consider borrowing the pattern binding + | +LL | let Bar(x, ref y) = bar.as_mut(); + | +++ + +error[E0507]: cannot move out of a shared reference + --> $DIR/pattern-matching-deref-pattern.rs:114:25 + | +LL | let Bar(x, y) = bar.as_ref(); + | - - ^^^^^^^^^^^^ + | | | + | | ...and here + | data moved here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider borrowing the pattern binding + | +LL | let Bar(ref x, y) = bar.as_ref(); + | +++ +help: consider borrowing the pattern binding + | +LL | let Bar(x, ref y) = bar.as_ref(); + | +++ + +error[E0507]: cannot move out of a shared reference + --> $DIR/pattern-matching-deref-pattern.rs:104:21 + | +LL | let Bar(x, y) = bar.as_ref(); + | - - ^^^^^^^^^^^^ + | | | + | | ...and here + | data moved here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider borrowing the pattern binding + | +LL | let Bar(ref x, y) = bar.as_ref(); + | +++ +help: consider borrowing the pattern binding + | +LL | let Bar(x, ref y) = bar.as_ref(); + | +++ + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/pin-ergonomics/pattern-matching-deref-pattern.rs b/tests/ui/pin-ergonomics/pattern-matching-deref-pattern.rs new file mode 100644 index 0000000000000..3ec9b8fe476f1 --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching-deref-pattern.rs @@ -0,0 +1,124 @@ +//@ revisions: pin_ergonomics normal +//@ edition:2024 +//@[pin_ergonomics] check-pass +#![cfg_attr(pin_ergonomics, feature(pin_ergonomics))] +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +// This test verifies that the `pin_ergonomics` feature works well +// together with the `deref_patterns` feature. + +use std::pin::Pin; + +#[cfg_attr(pin_ergonomics, pin_v2)] +struct Foo { + x: T, + y: U, +} + +#[cfg_attr(pin_ergonomics, pin_v2)] +struct Bar(T, U); + +#[cfg_attr(pin_ergonomics, pin_v2)] +enum Baz { + Foo(T, U), + Bar { x: T, y: U }, +} + +trait IsPinMut {} +trait IsPinConst {} +impl IsPinMut for Pin<&mut T> {} +impl IsPinConst for Pin<&T> {} + +fn assert_pin_mut(_: T) {} +fn assert_pin_const(_: T) {} + +fn foo_mut(mut foo: Pin<&mut Foo>) { + let Foo { .. } = foo.as_mut(); + let Foo { x, y } = foo.as_mut(); + //[normal]~^ ERROR cannot move out of a shared reference + #[cfg(pin_ergonomics)] + assert_pin_mut(x); + #[cfg(pin_ergonomics)] + assert_pin_mut(y); + let Pin { .. } = foo.as_mut(); + + let _ = || { + let Foo { .. } = foo.as_mut(); + let Foo { x, y } = foo.as_mut(); + //[normal]~^ ERROR cannot move out of a shared reference + #[cfg(pin_ergonomics)] + assert_pin_mut(x); + #[cfg(pin_ergonomics)] + assert_pin_mut(y); + let Pin { .. } = foo.as_mut(); + }; +} + +fn foo_const(foo: Pin<&Foo>) { + let Foo { .. } = foo.as_ref(); + let Foo { x, y } = foo.as_ref(); + //[normal]~^ ERROR cannot move out of a shared reference + #[cfg(pin_ergonomics)] + assert_pin_const(x); + #[cfg(pin_ergonomics)] + assert_pin_const(y); + let Pin { .. } = foo.as_ref(); + + let _ = || { + let Foo { .. } = foo.as_ref(); + let Foo { x, y } = foo.as_ref(); + //[normal]~^ ERROR cannot move out of a shared reference + #[cfg(pin_ergonomics)] + assert_pin_const(x); + #[cfg(pin_ergonomics)] + assert_pin_const(y); + let Pin { .. } = foo.as_ref(); + }; +} + +fn bar_mut(mut bar: Pin<&mut Bar>) { + let Bar(..) = bar.as_mut(); + let Bar(x, y) = bar.as_mut(); + //[normal]~^ ERROR cannot move out of a shared reference + #[cfg(pin_ergonomics)] + assert_pin_mut(x); + #[cfg(pin_ergonomics)] + assert_pin_mut(y); + let Pin { .. } = bar.as_mut(); + + let _ = || { + let Bar(..) = bar.as_mut(); + let Bar(x, y) = bar.as_mut(); + //[normal]~^ ERROR cannot move out of a shared reference + #[cfg(pin_ergonomics)] + assert_pin_mut(x); + #[cfg(pin_ergonomics)] + assert_pin_mut(y); + let Pin { .. } = bar.as_mut(); + }; +} + +fn bar_const(bar: Pin<&Bar>) { + let Bar(..) = bar.as_ref(); + let Bar(x, y) = bar.as_ref(); + //[normal]~^ ERROR cannot move out of a shared reference + #[cfg(pin_ergonomics)] + assert_pin_const(x); + #[cfg(pin_ergonomics)] + assert_pin_const(y); + let Pin { .. } = bar.as_ref(); + + let _ = || { + let Bar(..) = bar.as_ref(); + let Bar(x, y) = bar.as_ref(); + //[normal]~^ ERROR cannot move out of a shared reference + #[cfg(pin_ergonomics)] + assert_pin_const(x); + #[cfg(pin_ergonomics)] + assert_pin_const(y); + let Pin { .. } = bar.as_ref(); + }; +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.both.stderr b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.both.stderr new file mode 100644 index 0000000000000..9bcb41299b7da --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.both.stderr @@ -0,0 +1,142 @@ +error: cannot project on type that is not `#[pin_v2]` + --> $DIR/pattern-matching-mix-deref-pattern.rs:121:9 + | +LL | let NonPinProject { x } = foo; + | ^^^^^^^^^^^^^^^^^^^ + | +note: type defined here + --> $DIR/pattern-matching-mix-deref-pattern.rs:28:1 + | +LL | struct NonPinProject { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add `#[pin_v2]` here + | +LL + #[pin_v2] +LL | struct NonPinProject { + | + +error: cannot project on type that is not `#[pin_v2]` + --> $DIR/pattern-matching-mix-deref-pattern.rs:125:9 + | +LL | let NonPinProject { x } = bar; + | ^^^^^^^^^^^^^^^^^^^ + | +note: type defined here + --> $DIR/pattern-matching-mix-deref-pattern.rs:28:1 + | +LL | struct NonPinProject { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add `#[pin_v2]` here + | +LL + #[pin_v2] +LL | struct NonPinProject { + | + +error: cannot project on type that is not `#[pin_v2]` + --> $DIR/pattern-matching-mix-deref-pattern.rs:131:9 + | +LL | NonPinProject { x } => {} + | ^^^^^^^^^^^^^^^^^^^ + | +note: type defined here + --> $DIR/pattern-matching-mix-deref-pattern.rs:28:1 + | +LL | struct NonPinProject { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add `#[pin_v2]` here + | +LL + #[pin_v2] +LL | struct NonPinProject { + | + +error: cannot project on type that is not `#[pin_v2]` + --> $DIR/pattern-matching-mix-deref-pattern.rs:139:9 + | +LL | NonPinProject { x } => {} + | ^^^^^^^^^^^^^^^^^^^ + | +note: type defined here + --> $DIR/pattern-matching-mix-deref-pattern.rs:28:1 + | +LL | struct NonPinProject { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add `#[pin_v2]` here + | +LL + #[pin_v2] +LL | struct NonPinProject { + | + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:37:9 + | +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Foo>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:45:9 + | +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Foo>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:59:9 + | +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Foo>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:67:9 + | +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Foo>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:81:9 + | +LL | Bar(x, y) => {} + | ^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Bar>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:89:9 + | +LL | Bar(x, y) => {} + | ^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Bar>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:103:9 + | +LL | Bar(x, y) => {} + | ^^^^^^^^^ matches on the result of dereferencing `Pin<&Bar>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Bar>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:111:9 + | +LL | Bar(x, y) => {} + | ^^^^^^^^^ matches on the result of dereferencing `Pin<&Bar>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Bar>` + +error: aborting due to 12 previous errors + diff --git a/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.deref_patterns.stderr b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.deref_patterns.stderr new file mode 100644 index 0000000000000..fa2e418591c1f --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.deref_patterns.stderr @@ -0,0 +1,92 @@ +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:37:9 + | +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Foo>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:45:9 + | +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Foo>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:59:9 + | +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Foo>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:67:9 + | +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Foo>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:81:9 + | +LL | Bar(x, y) => {} + | ^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Bar>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:89:9 + | +LL | Bar(x, y) => {} + | ^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Bar>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:103:9 + | +LL | Bar(x, y) => {} + | ^^^^^^^^^ matches on the result of dereferencing `Pin<&Bar>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Bar>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:111:9 + | +LL | Bar(x, y) => {} + | ^^^^^^^^^ matches on the result of dereferencing `Pin<&Bar>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Bar>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:131:9 + | +LL | NonPinProject { x } => {} + | ^^^^^^^^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut NonPinProject>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut NonPinProject>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:139:9 + | +LL | NonPinProject { x } => {} + | ^^^^^^^^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&NonPinProject>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&NonPinProject>` + +error: aborting due to 10 previous errors + diff --git a/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.normal.stderr b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.normal.stderr new file mode 100644 index 0000000000000..0e55a51702842 --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.normal.stderr @@ -0,0 +1,243 @@ +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:33:9 + | +LL | let Foo { x, y } = foo.as_mut(); + | ^^^^^^^^^^^^ ------------ this expression has type `Pin<&mut Foo>` + | | + | expected `Pin<&mut Foo>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&mut Foo>` + found struct `Foo<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Foo { x, y } = *foo.as_mut(); + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:37:9 + | +LL | match foo.as_mut() { + | ------------ this expression has type `Pin<&mut Foo>` +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ expected `Pin<&mut Foo>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&mut Foo>` + found struct `Foo<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *foo.as_mut() { + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:45:9 + | +LL | let _ = || match foo.as_mut() { + | ------------ this expression has type `Pin<&mut Foo>` +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ expected `Pin<&mut Foo>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&mut Foo>` + found struct `Foo<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let _ = || match *foo.as_mut() { + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:55:9 + | +LL | let Foo { x, y } = foo; + | ^^^^^^^^^^^^ --- this expression has type `Pin<&Foo>` + | | + | expected `Pin<&Foo>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&Foo>` + found struct `Foo<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Foo { x, y } = *foo; + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:59:9 + | +LL | match foo { + | --- this expression has type `Pin<&Foo>` +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ expected `Pin<&Foo>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&Foo>` + found struct `Foo<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *foo { + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:67:9 + | +LL | let _ = || match foo { + | --- this expression has type `Pin<&Foo>` +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ expected `Pin<&Foo>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&Foo>` + found struct `Foo<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let _ = || match *foo { + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:77:9 + | +LL | let Bar(x, y) = bar.as_mut(); + | ^^^^^^^^^ ------------ this expression has type `Pin<&mut Bar>` + | | + | expected `Pin<&mut Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&mut Bar>` + found struct `Bar<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Bar(x, y) = *bar.as_mut(); + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:81:9 + | +LL | match bar.as_mut() { + | ------------ this expression has type `Pin<&mut Bar>` +LL | Bar(x, y) => {} + | ^^^^^^^^^ expected `Pin<&mut Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&mut Bar>` + found struct `Bar<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *bar.as_mut() { + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:89:9 + | +LL | let _ = || match bar.as_mut() { + | ------------ this expression has type `Pin<&mut Bar>` +LL | Bar(x, y) => {} + | ^^^^^^^^^ expected `Pin<&mut Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&mut Bar>` + found struct `Bar<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let _ = || match *bar.as_mut() { + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:99:9 + | +LL | let Bar(x, y) = bar; + | ^^^^^^^^^ --- this expression has type `Pin<&Bar>` + | | + | expected `Pin<&Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&Bar>` + found struct `Bar<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Bar(x, y) = *bar; + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:103:9 + | +LL | match bar { + | --- this expression has type `Pin<&Bar>` +LL | Bar(x, y) => {} + | ^^^^^^^^^ expected `Pin<&Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&Bar>` + found struct `Bar<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *bar { + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:111:9 + | +LL | let _ = || match bar { + | --- this expression has type `Pin<&Bar>` +LL | Bar(x, y) => {} + | ^^^^^^^^^ expected `Pin<&Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&Bar>` + found struct `Bar<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let _ = || match *bar { + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:121:9 + | +LL | let NonPinProject { x } = foo; + | ^^^^^^^^^^^^^^^^^^^ --- this expression has type `Pin<&mut NonPinProject>` + | | + | expected `Pin<&mut NonPinProject>`, found `NonPinProject<_>` + | + = note: expected struct `Pin<&mut NonPinProject>` + found struct `NonPinProject<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let NonPinProject { x } = *foo; + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:125:9 + | +LL | let NonPinProject { x } = bar; + | ^^^^^^^^^^^^^^^^^^^ --- this expression has type `Pin<&NonPinProject>` + | | + | expected `Pin<&NonPinProject>`, found `NonPinProject<_>` + | + = note: expected struct `Pin<&NonPinProject>` + found struct `NonPinProject<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let NonPinProject { x } = *bar; + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:131:9 + | +LL | match foo { + | --- this expression has type `Pin<&mut NonPinProject>` +LL | NonPinProject { x } => {} + | ^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut NonPinProject>`, found `NonPinProject<_>` + | + = note: expected struct `Pin<&mut NonPinProject>` + found struct `NonPinProject<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *foo { + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching-mix-deref-pattern.rs:139:9 + | +LL | match bar { + | --- this expression has type `Pin<&NonPinProject>` +LL | NonPinProject { x } => {} + | ^^^^^^^^^^^^^^^^^^^ expected `Pin<&NonPinProject>`, found `NonPinProject<_>` + | + = note: expected struct `Pin<&NonPinProject>` + found struct `NonPinProject<_>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *bar { + | + + +error: aborting due to 16 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.pin_ergonomics.stderr b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.pin_ergonomics.stderr new file mode 100644 index 0000000000000..9bcb41299b7da --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.pin_ergonomics.stderr @@ -0,0 +1,142 @@ +error: cannot project on type that is not `#[pin_v2]` + --> $DIR/pattern-matching-mix-deref-pattern.rs:121:9 + | +LL | let NonPinProject { x } = foo; + | ^^^^^^^^^^^^^^^^^^^ + | +note: type defined here + --> $DIR/pattern-matching-mix-deref-pattern.rs:28:1 + | +LL | struct NonPinProject { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add `#[pin_v2]` here + | +LL + #[pin_v2] +LL | struct NonPinProject { + | + +error: cannot project on type that is not `#[pin_v2]` + --> $DIR/pattern-matching-mix-deref-pattern.rs:125:9 + | +LL | let NonPinProject { x } = bar; + | ^^^^^^^^^^^^^^^^^^^ + | +note: type defined here + --> $DIR/pattern-matching-mix-deref-pattern.rs:28:1 + | +LL | struct NonPinProject { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add `#[pin_v2]` here + | +LL + #[pin_v2] +LL | struct NonPinProject { + | + +error: cannot project on type that is not `#[pin_v2]` + --> $DIR/pattern-matching-mix-deref-pattern.rs:131:9 + | +LL | NonPinProject { x } => {} + | ^^^^^^^^^^^^^^^^^^^ + | +note: type defined here + --> $DIR/pattern-matching-mix-deref-pattern.rs:28:1 + | +LL | struct NonPinProject { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add `#[pin_v2]` here + | +LL + #[pin_v2] +LL | struct NonPinProject { + | + +error: cannot project on type that is not `#[pin_v2]` + --> $DIR/pattern-matching-mix-deref-pattern.rs:139:9 + | +LL | NonPinProject { x } => {} + | ^^^^^^^^^^^^^^^^^^^ + | +note: type defined here + --> $DIR/pattern-matching-mix-deref-pattern.rs:28:1 + | +LL | struct NonPinProject { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add `#[pin_v2]` here + | +LL + #[pin_v2] +LL | struct NonPinProject { + | + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:37:9 + | +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Foo>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:45:9 + | +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Foo>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:59:9 + | +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Foo>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:67:9 + | +LL | Foo { x, y } => {} + | ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Foo>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:81:9 + | +LL | Bar(x, y) => {} + | ^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Bar>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:89:9 + | +LL | Bar(x, y) => {} + | ^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&mut Bar>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:103:9 + | +LL | Bar(x, y) => {} + | ^^^^^^^^^ matches on the result of dereferencing `Pin<&Bar>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Bar>` + +error: mix of deref patterns and normal constructors + --> $DIR/pattern-matching-mix-deref-pattern.rs:111:9 + | +LL | Bar(x, y) => {} + | ^^^^^^^^^ matches on the result of dereferencing `Pin<&Bar>` +... +LL | Pin { .. } => {} + | ^^^^^^^^^^ matches directly on `Pin<&Bar>` + +error: aborting due to 12 previous errors + diff --git a/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.rs b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.rs new file mode 100644 index 0000000000000..2b2a4e61abfd1 --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.rs @@ -0,0 +1,148 @@ +//@ revisions: normal pin_ergonomics deref_patterns both +//@ edition:2024 +#![cfg_attr(any(pin_ergonomics, both), feature(pin_ergonomics))] +#![cfg_attr(any(deref_patterns, both), feature(deref_patterns))] +#![allow(incomplete_features)] + +// This test verifies that the `pin_ergonomics` feature works well +// together with the `deref_patterns` feature under the error: +// "mix of deref patterns and normal constructors". + +use std::pin::Pin; + +#[cfg_attr(any(pin_ergonomics, both), pin_v2)] +struct Foo { + x: T, + y: U, +} + +#[cfg_attr(any(pin_ergonomics, both), pin_v2)] +struct Bar(T, U); + +#[cfg_attr(any(pin_ergonomics, both), pin_v2)] +enum Baz { + Foo(T, U), + Bar { x: T, y: U }, +} + +struct NonPinProject { + x: T, +} + +fn foo_mut(mut foo: Pin<&mut Foo>) { + let Foo { x, y } = foo.as_mut(); + //[normal]~^ ERROR mismatched types + + match foo.as_mut() { + Foo { x, y } => {} + //[normal]~^ ERROR mismatched types + //[deref_patterns]~^^ ERROR mix of deref patterns and normal constructors + //[pin_ergonomics]~^^^ ERROR mix of deref patterns and normal constructors + //[both]~^^^^ ERROR mix of deref patterns and normal constructors + Pin { .. } => {} + } + let _ = || match foo.as_mut() { + Foo { x, y } => {} + //[normal]~^ ERROR mismatched types + //[deref_patterns]~^^ ERROR mix of deref patterns and normal constructors + //[pin_ergonomics]~^^^ ERROR mix of deref patterns and normal constructors + //[both]~^^^^ ERROR mix of deref patterns and normal constructors + Pin { .. } => {} + }; +} + +fn foo_const(foo: Pin<&Foo>) { + let Foo { x, y } = foo; + //[normal]~^ ERROR mismatched types + + match foo { + Foo { x, y } => {} + //[normal]~^ ERROR mismatched types + //[deref_patterns]~^^ ERROR mix of deref patterns and normal constructors + //[pin_ergonomics]~^^^ ERROR mix of deref patterns and normal constructors + //[both]~^^^^ ERROR mix of deref patterns and normal constructors + Pin { .. } => {} + } + let _ = || match foo { + Foo { x, y } => {} + //[normal]~^ ERROR mismatched types + //[deref_patterns]~^^ ERROR mix of deref patterns and normal constructors + //[pin_ergonomics]~^^^ ERROR mix of deref patterns and normal constructors + //[both]~^^^^ ERROR mix of deref patterns and normal constructors + Pin { .. } => {} + }; +} + +fn bar_mut(bar: Pin<&mut Bar>) { + let Bar(x, y) = bar.as_mut(); + //[normal]~^ ERROR mismatched types + + match bar.as_mut() { + Bar(x, y) => {} + //[normal]~^ ERROR mismatched types + //[deref_patterns]~^^ ERROR mix of deref patterns and normal constructors + //[pin_ergonomics]~^^^ ERROR mix of deref patterns and normal constructors + //[both]~^^^^ ERROR mix of deref patterns and normal constructors + Pin { .. } => {} + } + let _ = || match bar.as_mut() { + Bar(x, y) => {} + //[normal]~^ ERROR mismatched types + //[deref_patterns]~^^ ERROR mix of deref patterns and normal constructors + //[pin_ergonomics]~^^^ ERROR mix of deref patterns and normal constructors + //[both]~^^^^ ERROR mix of deref patterns and normal constructors + Pin { .. } => {} + }; +} + +fn bar_const(bar: Pin<&Bar>) { + let Bar(x, y) = bar; + //[normal]~^ ERROR mismatched types + + match bar { + Bar(x, y) => {} + //[normal]~^ ERROR mismatched types + //[deref_patterns]~^^ ERROR mix of deref patterns and normal constructors + //[pin_ergonomics]~^^^ ERROR mix of deref patterns and normal constructors + //[both]~^^^^ ERROR mix of deref patterns and normal constructors + Pin { .. } => {} + } + let _ = || match bar { + Bar(x, y) => {} + //[normal]~^ ERROR mismatched types + //[deref_patterns]~^^ ERROR mix of deref patterns and normal constructors + //[pin_ergonomics]~^^^ ERROR mix of deref patterns and normal constructors + //[both]~^^^^ ERROR mix of deref patterns and normal constructors + Pin { .. } => {} + }; +} + +fn non_pin_project(foo: Pin<&mut NonPinProject>, bar: Pin<&NonPinProject>) { + let NonPinProject { x } = foo; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR cannot project on type that is not `#[pin_v2]` + //[both]~^^^ ERROR cannot project on type that is not `#[pin_v2]` + let NonPinProject { x } = bar; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR cannot project on type that is not `#[pin_v2]` + //[both]~^^^ ERROR cannot project on type that is not `#[pin_v2]` + + match foo { + NonPinProject { x } => {} + //[normal]~^ ERROR mismatched types + //[deref_patterns]~^^ ERROR mix of deref patterns and normal constructors + //[pin_ergonomics]~^^^ ERROR cannot project on type that is not `#[pin_v2]` + //[both]~^^^^ ERROR cannot project on type that is not `#[pin_v2]` + Pin { .. } => {} + } + match bar { + NonPinProject { x } => {} + //[normal]~^ ERROR mismatched types + //[deref_patterns]~^^ ERROR mix of deref patterns and normal constructors + //[pin_ergonomics]~^^^ ERROR cannot project on type that is not `#[pin_v2]` + //[both]~^^^^ ERROR cannot project on type that is not `#[pin_v2]` + Pin { .. } => {} + } +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/pattern-matching.normal.stderr b/tests/ui/pin-ergonomics/pattern-matching.normal.stderr new file mode 100644 index 0000000000000..8ec481fba9e0d --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching.normal.stderr @@ -0,0 +1,242 @@ +error[E0658]: the `#[pin_v2]` attribute is an experimental feature + --> $DIR/pattern-matching.rs:12:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = 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]: the `#[pin_v2]` attribute is an experimental feature + --> $DIR/pattern-matching.rs:18:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = 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[E0308]: mismatched types + --> $DIR/pattern-matching.rs:33:9 + | +LL | let Foo { x, y } = foo_mut; + | ^^^^^^^^^^^^ ------- this expression has type `Pin<&mut Foo>` + | | + | expected `Pin<&mut Foo>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&mut Foo>` + found struct `Foo<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Foo { x, y } = *foo_mut; + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:38:9 + | +LL | let Foo { x, y } = foo_const; + | ^^^^^^^^^^^^ --------- this expression has type `Pin<&Foo>` + | | + | expected `Pin<&Foo>`, found `Foo<_, _>` + | + = note: expected struct `Pin<&Foo>` + found struct `Foo<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let Foo { x, y } = *foo_const; + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:46:9 + | +LL | match bar_mut { + | ------- this expression has type `Pin<&mut Bar>` +LL | Bar::Foo(x, y) => { + | ^^^^^^^^^^^^^^ expected `Pin<&mut Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&mut Bar>` + found enum `Bar<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *bar_mut { + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:51:18 + | +LL | _ if let Bar::Bar { x, y } = bar_mut => { + | ^^^^^^^^^^^^^^^^^ ------- this expression has type `Pin<&mut Bar>` + | | + | expected `Pin<&mut Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&mut Bar>` + found enum `Bar<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | _ if let Bar::Bar { x, y } = *bar_mut => { + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:59:9 + | +LL | match bar_const { + | --------- this expression has type `Pin<&Bar>` +LL | Bar::Bar { x, y } => { + | ^^^^^^^^^^^^^^^^^ expected `Pin<&Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&Bar>` + found enum `Bar<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | match *bar_const { + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:64:18 + | +LL | _ if let Bar::Foo(x, y) = bar_const => { + | ^^^^^^^^^^^^^^ --------- this expression has type `Pin<&Bar>` + | | + | expected `Pin<&Bar>`, found `Bar<_, _>` + | + = note: expected struct `Pin<&Bar>` + found enum `Bar<_, _>` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | _ if let Bar::Foo(x, y) = *bar_const => { + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:74:9 + | +LL | let (Foo { x, y },) = foo_mut; + | ^^^^^^^^^^^^^^^ ------- this expression has type `Pin<&mut (Foo,)>` + | | + | expected `Pin<&mut (Foo,)>`, found `(_,)` + | + = note: expected struct `Pin<&mut (Foo,)>` + found tuple `(_,)` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let (Foo { x, y },) = *foo_mut; + | + + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:78:9 + | +LL | let (Foo { x, y },) = foo_const; + | ^^^^^^^^^^^^^^^ --------- this expression has type `Pin<&(Foo,)>` + | | + | expected `Pin<&(Foo,)>`, found `(_,)` + | + = note: expected struct `Pin<&(Foo,)>` + found tuple `(_,)` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | let (Foo { x, y },) = *foo_const; + | + + +error[E0529]: expected an array or slice, found `Pin<&mut [Foo; 1]>` + --> $DIR/pattern-matching.rs:85:9 + | +LL | let [Foo { x, y }] = foo_mut; + | ^^^^^^^^^^^^^^ pattern cannot match with input type `Pin<&mut [Foo; 1]>` + +error[E0529]: expected an array or slice, found `Pin<&[Foo; 1]>` + --> $DIR/pattern-matching.rs:89:9 + | +LL | let [Foo { x, y }] = foo_const; + | ^^^^^^^^^^^^^^ pattern cannot match with input type `Pin<&[Foo; 1]>` + +error[E0529]: expected an array or slice, found `Pin<&mut [Foo]>` + --> $DIR/pattern-matching.rs:96:12 + | +LL | if let [Foo { x, y }] = foo_mut { + | ^^^^^^^^^^^^^^ pattern cannot match with input type `Pin<&mut [Foo]>` + +error[E0529]: expected an array or slice, found `Pin<&[Foo]>` + --> $DIR/pattern-matching.rs:101:12 + | +LL | if let [Foo { x, y }] = foo_const { + | ^^^^^^^^^^^^^^ pattern cannot match with input type `Pin<&[Foo]>` + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:109:5 + | +LL | (&mut x,): Pin<&'a mut (&'a mut Foo,)>, + | ^^^^^^^^^ --------------------------------- expected due to this + | | + | expected `Pin<&mut (&mut Foo,)>`, found `(_,)` + | + = note: expected struct `Pin<&'a mut (&'a mut Foo,)>` + found tuple `(_,)` + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:115:5 + | +LL | (&mut x,): Pin<&'a mut &'a mut (Foo,)>, + | ^^^^^^^^^ --------------------------------- expected due to this + | | + | expected `Pin<&mut &mut (Foo,)>`, found `(_,)` + | + = note: expected struct `Pin<&'a mut &'a mut (Foo,)>` + found tuple `(_,)` + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:121:5 + | +LL | &mut (x,): Pin<&'a mut (&'a mut Foo,)>, + | ^^^^^^^^^ --------------------------------- expected due to this + | | + | expected `Pin<&mut (&mut Foo,)>`, found `&mut _` + | + = note: expected struct `Pin<&'a mut (&'a mut Foo,)>` + found mutable reference `&mut _` +help: you might have meant to use field `pointer` whose type is `&'a mut (&'a mut Foo,)` + | +LL | &mut (x,): Pin<&'a mut (&'a mut Foo,)>.pointer, + | ++++++++ + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:127:5 + | +LL | &mut (x,): Pin<&'a mut &'a mut (Foo,)>, + | ^^^^^^^^^ --------------------------------- expected due to this + | | + | expected `Pin<&mut &mut (Foo,)>`, found `&mut _` + | + = note: expected struct `Pin<&'a mut &'a mut (Foo,)>` + found mutable reference `&mut _` +help: you might have meant to use field `pointer` whose type is `&'a mut &'a mut (Foo,)` + | +LL | &mut (x,): Pin<&'a mut &'a mut (Foo,)>.pointer, + | ++++++++ + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:133:5 + | +LL | (x,): Pin<&'a mut (&'a mut Foo,)>, + | ^^^^ --------------------------------- expected due to this + | | + | expected `Pin<&mut (&mut Foo,)>`, found `(_,)` + | + = note: expected struct `Pin<&'a mut (&'a mut Foo,)>` + found tuple `(_,)` + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:139:5 + | +LL | (x,): Pin<&'a mut &'a mut (Foo,)>, + | ^^^^ --------------------------------- expected due to this + | | + | expected `Pin<&mut &mut (Foo,)>`, found `(_,)` + | + = note: expected struct `Pin<&'a mut &'a mut (Foo,)>` + found tuple `(_,)` + +error: aborting due to 20 previous errors + +Some errors have detailed explanations: E0308, E0529, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pin-ergonomics/pattern-matching.pin_ergonomics.stderr b/tests/ui/pin-ergonomics/pattern-matching.pin_ergonomics.stderr new file mode 100644 index 0000000000000..8cb032b73d859 --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching.pin_ergonomics.stderr @@ -0,0 +1,54 @@ +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:115:6 + | +LL | (&mut x,): Pin<&'a mut &'a mut (Foo,)>, + | ^^^^^^ --------------------------------- expected due to this + | | + | expected `Foo`, found `&mut _` + | + = note: expected struct `Foo` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/pattern-matching.rs:115:6 + | +LL | (&mut x,): Pin<&'a mut &'a mut (Foo,)>, + | ^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - (&mut x,): Pin<&'a mut &'a mut (Foo,)>, +LL + (x,): Pin<&'a mut &'a mut (Foo,)>, + | + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:121:5 + | +LL | &mut (x,): Pin<&'a mut (&'a mut Foo,)>, + | ^^^^^^^^^ --------------------------------- expected due to this + | | + | expected `Pin<&mut (&mut Foo,)>`, found `&mut _` + | + = note: expected struct `Pin<&'a mut (&'a mut Foo,)>` + found mutable reference `&mut _` +help: you might have meant to use field `pointer` whose type is `&'a mut (&'a mut Foo,)` + | +LL | &mut (x,): Pin<&'a mut (&'a mut Foo,)>.pointer, + | ++++++++ + +error[E0308]: mismatched types + --> $DIR/pattern-matching.rs:127:5 + | +LL | &mut (x,): Pin<&'a mut &'a mut (Foo,)>, + | ^^^^^^^^^ --------------------------------- expected due to this + | | + | expected `Pin<&mut &mut (Foo,)>`, found `&mut _` + | + = note: expected struct `Pin<&'a mut &'a mut (Foo,)>` + found mutable reference `&mut _` +help: you might have meant to use field `pointer` whose type is `&'a mut &'a mut (Foo,)` + | +LL | &mut (x,): Pin<&'a mut &'a mut (Foo,)>.pointer, + | ++++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pin-ergonomics/pattern-matching.rs b/tests/ui/pin-ergonomics/pattern-matching.rs new file mode 100644 index 0000000000000..96a4705bf9b3b --- /dev/null +++ b/tests/ui/pin-ergonomics/pattern-matching.rs @@ -0,0 +1,144 @@ +//@ revisions: pin_ergonomics normal +//@ edition:2024 +#![cfg_attr(pin_ergonomics, feature(pin_ergonomics))] +#![feature(if_let_guard, negative_impls)] +#![allow(incomplete_features)] + +use std::pin::Pin; + +// This test verifies that a `&pin mut T` can be projected to a pinned +// reference field `&pin mut T.U` when `T` is marked with `#[pin_v2]`. + +#[pin_v2] //[normal]~ ERROR the `#[pin_v2]` attribute is an experimental feature +struct Foo { + x: T, + y: U, +} + +#[pin_v2] //[normal]~ ERROR the `#[pin_v2]` attribute is an experimental feature +enum Bar { + Foo(T, U), + Bar { x: T, y: U }, +} + +trait IsPinMut {} +trait IsPinConst {} +impl IsPinMut for Pin<&mut T> {} +impl IsPinConst for Pin<&T> {} + +fn assert_pin_mut(_: T) {} +fn assert_pin_const(_: T) {} + +fn foo(foo_mut: Pin<&mut Foo>, foo_const: Pin<&Foo>) { + let Foo { x, y } = foo_mut; + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_pin_mut(y); + + let Foo { x, y } = foo_const; + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_pin_const(y); +} + +fn bar(bar_mut: Pin<&mut Bar>, bar_const: Pin<&Bar>) { + match bar_mut { + Bar::Foo(x, y) => { + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_pin_mut(y); + } + _ if let Bar::Bar { x, y } = bar_mut => { + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_pin_mut(y); + } + _ => {} + } + match bar_const { + Bar::Bar { x, y } => { + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_pin_const(y); + } + _ if let Bar::Foo(x, y) = bar_const => { + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_pin_const(y); + } + _ => {} + } +} + +fn pin_mut_tuple(foo_mut: Pin<&mut (Foo,)>, foo_const: Pin<&(Foo,)>) { + let (Foo { x, y },) = foo_mut; + //[normal]~^ ERROR mismatched types + assert_pin_mut(x); + assert_pin_mut(y); + let (Foo { x, y },) = foo_const; + //[normal]~^ ERROR mismatched types + assert_pin_const(x); + assert_pin_const(y); +} + +fn pin_mut_array(foo_mut: Pin<&mut [Foo; 1]>, foo_const: Pin<&[Foo; 1]>) { + let [Foo { x, y }] = foo_mut; + //[normal]~^ ERROR expected an array or slice, found `Pin<&mut [Foo; 1]>` + assert_pin_mut(x); + assert_pin_mut(y); + let [Foo { x, y }] = foo_const; + //[normal]~^ ERROR expected an array or slice, found `Pin<&[Foo; 1]>` + assert_pin_const(x); + assert_pin_const(y); +} + +fn pin_mut_slice(foo_mut: Pin<&mut [Foo]>, foo_const: Pin<&[Foo]>) { + if let [Foo { x, y }] = foo_mut { + //[normal]~^ ERROR expected an array or slice, found `Pin<&mut [Foo]>` + assert_pin_mut(x); + assert_pin_mut(y); + } + if let [Foo { x, y }] = foo_const { + //[normal]~^ ERROR expected an array or slice, found `Pin<&[Foo]>` + assert_pin_const(x); + assert_pin_const(y); + } +} + +fn tuple_ref_mut_pat_and_pin_mut_of_tuple_mut_ty<'a, T, U>( + (&mut x,): Pin<&'a mut (&'a mut Foo,)>, //[normal]~ ERROR mismatched type +) -> Pin<&'a mut Foo> { + x +} + +fn tuple_ref_mut_pat_and_pin_mut_of_mut_tuple_ty<'a, T, U>( + (&mut x,): Pin<&'a mut &'a mut (Foo,)>, //~ ERROR mismatched type +) -> Pin<&'a mut Foo> { + x +} + +fn ref_mut_tuple_pat_and_pin_mut_of_tuple_mut_ty<'a, T, U>( + &mut (x,): Pin<&'a mut (&'a mut Foo,)>, //~ ERROR mismatched type +) -> Pin<&'a mut Foo> { + x +} + +fn ref_mut_tuple_pat_and_pin_mut_of_mut_tuple_ty<'a, T, U>( + &mut (x,): Pin<&'a mut &'a mut (Foo,)>, //~ ERROR mismatched type +) -> Pin<&'a mut Foo> { + x +} + +fn tuple_pat_and_pin_mut_of_tuple_mut_ty<'a, T, U>( + (x,): Pin<&'a mut (&'a mut Foo,)>, //[normal]~ ERROR mismatched type +) -> Pin<&'a mut &'a mut Foo> { + x // ok +} + +fn tuple_pat_and_pin_mut_of_mut_tuple_ty<'a, T, U>( + (x,): Pin<&'a mut &'a mut (Foo,)>, //[normal]~ ERROR mismatched type +) -> Pin<&'a mut Foo> { + x +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/pin_v2-attr.rs b/tests/ui/pin-ergonomics/pin_v2-attr.rs new file mode 100644 index 0000000000000..af958952d0840 --- /dev/null +++ b/tests/ui/pin-ergonomics/pin_v2-attr.rs @@ -0,0 +1,144 @@ +#![feature( + pin_ergonomics, + where_clause_attrs, + trait_alias, + extern_types, + associated_type_defaults, + fn_delegation, +)] +#![allow(incomplete_features)] +#![pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on crates + +// allowed + +#[pin_v2] +struct Struct {} + +#[pin_v2] +enum Enum {} + +#[pin_v2] +union Union { + field: (), +} + +// disallowed + +enum Foo<#[pin_v2] T, #[pin_v2] U = ()> { + //~^ ERROR `#[pin_v2]` attribute cannot be used on function params + //~| ERROR `#[pin_v2]` attribute cannot be used on function params + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on enum variants + UnitVariant, + TupleVariant(#[pin_v2] T), //~ ERROR `#[pin_v2]` attribute cannot be used on struct fields + StructVariant { + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on struct fields + field: U, + }, +} + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on traits +trait Trait { + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on associated consts + const ASSOC_CONST: () = (); + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on associated types + type AssocType = (); + + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on required trait methods + fn method(); + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on provided trait methods + fn method_with_body() {} +} + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on trait aliases +trait TraitAlias = Trait; + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on inherent impl blocks +impl Struct { + // FIXME: delegation macros are not tested yet (how to?) + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on delegations + reuse ::type_id; + + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on inherent methods + fn method() {} +} + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on trait impl blocks +impl Trait for Enum { + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on trait methods in impl blocks + fn method() {} +} + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on extern crates +extern crate alloc; + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on use statements +use std::pin::Pin; + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on statics +static STATIC: () = (); + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on constants +const CONST: () = (); + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on functions +fn f(#[pin_v2] param: Foo) +//~^ ERROR `#[pin_v2]` attribute cannot be used on function params +//~| ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters +where + #[pin_v2] + //~^ ERROR `#[pin_v2]` attribute cannot be used on where predicates + T:, +{ + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on closures + || (); + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on expressions + [(), (), ()]; + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on statements + let _: Foo<(), ()> = Foo::StructVariant { + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on struct fields + field: (), + }; + match param { + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on match arms + Foo::UnitVariant => {} + Foo::TupleVariant(..) => {} + Foo::StructVariant { + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on pattern fields + field, + } => {} + } +} + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on modules +mod m {} + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on foreign modules +extern "C" { + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on foreign types + type ForeignTy; + + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on foreign statics + static EXTERN_STATIC: (); + + #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on foreign functions + fn extern_fn(); +} + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on type alias +type Type = (); + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on macro defs +macro_rules! macro_def { + () => {}; +} + +#[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on macro calls +macro_def!(); + +std::arch::global_asm! { + "{}", + #[pin_v2] //~ ERROR this attribute is not supported on assembly + const 0 +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/pin_v2-attr.stderr b/tests/ui/pin-ergonomics/pin_v2-attr.stderr new file mode 100644 index 0000000000000..fb3e50a23fe74 --- /dev/null +++ b/tests/ui/pin-ergonomics/pin_v2-attr.stderr @@ -0,0 +1,318 @@ +error: `#[pin_v2]` attribute cannot be used on macro calls + --> $DIR/pin_v2-attr.rs:135:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: this attribute is not supported on assembly + --> $DIR/pin_v2-attr.rs:140:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/pin_v2-attr.rs:84:12 + | +LL | fn f(#[pin_v2] param: Foo) + | ^^^^^^^^^ + +error: `#[pin_v2]` attribute cannot be used on crates + --> $DIR/pin_v2-attr.rs:10:1 + | +LL | #![pin_v2] + | ^^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on function params + --> $DIR/pin_v2-attr.rs:27:10 + | +LL | enum Foo<#[pin_v2] T, #[pin_v2] U = ()> { + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on function params + --> $DIR/pin_v2-attr.rs:27:23 + | +LL | enum Foo<#[pin_v2] T, #[pin_v2] U = ()> { + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on enum variants + --> $DIR/pin_v2-attr.rs:30:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on struct fields + --> $DIR/pin_v2-attr.rs:32:18 + | +LL | TupleVariant(#[pin_v2] T), + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on struct fields + --> $DIR/pin_v2-attr.rs:34:9 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on traits + --> $DIR/pin_v2-attr.rs:39:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on associated consts + --> $DIR/pin_v2-attr.rs:41:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on associated types + --> $DIR/pin_v2-attr.rs:43:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on required trait methods + --> $DIR/pin_v2-attr.rs:46:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on provided trait methods + --> $DIR/pin_v2-attr.rs:48:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on trait aliases + --> $DIR/pin_v2-attr.rs:52:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on inherent impl blocks + --> $DIR/pin_v2-attr.rs:55:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on delegations + --> $DIR/pin_v2-attr.rs:58:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on inherent methods + --> $DIR/pin_v2-attr.rs:61:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on trait impl blocks + --> $DIR/pin_v2-attr.rs:65:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on trait methods in impl blocks + --> $DIR/pin_v2-attr.rs:67:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on extern crates + --> $DIR/pin_v2-attr.rs:71:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on use statements + --> $DIR/pin_v2-attr.rs:74:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on statics + --> $DIR/pin_v2-attr.rs:77:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on constants + --> $DIR/pin_v2-attr.rs:80:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on functions + --> $DIR/pin_v2-attr.rs:83:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on function params + --> $DIR/pin_v2-attr.rs:84:12 + | +LL | fn f(#[pin_v2] param: Foo) + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on closures + --> $DIR/pin_v2-attr.rs:92:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on expressions + --> $DIR/pin_v2-attr.rs:94:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on struct fields + --> $DIR/pin_v2-attr.rs:98:9 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on statements + --> $DIR/pin_v2-attr.rs:96:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on match arms + --> $DIR/pin_v2-attr.rs:102:9 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on pattern fields + --> $DIR/pin_v2-attr.rs:106:13 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on where predicates + --> $DIR/pin_v2-attr.rs:88:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on modules + --> $DIR/pin_v2-attr.rs:112:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on foreign modules + --> $DIR/pin_v2-attr.rs:115:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on foreign types + --> $DIR/pin_v2-attr.rs:117:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on foreign statics + --> $DIR/pin_v2-attr.rs:120:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on foreign functions + --> $DIR/pin_v2-attr.rs:123:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on type aliases + --> $DIR/pin_v2-attr.rs:127:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: `#[pin_v2]` attribute cannot be used on macro defs + --> $DIR/pin_v2-attr.rs:130:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + | + = help: `#[pin_v2]` can be applied to data types and unions + +error: aborting due to 40 previous errors +