Rollup merge of #139751 - frank-king:feature/pin-project, r=Nadrieril,traviscross

Implement pin-project in pattern matching for `&pin mut|const T`

This PR implements part of rust-lang/rust#130494. It supports pin-project in pattern matching for `&pin mut|const T`.

~Pin-projection by field access (i.e. `&pin mut|const place.field`) is not fully supported yet since pinned-borrow is not ready (rust-lang/rust#135731).~

CC ``````@traviscross``````
This commit is contained in:
Matthias Krüger 2025-11-01 08:25:44 +01:00 committed by GitHub
commit dc9060688a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
60 changed files with 2437 additions and 118 deletions

View file

@ -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 ",
}
}
}

View file

@ -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<Symbol, usize>,
rustc_span::ErrorGuaranteed,

View file

@ -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)
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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<S: Stage> NoArgsAttributeParser<S> for PinV2Parser {
const PATH: &[Symbol] = &[sym::pin_v2];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Enum),
Allow(Target::Struct),
Allow(Target::Union),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::PinV2;
}

View file

@ -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<WithoutArgs<NonExhaustiveParser>>,
Single<WithoutArgs<ParenSugarParser>>,
Single<WithoutArgs<PassByValueParser>>,
Single<WithoutArgs<PinV2Parser>>,
Single<WithoutArgs<PointeeParser>>,
Single<WithoutArgs<ProcMacroAttributeParser>>,
Single<WithoutArgs<ProcMacroParser>>,

View file

@ -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;

View file

@ -2582,6 +2582,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(..)

View file

@ -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:
// ==========================================================================

View file

@ -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),

View file

@ -77,6 +77,7 @@ impl AttributeKind {
PassByValue(..) => Yes,
Path(..) => No,
PatternComplexityLimit { .. } => No,
PinV2(..) => Yes,
Pointee(..) => No,
ProcMacro(..) => No,
ProcMacroAttribute(..) => No,

View file

@ -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;

View file

@ -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)),

View file

@ -1925,10 +1925,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);

View file

@ -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}

View file

@ -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<Span>,
#[suggestion(code = "#[pin_v2]\n", applicability = "machine-applicable")]
pub sugg_span: Option<Span>,
}

View file

@ -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` ...

View file

@ -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<Box<T>>` 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<Span> = 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<Target = T>`; 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<Result<ResolvedPat<'tcx>, 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<Target = T>`; 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"

View file

@ -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)
{

View file

@ -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<T>`.
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,
}

View file

@ -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<T>`.
#[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()

View file

@ -1349,6 +1349,23 @@ impl<'tcx> Ty<'tcx> {
}
}
pub fn pinned_ty(self) -> Option<Ty<'tcx>> {
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<T>`.
pub fn expect_boxed_ty(self) -> Ty<'tcx> {
self.boxed_ty()

View file

@ -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 })
}
}

View file

@ -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(

View file

@ -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

View file

@ -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!(

View file

@ -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`.

View file

@ -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.

View file

@ -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),
}
};

View file

@ -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`).

View file

@ -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)

View file

@ -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);

View file

@ -1668,6 +1668,7 @@ symbols! {
pin,
pin_ergonomics,
pin_macro,
pin_v2,
platform_intrinsics,
plugin,
plugin_registrar,

View file

@ -94,7 +94,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<Hir
// We'll just ignore mut and ref mut for simplicity sake right now
if let hir::PatKind::Binding(hir::BindingMode(by_ref, hir::Mutability::Not), value_hir_id, ident, sub_pat) =
pat.kind
&& by_ref != hir::ByRef::Yes(hir::Mutability::Mut)
&& !matches!(by_ref, hir::ByRef::Yes(_, hir::Mutability::Mut))
{
// This block catches bindings with sub patterns. It would be hard to build a correct suggestion
// for them and it's likely that the user knows what they are doing in such a case.

View file

@ -63,7 +63,7 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
.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

View file

@ -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`
(

View file

@ -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

View file

@ -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,

View file

@ -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!(

View file

@ -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)

View file

@ -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);

View file

@ -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;
},

View file

@ -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

View file

@ -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);

View file

@ -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
}

View file

@ -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 <https://github.com/rust-lang/rust/issues/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`.

View file

@ -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`.

View file

@ -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<T, U> {
x: T,
y: U,
}
#[cfg_attr(pin_ergonomics, pin_v2)]
struct Bar<T, U>(T, U);
#[cfg_attr(pin_ergonomics, pin_v2)]
enum Baz<T, U> {
Foo(T, U),
Bar { x: T, y: U },
}
trait IsPinMut {}
trait IsPinConst {}
impl<T: ?Sized> IsPinMut for Pin<&mut T> {}
impl<T: ?Sized> IsPinConst for Pin<&T> {}
fn assert_pin_mut<T: IsPinMut>(_: T) {}
fn assert_pin_const<T: IsPinConst>(_: T) {}
fn foo_mut<T: Unpin, U: Unpin>(mut foo: Pin<&mut Foo<T, U>>) {
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<T: Unpin, U: Unpin>(foo: Pin<&Foo<T, U>>) {
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<T: Unpin, U: Unpin>(mut bar: Pin<&mut Bar<T, U>>) {
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<T: Unpin, U: Unpin>(bar: Pin<&Bar<T, U>>) {
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() {}

View file

@ -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<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct NonPinProject<T> {
|
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<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct NonPinProject<T> {
|
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<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct NonPinProject<T> {
|
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<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct NonPinProject<T> {
|
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
error: aborting due to 12 previous errors

View file

@ -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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
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<T>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut NonPinProject<T>>`
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<U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&NonPinProject<U>>`
error: aborting due to 10 previous errors

View file

@ -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<T, U>>`
| |
| expected `Pin<&mut Foo<T, U>>`, found `Foo<_, _>`
|
= note: expected struct `Pin<&mut Foo<T, U>>`
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<T, U>>`
LL | Foo { x, y } => {}
| ^^^^^^^^^^^^ expected `Pin<&mut Foo<T, U>>`, found `Foo<_, _>`
|
= note: expected struct `Pin<&mut Foo<T, U>>`
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<T, U>>`
LL | Foo { x, y } => {}
| ^^^^^^^^^^^^ expected `Pin<&mut Foo<T, U>>`, found `Foo<_, _>`
|
= note: expected struct `Pin<&mut Foo<T, U>>`
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<T, U>>`
| |
| expected `Pin<&Foo<T, U>>`, found `Foo<_, _>`
|
= note: expected struct `Pin<&Foo<T, U>>`
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<T, U>>`
LL | Foo { x, y } => {}
| ^^^^^^^^^^^^ expected `Pin<&Foo<T, U>>`, found `Foo<_, _>`
|
= note: expected struct `Pin<&Foo<T, U>>`
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<T, U>>`
LL | Foo { x, y } => {}
| ^^^^^^^^^^^^ expected `Pin<&Foo<T, U>>`, found `Foo<_, _>`
|
= note: expected struct `Pin<&Foo<T, U>>`
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<T, U>>`
| |
| expected `Pin<&mut Bar<T, U>>`, found `Bar<_, _>`
|
= note: expected struct `Pin<&mut Bar<T, U>>`
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<T, U>>`
LL | Bar(x, y) => {}
| ^^^^^^^^^ expected `Pin<&mut Bar<T, U>>`, found `Bar<_, _>`
|
= note: expected struct `Pin<&mut Bar<T, U>>`
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<T, U>>`
LL | Bar(x, y) => {}
| ^^^^^^^^^ expected `Pin<&mut Bar<T, U>>`, found `Bar<_, _>`
|
= note: expected struct `Pin<&mut Bar<T, U>>`
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<T, U>>`
| |
| expected `Pin<&Bar<T, U>>`, found `Bar<_, _>`
|
= note: expected struct `Pin<&Bar<T, U>>`
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<T, U>>`
LL | Bar(x, y) => {}
| ^^^^^^^^^ expected `Pin<&Bar<T, U>>`, found `Bar<_, _>`
|
= note: expected struct `Pin<&Bar<T, U>>`
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<T, U>>`
LL | Bar(x, y) => {}
| ^^^^^^^^^ expected `Pin<&Bar<T, U>>`, found `Bar<_, _>`
|
= note: expected struct `Pin<&Bar<T, U>>`
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<T>>`
| |
| expected `Pin<&mut NonPinProject<T>>`, found `NonPinProject<_>`
|
= note: expected struct `Pin<&mut NonPinProject<T>>`
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<U>>`
| |
| expected `Pin<&NonPinProject<U>>`, found `NonPinProject<_>`
|
= note: expected struct `Pin<&NonPinProject<U>>`
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<T>>`
LL | NonPinProject { x } => {}
| ^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut NonPinProject<T>>`, found `NonPinProject<_>`
|
= note: expected struct `Pin<&mut NonPinProject<T>>`
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<U>>`
LL | NonPinProject { x } => {}
| ^^^^^^^^^^^^^^^^^^^ expected `Pin<&NonPinProject<U>>`, found `NonPinProject<_>`
|
= note: expected struct `Pin<&NonPinProject<U>>`
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`.

View file

@ -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<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct NonPinProject<T> {
|
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<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct NonPinProject<T> {
|
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<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct NonPinProject<T> {
|
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<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct NonPinProject<T> {
|
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
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<T, U>>`
...
LL | Pin { .. } => {}
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
error: aborting due to 12 previous errors

View file

@ -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<T, U> {
x: T,
y: U,
}
#[cfg_attr(any(pin_ergonomics, both), pin_v2)]
struct Bar<T, U>(T, U);
#[cfg_attr(any(pin_ergonomics, both), pin_v2)]
enum Baz<T, U> {
Foo(T, U),
Bar { x: T, y: U },
}
struct NonPinProject<T> {
x: T,
}
fn foo_mut<T: Unpin, U: Unpin>(mut foo: Pin<&mut Foo<T, U>>) {
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<T: Unpin, U: Unpin>(foo: Pin<&Foo<T, U>>) {
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<T: Unpin, U: Unpin>(bar: Pin<&mut Bar<T, U>>) {
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<T: Unpin, U: Unpin>(bar: Pin<&Bar<T, U>>) {
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<T, U: Unpin>(foo: Pin<&mut NonPinProject<T>>, bar: Pin<&NonPinProject<U>>) {
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() {}

View file

@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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<T, U>>`
| |
| expected `Pin<&mut Foo<T, U>>`, found `Foo<_, _>`
|
= note: expected struct `Pin<&mut Foo<T, U>>`
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<T, U>>`
| |
| expected `Pin<&Foo<T, U>>`, found `Foo<_, _>`
|
= note: expected struct `Pin<&Foo<T, U>>`
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<T, U>>`
LL | Bar::Foo(x, y) => {
| ^^^^^^^^^^^^^^ expected `Pin<&mut Bar<T, U>>`, found `Bar<_, _>`
|
= note: expected struct `Pin<&mut Bar<T, U>>`
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<T, U>>`
| |
| expected `Pin<&mut Bar<T, U>>`, found `Bar<_, _>`
|
= note: expected struct `Pin<&mut Bar<T, U>>`
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<T, U>>`
LL | Bar::Bar { x, y } => {
| ^^^^^^^^^^^^^^^^^ expected `Pin<&Bar<T, U>>`, found `Bar<_, _>`
|
= note: expected struct `Pin<&Bar<T, U>>`
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<T, U>>`
| |
| expected `Pin<&Bar<T, U>>`, found `Bar<_, _>`
|
= note: expected struct `Pin<&Bar<T, U>>`
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<T, U>,)>`
| |
| expected `Pin<&mut (Foo<T, U>,)>`, found `(_,)`
|
= note: expected struct `Pin<&mut (Foo<T, U>,)>`
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<T, U>,)>`
| |
| expected `Pin<&(Foo<T, U>,)>`, found `(_,)`
|
= note: expected struct `Pin<&(Foo<T, U>,)>`
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<T, U>; 1]>`
--> $DIR/pattern-matching.rs:85:9
|
LL | let [Foo { x, y }] = foo_mut;
| ^^^^^^^^^^^^^^ pattern cannot match with input type `Pin<&mut [Foo<T, U>; 1]>`
error[E0529]: expected an array or slice, found `Pin<&[Foo<T, U>; 1]>`
--> $DIR/pattern-matching.rs:89:9
|
LL | let [Foo { x, y }] = foo_const;
| ^^^^^^^^^^^^^^ pattern cannot match with input type `Pin<&[Foo<T, U>; 1]>`
error[E0529]: expected an array or slice, found `Pin<&mut [Foo<T, U>]>`
--> $DIR/pattern-matching.rs:96:12
|
LL | if let [Foo { x, y }] = foo_mut {
| ^^^^^^^^^^^^^^ pattern cannot match with input type `Pin<&mut [Foo<T, U>]>`
error[E0529]: expected an array or slice, found `Pin<&[Foo<T, U>]>`
--> $DIR/pattern-matching.rs:101:12
|
LL | if let [Foo { x, y }] = foo_const {
| ^^^^^^^^^^^^^^ pattern cannot match with input type `Pin<&[Foo<T, U>]>`
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:109:5
|
LL | (&mut x,): Pin<&'a mut (&'a mut Foo<T, U>,)>,
| ^^^^^^^^^ --------------------------------- expected due to this
| |
| expected `Pin<&mut (&mut Foo<T, U>,)>`, found `(_,)`
|
= note: expected struct `Pin<&'a mut (&'a mut Foo<T, U>,)>`
found tuple `(_,)`
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:115:5
|
LL | (&mut x,): Pin<&'a mut &'a mut (Foo<T, U>,)>,
| ^^^^^^^^^ --------------------------------- expected due to this
| |
| expected `Pin<&mut &mut (Foo<T, U>,)>`, found `(_,)`
|
= note: expected struct `Pin<&'a mut &'a mut (Foo<T, U>,)>`
found tuple `(_,)`
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:121:5
|
LL | &mut (x,): Pin<&'a mut (&'a mut Foo<T, U>,)>,
| ^^^^^^^^^ --------------------------------- expected due to this
| |
| expected `Pin<&mut (&mut Foo<T, U>,)>`, found `&mut _`
|
= note: expected struct `Pin<&'a mut (&'a mut Foo<T, U>,)>`
found mutable reference `&mut _`
help: you might have meant to use field `pointer` whose type is `&'a mut (&'a mut Foo<T, U>,)`
|
LL | &mut (x,): Pin<&'a mut (&'a mut Foo<T, U>,)>.pointer,
| ++++++++
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:127:5
|
LL | &mut (x,): Pin<&'a mut &'a mut (Foo<T, U>,)>,
| ^^^^^^^^^ --------------------------------- expected due to this
| |
| expected `Pin<&mut &mut (Foo<T, U>,)>`, found `&mut _`
|
= note: expected struct `Pin<&'a mut &'a mut (Foo<T, U>,)>`
found mutable reference `&mut _`
help: you might have meant to use field `pointer` whose type is `&'a mut &'a mut (Foo<T, U>,)`
|
LL | &mut (x,): Pin<&'a mut &'a mut (Foo<T, U>,)>.pointer,
| ++++++++
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:133:5
|
LL | (x,): Pin<&'a mut (&'a mut Foo<T, U>,)>,
| ^^^^ --------------------------------- expected due to this
| |
| expected `Pin<&mut (&mut Foo<T, U>,)>`, found `(_,)`
|
= note: expected struct `Pin<&'a mut (&'a mut Foo<T, U>,)>`
found tuple `(_,)`
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:139:5
|
LL | (x,): Pin<&'a mut &'a mut (Foo<T, U>,)>,
| ^^^^ --------------------------------- expected due to this
| |
| expected `Pin<&mut &mut (Foo<T, U>,)>`, found `(_,)`
|
= note: expected struct `Pin<&'a mut &'a mut (Foo<T, U>,)>`
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`.

View file

@ -0,0 +1,54 @@
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:115:6
|
LL | (&mut x,): Pin<&'a mut &'a mut (Foo<T, U>,)>,
| ^^^^^^ --------------------------------- expected due to this
| |
| expected `Foo<T, U>`, found `&mut _`
|
= note: expected struct `Foo<T, U>`
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<T, U>,)>,
| ^^^^^^
help: consider removing `&mut` from the pattern
|
LL - (&mut x,): Pin<&'a mut &'a mut (Foo<T, U>,)>,
LL + (x,): Pin<&'a mut &'a mut (Foo<T, U>,)>,
|
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:121:5
|
LL | &mut (x,): Pin<&'a mut (&'a mut Foo<T, U>,)>,
| ^^^^^^^^^ --------------------------------- expected due to this
| |
| expected `Pin<&mut (&mut Foo<T, U>,)>`, found `&mut _`
|
= note: expected struct `Pin<&'a mut (&'a mut Foo<T, U>,)>`
found mutable reference `&mut _`
help: you might have meant to use field `pointer` whose type is `&'a mut (&'a mut Foo<T, U>,)`
|
LL | &mut (x,): Pin<&'a mut (&'a mut Foo<T, U>,)>.pointer,
| ++++++++
error[E0308]: mismatched types
--> $DIR/pattern-matching.rs:127:5
|
LL | &mut (x,): Pin<&'a mut &'a mut (Foo<T, U>,)>,
| ^^^^^^^^^ --------------------------------- expected due to this
| |
| expected `Pin<&mut &mut (Foo<T, U>,)>`, found `&mut _`
|
= note: expected struct `Pin<&'a mut &'a mut (Foo<T, U>,)>`
found mutable reference `&mut _`
help: you might have meant to use field `pointer` whose type is `&'a mut &'a mut (Foo<T, U>,)`
|
LL | &mut (x,): Pin<&'a mut &'a mut (Foo<T, U>,)>.pointer,
| ++++++++
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -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<T, U> {
x: T,
y: U,
}
#[pin_v2] //[normal]~ ERROR the `#[pin_v2]` attribute is an experimental feature
enum Bar<T, U> {
Foo(T, U),
Bar { x: T, y: U },
}
trait IsPinMut {}
trait IsPinConst {}
impl<T: ?Sized> IsPinMut for Pin<&mut T> {}
impl<T: ?Sized> IsPinConst for Pin<&T> {}
fn assert_pin_mut<T: IsPinMut>(_: T) {}
fn assert_pin_const<T: IsPinConst>(_: T) {}
fn foo<T: Unpin, U: Unpin>(foo_mut: Pin<&mut Foo<T, U>>, foo_const: Pin<&Foo<T, U>>) {
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<T: Unpin, U: Unpin>(bar_mut: Pin<&mut Bar<T, U>>, bar_const: Pin<&Bar<T, U>>) {
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<T, U>(foo_mut: Pin<&mut (Foo<T, U>,)>, foo_const: Pin<&(Foo<T, U>,)>) {
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<T, U>(foo_mut: Pin<&mut [Foo<T, U>; 1]>, foo_const: Pin<&[Foo<T, U>; 1]>) {
let [Foo { x, y }] = foo_mut;
//[normal]~^ ERROR expected an array or slice, found `Pin<&mut [Foo<T, U>; 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<T, U>; 1]>`
assert_pin_const(x);
assert_pin_const(y);
}
fn pin_mut_slice<T, U>(foo_mut: Pin<&mut [Foo<T, U>]>, foo_const: Pin<&[Foo<T, U>]>) {
if let [Foo { x, y }] = foo_mut {
//[normal]~^ ERROR expected an array or slice, found `Pin<&mut [Foo<T, U>]>`
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<T, U>]>`
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<T, U>,)>, //[normal]~ ERROR mismatched type
) -> Pin<&'a mut Foo<T, U>> {
x
}
fn tuple_ref_mut_pat_and_pin_mut_of_mut_tuple_ty<'a, T, U>(
(&mut x,): Pin<&'a mut &'a mut (Foo<T, U>,)>, //~ ERROR mismatched type
) -> Pin<&'a mut Foo<T, U>> {
x
}
fn ref_mut_tuple_pat_and_pin_mut_of_tuple_mut_ty<'a, T, U>(
&mut (x,): Pin<&'a mut (&'a mut Foo<T, U>,)>, //~ ERROR mismatched type
) -> Pin<&'a mut Foo<T, U>> {
x
}
fn ref_mut_tuple_pat_and_pin_mut_of_mut_tuple_ty<'a, T, U>(
&mut (x,): Pin<&'a mut &'a mut (Foo<T, U>,)>, //~ ERROR mismatched type
) -> Pin<&'a mut Foo<T, U>> {
x
}
fn tuple_pat_and_pin_mut_of_tuple_mut_ty<'a, T, U>(
(x,): Pin<&'a mut (&'a mut Foo<T, U>,)>, //[normal]~ ERROR mismatched type
) -> Pin<&'a mut &'a mut Foo<T, U>> {
x // ok
}
fn tuple_pat_and_pin_mut_of_mut_tuple_ty<'a, T, U>(
(x,): Pin<&'a mut &'a mut (Foo<T, U>,)>, //[normal]~ ERROR mismatched type
) -> Pin<&'a mut Foo<T, U>> {
x
}
fn main() {}

View file

@ -0,0 +1,138 @@
#![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 <Struct as std::any::Any>::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<T, U>(#[pin_v2] param: Foo<T, U>)
//~^ 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!();
fn main() {}

View file

@ -0,0 +1,312 @@
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: 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<T, U>(#[pin_v2] param: Foo<T, U>)
| ^^^^^^^^^
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<T, U>(#[pin_v2] param: Foo<T, U>)
| ^^^^^^^^^
|
= 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 39 previous errors