about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYuki Okushi <jtitor@2k36.org>2021-07-01 05:20:58 +0900
committerGitHub <noreply@github.com>2021-07-01 05:20:58 +0900
commitdfe05c0ea01f94e1701e8f1182b52b0f42682b3b (patch)
tree9889c8379160e791f485c57188bbc72636a945e2
parent56ddef8ab855ebdd57febde8356e890cdc03f118 (diff)
parent0c267830d5afdeea2058f0b97e69cf1afbb3d3da (diff)
Rollup merge of #86728 - FabianWolff:issue-86721, r=LeSeulArtichaut
Check node kind to avoid ICE in `check_expr_return()`

This PR fixes #86721. The ICE described there is apparently due to a misunderstanding:
https://github.com/rust-lang/rust/blob/e98897e5dc9898707bf4331c43b2e76ab7e282fe/compiler/rustc_typeck/src/check/expr.rs#L684-L685

Intuitively, one would think that calling `expect_item()` after `get_parent_item()` should succeed, but as it turns out, `get_parent_item()` can also return foreign, trait, and impl items as well as crates, whereas `expect_item()` specifically expects a `Node::Item`. I have therefore added an extra check to prevent this ICE.
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs20
-rw-r--r--src/test/ui/return/issue-86188-return-not-in-fn-body.rs19
-rw-r--r--src/test/ui/return/issue-86188-return-not-in-fn-body.stderr28
-rw-r--r--src/test/ui/typeck/issue-86721-return-expr-ice.rev1.stderr9
-rw-r--r--src/test/ui/typeck/issue-86721-return-expr-ice.rev2.stderr9
-rw-r--r--src/test/ui/typeck/issue-86721-return-expr-ice.rs17
6 files changed, 97 insertions, 5 deletions
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index f69839bf859..cfe1d1c6871 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -682,9 +682,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             };
 
             let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id);
-            let encl_item = self.tcx.hir().expect_item(encl_item_id);
 
-            if let hir::ItemKind::Fn(..) = encl_item.kind {
+            if let Some(hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Fn(..),
+                span: encl_fn_span,
+                ..
+            }))
+            | Some(hir::Node::TraitItem(hir::TraitItem {
+                kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
+                span: encl_fn_span,
+                ..
+            }))
+            | Some(hir::Node::ImplItem(hir::ImplItem {
+                kind: hir::ImplItemKind::Fn(..),
+                span: encl_fn_span,
+                ..
+            })) = self.tcx.hir().find(encl_item_id)
+            {
                 // We are inside a function body, so reporting "return statement
                 // outside of function body" needs an explanation.
 
@@ -698,7 +712,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let encl_body = self.tcx.hir().body(encl_body_id);
 
                 err.encl_body_span = Some(encl_body.value.span);
-                err.encl_fn_span = Some(encl_item.span);
+                err.encl_fn_span = Some(*encl_fn_span);
             }
 
             self.tcx.sess.emit_err(err);
diff --git a/src/test/ui/return/issue-86188-return-not-in-fn-body.rs b/src/test/ui/return/issue-86188-return-not-in-fn-body.rs
index 23cc9f0512c..4f076fa0693 100644
--- a/src/test/ui/return/issue-86188-return-not-in-fn-body.rs
+++ b/src/test/ui/return/issue-86188-return-not-in-fn-body.rs
@@ -12,6 +12,25 @@ const C: [(); 42] = {
     }]
 };
 
+struct S {}
+trait Tr {
+    fn foo();
+    fn bar() {
+    //~^ NOTE: ...not the enclosing function body
+        [(); return];
+        //~^ ERROR: return statement outside of function body [E0572]
+        //~| NOTE: the return is part of this body...
+    }
+}
+impl Tr for S {
+    fn foo() {
+    //~^ NOTE: ...not the enclosing function body
+        [(); return];
+        //~^ ERROR: return statement outside of function body [E0572]
+        //~| NOTE: the return is part of this body...
+    }
+}
+
 fn main() {
 //~^ NOTE: ...not the enclosing function body
     [(); return || {
diff --git a/src/test/ui/return/issue-86188-return-not-in-fn-body.stderr b/src/test/ui/return/issue-86188-return-not-in-fn-body.stderr
index 9275cb91dd3..d7eeb3a7290 100644
--- a/src/test/ui/return/issue-86188-return-not-in-fn-body.stderr
+++ b/src/test/ui/return/issue-86188-return-not-in-fn-body.stderr
@@ -9,7 +9,31 @@ LL | |     }]
    | |_____^
 
 error[E0572]: return statement outside of function body
-  --> $DIR/issue-86188-return-not-in-fn-body.rs:17:10
+  --> $DIR/issue-86188-return-not-in-fn-body.rs:20:14
+   |
+LL | /     fn bar() {
+LL | |
+LL | |         [(); return];
+   | |              ^^^^^^ the return is part of this body...
+LL | |
+LL | |
+LL | |     }
+   | |_____- ...not the enclosing function body
+
+error[E0572]: return statement outside of function body
+  --> $DIR/issue-86188-return-not-in-fn-body.rs:28:14
+   |
+LL | /     fn foo() {
+LL | |
+LL | |         [(); return];
+   | |              ^^^^^^ the return is part of this body...
+LL | |
+LL | |
+LL | |     }
+   | |_____- ...not the enclosing function body
+
+error[E0572]: return statement outside of function body
+  --> $DIR/issue-86188-return-not-in-fn-body.rs:36:10
    |
 LL |  / fn main() {
 LL |  |
@@ -23,6 +47,6 @@ LL | ||     }];
 LL |  | }
    |  |_- ...not the enclosing function body
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0572`.
diff --git a/src/test/ui/typeck/issue-86721-return-expr-ice.rev1.stderr b/src/test/ui/typeck/issue-86721-return-expr-ice.rev1.stderr
new file mode 100644
index 00000000000..b1111fcf148
--- /dev/null
+++ b/src/test/ui/typeck/issue-86721-return-expr-ice.rev1.stderr
@@ -0,0 +1,9 @@
+error[E0572]: return statement outside of function body
+  --> $DIR/issue-86721-return-expr-ice.rs:9:22
+   |
+LL |     const U: usize = return;
+   |                      ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0572`.
diff --git a/src/test/ui/typeck/issue-86721-return-expr-ice.rev2.stderr b/src/test/ui/typeck/issue-86721-return-expr-ice.rev2.stderr
new file mode 100644
index 00000000000..f489ae2002a
--- /dev/null
+++ b/src/test/ui/typeck/issue-86721-return-expr-ice.rev2.stderr
@@ -0,0 +1,9 @@
+error[E0572]: return statement outside of function body
+  --> $DIR/issue-86721-return-expr-ice.rs:15:20
+   |
+LL |     fn foo(a: [(); return]);
+   |                    ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0572`.
diff --git a/src/test/ui/typeck/issue-86721-return-expr-ice.rs b/src/test/ui/typeck/issue-86721-return-expr-ice.rs
new file mode 100644
index 00000000000..cd7135f18b1
--- /dev/null
+++ b/src/test/ui/typeck/issue-86721-return-expr-ice.rs
@@ -0,0 +1,17 @@
+// Regression test for the ICE described in #86721.
+
+// revisions: rev1 rev2
+#![cfg_attr(any(), rev1, rev2)]
+#![crate_type="lib"]
+
+#[cfg(any(rev1))]
+trait T {
+    const U: usize = return;
+    //[rev1]~^ ERROR: return statement outside of function body [E0572]
+}
+
+#[cfg(any(rev2))]
+trait T2 {
+    fn foo(a: [(); return]);
+    //[rev2]~^ ERROR: return statement outside of function body [E0572]
+}