From c660201f8245df541041420b3a2087207c8e2ed9 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 24 Sep 2026 13:30:18 +0100 Subject: [PATCH] rust: pin-init: internal: pin_data: parse explicit `#[borrowed]` annotation `#[borrowed]` attribute explicitly marks a field as potentially being borrowed by other fields. Acked-by: Benno Lossin Link: https://patch.msgid.link/20261008-dev-selfref-v2-13-e280b3c8fba5@garyguo.net/ Signed-off-by: Gary Guo --- rust/pin-init/internal/src/pin_data.rs | 36 +++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/rust/pin-init/internal/src/pin_data.rs b/rust/pin-init/internal/src/pin_data.rs index f27dff95a11a..9b584e4c6d5d 100644 --- a/rust/pin-init/internal/src/pin_data.rs +++ b/rust/pin-init/internal/src/pin_data.rs @@ -11,8 +11,8 @@ spanned::Spanned, visit::Visit, visit_mut::VisitMut, - Field, Fields, GenericParam, Generics, Ident, Index, Item, ItemStruct, Lifetime, LifetimeParam, - Member, PathSegment, Token, Type, TypePath, + Attribute, Field, Fields, GenericParam, Generics, Ident, Index, Item, ItemStruct, Lifetime, + LifetimeParam, Member, Meta, PathSegment, Token, Type, TypePath, }; use crate::{ @@ -55,11 +55,25 @@ fn to_tokens(&self, tokens: &mut TokenStream) { /// Description of how a field is borrowed. #[derive(Clone, Copy, Default, PartialEq, Eq)] enum BorrowedKind { - /// Implicitly inferreed. + /// `#[borrowed]`, or implicitly inferreed. #[default] Shared, } +impl BorrowedKind { + fn parse(dcx: &mut DiagCtxt, attrs: &mut Vec) -> Option { + let attr = attrs.extract_single_attr(dcx, "borrowed")?; + + Some(if let Meta::Path(_) = attr.meta { + BorrowedKind::Shared + } else { + // Swallow the error and recover by inferring shared. + dcx.error(attr.path(), "unexpected `#[borrowed]` attribute"); + BorrowedKind::Shared + }) + } +} + /// Information about a borrowed field. struct BorrowedInfo { kind: BorrowedKind, @@ -305,11 +319,25 @@ fn expand( }) .visit_type(&field.ty); + let borrowed = BorrowedKind::parse(dcx, &mut field.attrs).and_then(|kind| { + let lifetime = Lifetime::from_ident(&member.as_ident()); + + if bound_lifetimes.contains(&lifetime) { + dcx.error( + &lifetime, + format!("`{lifetime}` appear in generics and would conflict with field lifetime"), + ); + return None; + } + + Some(BorrowedInfo { kind, lifetime }) + }); + FieldInfo { field, member, pinned, - borrowed: None, + borrowed, captures, generic_lt_captures, generic_ty_captures,