From 2586e962e0924d832c708a7308d88da27d8bc01b Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Tue, 29 Jun 2021 22:11:48 +0200 Subject: [PATCH 1/3] Check node kind to avoid ICE in `check_expr_return()` --- compiler/rustc_typeck/src/check/expr.rs | 28 +++++++++++-------- .../ui/typeck/issue-86721-return-expr-ice.rs | 8 ++++++ .../typeck/issue-86721-return-expr-ice.stderr | 9 ++++++ 3 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/typeck/issue-86721-return-expr-ice.rs create mode 100644 src/test/ui/typeck/issue-86721-return-expr-ice.stderr diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index f69839bf859..1f929af6cc5 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -682,23 +682,27 @@ 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 { - // We are inside a function body, so reporting "return statement - // outside of function body" needs an explanation. + // Somewhat confusingly, get_parent_item() does not necessarily return an + // item -- it can also return a Foreign-/Impl-/TraitItem or a Crate (see + // issue #86721). If it does, we still report the same error. + if let Some(hir::Node::Item(encl_item)) = self.tcx.hir().find(encl_item_id) { + if let hir::ItemKind::Fn(..) = encl_item.kind { + // We are inside a function body, so reporting "return statement + // outside of function body" needs an explanation. - let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id); + let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id); - // If this didn't hold, we would not have to report an error in - // the first place. - assert_ne!(encl_item_id, encl_body_owner_id); + // If this didn't hold, we would not have to report an error in + // the first place. + assert_ne!(encl_item_id, encl_body_owner_id); - let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id); - let encl_body = self.tcx.hir().body(encl_body_id); + let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id); + 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_body_span = Some(encl_body.value.span); + err.encl_fn_span = Some(encl_item.span); + } } self.tcx.sess.emit_err(err); 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..9216fb0d171 --- /dev/null +++ b/src/test/ui/typeck/issue-86721-return-expr-ice.rs @@ -0,0 +1,8 @@ +// Regression test for the ICE described in #86721. + +#![crate_type="lib"] + +trait T { + const U: usize = return; + //~^ ERROR: return statement outside of function body [E0572] +} diff --git a/src/test/ui/typeck/issue-86721-return-expr-ice.stderr b/src/test/ui/typeck/issue-86721-return-expr-ice.stderr new file mode 100644 index 00000000000..39f8fb8da14 --- /dev/null +++ b/src/test/ui/typeck/issue-86721-return-expr-ice.stderr @@ -0,0 +1,9 @@ +error[E0572]: return statement outside of function body + --> $DIR/issue-86721-return-expr-ice.rs:6:22 + | +LL | const U: usize = return; + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0572`. From 11fd8579e44950c0cca82bb389d255962854b9ce Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Wed, 30 Jun 2021 13:56:26 +0200 Subject: [PATCH 2/3] Emit explanatory note for functions in trait and impl items as well --- compiler/rustc_typeck/src/check/expr.rs | 24 ++++++++++++---- .../issue-86188-return-not-in-fn-body.rs | 19 +++++++++++++ .../issue-86188-return-not-in-fn-body.stderr | 28 +++++++++++++++++-- ...> issue-86721-return-expr-ice.rev1.stderr} | 2 +- .../issue-86721-return-expr-ice.rev2.stderr | 9 ++++++ .../ui/typeck/issue-86721-return-expr-ice.rs | 11 +++++++- 6 files changed, 83 insertions(+), 10 deletions(-) rename src/test/ui/typeck/{issue-86721-return-expr-ice.stderr => issue-86721-return-expr-ice.rev1.stderr} (83%) create mode 100644 src/test/ui/typeck/issue-86721-return-expr-ice.rev2.stderr diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 1f929af6cc5..de38c41e93c 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -683,11 +683,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id); - // Somewhat confusingly, get_parent_item() does not necessarily return an - // item -- it can also return a Foreign-/Impl-/TraitItem or a Crate (see - // issue #86721). If it does, we still report the same error. - if let Some(hir::Node::Item(encl_item)) = self.tcx.hir().find(encl_item_id) { - if let hir::ItemKind::Fn(..) = encl_item.kind { + if self.tcx.hir().maybe_body_owned_by(encl_item_id).is_some() { + 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(..), + 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. @@ -701,7 +713,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); } } 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.stderr b/src/test/ui/typeck/issue-86721-return-expr-ice.rev1.stderr similarity index 83% rename from src/test/ui/typeck/issue-86721-return-expr-ice.stderr rename to src/test/ui/typeck/issue-86721-return-expr-ice.rev1.stderr index 39f8fb8da14..b1111fcf148 100644 --- a/src/test/ui/typeck/issue-86721-return-expr-ice.stderr +++ b/src/test/ui/typeck/issue-86721-return-expr-ice.rev1.stderr @@ -1,5 +1,5 @@ error[E0572]: return statement outside of function body - --> $DIR/issue-86721-return-expr-ice.rs:6:22 + --> $DIR/issue-86721-return-expr-ice.rs:9:22 | LL | const U: usize = return; | ^^^^^^ 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 index 9216fb0d171..cd7135f18b1 100644 --- a/src/test/ui/typeck/issue-86721-return-expr-ice.rs +++ b/src/test/ui/typeck/issue-86721-return-expr-ice.rs @@ -1,8 +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; - //~^ ERROR: return statement outside of function body [E0572] + //[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] } From 0c267830d5afdeea2058f0b97e69cf1afbb3d3da Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Wed, 30 Jun 2021 18:27:07 +0200 Subject: [PATCH 3/3] Match on `hir::TraitFn::Provided` instead of using `maybe_body_owned_by` --- compiler/rustc_typeck/src/check/expr.rs | 54 ++++++++++++------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index de38c41e93c..cfe1d1c6871 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -683,38 +683,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id); - if self.tcx.hir().maybe_body_owned_by(encl_item_id).is_some() { - 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(..), - 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. + 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. - let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id); + let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id); - // If this didn't hold, we would not have to report an error in - // the first place. - assert_ne!(encl_item_id, encl_body_owner_id); + // If this didn't hold, we would not have to report an error in + // the first place. + assert_ne!(encl_item_id, encl_body_owner_id); - let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id); - let encl_body = self.tcx.hir().body(encl_body_id); + let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id); + 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_fn_span); - } + err.encl_body_span = Some(encl_body.value.span); + err.encl_fn_span = Some(*encl_fn_span); } self.tcx.sess.emit_err(err);