Bad macro usage error message does not include correct error location
Consider this reduced test case:
macro_rules! match_ignore_ascii_case {
(@inner $value:expr) => { () };
( $($rest:tt)* ) => { match_ignore_ascii_case!(@inner $($rest)*) };
}
fn main() {
// This is fine
match_ignore_ascii_case!(1);
// This causes an error as it doesn’t match the expected syntax
// but the error message does not the location of the actual error.
match_ignore_ascii_case!(2 => 3);
}
The @inner indirection exists because the non-reduced macro is recursive:
- https://play.rust-lang.org/?gist=f8b1652f43cc720f89a3&version=nightly
- https://users.rust-lang.org/t/writing-a-macro-rules-macro-used-like-a-match-expression/4328
This fails to compile (as it should) but the error message does not include the real location of the error, which is line 12. It can be hard to track down in a large crate with many users of the macro.
a.rs:3:52: 3:53 error: unexpected token: `@`
a.rs:3 ( $($rest:tt)* ) => { match_ignore_ascii_case!(@inner $($rest)*) };
The error message looks even worse when the macro is used (with incorrect syntax) from another crate
<cssparser macros>:12:1: 12:2 error: unexpected token: `@`
<cssparser macros>:12 @ inner $ value , ( $ ( $ rest ) * ) -> (
When the expanded code contains a non-macro-related error (say, a type mismatch), it at least shows a macro expansion backtrace. It's very hard to read, but gives spans at least. I guess that would be a start.
Alex Burka at 2016-01-19 23:27:00
The trouble is you get the same error if you screw up writing the macro, e.g. misspell
@inneror order something backwards in one of the arms. It isn't the caller's fault for sure.Alex Burka at 2016-01-19 23:27:55
Yes, I don’t have an example at hand to copy/past but I see the kind of error message you mean. It may be the caller’s fault even if it isn’t necessarily. A macro expansion backtrace would be useful here.
Simon Sapin at 2016-01-20 07:20:25
Current output:
error: recursion limit reached while expanding the macro `match_ignore_ascii_case` --> src/main.rs:3:27 | 3 | ( $($rest:tt)* ) => { match_ignore_ascii_case!(@inner $($rest)*) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... 12 | match_ignore_ascii_case!(2 => 3); | --------------------------------- in this macro invocation | = help: consider adding a `#![recursion_limit="128"]` attribute to your crateEsteban Kuber at 2017-09-21 22:01:57
Triage: no change.
Esteban Kuber at 2019-05-22 01:23:33
Triage: no change.
Esteban Kuber at 2022-06-08 21:42:45
Triage: no change.
Esteban Kuber at 2022-12-28 23:02:34