Reputation: 177
I made a simple macro that returns the taken parameter.
macro_rules! n {
($n:expr) => {{
let val: usize = $n;
match val {
0 => 0,
_ => n!(val - 1),
}
}};
}
When I compile this code with the option external-macro-backtrace
, it raises an error:
error: recursion limit reached while expanding the macro `n`
--> src/main.rs:15:18
|
10 | macro_rules! n {
| _-
| |_|
| |
11 | | ($n:expr) => {{
12 | | let val: usize = $n;
13 | | match val {
14 | | 0 => 0,
15 | | _ => n!(val - 1),
| | ^^^^^^^^^^^
| | |
| | in this macro invocation
16 | | }
17 | | }};
18 | | }
| | -
| |_|
| |_in this expansion of `n!`
| in this expansion of `n!`
...
31 | | n!(1);
| | ------ in this macro invocation
|
= help: consider adding a `#![recursion_limit="128"]` attribute to your crate
I changed the recursion_limit
to 128 and higher, but the compiler error message just increase as well. Even when I call n!(0)
it makes the same error. I think it is infinite recursion, but I can't find the reason.
Upvotes: 1
Views: 890
Reputation: 10247
Well, it really is an infinite recursion. Check what your macro invocation n!(0)
will be expanded into:
{
let val: usize = 0;
match val {
0 => 0,
_ => n!(0 - 1),
}
}
...and since there's no way for argument of n!
to stop growing negative, it'll repeat (with n!(0 - 1 - 1)
in the second match arm, then n!(0 - 1 - 1 - 1)
etc.) infinitely.
The key point here is that the macro expansion happens in compile-time, while the match
statement you're trying to use to limit the recursion is invoked only at run-time and can't stop anything from appear before that. Unhappily, there's no easy way to do this, since Rust won't evaluate macro arguments (even if it's a constant expression), and so just adding the (0) => {0}
branch to the macro won't work, since the macro will be invoked as (for example) n!(1 - 1)
.
Upvotes: 2