Repository navigation
#![recursion_limit] behaves strangely #75602
Description
Activity
- addedC-bugCategory: This is a bug.Category: This is a bug.I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
on Aug 16, 2020 - removedI-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️
on Aug 17, 2020 I’ve never worked on the Rust compiler before, so I doubt I’ll be of any help here, but I quickly ran a GitHub search for
RustaceansAreAwesomeon this repo and found this. No idea what it means but hopefully is helpful in some way.I found a similar, but more egregious bug. (See #76424). Should I merge them?
This code doesn't make any macro calls, yet somehow exceeds the recursion limit.
I'm pretty sure the recursion limit applies to all parts of the compiler, not just macros. So the bit about weird errors when the limit is 1 seems fine to me. But it should probably enforce that the limit is at least a number.
This code doesn't make any macro calls, yet somehow exceeds the recursion limit.
I'm pretty sure the recursion limit applies to all parts of the compiler, not just macros. So the bit about weird errors when the limit is 1 seems fine to me.
Certainly, running
rustc --explain E0275confirms that:An evaluation of a trait requirement overflowed. Erroneous code example: trait Foo {} struct Bar<T>(T); impl<T> Foo for T where Bar<T>: Foo {} This error occurs when there was a recursive trait requirement that overflowed before it could be evaluated. This often means that there is an unbounded recursion in resolving some type bounds. To determine if a `T` is `Foo`, we need to check if `Bar<T>` is `Foo`. However, to do this check, we need to determine that `Bar<Bar<T>>` is `Foo`. To determine this, we check if `Bar<Bar<Bar<T>>>` is `Foo`, and so on. This is clearly a recursive requirement that can't be resolved directly. Consider changing your trait bounds so that they're less self-referential.But it should probably enforce that the limit is at least a number.
Yes, of course the compiler should set a minimum recursion limit to avoid breaking things.
- addedA-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lints
on Oct 11, 2021 Current version:
#![recursion_limit = "1"] fn main() { }
emits
Compiling playground v0.0.1 (/playground) error: reached the recursion limit while instantiating `<fn() as FnOnce<()>>::call_once - shim(fn())` | note: `call_once` defined here error: could not compile `playground` due to previous errorNote: for some reason this does not break if it is layered all on one line, like
#![recursion_limit = "1"] fn main() { }
So yeah, there's an unfortunate thing here where there are a bunch of implicit pieces of code embedded as part of
fn main()that, if you lower the overflow requirement too far, it starts breaking their minimum recursion requirements, which results in confusing diagnostics. I am not sure how we would stop this, though, since it does not seem easy to automatically detect when the code is coming in from the lang startup.A mildly hackish answer might be that we could set a hard floor of a recursion requirement of 3, which stops this from breaking on such a trivial example.
This is the current state of play, using cargo 1.98.0 (797e8a9bc 2026-08-05):
#![recursion_limit = "malformed"] fn main() { }Which compiles gives the error:
Compiling reclim v0.1.0 (/Users/rod/code/rust/triage/2026/08/reclim) error: `limit` must be a non-negative integer --> src/main.rs:1:1 | 1 | #![recursion_limit = "malformed"] fn main() { } | ^^^^^^^^^^^^^^^^^^^^^-----------^ | | | not a valid integer error: could not compile `reclim` (bin "reclim") due to 1 previous errorTherefore the limit is checked to be well formed. Changing "malformed" to "1", changes the error to:
Compiling reclim v0.1.0 (/Users/rod/code/rust/triage/2026/08/reclim) error[E0275]: overflow evaluating the requirement `&mut Self: DispatchFromDyn<&mut RustaceansAreAwesome>` | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`reclim`) For more information about this error, try `rustc --explain E0275`. error: could not compile `reclim` (bin "reclim") due to 1 previous errorTherefore the original issue is replicated on a single line of code. Changing the "1" to "2", also changes the error to:
Compiling reclim v0.1.0 (/Users/rod/code/rust/triage/2026/08/reclim) error: queries overflow the depth limit! --> /Users/rod/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/process.rs:2691:9 | 2691 | ExitCode::SUCCESS | ^^^^^^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "4"]` attribute to your crate (`reclim`) = note: query depth increased by 4 when simplifying constant for the type system `std::process::ExitCode::SUCCESS` error: could not compile `reclim` (bin "reclim") due to 1 previous errorChange the "2" to "4" again changes the error to:
Compiling reclim v0.1.0 (/Users/rod/code/rust/triage/2026/08/reclim) error: queries overflow the depth limit! --> /Users/rod/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/rt.rs:206:9 | 206 | &move || crate::sys::backtrace::__rust_begin_short_backtrace(main).report().to_i32(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "8"]` attribute to your crate (`reclim`) = note: query depth increased by 6 when computing layout of `&dyn core::ops::function::Fn() -> i32 + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe` error: could not compile `reclim` (bin "reclim") due to 1 previous errorChange "4" to "8" and it builds, note 5 or more works. May be we should add a check for values <5 and a message that is the minimum valid recursion limit? Or are there code sequences with a lower recursion requirements? It seems unlikely.
I was playing around with
recursion_limit, and I realized thatrecursion_limitdoesn't check for bad values.#![recursion_limit = "malformed"] fn main() {}, for example, compiles without error. Moreover, when set to1, the Rust compiler raises a weird error:What is
RustaceansAreAwesome? This code doesn't make any macro calls, yet somehow exceeds the recursion limit.Version
rustc --version --verbose:Code