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:
e98897e5dc/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.
This commit is contained in:
Yuki Okushi 2021-07-01 05:20:58 +09:00 committed by GitHub
commit dfe05c0ea0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 97 additions and 5 deletions

View File

@ -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);

View File

@ -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 || {

View File

@ -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`.

View File

@ -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`.

View File

@ -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`.

View File

@ -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]
}