[Pre-RFC] changing how the macro recursion limit works


The macro recursion limit is pretty annoying. For one thing, if you have a deeply recursive macro, this pushes a burden onto your client crates: they all have to manually annotate themselves with a high recursion limit. Also, I’ve never really seen this catch an actual infinite recursion in practice.

I think the way I would like it to work is this: the default is perhaps to have a low recursion limit. But you can annotate a macro definition with some simple annotation to raise the bar. This will make the limit something very high (maybe even infinity, not sure what happens we actually overflow the stack right now, crash?). During macro expansion, if we are expanding a macro with an associated limit, we will ignore the crate’s local limit and use this very high limit instead.


This would definitely be useful for quote where it doesn’t take much to hit that default recursion limit.

I’d prefer an attribute that communicated the fact that this macro may recurse a bunch of times but will definitely terminate, rather than setting the limit to some arbitrarily high number (maybe that’s what it’d do under-the-hood).


I meant more as an impl strategy. That is, we probably don’t want to literally recurse with no limit at all, but I kind of want to make this a binary switch. TBH, I’m tempted to just remove the recursion limit on macros altogether – I’m not sure if it’s ever really helped anyone?


I wonder if a fuzzer could find its way to an infinite macro expansion…


An infinite recursion would involve calling the macro again with the same arguments (not necessarily immediately). Some hashing or comparison of arguments could be used to detect that, although at a small cost. So maybe you could avoid a limit altogether. Edit: i.e. check down the stack to the outer invocations to see if any are the same. Even an O(N) check might be viable.


You can get infinitely unique recursions too:

macro_rules! foo {
    ($($x:tt)*) => (foo!($($x)* and more))

macro_rules! bar {
    ($x:expr) => (bar!($x + 1))