Braced macros are inconsistent with other braced items
Consider the following macro:
macro_rules! test {
() => ( "hello" )
}
The following function compiles as expected if the macro is invoked with parenthesis:
fn string_len() -> usize {
test!().len()
}
However, if I invoke the macro with curly braces instead, Rust emits an error:
fn string_len() -> usize {
test!{ }.len()
}
rustc 1.15.1 (021bd294c 2017-02-08)
error: expected expression, found `.`
--> <anon>:2:13
|
2 | test!{ }.len()
| ^
From discussions with @eddyb, this occurs because the macro is being treated as expanding into a statement as opposed to an expression. This is inconsistent with how other curly-braced constructs are treated. For instance, the following functions as expected:
fn string_len() -> usize {
{ "hello" }.len()
}
It seems that the expansion site is not correctly being identified as an expression or statement. In this case, the . suffix to the macro invocation clearly determines that the macro should expand to an expression.
cc @nrc @jseyfried
Eduard-Mihai Burtescu at 2017-02-25 22:55:40
Triage: Still an issue. Error message:
error: expected expression, found `.` --> src/main.rs:6:12 | 6 | test!{}.len() | ^ expected expression error[E0308]: mismatched types --> src/main.rs:2:13 | 2 | () => ( "hello" ) | ^^^^^^^ expected usize, found reference ... 5 | fn string_len() -> usize { | ----- expected `usize` because of return type 6 | test!{}.len() | ------- in this macro invocation | = note: expected type `usize` found type `&'static str`Phlosioneer at 2018-03-07 03:55:09
I just rediscovered this issue for myself, but unfortunately it strikes me as impractical to try and change this behavior. Consider this code:
fn f() -> [usize; 1] { mac! {} [1] }In order to tell whether this parses as
mac!{}[1]ormac! {}; [1], we would have to know whethermac!{}expands to an item or an expression. If it expands tofn g() {...}, the function returns[1]; if it expands to, e.g.,[[0], [12]], the function returns[12]. This leaves the door open to writing some obscure C-like macro code that I don't think anybody wants to have to read. It would probably also make the language grammar harder to define, in case that matters to anyone.It might be possible to allow this in cases where the next token cannot start an expression, which would make the
test!{}.len()example work, but curly brace macros would still be gimped compared to the other two paren types. I suspect this is simply an inherent drawback in the original decision to let curly brace macros be used this way.I might be belaboring the point, but basically I'm just saying I personally don't see this as a bug and I wouldn't change anything except to improve the error message.
Matthew McAllister at 2020-07-17 03:57:03
Compiles on
rustc 1.80.0: https://rust.godbolt.org/z/xsxrGPfrsVeera at 2024-07-26 01:17:46