Cannot generate unit struct with a macros
It doesn't seem possible to generate unit struct declaration from a macros in neither stable nor nightly version of Rust.
A simplified playground sample:
macro_rules! def_struct {
($name:ident $($body:tt)*) => {
pub struct $name $($body)*
};
}
def_struct!(X {}); // compiles
def_struct!(Y); // doesn't
fn main() {}
When trying to expand the second macro call, Rust complains:
error: expected `where`, `{`, `(`, or `;` after struct name, found `<eof>`
--> src/main.rs:3:16
|
3 | pub struct $name $($body)*
| ^^^^^
...
8 | def_struct!(Y); // doesn't
| --------------- in this macro invocation
If I add a semicolon as it asks right after the struct definition, the unit macro call starts compiling fine:
macro_rules! def_struct {
($name:ident $($body:tt)*) => {
pub struct $name $($body)*;
};
}
def_struct!(Y); // compiles
def_struct!(X {}); // doesn't
fn main() {}
but the other one fails instead:
error: macro expansion ignores token `;` and any following
--> src/main.rs:3:31
|
3 | pub struct $name $($body)*;
| ^
|
note: caused by the macro expansion here; the usage of `def_struct!` is likely invalid in item context
--> src/main.rs:8:1
|
8 | def_struct!(X {}); // compiles
| ^^^^^^^^^^^^^^^^^^
The two errors seem to contradict each other here. The only obvious workaround to make both cases work I could find is to split macro definition into two, one with semicolon and another without:
macro_rules! def_struct {
($name:ident) => {
pub struct $name;
};
($name:ident $body:tt) => {
pub struct $name $body
}
}
def_struct!(X {}); // compiles
def_struct!(Y); // compiles
fn main() {}
But this is not very clean and gets even harder in more complicated macros. Is there any reason for such behaviour or is it a bug and it would be possible to allow macro to generate unit structs that are not followed by a semicolon, just like any other?
I'm not quite sure what you are asking for here. Normal struct definition syntax has a semicolon after unit and tuple structs, but not curly-brace structs. So I don't see any contradiction in the errors you report. Why should macros get special dispensation to skip it?
Alex Burka at 2017-12-22 16:12:15
Normal struct definition syntax has a semicolon after unit and tuple structs, but not curly-brace structs.
Hmm you're right, it just gets awkward because macros that expand to items, on the other hand, already always require semicolon after them, so it feels somewhat expected that Rust would automatically use it for the generated item when necessary.
Ingvar Stepanyan at 2017-12-22 18:59:05
Btw, thanks for mentioning tuples, the error for them is even more confusing:
macro_rules! def_struct { ($name:ident $($body:tt)*) => { pub struct $name $($body)* }; } def_struct!(X {}); // compiles def_struct!(Y ()); fn main() {}error: expected one of `;` or `where`, found `<eof>` --> src/main.rs:3:29 | 3 | pub struct $name $($body)* | ^ expected one of `;` or `where` hereIt's okay here as it points directly to struct, but if this is generated by recursive macro, it points to the callee
macro_name!(...)side and until now I couldn't even understand what it means by "expected one of;orwherehere" pointing to it.Would be nice to at least update that error to mention "after tuple-like struct body" similarly to "after struct name" in the existing error for unit structs.
Ingvar Stepanyan at 2017-12-22 19:05:48