From 804e9e546dbf246b671542a3813d38ee56e14a28 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 24 May 2020 16:03:11 +0100 Subject: [PATCH] mir: adjust conditional in recursion limit check This commit adjusts the condition used in the recursion limit check of the monomorphization collector, from `>` to `>=`. In #67552, the test case had infinite indirect recursion, repeating a handful of functions (from the perspective of the monomorphization collector): `rec` -> `identity` -> `Iterator::count` -> `Iterator::fold` -> `Iterator::next` -> `rec`. During this process, `resolve_associated_item` was invoked for `Iterator::fold` (during the construction of an `Instance`), and ICE'd due to substitutions needing inference. However, previous iterations of this recursion would have called this function for `Iterator::fold` - and did! - and succeeded in doing so (trivially checkable from debug logging, `()` is present where `_` is in the substs of the failing execution). The expected outcome of this test case would be a recursion limit error (which is present when the `identity` fn indirection is removed), and the recursion depth of `rec` is increasing (other functions finish collecting their neighbours and thus have their recursion depths reset). When the ICE occurs, the recursion depth of `rec` is 256 (which matches the recursion limit), which suggests perhaps that a different part of the compiler is using a `>=` comparison and returning a different result on this recursion rather than what it returned in every previous recursion, thus stopping the monomorphization collector from reporting an error on the next recursion, where `recursion_depth_of_rec > 256` would have been true. With grep and some educated guesses, we can determine that the recursion limit check at line 818 in `src/librustc_trait_selection/traits/project.rs` is the other check that is using a different comparison. Modifying either comparison to be `>` or `>=` respectively will fix the error, but changing the monomorphization collector produces the nicer error. Signed-off-by: David Wood --- src/librustc_mir/monomorphize/collector.rs | 2 +- .../ui/infinite/infinite-instantiation.stderr | 2 +- src/test/ui/issues/issue-67552.rs | 30 +++++++++++++++++++ src/test/ui/issues/issue-67552.stderr | 14 +++++++++ src/test/ui/issues/issue-8727.stderr | 2 +- ...-38591-non-regular-dropck-recursion.stderr | 2 +- src/test/ui/recursion/recursion.stderr | 2 +- 7 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/issues/issue-67552.rs create mode 100644 src/test/ui/issues/issue-67552.stderr diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index c75e8414e8cc..1c5c13f843d7 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -430,7 +430,7 @@ fn check_recursion_limit<'tcx>( // Code that needs to instantiate the same function recursively // more than the recursion limit is assumed to be causing an // infinite expansion. - if adjusted_recursion_depth > tcx.sess.recursion_limit() { + if adjusted_recursion_depth >= tcx.sess.recursion_limit() { let error = format!("reached the recursion limit while instantiating `{}`", instance); if let Some(def_id) = def_id.as_local() { let hir_id = tcx.hir().as_local_hir_id(def_id); diff --git a/src/test/ui/infinite/infinite-instantiation.stderr b/src/test/ui/infinite/infinite-instantiation.stderr index ae81c680a7b6..f1c04447986b 100644 --- a/src/test/ui/infinite/infinite-instantiation.stderr +++ b/src/test/ui/infinite/infinite-instantiation.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/infinite-instantiation.rs:25:1 | LL | / fn function(counter: usize, t: T) { diff --git a/src/test/ui/issues/issue-67552.rs b/src/test/ui/issues/issue-67552.rs new file mode 100644 index 000000000000..1400c6f97b60 --- /dev/null +++ b/src/test/ui/issues/issue-67552.rs @@ -0,0 +1,30 @@ +// build-fail + +fn main() { + rec(Empty); +} + +struct Empty; + +impl Iterator for Empty { + type Item = (); + fn next<'a>(&'a mut self) -> core::option::Option<()> { + None + } +} + +fn identity(x: T) -> T { + x +} + +fn rec(mut it: T) +//~^ ERROR reached the recursion limit while instantiating +where + T: Iterator, +{ + if () == () { + T::count(it); + } else { + rec(identity(&mut it)) + } +} diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr new file mode 100644 index 000000000000..97ad76e207d0 --- /dev/null +++ b/src/test/ui/issues/issue-67552.stderr @@ -0,0 +1,14 @@ +error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty>` + --> $DIR/issue-67552.rs:20:1 + | +LL | / fn rec(mut it: T) +LL | | +LL | | where +LL | | T: Iterator, +... | +LL | | } +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-8727.stderr b/src/test/ui/issues/issue-8727.stderr index ee0672c598d5..8f581a358e1e 100644 --- a/src/test/ui/issues/issue-8727.stderr +++ b/src/test/ui/issues/issue-8727.stderr @@ -9,7 +9,7 @@ LL | generic::>(); = note: `#[warn(unconditional_recursion)]` on by default = help: a `loop` may express intention better if this is on purpose -error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-8727.rs:6:1 | LL | / fn generic() { diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index de6df4cd0268..d64149d1437f 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::> - shim(Some(S))` +error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::> - shim(Some(S))` error: aborting due to previous error diff --git a/src/test/ui/recursion/recursion.stderr b/src/test/ui/recursion/recursion.stderr index 1a65b0e84f6a..ded8b3f87db6 100644 --- a/src/test/ui/recursion/recursion.stderr +++ b/src/test/ui/recursion/recursion.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/recursion.rs:15:1 | LL | / fn test (n:isize, i:isize, first:T, second:T) ->isize {