mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
rust: pin-init: internal: pin_data: parse explicit #[uses] annotation
Add support for explicit self-referential annotations.
`#[uses]` attribute is used to mark what other field lifetimes are
captured by this field, and also the variance of the type in respect to the
field lifetimes. For example,
#[uses('a: covariant, 'b: invariant)]
indicates that the field captures the field lifetime `'a` covariantly, and
field lifetime `'b` invariantly. Many types are covariant, so this is the
default variance if the variance is omitted (e.g. `#[uses('a)]`),
consistent with the automatically inferred borrow.
Acked-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20261008-dev-selfref-v2-15-e280b3c8fba5@garyguo.net/
Signed-off-by: Gary Guo <gary@garyguo.net>
This commit is contained in:
parent
0b326dd96e
commit
59a9b11bcc
|
|
@ -21,6 +21,9 @@
|
|||
};
|
||||
|
||||
pub(crate) mod kw {
|
||||
syn::custom_keyword!(covariant);
|
||||
syn::custom_keyword!(invariant);
|
||||
syn::custom_keyword!(contravariant);
|
||||
syn::custom_keyword!(PinnedDrop);
|
||||
}
|
||||
|
||||
|
|
@ -93,9 +96,37 @@ struct BorrowedInfo {
|
|||
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq)]
|
||||
enum Variance {
|
||||
/// Implicitly inferred variance.
|
||||
/// `covariant` annotation, or implicitly inferred.
|
||||
#[default]
|
||||
Covariant,
|
||||
// `invariant` annotation.
|
||||
Invariant,
|
||||
}
|
||||
|
||||
impl Parse for Variance {
|
||||
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||
let lh = input.lookahead1();
|
||||
Ok(if lh.peek(kw::covariant) {
|
||||
let _: kw::covariant = input.parse()?;
|
||||
Variance::Covariant
|
||||
} else if lh.peek(kw::invariant) {
|
||||
let _: kw::invariant = input.parse()?;
|
||||
Variance::Invariant
|
||||
} else if lh.peek(kw::contravariant) {
|
||||
// Field lifetimes are inherently covariant, so combining with contravariance,
|
||||
// we would constrain it to be invariant.
|
||||
let token: kw::contravariant = input.parse()?;
|
||||
DiagCtxt::current(|dcx| {
|
||||
dcx.error(
|
||||
token,
|
||||
"field lifetimes cannot be `contravariant`; use `invariant` instead",
|
||||
)
|
||||
});
|
||||
Variance::Invariant
|
||||
} else {
|
||||
Err(lh.error())?
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about field lifetimes captured in a type.
|
||||
|
|
@ -131,7 +162,65 @@ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|||
}
|
||||
}
|
||||
|
||||
#[expect(unused)]
|
||||
impl Parse for Capture {
|
||||
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||
let lifetime = input.parse()?;
|
||||
let variance = if input.peek(Token![:]) {
|
||||
let _: Token![:] = input.parse()?;
|
||||
input.parse()?
|
||||
} else {
|
||||
// If variance is not explicitly specified, infer covariance by default.
|
||||
Variance::Covariant
|
||||
};
|
||||
Ok(Capture { variance, lifetime })
|
||||
}
|
||||
}
|
||||
|
||||
impl Capture {
|
||||
fn parse_list(
|
||||
dcx: &mut DiagCtxt,
|
||||
attrs: &mut Vec<Attribute>,
|
||||
bound_lifetimes: &BTreeSet<&Lifetime>,
|
||||
field_idx_map: &BTreeMap<Ident, usize>,
|
||||
) -> Option<(BTreeSet<Capture>, Variance)> {
|
||||
let attr = attrs.extract_single_attr(dcx, "uses")?;
|
||||
let punctuated: Punctuated<Capture, Token![,]> = attr
|
||||
.parse_args_with(Punctuated::parse_terminated)
|
||||
.map_err(ErrorGuaranteed::from)
|
||||
.ok()?;
|
||||
|
||||
// Check for misuses inside attribute.
|
||||
let mut set = BTreeSet::new();
|
||||
for borrow in punctuated {
|
||||
let lt = &borrow.lifetime;
|
||||
if set.contains(&borrow) {
|
||||
dcx.error(lt, format!("lifetime `{lt}` is mentioned more than once"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if bound_lifetimes.contains(lt) {
|
||||
dcx.error(
|
||||
lt,
|
||||
format!("`{lt}` is a struct generics and cannot be used in `#[uses]`"),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if lt.ident != "_" && !field_idx_map.contains_key(<.ident) {
|
||||
dcx.error(lt, format!("`{lt}` is not a field name"));
|
||||
continue;
|
||||
}
|
||||
|
||||
set.insert(borrow);
|
||||
}
|
||||
|
||||
let wildcard = Lifetime::new("'_", Span::mixed_site());
|
||||
let wildcard_variance = set.take(&wildcard).map(|b| b.variance).unwrap_or_default();
|
||||
Some((set, wildcard_variance))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
struct FieldInfo {
|
||||
field: Field,
|
||||
member: Member,
|
||||
|
|
@ -275,8 +364,10 @@ fn expand(
|
|||
}),
|
||||
};
|
||||
|
||||
let mut captures = BTreeSet::new();
|
||||
let wildcard_variance = Variance::default();
|
||||
// Parse `#[uses]` attribute.
|
||||
let (mut captures, wildcard_variance) =
|
||||
Capture::parse_list(dcx, &mut field.attrs, &bound_lifetimes, &field_idx_map)
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut generic_lt_captures = BTreeSet::new();
|
||||
let mut generic_ty_captures = BTreeSet::new();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user