diff --git a/const-type-layout-derive/Cargo.toml b/const-type-layout-derive/Cargo.toml index e6152d0..874c4a8 100644 --- a/const-type-layout-derive/Cargo.toml +++ b/const-type-layout-derive/Cargo.toml @@ -16,7 +16,7 @@ proc-macro = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -syn = { version = "1.0", features = ["clone-impls", "derive", "parsing", "printing", "proc-macro"], default-features = false } +syn = { version = "2.0", features = ["clone-impls", "derive", "parsing", "printing", "proc-macro"], default-features = false } quote = { version = "1.0", default-features = false } proc-macro2 = { version = "1.0", default-features = false } proc-macro-error2 = { version = "2.0", default-features = false } diff --git a/const-type-layout-derive/src/lib.rs b/const-type-layout-derive/src/lib.rs index 728e06d..1c5b691 100644 --- a/const-type-layout-derive/src/lib.rs +++ b/const-type-layout-derive/src/lib.rs @@ -139,13 +139,13 @@ fn parse_attributes(attrs: &[syn::Attribute], type_params: &mut Vec<&syn::Ident> let mut crate_path = None; for attr in attrs { - if attr.path.is_ident("repr") { - if let Ok(syn::Meta::List(syn::MetaList { nested, .. })) = attr.parse_meta() { + #[allow(clippy::collapsible_if)] + if attr.path().is_ident("repr") { + if let Ok(nested) = attr.parse_args_with( + syn::punctuated::Punctuated::::parse_terminated, + ) { for meta in nested { - reprs.push(match meta { - syn::NestedMeta::Lit(lit) => lit_to_string(&lit), - syn::NestedMeta::Meta(meta) => meta_to_string(&meta), - }); + reprs.push(quote!(#meta).to_string()); } } else { emit_warning!( @@ -153,88 +153,94 @@ fn parse_attributes(attrs: &[syn::Attribute], type_params: &mut Vec<&syn::Ident> "[const-type-layout]: #[repr] attribute is not in meta list format." ); } - } else if attr.path.is_ident("layout") { - if let Ok(syn::Meta::List(list)) = attr.parse_meta() { - for meta in &list.nested { - if let syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue { - path, - lit: syn::Lit::Str(s), - .. - })) = &meta - { - if path.is_ident("free") { - match syn::parse_str::(&s.value()) { - Ok(param) => { - type_params.iter().position(|ty| **ty == param).map_or_else( - || { - emit_error!( - s.span(), - "[const-type-layout]: Invalid #[layout(free)] \ - attribute: \"{}\" is either not a type parameter \ - or has already been freed (duplicate attribute).", - param, - ); - }, - |i| { - type_params.swap_remove(i); - }, - ); - }, - Err(err) => emit_error!( - s.span(), - "[const-type-layout]: Invalid #[layout(free = \"\")] \ - attribute: {}.", - err - ), - } - } else if path.is_ident("bound") { - match syn::parse_str(&s.value()) { - Ok(bound) => extra_bounds.push(bound), - Err(err) => emit_error!( - s.span(), - "[const-type-layout]: Invalid #[layout(bound = \ - \"\")] attribute: {}.", - err - ), - } - } else if path.is_ident("crate") { - match syn::parse_str::(&s.value()) { - Ok(new_crate_path) => { - if crate_path.is_none() { - crate_path = Some( - syn::parse_quote_spanned! { s.span() => #new_crate_path }, - ); - } else { + } else if attr.path().is_ident("layout") { + #[allow(clippy::blocks_in_conditions)] + if attr + .parse_nested_meta(|meta| { + let Ok(value) = meta.value() else { + emit_error!( + meta.path.span(), + "[const-type-layout]: Expected #[layout(attr = \"value\")] syntax." + ); + return Ok(()); + }; + let Ok(s) = ::parse(value) else { + emit_error!( + value.span(), + "[const-type-layout]: Expected #[layout(attr = \"value\")] syntax." + ); + return Ok(()); + }; + + if meta.path.is_ident("free") { + match syn::parse_str::(&s.value()) { + Ok(param) => { + type_params.iter().position(|ty| **ty == param).map_or_else( + || { emit_error!( s.span(), - "[const-type-layout]: Duplicate #[layout(crate)] \ - attribute: the crate path for `const-type-layout` \ - can only be set once per `derive`.", + "[const-type-layout]: Invalid #[layout(free)] \ + attribute: \"{}\" is either not a type parameter or \ + has already been freed (duplicate attribute).", + param, ); - } - }, - Err(err) => emit_error!( - s.span(), - "[const-type-layout]: Invalid #[layout(crate = \ - \"\")] attribute: {}.", - err - ), - } - } else { - emit_error!( - path.span(), - "[const-type-layout]: Unknown attribute, use `bound`, `crate`, or \ - `free`." - ); + }, + |i| { + type_params.swap_remove(i); + }, + ); + }, + Err(err) => emit_error!( + s.span(), + "[const-type-layout]: Invalid #[layout(free = \"\")] \ + attribute: {}.", + err + ), + } + } else if meta.path.is_ident("bound") { + match syn::parse_str::(&s.value()) { + Ok(bound) => extra_bounds.push(bound), + Err(err) => emit_error!( + s.span(), + "[const-type-layout]: Invalid #[layout(bound = \ + \"\")] attribute: {}.", + err + ), + } + } else if meta.path.is_ident("crate") { + match syn::parse_str::(&s.value()) { + Ok(new_crate_path) => { + if crate_path.is_none() { + crate_path = Some( + syn::parse_quote_spanned! { s.span() => #new_crate_path }, + ); + } else { + emit_error!( + meta.path.span(), + "[const-type-layout]: Duplicate #[layout(crate)] \ + attribute: the crate path for `const-type-layout` can \ + only be set once per `derive`.", + ); + } + }, + Err(err) => emit_error!( + s.span(), + "[const-type-layout]: Invalid #[layout(crate = \"\")] \ + attribute: {}.", + err + ), } } else { emit_error!( - meta.span(), - "[const-type-layout]: Expected #[layout(attr = \"value\")] syntax." + meta.path.span(), + "[const-type-layout]: Unknown attribute, use `bound`, `crate`, or \ + `free`." ); } - } - } else { + Ok(()) + }) + .is_err() + { emit_error!( attr.span(), "[const-type-layout]: Expected #[layout(attr = \"value\")] syntax." @@ -257,32 +263,6 @@ fn parse_attributes(attrs: &[syn::Attribute], type_params: &mut Vec<&syn::Ident> } } -fn meta_to_string(meta: &syn::Meta) -> String { - match meta { - syn::Meta::List(syn::MetaList { path, nested, .. }) => { - let mut list = nested - .iter() - .map(|meta| match meta { - syn::NestedMeta::Lit(lit) => lit_to_string(lit), - syn::NestedMeta::Meta(meta) => meta_to_string(meta), - }) - .collect::>(); - list.sort(); - list.dedup(); - - format!("{}({})", quote!(#path), intersperse_commas(list)) - }, - syn::Meta::NameValue(syn::MetaNameValue { path, lit, .. }) => { - format!("{}={}", quote!(#path), lit_to_string(lit)) - }, - syn::Meta::Path(path) => quote!(#path).to_string(), - } -} - -fn lit_to_string(lit: &syn::Lit) -> String { - quote!(#lit).to_string().escape_default().to_string() -} - fn intersperse_commas(items: Vec) -> String { let mut acc = String::with_capacity( items.iter().map(String::len).sum::() + items.len().saturating_sub(1), diff --git a/try-crate/src/main.rs b/try-crate/src/main.rs index ba43b03..e21aca1 100644 --- a/try-crate/src/main.rs +++ b/try-crate/src/main.rs @@ -159,12 +159,8 @@ pub struct MyPhantomData { #[repr(transparent)] pub struct Wrapper(f64); -// FIXME: move bound from where clause to impl bound -// https://github.com/dtolnay/syn/issues/1238 #[derive(TypeLayout)] -pub struct Bounded(T) -where - T: std::fmt::Debug + TypeGraphLayout; +pub struct Bounded(T); fn main() { println!("{:#?}", Foo1::TYPE_GRAPH);