Skip to content

Commit 3ac3432

Browse files
committed
Allow other attributes in #[pin_data] structs
When the `__pin_data!(find_pinned_fields:` part of the macro encounters an unknown attribute (anything apart from `$[pin]`) before a field, it is put into the accumulator and the macro proceeds further. Whatever is in the accumulator is later saved into `$fields` and then also into `$pinned` or `$not_pinned` depending on whether that field is pinned. Pinned fields, with all their unknown attributes are also used in the internal `__Unpin` struct. A field can have multiple different attributes, mostly belonging into two different categories. Built-in (defined by the language itself) and arbitrary (any other attribute that is used by another proc-macro crate). Out of the built-in ones [1] the only things that make sense to be usable for struct fields are most probably just "cfg", "doc", lint levels ("allow", "expect", "warn", "deny", "forbid"), and "deprecated". Out of these the only one that makes sense to keep around for the pin_data macro is "cfg" since that one does a conditional compilation and we only want the members to be included if they are included in the original struct. From the arbitrary (basically unknown) ones there is no reason for them to be used, mainly because they will likely be part of a derive which will not be included for the `__Unpin` struct, therefore making the code fail to compile if included. Since those need to be kept for the original struct, move them to the `$fields` instead of `$accum` in order not to pollute the `struct __Unpin` with unknown attributes. To put this all together, add a test with a custom attribute that fails without this fix. Unfortunately, another crate needs to be added for the test. [1] https://doc.rust-lang.org/reference/attributes.html#built-in-attributes-index Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
1 parent bc137a3 commit 3ac3432

File tree

7 files changed

+92
-3
lines changed

7 files changed

+92
-3
lines changed

Cargo.lock

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ trybuild = { version = "1.0", features = ["diff"] }
3232
macrotest = "1.0"
3333
# needed for macrotest, have to enable verbatim feature to be able to format `&raw` expressions.
3434
prettyplease = { version = "0.2", features = ["verbatim"] }
35+
test_dummy_only = { path = "./test_dummy_only" }
3536

3637
[lints.rust]
3738
non_ascii_idents = "deny"

src/macros.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -779,8 +779,9 @@ macro_rules! __pin_data {
779779
@ty_generics($($ty_generics:tt)*),
780780
@decl_generics($($decl_generics:tt)*),
781781
@where($($whr:tt)*),
782-
// Some other attribute, just put it into `$accum`.
783-
@fields_munch(#[$($attr:tt)*] $($rest:tt)*),
782+
// The #[cfg] attribute needs to be kept for our fields to make sense,
783+
// so put it into `$accum`.
784+
@fields_munch(#[cfg $($attr:tt)*] $($rest:tt)*),
784785
@pinned($($pinned:tt)*),
785786
@not_pinned($($not_pinned:tt)*),
786787
@fields($($fields:tt)*),
@@ -800,7 +801,42 @@ macro_rules! __pin_data {
800801
@pinned($($pinned)*),
801802
@not_pinned($($not_pinned)*),
802803
@fields($($fields)*),
803-
@accum($($accum)* #[$($attr)*]),
804+
@accum($($accum)* #[cfg $($attr)*]),
805+
@is_pinned($($is_pinned)?),
806+
@pinned_drop($($pinned_drop)?),
807+
);
808+
};
809+
(find_pinned_fields:
810+
@struct_attrs($($struct_attrs:tt)*),
811+
@vis($vis:vis),
812+
@name($name:ident),
813+
@impl_generics($($impl_generics:tt)*),
814+
@ty_generics($($ty_generics:tt)*),
815+
@decl_generics($($decl_generics:tt)*),
816+
@where($($whr:tt)*),
817+
// Some other attribute, we only need to keep it for the original
818+
// struct, just put it into `$fields`.
819+
@fields_munch(#[$($attr:tt)*] $($rest:tt)*),
820+
@pinned($($pinned:tt)*),
821+
@not_pinned($($not_pinned:tt)*),
822+
@fields($($fields:tt)*),
823+
@accum($($accum:tt)*),
824+
@is_pinned($($is_pinned:ident)?),
825+
@pinned_drop($($pinned_drop:ident)?),
826+
) => {
827+
$crate::__pin_data!(find_pinned_fields:
828+
@struct_attrs($($struct_attrs)*),
829+
@vis($vis),
830+
@name($name),
831+
@impl_generics($($impl_generics)*),
832+
@ty_generics($($ty_generics)*),
833+
@decl_generics($($decl_generics)*),
834+
@where($($whr)*),
835+
@fields_munch($($rest)*),
836+
@pinned($($pinned)*),
837+
@not_pinned($($not_pinned)*),
838+
@fields($($fields)* #[$($attr)*]),
839+
@accum($($accum)*),
804840
@is_pinned($($is_pinned)?),
805841
@pinned_drop($($pinned_drop)?),
806842
);

test_dummy_only/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test_dummy_only/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "test_dummy_only"
3+
version = "0.0.1"
4+
edition = "2021"
5+
6+
authors = ["y86-dev"]
7+
license = "MIT OR Apache-2.0"
8+
description = "Proc macro only for test reproduction."
9+
10+
publish = false
11+
12+
[lib]
13+
proc-macro = true

test_dummy_only/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#[proc_macro_derive(Dummy, attributes(dummy_attr))]
2+
pub fn derive_device(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
3+
proc_macro::TokenStream::new()
4+
}

tests/extra_attrs.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
2+
3+
use pinned_init::*;
4+
use test_dummy_only::Dummy;
5+
6+
#[pin_data]
7+
#[derive(Dummy)]
8+
struct Pointless {
9+
#[pin]
10+
#[dummy_attr]
11+
#[cfg(test)]
12+
member: i8,
13+
#[pin]
14+
#[dummy_attr]
15+
#[cfg(not(test))]
16+
member: u8,
17+
}
18+
19+
#[test]
20+
fn multiple_attributes() {
21+
stack_pin_init!(let p = init!(Pointless { member: 0 }));
22+
println!("{}", p.member);
23+
}

0 commit comments

Comments
 (0)