diff --git a/Cargo.lock b/Cargo.lock index 5766ef8d..80cf21f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,10 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" +[[package]] +name = "dummy" +version = "0.0.0" + [[package]] name = "equivalent" version = "1.0.1" @@ -87,6 +91,7 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" name = "pin-init" version = "0.0.10" dependencies = [ + "dummy", "libc", "macrotest", "paste", diff --git a/Cargo.toml b/Cargo.toml index 2edd1efd..de2f91ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ trybuild = { version = "1.0", features = ["diff"] } macrotest = "1.0" # needed for macrotest, have to enable verbatim feature to be able to format `&raw` expressions. prettyplease = { version = "0.2.37", features = ["verbatim"] } +dummy = { path = "tests/dummy" } [lints.rust] stable_features = "allow" diff --git a/internal/src/pin_data.rs b/internal/src/pin_data.rs index 7d871236..076df838 100644 --- a/internal/src/pin_data.rs +++ b/internal/src/pin_data.rs @@ -7,7 +7,7 @@ use syn::{ parse_quote, parse_quote_spanned, spanned::Spanned, visit_mut::VisitMut, - Field, Generics, Ident, Item, PathSegment, Type, TypePath, Visibility, WhereClause, + Attribute, Field, Generics, Ident, Item, PathSegment, Type, TypePath, Visibility, WhereClause, }; use crate::diagnostics::{DiagCtxt, ErrorGuaranteed}; @@ -35,6 +35,11 @@ impl Parse for Args { } } +fn keep_attr(a: &Attribute) -> bool { + let p = a.path(); + ["cfg", "doc"].iter().any(|a| p.is_ident(a)) +} + pub(crate) fn pin_data( args: Args, input: Item, @@ -77,9 +82,9 @@ pub(crate) fn pin_data( .fields .iter_mut() .map(|field| { - let len = field.attrs.len(); - field.attrs.retain(|a| !a.path().is_ident("pin")); - (len != field.attrs.len(), &*field) + let pinned = field.attrs.iter().any(|a| a.path().is_ident("pin")); + field.attrs.retain(keep_attr); + (pinned, &*field) }) .collect(); @@ -259,7 +264,7 @@ fn generate_projections( }, )| { let mut attrs = attrs.clone(); - attrs.retain(|a| !a.path().is_ident("pin")); + attrs.retain(keep_attr); let mut no_doc_attrs = attrs.clone(); no_doc_attrs.retain(|a| !a.path().is_ident("doc")); let ident = ident @@ -359,7 +364,7 @@ fn generate_the_pin_data( pinned: bool, ) -> TokenStream { let mut attrs = attrs.clone(); - attrs.retain(|a| !a.path().is_ident("pin")); + attrs.retain(keep_attr); let ident = ident .as_ref() .expect("only structs with named fields are supported"); diff --git a/tests/dummy/Cargo.toml b/tests/dummy/Cargo.toml new file mode 100644 index 00000000..366378e9 --- /dev/null +++ b/tests/dummy/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "dummy" +version = "0.0.0" +edition = "2024" + +license = "MIT OR Apache-2.0" +description = "Proc macro only for test reproduction." + +publish = false + +[lib] +proc-macro = true diff --git a/tests/dummy/src/lib.rs b/tests/dummy/src/lib.rs new file mode 100644 index 00000000..0ea09257 --- /dev/null +++ b/tests/dummy/src/lib.rs @@ -0,0 +1,4 @@ +#[proc_macro_derive(Dummy, attributes(dummy_attr))] +pub fn derive_device(_: proc_macro::TokenStream) -> proc_macro::TokenStream { + proc_macro::TokenStream::new() +} diff --git a/tests/extra_attrs.rs b/tests/extra_attrs.rs new file mode 100644 index 00000000..4701f04c --- /dev/null +++ b/tests/extra_attrs.rs @@ -0,0 +1,21 @@ +use dummy::Dummy; +use pin_init::*; + +#[pin_data] +#[derive(Dummy)] +struct Pointless { + #[pin] + #[dummy_attr] + #[cfg(test)] + member: i8, + #[pin] + #[dummy_attr] + #[cfg(not(test))] + member: u8, +} + +#[test] +fn multiple_attributes() { + stack_pin_init!(let p = init!(Pointless { member: 0 })); + println!("{}", p.member); +}