summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-05-26 23:54:06 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-05-26 23:54:06 +0000
commitfc5427bddf3519c15510fbf933063cf3a035da16 (patch)
tree9cbb0fb46dab16628c26e4667f91ac6db791b4dd
parent8cded5437e359c67fe7523fb3fd22ed3c256036d (diff)
parent2f79acbc52e50e5b980a835c6f6b807cf11449ab (diff)
downloadpin-project-internal-fc5427bddf3519c15510fbf933063cf3a035da16.tar.gz
Snap for 10214594 from 2f79acbc52e50e5b980a835c6f6b807cf11449ab to sdk-release
Change-Id: I646c2af8d80af123645cca7094658ea197680cdf
-rw-r--r--patches/syn-2.diff378
-rw-r--r--src/pin_project/args.rs11
-rw-r--r--src/pin_project/derive.rs67
-rw-r--r--src/pinned_drop.rs59
-rw-r--r--src/utils.rs33
5 files changed, 455 insertions, 93 deletions
diff --git a/patches/syn-2.diff b/patches/syn-2.diff
new file mode 100644
index 0000000..143c988
--- /dev/null
+++ b/patches/syn-2.diff
@@ -0,0 +1,378 @@
+diff --git a/src/pin_project/args.rs b/src/pin_project/args.rs
+index d0d4f36..d242ae7 100644
+--- a/src/pin_project/args.rs
++++ b/src/pin_project/args.rs
+@@ -16,10 +16,9 @@ pub(super) fn parse_args(attrs: &[Attribute]) -> Result<Args> {
+ impl Parse for Input {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ Ok(Self((|| {
+- let content = input.parenthesized().ok()?;
+- let private = content.parse::<Ident>().ok()?;
++ let private = input.parse::<Ident>().ok()?;
+ if private == "__private" {
+- content.parenthesized().ok()?.parse::<TokenStream>().ok()
++ input.parenthesized().ok()?.parse::<TokenStream>().ok()
+ } else {
+ None
+ }
+@@ -31,10 +30,10 @@ pub(super) fn parse_args(attrs: &[Attribute]) -> Result<Args> {
+ bail!(attr, "duplicate #[pin_project] attribute");
+ }
+
+- let mut attrs = attrs.iter().filter(|attr| attr.path.is_ident(PIN));
++ let mut attrs = attrs.iter().filter(|attr| attr.path().is_ident(PIN));
+
+ let prev = if let Some(attr) = attrs.next() {
+- (attr, syn::parse2::<Input>(attr.tokens.clone()).unwrap().0)
++ (attr, syn::parse2::<Input>(attr.meta.require_list()?.tokens.clone())?.0)
+ } else {
+ // This only fails if another macro removes `#[pin]`.
+ bail!(TokenStream::new(), "#[pin_project] attribute has been removed");
+@@ -46,7 +45,7 @@ pub(super) fn parse_args(attrs: &[Attribute]) -> Result<Args> {
+ // has the same span as `#[pin_project]`, it is possible
+ // that a useless error message will be generated.
+ // So, use the span of `prev_attr` if it is not a valid attribute.
+- let res = syn::parse2::<Input>(attr.tokens.clone()).unwrap().0;
++ let res = syn::parse2::<Input>(attr.meta.require_list()?.tokens.clone())?.0;
+ let span = match (prev_res, res) {
+ (Some(_), _) => attr,
+ (None, _) => prev_attr,
+diff --git a/src/pin_project/derive.rs b/src/pin_project/derive.rs
+index fd2375d..d2b2b5e 100644
+--- a/src/pin_project/derive.rs
++++ b/src/pin_project/derive.rs
+@@ -1,9 +1,9 @@
+ use proc_macro2::{Delimiter, Group, Span, TokenStream};
+ use quote::{format_ident, quote, quote_spanned, ToTokens};
+ use syn::{
+- parse_quote, token, visit_mut::VisitMut, Attribute, Data, DataEnum, DeriveInput, Error, Field,
+- Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Index, Lifetime, LifetimeDef, Meta,
+- MetaList, MetaNameValue, NestedMeta, Result, Token, Type, Variant, Visibility, WhereClause,
++ parse_quote, punctuated::Punctuated, token, visit_mut::VisitMut, Attribute, Data, DataEnum,
++ DeriveInput, Error, Field, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Index,
++ Lifetime, LifetimeParam, Meta, Result, Token, Type, Variant, Visibility, WhereClause,
+ };
+
+ use super::{
+@@ -235,7 +235,7 @@ impl<'a> Context<'a> {
+ }
+ }
+
+-#[derive(Copy, Clone, Eq, PartialEq)]
++#[derive(Copy, Clone, PartialEq)]
+ enum TypeKind {
+ Enum,
+ Struct,
+@@ -305,7 +305,7 @@ fn validate_struct(ident: &Ident, fields: &Fields) -> Result<()> {
+ fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> {
+ if variants.is_empty() {
+ return Err(Error::new(
+- brace_token.span,
++ brace_token.span.join(),
+ "#[pin_project] attribute may not be used on enums without variants",
+ ));
+ }
+@@ -569,7 +569,9 @@ fn visit_fields<'a>(
+ let mut proj_move = TokenStream::new();
+ let mut pinned_bindings = Vec::with_capacity(fields.len());
+
+- for (i, Field { attrs, vis, ident, colon_token, ty }) in fields.iter().enumerate() {
++ for (i, Field { attrs, vis, ident, colon_token, ty, mutability: _ }) in
++ fields.iter().enumerate()
++ {
+ let binding = ident.clone().unwrap_or_else(|| format_ident!("_{}", i));
+ proj_pat.extend(quote!(#binding,));
+ let lifetime = &cx.proj.lifetime;
+@@ -768,7 +770,7 @@ fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
+ // This ensures that any unused type parameters
+ // don't end up with `Unpin` bounds.
+ let lifetime_fields = cx.orig.generics.lifetimes().enumerate().map(
+- |(i, LifetimeDef { lifetime, .. })| {
++ |(i, LifetimeParam { lifetime, .. })| {
+ let field_ident = format_ident!("__lifetime{}", i);
+ quote!(#field_ident: &#lifetime ())
+ },
+@@ -1016,33 +1018,26 @@ fn make_proj_impl(
+ /// - Generates a function that borrows fields without an unsafe block and
+ /// forbidding `unaligned_references` lint.
+ fn ensure_not_packed(orig: &OriginalType<'_>, fields: Option<&Fields>) -> Result<TokenStream> {
+- for meta in orig.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) {
+- if let Meta::List(list) = meta {
++ for attr in orig.attrs {
++ if let Meta::List(ref list) = attr.meta {
+ if list.path.is_ident("repr") {
+- for repr in list.nested.iter() {
+- match repr {
+- NestedMeta::Meta(Meta::Path(path))
+- | NestedMeta::Meta(Meta::List(MetaList { path, .. }))
+- | NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, .. })) => {
+- if path.is_ident("packed") {
+- let msg = if fields.is_none() {
+- // #[repr(packed)] cannot be apply on enums and will be rejected by rustc.
+- // However, we should not rely on the behavior of rustc that rejects this.
+- // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
+- "#[repr(packed)] attribute should be applied to a struct or union"
+- } else if let NestedMeta::Meta(Meta::NameValue(..)) = repr {
+- // #[repr(packed = "")] is not valid format of #[repr(packed)] and will be
+- // rejected by rustc.
+- // However, we should not rely on the behavior of rustc that rejects this.
+- // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
+- "#[repr(packed)] attribute should not be name-value pair"
+- } else {
+- "#[pin_project] attribute may not be used on #[repr(packed)] types"
+- };
+- bail!(repr, msg);
+- }
+- }
+- NestedMeta::Lit(..) => {}
++ for repr in list.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)? {
++ if repr.path().is_ident("packed") {
++ let msg = if fields.is_none() {
++ // #[repr(packed)] cannot be apply on enums and will be rejected by rustc.
++ // However, we should not rely on the behavior of rustc that rejects this.
++ // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
++ "#[repr(packed)] attribute should be applied to a struct or union"
++ } else if repr.require_name_value().is_ok() {
++ // #[repr(packed = "")] is not valid format of #[repr(packed)] and will be
++ // rejected by rustc.
++ // However, we should not rely on the behavior of rustc that rejects this.
++ // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
++ "#[repr(packed)] attribute should not be name-value pair"
++ } else {
++ "#[pin_project] attribute may not be used on #[repr(packed)] types"
++ };
++ bail!(repr, msg);
+ }
+ }
+ }
+@@ -1063,10 +1058,10 @@ fn ensure_not_packed(orig: &OriginalType<'_>, fields: Option<&Fields>) -> Result
+ // ```rust
+ // #[forbid(unaligned_references)]
+ // fn assert_not_repr_packed(val: &MyStruct) {
+- // let _field1 = &val.field1;
+- // let _field2 = &val.field2;
++ // let _field_1 = &val.field_1;
++ // let _field_2 = &val.field_2;
+ // ...
+- // let _fieldn = &val.fieldn;
++ // let _field_n = &val.field_n;
+ // }
+ // ```
+ //
+diff --git a/src/pinned_drop.rs b/src/pinned_drop.rs
+index 912989d..d30ecbe 100644
+--- a/src/pinned_drop.rs
++++ b/src/pinned_drop.rs
+@@ -1,16 +1,18 @@
+ use proc_macro2::TokenStream;
+ use quote::{format_ident, quote, ToTokens};
+ use syn::{
+- parse_quote, spanned::Spanned, visit_mut::VisitMut, Error, FnArg, GenericArgument, ImplItem,
+- ItemImpl, Pat, PatIdent, Path, PathArguments, Result, ReturnType, Signature, Token, Type,
+- TypePath, TypeReference,
++ parse_quote, spanned::Spanned, token::Colon, visit_mut::VisitMut, Error, FnArg,
++ GenericArgument, Ident, ImplItem, ItemImpl, Pat, PatIdent, PatType, Path, PathArguments,
++ Result, ReturnType, Signature, Token, Type, TypePath, TypeReference,
+ };
+
+-use crate::utils::{parse_as_empty, prepend_underscore_to_self, ReplaceReceiver, SliceExt};
++use crate::utils::{ReplaceReceiver, SliceExt};
+
+ pub(crate) fn attribute(args: &TokenStream, mut input: ItemImpl) -> TokenStream {
+ let res = (|| -> Result<()> {
+- parse_as_empty(args)?;
++ if !args.is_empty() {
++ bail!(args, "unexpected argument: `{}`", args)
++ }
+ validate_impl(&input)?;
+ expand_impl(&mut input);
+ Ok(())
+@@ -85,7 +87,7 @@ fn validate_impl(item: &ItemImpl) -> Result<()> {
+ ImplItem::Type(item) => {
+ bail!(item, "type `{}` is not a member of trait `PinnedDrop`", item.ident)
+ }
+- ImplItem::Method(method) => {
++ ImplItem::Fn(method) => {
+ validate_sig(&method.sig)?;
+ if i == 0 {
+ Ok(())
+@@ -124,14 +126,15 @@ fn validate_sig(sig: &Signature) -> Result<()> {
+
+ match sig.inputs.len() {
+ 1 => {}
+- 0 => return Err(Error::new(sig.paren_token.span, INVALID_ARGUMENT)),
++ 0 => return Err(Error::new(sig.paren_token.span.join(), INVALID_ARGUMENT)),
+ _ => bail!(sig.inputs, INVALID_ARGUMENT),
+ }
+
+- if let Some(FnArg::Typed(arg)) = sig.receiver() {
++ if let Some(arg) = sig.receiver() {
+ // (mut) self: <path>
+ if let Some(path) = get_ty_path(&arg.ty) {
+- let ty = path.segments.last().unwrap();
++ let ty =
++ path.segments.last().expect("Type paths should always have at least one segment");
+ if let PathArguments::AngleBracketed(args) = &ty.arguments {
+ // (mut) self: (<path>::)<ty><&mut <elem>..>
+ if let Some(GenericArgument::Type(Type::Reference(TypeReference {
+@@ -175,25 +178,16 @@ fn validate_sig(sig: &Signature) -> Result<()> {
+ // }
+ //
+ fn expand_impl(item: &mut ItemImpl) {
+- fn get_arg_pat(arg: &mut FnArg) -> Option<&mut PatIdent> {
+- if let FnArg::Typed(arg) = arg {
+- if let Pat::Ident(ident) = &mut *arg.pat {
+- return Some(ident);
+- }
+- }
+- None
+- }
+-
+ // `PinnedDrop` is a private trait and should not appear in docs.
+ item.attrs.push(parse_quote!(#[doc(hidden)]));
+
+- let path = &mut item.trait_.as_mut().unwrap().1;
++ let path = &mut item.trait_.as_mut().expect("unexpected inherent impl").1;
+ *path = parse_quote_spanned! { path.span() =>
+ ::pin_project::__private::PinnedDrop
+ };
+
+ let method =
+- if let ImplItem::Method(method) = &mut item.items[0] { method } else { unreachable!() };
++ if let ImplItem::Fn(method) = &mut item.items[0] { method } else { unreachable!() };
+
+ // `fn drop(mut self: Pin<&mut Self>)` -> `fn __drop_inner<T>(mut __self: Pin<&mut Receiver>)`
+ let drop_inner = {
+@@ -203,8 +197,20 @@ fn expand_impl(item: &mut ItemImpl) {
+ drop_inner.block.stmts.insert(0, parse_quote!(fn #ident() {}));
+ drop_inner.sig.ident = ident;
+ drop_inner.sig.generics = item.generics.clone();
+- let self_pat = get_arg_pat(&mut drop_inner.sig.inputs[0]).unwrap();
+- prepend_underscore_to_self(&mut self_pat.ident);
++ let receiver = drop_inner.sig.receiver().expect("drop() should have a receiver").clone();
++ let pat = Box::new(Pat::Ident(PatIdent {
++ attrs: Vec::new(),
++ by_ref: None,
++ mutability: receiver.mutability,
++ ident: Ident::new("__self", receiver.self_token.span()),
++ subpat: None,
++ }));
++ drop_inner.sig.inputs[0] = FnArg::Typed(PatType {
++ attrs: receiver.attrs,
++ pat,
++ colon_token: Colon::default(),
++ ty: receiver.ty,
++ });
+ let self_ty = if let Type::Path(ty) = &*item.self_ty { ty } else { unreachable!() };
+ let mut visitor = ReplaceReceiver(self_ty);
+ visitor.visit_signature_mut(&mut drop_inner.sig);
+@@ -214,9 +220,12 @@ fn expand_impl(item: &mut ItemImpl) {
+
+ // `fn drop(mut self: Pin<&mut Self>)` -> `unsafe fn drop(self: Pin<&mut Self>)`
+ method.sig.unsafety = Some(<Token![unsafe]>::default());
+- let self_pat = get_arg_pat(&mut method.sig.inputs[0]).unwrap();
+- self_pat.mutability = None;
+- let self_token = &self_pat.ident;
++ let self_token = if let FnArg::Receiver(ref mut rec) = method.sig.inputs[0] {
++ rec.mutability = None;
++ &rec.self_token
++ } else {
++ panic!("drop() should have a receiver")
++ };
+
+ method.block.stmts = parse_quote! {
+ #[allow(clippy::needless_pass_by_value)] // This lint does not warn the receiver.
+diff --git a/src/utils.rs b/src/utils.rs
+index 27373ef..3f4ec85 100644
+--- a/src/utils.rs
++++ b/src/utils.rs
+@@ -8,7 +8,7 @@ use syn::{
+ punctuated::Punctuated,
+ token,
+ visit_mut::{self, VisitMut},
+- Attribute, ExprPath, ExprStruct, Generics, Ident, Item, Lifetime, LifetimeDef, Macro, PatPath,
++ Attribute, ExprPath, ExprStruct, Generics, Ident, Item, Lifetime, LifetimeParam, Macro,
+ PatStruct, PatTupleStruct, Path, PathArguments, PredicateType, QSelf, Result, Token, Type,
+ TypeParamBound, TypePath, Variant, Visibility, WherePredicate,
+ };
+@@ -42,7 +42,7 @@ pub(crate) fn determine_lifetime_name(lifetime_name: &mut String, generics: &mut
+ struct CollectLifetimes(Vec<String>);
+
+ impl VisitMut for CollectLifetimes {
+- fn visit_lifetime_def_mut(&mut self, def: &mut LifetimeDef) {
++ fn visit_lifetime_param_mut(&mut self, def: &mut LifetimeParam) {
+ self.0.push(def.lifetime.to_string());
+ }
+ }
+@@ -84,7 +84,7 @@ pub(crate) fn insert_lifetime_and_bound(
+ pub(crate) fn insert_lifetime(generics: &mut Generics, lifetime: Lifetime) {
+ generics.lt_token.get_or_insert_with(<Token![<]>::default);
+ generics.gt_token.get_or_insert_with(<Token![>]>::default);
+- generics.params.insert(0, LifetimeDef::new(lifetime).into());
++ generics.params.insert(0, LifetimeParam::new(lifetime).into());
+ }
+
+ /// Determines the visibility of the projected types and projection methods.
+@@ -93,24 +93,12 @@ pub(crate) fn insert_lifetime(generics: &mut Generics, lifetime: Lifetime) {
+ /// Otherwise, returned visibility is the same as given visibility.
+ pub(crate) fn determine_visibility(vis: &Visibility) -> Visibility {
+ if let Visibility::Public(token) = vis {
+- parse_quote_spanned!(token.pub_token.span => pub(crate))
++ parse_quote_spanned!(token.span => pub(crate))
+ } else {
+ vis.clone()
+ }
+ }
+
+-/// Checks if `tokens` is an empty `TokenStream`.
+-///
+-/// This is almost equivalent to `syn::parse2::<Nothing>()`, but produces
+-/// a better error message and does not require ownership of `tokens`.
+-pub(crate) fn parse_as_empty(tokens: &TokenStream) -> Result<()> {
+- if tokens.is_empty() {
+- Ok(())
+- } else {
+- bail!(tokens, "unexpected token: `{}`", tokens)
+- }
+-}
+-
+ pub(crate) fn respan<T>(node: &T, span: Span) -> T
+ where
+ T: ToTokens + Parse,
+@@ -146,11 +134,11 @@ impl SliceExt for [Attribute] {
+ fn position_exact(&self, ident: &str) -> Result<Option<usize>> {
+ self.iter()
+ .try_fold((0, None), |(i, mut prev), attr| {
+- if attr.path.is_ident(ident) {
++ if attr.path().is_ident(ident) {
+ if prev.replace(i).is_some() {
+ bail!(attr, "duplicate #[{}] attribute", ident);
+ }
+- parse_as_empty(&attr.tokens)?;
++ attr.meta.require_path_only()?;
+ }
+ Ok((i + 1, prev))
+ })
+@@ -158,7 +146,7 @@ impl SliceExt for [Attribute] {
+ }
+
+ fn find(&self, ident: &str) -> Option<&Attribute> {
+- self.iter().position(|attr| attr.path.is_ident(ident)).map(|i| &self[i])
++ self.iter().position(|attr| attr.path().is_ident(ident)).map(|i| &self[i])
+ }
+ }
+
+@@ -335,13 +323,6 @@ impl VisitMut for ReplaceReceiver<'_> {
+ visit_mut::visit_expr_struct_mut(self, expr);
+ }
+
+- fn visit_pat_path_mut(&mut self, pat: &mut PatPath) {
+- if pat.qself.is_none() {
+- self.self_to_qself(&mut pat.qself, &mut pat.path);
+- }
+- visit_mut::visit_pat_path_mut(self, pat);
+- }
+-
+ fn visit_pat_struct_mut(&mut self, pat: &mut PatStruct) {
+ self.self_to_expr_path(&mut pat.path);
+ visit_mut::visit_pat_struct_mut(self, pat);
diff --git a/src/pin_project/args.rs b/src/pin_project/args.rs
index d0d4f36..d242ae7 100644
--- a/src/pin_project/args.rs
+++ b/src/pin_project/args.rs
@@ -16,10 +16,9 @@ pub(super) fn parse_args(attrs: &[Attribute]) -> Result<Args> {
impl Parse for Input {
fn parse(input: ParseStream<'_>) -> Result<Self> {
Ok(Self((|| {
- let content = input.parenthesized().ok()?;
- let private = content.parse::<Ident>().ok()?;
+ let private = input.parse::<Ident>().ok()?;
if private == "__private" {
- content.parenthesized().ok()?.parse::<TokenStream>().ok()
+ input.parenthesized().ok()?.parse::<TokenStream>().ok()
} else {
None
}
@@ -31,10 +30,10 @@ pub(super) fn parse_args(attrs: &[Attribute]) -> Result<Args> {
bail!(attr, "duplicate #[pin_project] attribute");
}
- let mut attrs = attrs.iter().filter(|attr| attr.path.is_ident(PIN));
+ let mut attrs = attrs.iter().filter(|attr| attr.path().is_ident(PIN));
let prev = if let Some(attr) = attrs.next() {
- (attr, syn::parse2::<Input>(attr.tokens.clone()).unwrap().0)
+ (attr, syn::parse2::<Input>(attr.meta.require_list()?.tokens.clone())?.0)
} else {
// This only fails if another macro removes `#[pin]`.
bail!(TokenStream::new(), "#[pin_project] attribute has been removed");
@@ -46,7 +45,7 @@ pub(super) fn parse_args(attrs: &[Attribute]) -> Result<Args> {
// has the same span as `#[pin_project]`, it is possible
// that a useless error message will be generated.
// So, use the span of `prev_attr` if it is not a valid attribute.
- let res = syn::parse2::<Input>(attr.tokens.clone()).unwrap().0;
+ let res = syn::parse2::<Input>(attr.meta.require_list()?.tokens.clone())?.0;
let span = match (prev_res, res) {
(Some(_), _) => attr,
(None, _) => prev_attr,
diff --git a/src/pin_project/derive.rs b/src/pin_project/derive.rs
index fd2375d..d2b2b5e 100644
--- a/src/pin_project/derive.rs
+++ b/src/pin_project/derive.rs
@@ -1,9 +1,9 @@
use proc_macro2::{Delimiter, Group, Span, TokenStream};
use quote::{format_ident, quote, quote_spanned, ToTokens};
use syn::{
- parse_quote, token, visit_mut::VisitMut, Attribute, Data, DataEnum, DeriveInput, Error, Field,
- Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Index, Lifetime, LifetimeDef, Meta,
- MetaList, MetaNameValue, NestedMeta, Result, Token, Type, Variant, Visibility, WhereClause,
+ parse_quote, punctuated::Punctuated, token, visit_mut::VisitMut, Attribute, Data, DataEnum,
+ DeriveInput, Error, Field, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Index,
+ Lifetime, LifetimeParam, Meta, Result, Token, Type, Variant, Visibility, WhereClause,
};
use super::{
@@ -235,7 +235,7 @@ impl<'a> Context<'a> {
}
}
-#[derive(Copy, Clone, Eq, PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
enum TypeKind {
Enum,
Struct,
@@ -305,7 +305,7 @@ fn validate_struct(ident: &Ident, fields: &Fields) -> Result<()> {
fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> {
if variants.is_empty() {
return Err(Error::new(
- brace_token.span,
+ brace_token.span.join(),
"#[pin_project] attribute may not be used on enums without variants",
));
}
@@ -569,7 +569,9 @@ fn visit_fields<'a>(
let mut proj_move = TokenStream::new();
let mut pinned_bindings = Vec::with_capacity(fields.len());
- for (i, Field { attrs, vis, ident, colon_token, ty }) in fields.iter().enumerate() {
+ for (i, Field { attrs, vis, ident, colon_token, ty, mutability: _ }) in
+ fields.iter().enumerate()
+ {
let binding = ident.clone().unwrap_or_else(|| format_ident!("_{}", i));
proj_pat.extend(quote!(#binding,));
let lifetime = &cx.proj.lifetime;
@@ -768,7 +770,7 @@ fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
// This ensures that any unused type parameters
// don't end up with `Unpin` bounds.
let lifetime_fields = cx.orig.generics.lifetimes().enumerate().map(
- |(i, LifetimeDef { lifetime, .. })| {
+ |(i, LifetimeParam { lifetime, .. })| {
let field_ident = format_ident!("__lifetime{}", i);
quote!(#field_ident: &#lifetime ())
},
@@ -1016,33 +1018,26 @@ fn make_proj_impl(
/// - Generates a function that borrows fields without an unsafe block and
/// forbidding `unaligned_references` lint.
fn ensure_not_packed(orig: &OriginalType<'_>, fields: Option<&Fields>) -> Result<TokenStream> {
- for meta in orig.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) {
- if let Meta::List(list) = meta {
+ for attr in orig.attrs {
+ if let Meta::List(ref list) = attr.meta {
if list.path.is_ident("repr") {
- for repr in list.nested.iter() {
- match repr {
- NestedMeta::Meta(Meta::Path(path))
- | NestedMeta::Meta(Meta::List(MetaList { path, .. }))
- | NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, .. })) => {
- if path.is_ident("packed") {
- let msg = if fields.is_none() {
- // #[repr(packed)] cannot be apply on enums and will be rejected by rustc.
- // However, we should not rely on the behavior of rustc that rejects this.
- // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
- "#[repr(packed)] attribute should be applied to a struct or union"
- } else if let NestedMeta::Meta(Meta::NameValue(..)) = repr {
- // #[repr(packed = "")] is not valid format of #[repr(packed)] and will be
- // rejected by rustc.
- // However, we should not rely on the behavior of rustc that rejects this.
- // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
- "#[repr(packed)] attribute should not be name-value pair"
- } else {
- "#[pin_project] attribute may not be used on #[repr(packed)] types"
- };
- bail!(repr, msg);
- }
- }
- NestedMeta::Lit(..) => {}
+ for repr in list.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)? {
+ if repr.path().is_ident("packed") {
+ let msg = if fields.is_none() {
+ // #[repr(packed)] cannot be apply on enums and will be rejected by rustc.
+ // However, we should not rely on the behavior of rustc that rejects this.
+ // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
+ "#[repr(packed)] attribute should be applied to a struct or union"
+ } else if repr.require_name_value().is_ok() {
+ // #[repr(packed = "")] is not valid format of #[repr(packed)] and will be
+ // rejected by rustc.
+ // However, we should not rely on the behavior of rustc that rejects this.
+ // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
+ "#[repr(packed)] attribute should not be name-value pair"
+ } else {
+ "#[pin_project] attribute may not be used on #[repr(packed)] types"
+ };
+ bail!(repr, msg);
}
}
}
@@ -1063,10 +1058,10 @@ fn ensure_not_packed(orig: &OriginalType<'_>, fields: Option<&Fields>) -> Result
// ```rust
// #[forbid(unaligned_references)]
// fn assert_not_repr_packed(val: &MyStruct) {
- // let _field1 = &val.field1;
- // let _field2 = &val.field2;
+ // let _field_1 = &val.field_1;
+ // let _field_2 = &val.field_2;
// ...
- // let _fieldn = &val.fieldn;
+ // let _field_n = &val.field_n;
// }
// ```
//
diff --git a/src/pinned_drop.rs b/src/pinned_drop.rs
index 912989d..d30ecbe 100644
--- a/src/pinned_drop.rs
+++ b/src/pinned_drop.rs
@@ -1,16 +1,18 @@
use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens};
use syn::{
- parse_quote, spanned::Spanned, visit_mut::VisitMut, Error, FnArg, GenericArgument, ImplItem,
- ItemImpl, Pat, PatIdent, Path, PathArguments, Result, ReturnType, Signature, Token, Type,
- TypePath, TypeReference,
+ parse_quote, spanned::Spanned, token::Colon, visit_mut::VisitMut, Error, FnArg,
+ GenericArgument, Ident, ImplItem, ItemImpl, Pat, PatIdent, PatType, Path, PathArguments,
+ Result, ReturnType, Signature, Token, Type, TypePath, TypeReference,
};
-use crate::utils::{parse_as_empty, prepend_underscore_to_self, ReplaceReceiver, SliceExt};
+use crate::utils::{ReplaceReceiver, SliceExt};
pub(crate) fn attribute(args: &TokenStream, mut input: ItemImpl) -> TokenStream {
let res = (|| -> Result<()> {
- parse_as_empty(args)?;
+ if !args.is_empty() {
+ bail!(args, "unexpected argument: `{}`", args)
+ }
validate_impl(&input)?;
expand_impl(&mut input);
Ok(())
@@ -85,7 +87,7 @@ fn validate_impl(item: &ItemImpl) -> Result<()> {
ImplItem::Type(item) => {
bail!(item, "type `{}` is not a member of trait `PinnedDrop`", item.ident)
}
- ImplItem::Method(method) => {
+ ImplItem::Fn(method) => {
validate_sig(&method.sig)?;
if i == 0 {
Ok(())
@@ -124,14 +126,15 @@ fn validate_sig(sig: &Signature) -> Result<()> {
match sig.inputs.len() {
1 => {}
- 0 => return Err(Error::new(sig.paren_token.span, INVALID_ARGUMENT)),
+ 0 => return Err(Error::new(sig.paren_token.span.join(), INVALID_ARGUMENT)),
_ => bail!(sig.inputs, INVALID_ARGUMENT),
}
- if let Some(FnArg::Typed(arg)) = sig.receiver() {
+ if let Some(arg) = sig.receiver() {
// (mut) self: <path>
if let Some(path) = get_ty_path(&arg.ty) {
- let ty = path.segments.last().unwrap();
+ let ty =
+ path.segments.last().expect("Type paths should always have at least one segment");
if let PathArguments::AngleBracketed(args) = &ty.arguments {
// (mut) self: (<path>::)<ty><&mut <elem>..>
if let Some(GenericArgument::Type(Type::Reference(TypeReference {
@@ -175,25 +178,16 @@ fn validate_sig(sig: &Signature) -> Result<()> {
// }
//
fn expand_impl(item: &mut ItemImpl) {
- fn get_arg_pat(arg: &mut FnArg) -> Option<&mut PatIdent> {
- if let FnArg::Typed(arg) = arg {
- if let Pat::Ident(ident) = &mut *arg.pat {
- return Some(ident);
- }
- }
- None
- }
-
// `PinnedDrop` is a private trait and should not appear in docs.
item.attrs.push(parse_quote!(#[doc(hidden)]));
- let path = &mut item.trait_.as_mut().unwrap().1;
+ let path = &mut item.trait_.as_mut().expect("unexpected inherent impl").1;
*path = parse_quote_spanned! { path.span() =>
::pin_project::__private::PinnedDrop
};
let method =
- if let ImplItem::Method(method) = &mut item.items[0] { method } else { unreachable!() };
+ if let ImplItem::Fn(method) = &mut item.items[0] { method } else { unreachable!() };
// `fn drop(mut self: Pin<&mut Self>)` -> `fn __drop_inner<T>(mut __self: Pin<&mut Receiver>)`
let drop_inner = {
@@ -203,8 +197,20 @@ fn expand_impl(item: &mut ItemImpl) {
drop_inner.block.stmts.insert(0, parse_quote!(fn #ident() {}));
drop_inner.sig.ident = ident;
drop_inner.sig.generics = item.generics.clone();
- let self_pat = get_arg_pat(&mut drop_inner.sig.inputs[0]).unwrap();
- prepend_underscore_to_self(&mut self_pat.ident);
+ let receiver = drop_inner.sig.receiver().expect("drop() should have a receiver").clone();
+ let pat = Box::new(Pat::Ident(PatIdent {
+ attrs: Vec::new(),
+ by_ref: None,
+ mutability: receiver.mutability,
+ ident: Ident::new("__self", receiver.self_token.span()),
+ subpat: None,
+ }));
+ drop_inner.sig.inputs[0] = FnArg::Typed(PatType {
+ attrs: receiver.attrs,
+ pat,
+ colon_token: Colon::default(),
+ ty: receiver.ty,
+ });
let self_ty = if let Type::Path(ty) = &*item.self_ty { ty } else { unreachable!() };
let mut visitor = ReplaceReceiver(self_ty);
visitor.visit_signature_mut(&mut drop_inner.sig);
@@ -214,9 +220,12 @@ fn expand_impl(item: &mut ItemImpl) {
// `fn drop(mut self: Pin<&mut Self>)` -> `unsafe fn drop(self: Pin<&mut Self>)`
method.sig.unsafety = Some(<Token![unsafe]>::default());
- let self_pat = get_arg_pat(&mut method.sig.inputs[0]).unwrap();
- self_pat.mutability = None;
- let self_token = &self_pat.ident;
+ let self_token = if let FnArg::Receiver(ref mut rec) = method.sig.inputs[0] {
+ rec.mutability = None;
+ &rec.self_token
+ } else {
+ panic!("drop() should have a receiver")
+ };
method.block.stmts = parse_quote! {
#[allow(clippy::needless_pass_by_value)] // This lint does not warn the receiver.
diff --git a/src/utils.rs b/src/utils.rs
index 27373ef..3f4ec85 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -8,7 +8,7 @@ use syn::{
punctuated::Punctuated,
token,
visit_mut::{self, VisitMut},
- Attribute, ExprPath, ExprStruct, Generics, Ident, Item, Lifetime, LifetimeDef, Macro, PatPath,
+ Attribute, ExprPath, ExprStruct, Generics, Ident, Item, Lifetime, LifetimeParam, Macro,
PatStruct, PatTupleStruct, Path, PathArguments, PredicateType, QSelf, Result, Token, Type,
TypeParamBound, TypePath, Variant, Visibility, WherePredicate,
};
@@ -42,7 +42,7 @@ pub(crate) fn determine_lifetime_name(lifetime_name: &mut String, generics: &mut
struct CollectLifetimes(Vec<String>);
impl VisitMut for CollectLifetimes {
- fn visit_lifetime_def_mut(&mut self, def: &mut LifetimeDef) {
+ fn visit_lifetime_param_mut(&mut self, def: &mut LifetimeParam) {
self.0.push(def.lifetime.to_string());
}
}
@@ -84,7 +84,7 @@ pub(crate) fn insert_lifetime_and_bound(
pub(crate) fn insert_lifetime(generics: &mut Generics, lifetime: Lifetime) {
generics.lt_token.get_or_insert_with(<Token![<]>::default);
generics.gt_token.get_or_insert_with(<Token![>]>::default);
- generics.params.insert(0, LifetimeDef::new(lifetime).into());
+ generics.params.insert(0, LifetimeParam::new(lifetime).into());
}
/// Determines the visibility of the projected types and projection methods.
@@ -93,24 +93,12 @@ pub(crate) fn insert_lifetime(generics: &mut Generics, lifetime: Lifetime) {
/// Otherwise, returned visibility is the same as given visibility.
pub(crate) fn determine_visibility(vis: &Visibility) -> Visibility {
if let Visibility::Public(token) = vis {
- parse_quote_spanned!(token.pub_token.span => pub(crate))
+ parse_quote_spanned!(token.span => pub(crate))
} else {
vis.clone()
}
}
-/// Checks if `tokens` is an empty `TokenStream`.
-///
-/// This is almost equivalent to `syn::parse2::<Nothing>()`, but produces
-/// a better error message and does not require ownership of `tokens`.
-pub(crate) fn parse_as_empty(tokens: &TokenStream) -> Result<()> {
- if tokens.is_empty() {
- Ok(())
- } else {
- bail!(tokens, "unexpected token: `{}`", tokens)
- }
-}
-
pub(crate) fn respan<T>(node: &T, span: Span) -> T
where
T: ToTokens + Parse,
@@ -146,11 +134,11 @@ impl SliceExt for [Attribute] {
fn position_exact(&self, ident: &str) -> Result<Option<usize>> {
self.iter()
.try_fold((0, None), |(i, mut prev), attr| {
- if attr.path.is_ident(ident) {
+ if attr.path().is_ident(ident) {
if prev.replace(i).is_some() {
bail!(attr, "duplicate #[{}] attribute", ident);
}
- parse_as_empty(&attr.tokens)?;
+ attr.meta.require_path_only()?;
}
Ok((i + 1, prev))
})
@@ -158,7 +146,7 @@ impl SliceExt for [Attribute] {
}
fn find(&self, ident: &str) -> Option<&Attribute> {
- self.iter().position(|attr| attr.path.is_ident(ident)).map(|i| &self[i])
+ self.iter().position(|attr| attr.path().is_ident(ident)).map(|i| &self[i])
}
}
@@ -335,13 +323,6 @@ impl VisitMut for ReplaceReceiver<'_> {
visit_mut::visit_expr_struct_mut(self, expr);
}
- fn visit_pat_path_mut(&mut self, pat: &mut PatPath) {
- if pat.qself.is_none() {
- self.self_to_qself(&mut pat.qself, &mut pat.path);
- }
- visit_mut::visit_pat_path_mut(self, pat);
- }
-
fn visit_pat_struct_mut(&mut self, pat: &mut PatStruct) {
self.self_to_expr_path(&mut pat.path);
visit_mut::visit_pat_struct_mut(self, pat);