Skip to content

Commit

Permalink
Merge #31
Browse files Browse the repository at this point in the history
31: Detect invalid attribute arguments r=taiki-e a=taiki-e



Co-authored-by: Taiki Endo <te316e89@gmail.com>
  • Loading branch information
bors[bot] and taiki-e committed Aug 5, 2019
2 parents bef01ec + 6872d8d commit 817b7bc
Show file tree
Hide file tree
Showing 12 changed files with 275 additions and 134 deletions.
17 changes: 8 additions & 9 deletions pin-project-internal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,26 @@ mod project;

use proc_macro::TokenStream;

use crate::utils::Nothing;

#[cfg(feature = "project_attr")]
#[proc_macro_attribute]
pub fn project(args: TokenStream, input: TokenStream) -> TokenStream {
assert!(args.is_empty());
TokenStream::from(project::attribute(input.into()))
let _: Nothing = syn::parse_macro_input!(args);
project::attribute(input.into()).into()
}

/// This is a doc comment from the defining crate!
#[proc_macro]
pub fn pin_project(input: TokenStream) -> TokenStream {
TokenStream::from(
pin_projectable::pin_project(input.into()).unwrap_or_else(|e| e.to_compile_error()),
)
pin_projectable::pin_project(input.into()).unwrap_or_else(|e| e.to_compile_error()).into()
}

#[proc_macro_attribute]
pub fn pin_projectable(args: TokenStream, input: TokenStream) -> TokenStream {
TokenStream::from(
pin_projectable::attribute(args.into(), input.into())
.unwrap_or_else(|e| e.to_compile_error()),
)
pin_projectable::attribute(args.into(), input.into())
.unwrap_or_else(|e| e.to_compile_error())
.into()
}

#[cfg(feature = "renamed")]
Expand Down
129 changes: 71 additions & 58 deletions pin-project-internal/src/pin_projectable/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub(super) fn parse(
}

let proj_ident = proj_ident(&item.ident);
let (proj_item_body, proj_arms) = variants(&mut item, &proj_ident, &mut impl_unpin);
let (proj_item_body, proj_arms) = variants(&mut item, &proj_ident, &mut impl_unpin)?;

let ident = &item.ident;
let proj_generics = proj_generics(&item.generics);
Expand Down Expand Up @@ -65,24 +65,29 @@ fn variants(
ItemEnum { variants, ident: enum_ident, .. }: &mut ItemEnum,
proj_ident: &Ident,
impl_unpin: &mut ImplUnpin,
) -> (TokenStream, TokenStream) {
) -> Result<(TokenStream, TokenStream)> {
let mut arm_vec = Vec::with_capacity(variants.len());
let mut ty_vec = Vec::with_capacity(variants.len());
variants.iter_mut().for_each(|Variant { fields, ident, .. }| {
let (proj_arm, proj_ty) = match fields {
Fields::Unnamed(fields) => unnamed(fields, ident, enum_ident, proj_ident, impl_unpin),
Fields::Named(fields) => named(fields, ident, enum_ident, proj_ident, impl_unpin),
Fields::Unit => unit(ident, enum_ident, proj_ident),
};

arm_vec.push(proj_arm);
ty_vec.push(proj_ty);
});

let proj_item_body = quote!({ #(#ty_vec,)* });
let proj_arms = quote!(#(#arm_vec,)*);

(proj_item_body, proj_arms)
variants
.iter_mut()
.try_for_each(|Variant { fields, ident, .. }| {
let (proj_arm, proj_ty) = match fields {
Fields::Unnamed(fields) => {
unnamed(fields, ident, enum_ident, proj_ident, impl_unpin)?
}
Fields::Named(fields) => named(fields, ident, enum_ident, proj_ident, impl_unpin)?,
Fields::Unit => unit(ident, enum_ident, proj_ident),
};

arm_vec.push(proj_arm);
ty_vec.push(proj_ty);
Ok(())
})
.map(|()| {
let proj_item_body = quote!({ #(#ty_vec,)* });
let proj_arms = quote!(#(#arm_vec,)*);
(proj_item_body, proj_arms)
})
}

fn named(
Expand All @@ -91,29 +96,33 @@ fn named(
enum_ident: &Ident,
proj_ident: &Ident,
impl_unpin: &mut ImplUnpin,
) -> (TokenStream, TokenStream) {
) -> Result<(TokenStream, TokenStream)> {
let mut pat_vec = Vec::with_capacity(fields.len());
let mut expr_vec = Vec::with_capacity(fields.len());
let mut ty_vec = Vec::with_capacity(fields.len());
fields.iter_mut().for_each(|Field { attrs, ident, ty, .. }| {
if attrs.find_remove(PIN) {
impl_unpin.push(ty);
expr_vec.push(quote!(#ident: ::core::pin::Pin::new_unchecked(#ident)));
ty_vec.push(quote!(#ident: ::core::pin::Pin<&'__a mut #ty>));
} else {
expr_vec.push(quote!(#ident: #ident));
ty_vec.push(quote!(#ident: &'__a mut #ty));
}

pat_vec.push(ident);
});

let proj_arm = quote! {
#enum_ident::#variant_ident { #(#pat_vec),* } => #proj_ident::#variant_ident { #(#expr_vec),* }
};
let proj_ty = quote!(#variant_ident { #(#ty_vec),* });
fields
.iter_mut()
.try_for_each(|Field { attrs, ident, ty, .. }| {
if let Some(attr) = attrs.find_remove(PIN) {
let _: Nothing = syn::parse2(attr.tts)?;
impl_unpin.push(ty);
expr_vec.push(quote!(#ident: ::core::pin::Pin::new_unchecked(#ident)));
ty_vec.push(quote!(#ident: ::core::pin::Pin<&'__a mut #ty>));
} else {
expr_vec.push(quote!(#ident: #ident));
ty_vec.push(quote!(#ident: &'__a mut #ty));
}

(proj_arm, proj_ty)
pat_vec.push(ident);
Ok(())
})
.map(|()| {
let proj_arm = quote! {
#enum_ident::#variant_ident { #(#pat_vec),* } => #proj_ident::#variant_ident { #(#expr_vec),* }
};
let proj_ty = quote!(#variant_ident { #(#ty_vec),* });
(proj_arm, proj_ty)
})
}

fn unnamed(
Expand All @@ -122,31 +131,36 @@ fn unnamed(
enum_ident: &Ident,
proj_ident: &Ident,
impl_unpin: &mut ImplUnpin,
) -> (TokenStream, TokenStream) {
) -> Result<(TokenStream, TokenStream)> {
let mut pat_vec = Vec::with_capacity(fields.len());
let mut expr_vec = Vec::with_capacity(fields.len());
let mut ty_vec = Vec::with_capacity(fields.len());
fields.iter_mut().enumerate().for_each(|(i, Field { attrs, ty, .. })| {
let x = Ident::new(&format!("_x{}", i), Span::call_site());

if attrs.find_remove(PIN) {
impl_unpin.push(ty);
expr_vec.push(quote!(::core::pin::Pin::new_unchecked(#x)));
ty_vec.push(quote!(::core::pin::Pin<&'__a mut #ty>));
} else {
expr_vec.push(quote!(#x));
ty_vec.push(quote!(&'__a mut #ty));
}

pat_vec.push(x);
});

let proj_arm = quote! {
#enum_ident::#variant_ident(#(#pat_vec),*) => #proj_ident::#variant_ident(#(#expr_vec),*)
};
let proj_ty = quote!(#variant_ident(#(#ty_vec),*));
fields
.iter_mut()
.enumerate()
.try_for_each(|(i, Field { attrs, ty, .. })| {
let x = Ident::new(&format!("_x{}", i), Span::call_site());

if let Some(attr) = attrs.find_remove(PIN) {
let _: Nothing = syn::parse2(attr.tts)?;
impl_unpin.push(ty);
expr_vec.push(quote!(::core::pin::Pin::new_unchecked(#x)));
ty_vec.push(quote!(::core::pin::Pin<&'__a mut #ty>));
} else {
expr_vec.push(quote!(#x));
ty_vec.push(quote!(&'__a mut #ty));
}

(proj_arm, proj_ty)
pat_vec.push(x);
Ok(())
})
.map(|()| {
let proj_arm = quote! {
#enum_ident::#variant_ident(#(#pat_vec),*) => #proj_ident::#variant_ident(#(#expr_vec),*)
};
let proj_ty = quote!(#variant_ident(#(#ty_vec),*));
(proj_arm, proj_ty)
})
}

fn unit(
Expand All @@ -158,6 +172,5 @@ fn unit(
#enum_ident::#variant_ident => #proj_ident::#variant_ident
};
let proj_ty = quote!(#variant_ident);

(proj_arm, proj_ty)
}
32 changes: 14 additions & 18 deletions pin-project-internal/src/pin_projectable/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use syn::{
Type, TypeTuple,
};

use crate::utils::VecExt;
use crate::utils::{Nothing, VecExt};

mod enums;
mod structs;
Expand Down Expand Up @@ -55,10 +55,7 @@ pub(super) fn pin_project(input: TokenStream) -> Result<TokenStream> {
match &mut item {
Item::Struct(ItemStruct { attrs, .. }) | Item::Enum(ItemEnum { attrs, .. }) => {
if found_type.is_none() {
if let Some(pos) = attrs.iter().position(|a| a.path.is_ident("pin_projectable")) {
// Remove the 'pin_projectable' attribute, to prevent it from
// being parsed again
let attr = attrs.remove(pos);
if let Some(attr) = attrs.find_remove("pin_projectable") {
let args = match attr.parse_meta()? {
Meta::List(l) => l.nested.into_token_stream(),
Meta::Word(_) => TokenStream::new(),
Expand All @@ -74,7 +71,8 @@ pub(super) fn pin_project(input: TokenStream) -> Result<TokenStream> {
}
},
Item::Fn(fn_) => {
if fn_.attrs.find_remove(PINNED_DROP) {
if let Some(attr)= fn_.attrs.find_remove(PINNED_DROP) {
let _: Nothing = syn::parse2(attr.tts)?;
if found_pinned_drop.is_none() {
if let ReturnType::Type(_, ty) = &fn_.decl.output {
match &**ty {
Expand Down Expand Up @@ -111,18 +109,16 @@ pub(super) fn attribute(args: TokenStream, input: TokenStream) -> Result<TokenSt
}

fn ensure_not_packed(attrs: &[Attribute]) -> Result<()> {
for attr in attrs {
if let Ok(meta) = attr.parse_meta() {
if let Meta::List(l) = meta {
if l.ident == "repr" {
for repr in l.nested.iter() {
if let NestedMeta::Meta(Meta::Word(w)) = repr {
if w == "packed" {
return Err(error!(
w,
"pin_projectable may not be used on #[repr(packed)] types"
));
}
for meta in attrs.iter().filter_map(|attr| attr.parse_meta().ok()) {
if let Meta::List(l) = meta {
if l.ident == "repr" {
for repr in l.nested.iter() {
if let NestedMeta::Meta(Meta::Word(w)) = repr {
if w == "packed" {
return Err(error!(
w,
"pin_projectable may not be used on #[repr(packed)] types"
));
}
}
}
Expand Down
81 changes: 45 additions & 36 deletions pin-project-internal/src/pin_projectable/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::{Field, Fields, FieldsNamed, FieldsUnnamed, Index, ItemStruct, Result};

use crate::utils::{proj_ident, VecExt};
use crate::utils::{proj_ident, Nothing, VecExt};

use super::*;

Expand All @@ -23,8 +23,8 @@ pub(super) fn parse(
}
Fields::Unit => return Err(error!(item, "cannot be implemented for structs with units")),

Fields::Named(fields) => named(fields, &mut impl_unpin),
Fields::Unnamed(fields) => unnamed(fields, &mut impl_unpin),
Fields::Named(fields) => named(fields, &mut impl_unpin)?,
Fields::Unnamed(fields) => unnamed(fields, &mut impl_unpin)?,
};

let ident = &item.ident;
Expand Down Expand Up @@ -58,46 +58,55 @@ pub(super) fn parse(
fn named(
FieldsNamed { named: fields, .. }: &mut FieldsNamed,
impl_unpin: &mut ImplUnpin,
) -> (TokenStream, TokenStream) {
) -> Result<(TokenStream, TokenStream)> {
let mut proj_fields = Vec::with_capacity(fields.len());
let mut proj_init = Vec::with_capacity(fields.len());
fields.iter_mut().for_each(|Field { attrs, ident, ty, .. }| {
if attrs.find_remove(PIN) {
impl_unpin.push(ty);
proj_fields.push(quote!(#ident: ::core::pin::Pin<&'__a mut #ty>));
proj_init.push(quote!(#ident: ::core::pin::Pin::new_unchecked(&mut this.#ident)));
} else {
proj_fields.push(quote!(#ident: &'__a mut #ty));
proj_init.push(quote!(#ident: &mut this.#ident));
}
});

let proj_item_body = quote!({ #(#proj_fields,)* });
let proj_init_body = quote!({ #(#proj_init,)* });

(proj_item_body, proj_init_body)
fields
.iter_mut()
.try_for_each(|Field { attrs, ident, ty, .. }| {
if let Some(attr) = attrs.find_remove(PIN) {
let _: Nothing = syn::parse2(attr.tts)?;
impl_unpin.push(ty);
proj_fields.push(quote!(#ident: ::core::pin::Pin<&'__a mut #ty>));
proj_init.push(quote!(#ident: ::core::pin::Pin::new_unchecked(&mut this.#ident)));
} else {
proj_fields.push(quote!(#ident: &'__a mut #ty));
proj_init.push(quote!(#ident: &mut this.#ident));
}
Ok(())
})
.map(|()| {
let proj_item_body = quote!({ #(#proj_fields,)* });
let proj_init_body = quote!({ #(#proj_init,)* });
(proj_item_body, proj_init_body)
})
}

fn unnamed(
FieldsUnnamed { unnamed: fields, .. }: &mut FieldsUnnamed,
impl_unpin: &mut ImplUnpin,
) -> (TokenStream, TokenStream) {
) -> Result<(TokenStream, TokenStream)> {
let mut proj_fields = Vec::with_capacity(fields.len());
let mut proj_init = Vec::with_capacity(fields.len());
fields.iter_mut().enumerate().for_each(|(i, Field { attrs, ty, .. })| {
let i = Index::from(i);
if attrs.find_remove(PIN) {
impl_unpin.push(ty);
proj_fields.push(quote!(::core::pin::Pin<&'__a mut #ty>));
proj_init.push(quote!(::core::pin::Pin::new_unchecked(&mut this.#i)));
} else {
proj_fields.push(quote!(&'__a mut #ty));
proj_init.push(quote!(&mut this.#i));
}
});

let proj_item_body = quote!((#(#proj_fields,)*););
let proj_init_body = quote!((#(#proj_init,)*));

(proj_item_body, proj_init_body)
fields
.iter_mut()
.enumerate()
.try_for_each(|(i, Field { attrs, ty, .. })| {
let i = Index::from(i);
if let Some(attr) = attrs.find_remove(PIN) {
let _: Nothing = syn::parse2(attr.tts)?;
impl_unpin.push(ty);
proj_fields.push(quote!(::core::pin::Pin<&'__a mut #ty>));
proj_init.push(quote!(::core::pin::Pin::new_unchecked(&mut this.#i)));
} else {
proj_fields.push(quote!(&'__a mut #ty));
proj_init.push(quote!(&mut this.#i));
}
Ok(())
})
.map(|()| {
let proj_item_body = quote!((#(#proj_fields,)*););
let proj_init_body = quote!((#(#proj_init,)*));
(proj_item_body, proj_init_body)
})
}
Loading

0 comments on commit 817b7bc

Please sign in to comment.