From 3838cfe40620db58140532895179150562b1a3b1 Mon Sep 17 00:00:00 2001 From: Juniper Tyree <50025784+juntyr@users.noreply.github.com> Date: Sat, 5 Oct 2024 15:12:45 +0000 Subject: [PATCH 1/2] Upgrade to syn v2.0 --- const-type-layout-derive/Cargo.toml | 2 +- const-type-layout-derive/src/lib.rs | 194 ++++++++++++---------------- 2 files changed, 85 insertions(+), 111 deletions(-) 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..ed7cbfd 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,88 @@ 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| { + if meta.path.is_ident("free") { + match meta + .value() + .and_then(::parse) + .and_then(|s| 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`.", + meta.path.span(), + "[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!( + meta.path.span(), + "[const-type-layout]: Invalid #[layout(free = \"\")] \ + attribute: {}.", + err + ), } - } else { - emit_error!( - meta.span(), - "[const-type-layout]: Expected #[layout(attr = \"value\")] syntax." - ); - } + } else if meta.path.is_ident("bound") { + match meta + .value() + .and_then(::parse) + .and_then(|s| syn::parse_str::(&s.value())) + { + Ok(bound) => extra_bounds.push(bound), + Err(err) => emit_error!( + meta.path.span(), + "[const-type-layout]: Invalid #[layout(bound = \ + \"\")] attribute: {}.", + err + ), + } + } else if meta.path.is_ident("crate") { + match meta + .value() + .and_then(::parse) + .and_then(|s| syn::parse_str::(&s.value())) + { + Ok(new_crate_path) => { + if crate_path.is_none() { + crate_path = Some( + syn::parse_quote_spanned! { meta.path.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!( + meta.path.span(), + "[const-type-layout]: Invalid #[layout(crate = \ + \"\")] attribute: {}.", + err + ), + } + } else { + emit_error!( + 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 +257,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), From 74dca17fdecd0e27dca4236f43ff5c802c2318c6 Mon Sep 17 00:00:00 2001 From: Juniper Tyree <50025784+juntyr@users.noreply.github.com> Date: Sun, 6 Oct 2024 09:08:23 +0000 Subject: [PATCH 2/2] Improve attribute parsing error spans --- const-type-layout-derive/src/lib.rs | 84 +++++++++++++++-------------- try-crate/src/main.rs | 6 +-- 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/const-type-layout-derive/src/lib.rs b/const-type-layout-derive/src/lib.rs index ed7cbfd..1c5b691 100644 --- a/const-type-layout-derive/src/lib.rs +++ b/const-type-layout-derive/src/lib.rs @@ -155,21 +155,33 @@ fn parse_attributes(attrs: &[syn::Attribute], type_params: &mut Vec<&syn::Ident> } } else if attr.path().is_ident("layout") { #[allow(clippy::blocks_in_conditions)] - if attr.parse_nested_meta(|meta| { - if meta.path.is_ident("free") { - match meta - .value() - .and_then(::parse) - .and_then(|s| syn::parse_str::(&s.value())) - { + 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!( - meta.path.span(), + s.span(), "[const-type-layout]: Invalid #[layout(free)] \ - attribute: \"{}\" is either not a type parameter \ - or has already been freed (duplicate attribute).", + attribute: \"{}\" is either not a type parameter or \ + has already been freed (duplicate attribute).", param, ); }, @@ -179,62 +191,56 @@ fn parse_attributes(attrs: &[syn::Attribute], type_params: &mut Vec<&syn::Ident> ); }, Err(err) => emit_error!( - meta.path.span(), + s.span(), "[const-type-layout]: Invalid #[layout(free = \"\")] \ attribute: {}.", err ), } - } else if meta.path.is_ident("bound") { - match meta - .value() - .and_then(::parse) - .and_then(|s| syn::parse_str::(&s.value())) - { + } else if meta.path.is_ident("bound") { + match syn::parse_str::(&s.value()) { Ok(bound) => extra_bounds.push(bound), Err(err) => emit_error!( - meta.path.span(), + s.span(), "[const-type-layout]: Invalid #[layout(bound = \ \"\")] attribute: {}.", err ), } - } else if meta.path.is_ident("crate") { - match meta - .value() - .and_then(::parse) - .and_then(|s| syn::parse_str::(&s.value())) - { + } 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! { meta.path.span() => #new_crate_path }, + 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`.", + attribute: the crate path for `const-type-layout` can \ + only be set once per `derive`.", ); } }, Err(err) => emit_error!( - meta.path.span(), - "[const-type-layout]: Invalid #[layout(crate = \ - \"\")] attribute: {}.", + s.span(), + "[const-type-layout]: Invalid #[layout(crate = \"\")] \ + attribute: {}.", err ), } - } else { - emit_error!( - meta.path.span(), - "[const-type-layout]: Unknown attribute, use `bound`, `crate`, or \ - `free`." - ); - } - Ok(()) - }).is_err() { + } else { + emit_error!( + meta.path.span(), + "[const-type-layout]: Unknown attribute, use `bound`, `crate`, or \ + `free`." + ); + } + Ok(()) + }) + .is_err() + { emit_error!( attr.span(), "[const-type-layout]: Expected #[layout(attr = \"value\")] syntax." 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);