Skip to content

Commit 974a783

Browse files
committed
internal: add syn version of [try_][pin_]init! macros
Implement the `[try_][pin_]init!` derive macro using syn to simplify parsing by not going through an additional declarative macro. This not only simplifies the code by a lot, increasing maintainability and making it easier to implement new features. But also improves the user experience by improving the error messages one gets when giving incorrect inputs to the macro. For example, placing a `,` after `..Zeroable::zeroed()` is not allowed: use pin_init::*; #[derive(Zeroable)] struct Foo { a: usize, b: usize, } fn main() { let _ = init!(Foo { a: 0, ..Zeroable::zeroed(), }); } The declarative macro produces this error: error: no rules expected `,` | 11 | let _ = init!(Foo { | _____________^ 12 | | a: 0, 13 | | ..Zeroable::zeroed(), 14 | | }); | |______^ no rules expected this token in macro call | note: while trying to match `)` --> src/macros.rs | | @munch_fields($(..Zeroable::zeroed())? $(,)?), | ^ = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) error: no rules expected `,` | 11 | let _ = init!(Foo { | _____________^ 12 | | a: 0, 13 | | ..Zeroable::zeroed(), 14 | | }); | |______^ no rules expected this token in macro call | note: while trying to match `)` --> src/macros.rs | | @munch_fields(..Zeroable::zeroed() $(,)?), | ^ = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) The syn version reduces this error to the much more manageable: error: unexpected token, expected `}` | 12 | ..Zeroable::zeroed(), | ^ This reimplementation is benefiting the most from syn, as can be seen in this example. It declares a struct with a single generic, but then supplies two type arguments in the initializer: use pin_init::*; struct Foo<T> { value: T, } fn main() { let _ = init!(Foo::<(), ()> { value <- (), }); } The declarative version emits the following unreadable mess of an error (shortened for brevity of the commit message): error: struct literal body without path | 7 | let _ = init!(Foo::<(), ()> { | _____________^ 8 | | value <- (), 9 | | }); | |______^ | = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) help: you might have forgotten to add the struct literal inside the block --> src/macros.rs | ~ ::core::ptr::write($slot, $t { SomeStruct { |9 $($acc)* ~ } }); | <...40 lines skipped...> error[E0061]: this function takes 2 arguments but 3 arguments were supplied | 7 | let _ = init!(Foo::<(), ()> { | _____________^ 8 | | value <- (), 9 | | }); | |______^ unexpected argument #3 | note: function defined here --> $RUST/core/src/ptr/mod.rs | | pub const unsafe fn write<T>(dst: *mut T, src: T) { | ^^^^^ = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) This error delightfully reduces to the simple and clear message: error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied | 7 | let _ = init!(Foo::<(), ()> { | ^^^ ---- help: remove the unnecessary generic argument | | | expected 1 generic argument | note: struct defined here, with 1 generic parameter: `T` --> tests/ui/compile-fail/init/wrong_generics2.rs:3:8 | 3 | struct Foo<T> { | ^^^ - The syn version is only enabled in the user-space version and disabled in the kernel until syn becomes available there. Signed-off-by: Benno Lossin <[email protected]>
1 parent e347ea7 commit 974a783

17 files changed

+595
-233
lines changed

internal/src/init.rs

Lines changed: 404 additions & 0 deletions
Large diffs are not rendered by default.

internal/src/lib.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ mod pinned_drop;
3333
#[cfg(kernel)]
3434
mod zeroable;
3535

36+
#[cfg(not(kernel))]
37+
mod init;
3638
#[cfg(not(kernel))]
3739
#[path = "syn_pin_data.rs"]
3840
mod pin_data;
@@ -62,3 +64,79 @@ pub fn derive_zeroable(input: TokenStream) -> TokenStream {
6264
pub fn maybe_derive_zeroable(input: TokenStream) -> TokenStream {
6365
zeroable::maybe_derive(input.into()).into()
6466
}
67+
68+
#[cfg(kernel)]
69+
#[proc_macro]
70+
pub fn pin_init(input: TokenStream) -> TokenStream {
71+
quote!(::pin_init::__internal_pin_init!(#input))
72+
}
73+
74+
#[cfg(not(kernel))]
75+
#[proc_macro]
76+
pub fn pin_init(input: TokenStream) -> TokenStream {
77+
use syn::parse_macro_input;
78+
init::init(
79+
parse_macro_input!(input as init::InPlaceInitializer),
80+
true,
81+
true,
82+
)
83+
.unwrap_or_else(|e| e.into_compile_error())
84+
.into()
85+
}
86+
87+
#[cfg(kernel)]
88+
#[proc_macro]
89+
pub fn init(input: TokenStream) -> TokenStream {
90+
quote!(::pin_init::__internal_init!(#input))
91+
}
92+
93+
#[cfg(not(kernel))]
94+
#[proc_macro]
95+
pub fn init(input: TokenStream) -> TokenStream {
96+
use syn::parse_macro_input;
97+
init::init(
98+
parse_macro_input!(input as init::InPlaceInitializer),
99+
true,
100+
false,
101+
)
102+
.unwrap_or_else(|e| e.into_compile_error())
103+
.into()
104+
}
105+
106+
#[cfg(kernel)]
107+
#[proc_macro]
108+
pub fn try_pin_init(input: TokenStream) -> TokenStream {
109+
quote!(::pin_init::__internal_try_pin_init!(#input))
110+
}
111+
112+
#[cfg(not(kernel))]
113+
#[proc_macro]
114+
pub fn try_pin_init(input: TokenStream) -> TokenStream {
115+
use syn::parse_macro_input;
116+
init::init(
117+
parse_macro_input!(input as init::InPlaceInitializer),
118+
false,
119+
true,
120+
)
121+
.unwrap_or_else(|e| e.into_compile_error())
122+
.into()
123+
}
124+
125+
#[cfg(kernel)]
126+
#[proc_macro]
127+
pub fn try_init(input: TokenStream) -> TokenStream {
128+
quote!(::pin_init::__internal_try_init!(#input))
129+
}
130+
131+
#[cfg(not(kernel))]
132+
#[proc_macro]
133+
pub fn try_init(input: TokenStream) -> TokenStream {
134+
use syn::parse_macro_input;
135+
init::init(
136+
parse_macro_input!(input as init::InPlaceInitializer),
137+
false,
138+
false,
139+
)
140+
.unwrap_or_else(|e| e.into_compile_error())
141+
.into()
142+
}

src/__internal.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,3 +291,65 @@ unsafe impl<T: ?Sized> PinInit<T, ()> for AlwaysFail<T> {
291291
Err(())
292292
}
293293
}
294+
295+
#[cfg(kernel)]
296+
#[macro_export]
297+
macro_rules! __internal_init {
298+
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
299+
$($fields:tt)*
300+
}) => {
301+
$crate::try_init!($(&$this in)? $t $(::<$($generics),*>)? {
302+
$($fields)*
303+
}? ::core::convert::Infallible)
304+
};
305+
}
306+
307+
#[cfg(kernel)]
308+
#[macro_export]
309+
macro_rules! __internal_pin_init {
310+
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
311+
$($fields:tt)*
312+
}) => {
313+
$crate::try_pin_init!($(&$this in)? $t $(::<$($generics),*>)? {
314+
$($fields)*
315+
}? ::core::convert::Infallible)
316+
};
317+
}
318+
319+
#[cfg(kernel)]
320+
#[macro_export]
321+
macro_rules! __internal_try_init {
322+
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
323+
$($fields:tt)*
324+
}? $err:ty) => {
325+
$crate::__init_internal!(
326+
@this($($this)?),
327+
@typ($t $(::<$($generics),*>)?),
328+
@fields($($fields)*),
329+
@error($err),
330+
@data(InitData, /*no use_data*/),
331+
@has_data(HasInitData, __init_data),
332+
@construct_closure(init_from_closure),
333+
@munch_fields($($fields)*),
334+
)
335+
};
336+
}
337+
338+
#[cfg(kernel)]
339+
#[macro_export]
340+
macro_rules! __internal_try_pin_init {
341+
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
342+
$($fields:tt)*
343+
}? $err:ty) => {
344+
$crate::__init_internal!(
345+
@this($($this)?),
346+
@typ($t $(::<$($generics),*>)? ),
347+
@fields($($fields)*),
348+
@error($err),
349+
@data(PinData, use_data),
350+
@has_data(HasPinData, __pin_data),
351+
@construct_closure(pin_init_from_closure),
352+
@munch_fields($($fields)*),
353+
)
354+
};
355+
}

src/lib.rs

Lines changed: 4 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -777,18 +777,7 @@ macro_rules! stack_try_pin_init {
777777
/// ```
778778
///
779779
/// [`NonNull<Self>`]: core::ptr::NonNull
780-
// For a detailed example of how this macro works, see the module documentation of the hidden
781-
// module `macros` inside of `macros.rs`.
782-
#[macro_export]
783-
macro_rules! pin_init {
784-
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
785-
$($fields:tt)*
786-
}) => {
787-
$crate::try_pin_init!($(&$this in)? $t $(::<$($generics),*>)? {
788-
$($fields)*
789-
}? ::core::convert::Infallible)
790-
};
791-
}
780+
pub use pin_init_internal::pin_init;
792781

793782
/// Construct an in-place, fallible pinned initializer for `struct`s.
794783
///
@@ -828,25 +817,7 @@ macro_rules! pin_init {
828817
/// }
829818
/// # let _ = Box::pin_init(BigBuf::new());
830819
/// ```
831-
// For a detailed example of how this macro works, see the module documentation of the hidden
832-
// module `macros` inside of `macros.rs`.
833-
#[macro_export]
834-
macro_rules! try_pin_init {
835-
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
836-
$($fields:tt)*
837-
}? $err:ty) => {
838-
$crate::__init_internal!(
839-
@this($($this)?),
840-
@typ($t $(::<$($generics),*>)? ),
841-
@fields($($fields)*),
842-
@error($err),
843-
@data(PinData, use_data),
844-
@has_data(HasPinData, __pin_data),
845-
@construct_closure(pin_init_from_closure),
846-
@munch_fields($($fields)*),
847-
)
848-
}
849-
}
820+
pub use pin_init_internal::try_pin_init;
850821

851822
/// Construct an in-place initializer for `struct`s.
852823
///
@@ -884,18 +855,7 @@ macro_rules! try_pin_init {
884855
/// }
885856
/// # let _ = Box::init(BigBuf::new());
886857
/// ```
887-
// For a detailed example of how this macro works, see the module documentation of the hidden
888-
// module `macros` inside of `macros.rs`.
889-
#[macro_export]
890-
macro_rules! init {
891-
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
892-
$($fields:tt)*
893-
}) => {
894-
$crate::try_init!($(&$this in)? $t $(::<$($generics),*>)? {
895-
$($fields)*
896-
}? ::core::convert::Infallible)
897-
}
898-
}
858+
pub use pin_init_internal::init;
899859

900860
/// Construct an in-place fallible initializer for `struct`s.
901861
///
@@ -933,25 +893,7 @@ macro_rules! init {
933893
/// }
934894
/// # let _ = Box::init(BigBuf::new());
935895
/// ```
936-
// For a detailed example of how this macro works, see the module documentation of the hidden
937-
// module `macros` inside of `macros.rs`.
938-
#[macro_export]
939-
macro_rules! try_init {
940-
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
941-
$($fields:tt)*
942-
}? $err:ty) => {
943-
$crate::__init_internal!(
944-
@this($($this)?),
945-
@typ($t $(::<$($generics),*>)?),
946-
@fields($($fields)*),
947-
@error($err),
948-
@data(InitData, /*no use_data*/),
949-
@has_data(HasInitData, __init_data),
950-
@construct_closure(init_from_closure),
951-
@munch_fields($($fields)*),
952-
)
953-
}
954-
}
896+
pub use pin_init_internal::try_init;
955897

956898
/// Asserts that a field on a struct using `#[pin_data]` is marked with `#[pin]` ie. that it is
957899
/// structurally pinned.
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
error[E0308]: mismatched types
2-
--> tests/ui/compile-fail/init/colon_instead_of_arrow.rs:21:9
2+
--> tests/ui/compile-fail/init/colon_instead_of_arrow.rs:21:31
33
|
44
14 | fn new() -> impl PinInit<Self> {
55
| ------------------ the found opaque type
66
...
77
21 | pin_init!(Self { bar: Bar::new() })
8-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9-
| |
10-
| expected `Bar`, found opaque type
11-
| arguments to this function are incorrect
8+
| --- ^^^^^^^^^^ expected `Bar`, found opaque type
9+
| |
10+
| arguments to this function are incorrect
1211
|
1312
= note: expected struct `Bar`
1413
found opaque type `impl pin_init::PinInit<Bar>`
@@ -17,4 +16,3 @@ note: function defined here
1716
|
1817
| pub const unsafe fn write<T>(dst: *mut T, src: T) {
1918
| ^^^^^
20-
= note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `pin_init` (in Nightly builds, run with -Z macro-backtrace for more info)
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
error[E0308]: mismatched types
2-
--> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:13
2+
--> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:28
33
|
44
8 | let _ = init!(Foo { a: () });
5-
| ^^^^^^^^^^^^^^^^^^^^
6-
| |
7-
| expected `usize`, found `()`
8-
| arguments to this function are incorrect
5+
| - ^^ expected `usize`, found `()`
6+
| |
7+
| arguments to this function are incorrect
98
|
109
note: function defined here
1110
--> $RUST/core/src/ptr/mod.rs
1211
|
1312
| pub const unsafe fn write<T>(dst: *mut T, src: T) {
1413
| ^^^^^
15-
= note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info)

tests/ui/compile-fail/init/invalid_init.stderr

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ error[E0277]: the trait bound `impl pin_init::PinInit<Bar>: Init<Bar>` is not sa
55
| _____________^
66
19 | | bar <- Bar::new(),
77
20 | | });
8-
| | ^
9-
| | |
10-
| |______the trait `Init<Bar>` is not implemented for `impl pin_init::PinInit<Bar>`
11-
| required by a bound introduced by this call
8+
| |______^ the trait `Init<Bar>` is not implemented for `impl pin_init::PinInit<Bar>`
129
|
1310
= help: the trait `Init<T, E>` is implemented for `ChainInit<I, F, T, E>`
14-
= note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info)
11+
= note: this error originates in the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info)
Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,5 @@
1-
error: no rules expected `c`
1+
error: expected `,`
22
--> tests/ui/compile-fail/init/missing_comma.rs:16:9
33
|
44
16 | c: Bar,
5-
| ^ no rules expected this token in macro call
6-
|
7-
note: while trying to match `,`
8-
--> src/macros.rs
9-
|
10-
| @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
11-
| ^
12-
13-
error: no rules expected `c`
14-
--> tests/ui/compile-fail/init/missing_comma.rs:16:9
15-
|
16-
16 | c: Bar,
17-
| ^ no rules expected this token in macro call
18-
|
19-
note: while trying to match `,`
20-
--> src/macros.rs
21-
|
22-
| @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
23-
| ^
5+
| ^

tests/ui/compile-fail/init/missing_comma_with_zeroable.stderr

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,12 @@ help: you can add the `dyn` keyword if you want a trait object
1010
| ++++ +
1111

1212
error[E0308]: mismatched types
13-
--> tests/ui/compile-fail/init/missing_comma_with_zeroable.rs:11:13
13+
--> tests/ui/compile-fail/init/missing_comma_with_zeroable.rs:12:12
1414
|
15-
11 | let _ = init!(Foo {
16-
| _____________^
17-
12 | | a: 0..Zeroable::zeroed()
18-
13 | | });
19-
| | ^
20-
| | |
21-
| |______expected `usize`, found `Range<{integer}>`
22-
| arguments to this function are incorrect
15+
12 | a: 0..Zeroable::zeroed()
16+
| - ^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `Range<{integer}>`
17+
| |
18+
| arguments to this function are incorrect
2319
|
2420
= note: expected type `usize`
2521
found struct `std::ops::Range<{integer}>`
@@ -28,7 +24,6 @@ note: function defined here
2824
|
2925
| pub const unsafe fn write<T>(dst: *mut T, src: T) {
3026
| ^^^^^
31-
= note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info)
3227

3328
error[E0063]: missing field `b` in initializer of `Foo`
3429
--> tests/ui/compile-fail/init/missing_comma_with_zeroable.rs:11:19
Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
error: unexpected end of macro invocation
2-
--> tests/ui/compile-fail/init/missing_error_type.rs:8:47
1+
error: unexpected end of input, expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, `dyn`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime
2+
--> tests/ui/compile-fail/init/missing_error_type.rs:8:13
33
|
44
8 | let _ = try_init!(Foo { x: Box::new(0)? }?);
5-
| ^ missing tokens in macro arguments
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
note: while trying to match meta-variable `$err:ty`
8-
--> src/lib.rs
9-
|
10-
| }? $err:ty) => {
11-
| ^^^^^^^
7+
= note: this error originates in the macro `try_init` (in Nightly builds, run with -Z macro-backtrace for more info)

tests/ui/compile-fail/init/missing_pin_data.stderr

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ error[E0599]: no associated item named `__pin_data` found for struct `Foo` in th
1010
= help: items from traits can only be used if the trait is implemented and in scope
1111
= note: the following trait defines an item `__pin_data`, perhaps you need to implement it:
1212
candidate #1: `HasPinData`
13-
= note: this error originates in the macro `$crate::try_pin_init` which comes from the expansion of the macro `pin_init` (in Nightly builds, run with -Z macro-backtrace for more info)
13+
= note: this error originates in the macro `pin_init` (in Nightly builds, run with -Z macro-backtrace for more info)
1414
help: there is an associated function `__init_data` with a similar name
15-
--> src/lib.rs
1615
|
17-
- @has_data(HasPinData, __pin_data),
18-
+ @has_data(HasPinData, __init_data),
16+
9 - pin_init!(Self { a: 42 })
17+
9 + __init_data
1918
|

0 commit comments

Comments
 (0)