about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-08-01 11:56:02 +0000
committerbors <bors@rust-lang.org>2021-08-01 11:56:02 +0000
commit8d57c0ab2b2e1aae07c1b8638358fb7a909940bc (patch)
treee78262bf28d13755e97f8905f9819261deeed976
parentaadd6189ad5c81f50d942c584ed1c1b49892765f (diff)
parent2aa199632917dc1afa4b80d60d291a278e0bfb24 (diff)
downloadrust-8d57c0ab2b2e1aae07c1b8638358fb7a909940bc.tar.gz
rust-8d57c0ab2b2e1aae07c1b8638358fb7a909940bc.zip
Auto merge of #87546 - rusticstuff:issue87450-take-two, r=davidtwco
Bail on any found recursion when expanding opaque types

Fixes #87450. More of a bandaid because it does not fix the exponential complexity of the type folding used for opaque type expansion.
-rw-r--r--compiler/rustc_middle/src/ty/util.rs6
-rw-r--r--src/test/ui/impl-trait/issue-87450.rs16
-rw-r--r--src/test/ui/impl-trait/issue-87450.stderr27
3 files changed, 48 insertions, 1 deletions
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 485be4c9987..9ba85e58018 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -540,6 +540,7 @@ impl<'tcx> TyCtxt<'tcx> {
             expanded_cache: FxHashMap::default(),
             primary_def_id: Some(def_id),
             found_recursion: false,
+            found_any_recursion: false,
             check_recursion: true,
             tcx: self,
         };
@@ -560,6 +561,7 @@ struct OpaqueTypeExpander<'tcx> {
     expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>,
     primary_def_id: Option<DefId>,
     found_recursion: bool,
+    found_any_recursion: bool,
     /// Whether or not to check for recursive opaque types.
     /// This is `true` when we're explicitly checking for opaque type
     /// recursion, and 'false' otherwise to avoid unnecessary work.
@@ -569,7 +571,7 @@ struct OpaqueTypeExpander<'tcx> {
 
 impl<'tcx> OpaqueTypeExpander<'tcx> {
     fn expand_opaque_ty(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> Option<Ty<'tcx>> {
-        if self.found_recursion {
+        if self.found_any_recursion {
             return None;
         }
         let substs = substs.fold_with(self);
@@ -591,6 +593,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
         } else {
             // If another opaque type that we contain is recursive, then it
             // will report the error, so we don't have to.
+            self.found_any_recursion = true;
             self.found_recursion = def_id == *self.primary_def_id.as_ref().unwrap();
             None
         }
@@ -1078,6 +1081,7 @@ pub fn normalize_opaque_types(
         expanded_cache: FxHashMap::default(),
         primary_def_id: None,
         found_recursion: false,
+        found_any_recursion: false,
         check_recursion: false,
         tcx,
     };
diff --git a/src/test/ui/impl-trait/issue-87450.rs b/src/test/ui/impl-trait/issue-87450.rs
new file mode 100644
index 00000000000..983ef7cfbe0
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-87450.rs
@@ -0,0 +1,16 @@
+fn bar() -> impl Fn() {
+    wrap(wrap(wrap(wrap(foo()))))
+}
+
+fn foo() -> impl Fn() {
+    //~^ WARNING 5:1: 5:22: function cannot return without recursing [unconditional_recursion]
+    //~| ERROR 5:13: 5:22: cannot resolve opaque type [E0720]
+    wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo())))))))
+}
+
+fn wrap(f: impl Fn()) -> impl Fn() {
+    move || f()
+}
+
+fn main() {
+}
diff --git a/src/test/ui/impl-trait/issue-87450.stderr b/src/test/ui/impl-trait/issue-87450.stderr
new file mode 100644
index 00000000000..83eb33efc6b
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-87450.stderr
@@ -0,0 +1,27 @@
+warning: function cannot return without recursing
+  --> $DIR/issue-87450.rs:5:1
+   |
+LL | fn foo() -> impl Fn() {
+   | ^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+...
+LL |     wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo())))))))
+   |                                        ----- recursive call site
+   |
+   = note: `#[warn(unconditional_recursion)]` on by default
+   = help: a `loop` may express intention better if this is on purpose
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/issue-87450.rs:5:13
+   |
+LL | fn foo() -> impl Fn() {
+   |             ^^^^^^^^^ recursive opaque type
+...
+LL |     wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo())))))))
+   |     ----------------------------------------------- returning here with type `impl Fn<()>`
+...
+LL | fn wrap(f: impl Fn()) -> impl Fn() {
+   |                          --------- returning this opaque type `impl Fn<()>`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0720`.