diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 28ab6b15133..f69839bf859 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -675,7 +675,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { if self.ret_coercion.is_none() { - self.tcx.sess.emit_err(ReturnStmtOutsideOfFnBody { span: expr.span }); + let mut err = ReturnStmtOutsideOfFnBody { + span: expr.span, + encl_body_span: None, + encl_fn_span: None, + }; + + 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. + + 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); + + 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); + } + + self.tcx.sess.emit_err(err); + + if let Some(e) = expr_opt { + // We still have to type-check `e` (issue #86188), but calling + // `check_return_expr` only works inside fn bodies. + self.check_expr(e); + } } else if let Some(e) = expr_opt { if self.ret_coercion_span.get().is_none() { self.ret_coercion_span.set(Some(e.span)); diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 5068242692a..1a21c085d53 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -147,6 +147,10 @@ pub struct TypeofReservedKeywordUsed { pub struct ReturnStmtOutsideOfFnBody { #[message = "return statement outside of function body"] pub span: Span, + #[label = "the return is part of this body..."] + pub encl_body_span: Option, + #[label = "...not the enclosing function body"] + pub encl_fn_span: Option, } #[derive(SessionDiagnostic)] diff --git a/src/test/ui/issues/issue-51714.rs b/src/test/ui/issues/issue-51714.rs index 0dc588d75c6..8716524d6f4 100644 --- a/src/test/ui/issues/issue-51714.rs +++ b/src/test/ui/issues/issue-51714.rs @@ -1,13 +1,21 @@ fn main() { +//~^ NOTE: not the enclosing function body +//~| NOTE: not the enclosing function body +//~| NOTE: not the enclosing function body +//~| NOTE: not the enclosing function body |_: [_; return || {}] | {}; - //~^ ERROR return statement outside of function body + //~^ ERROR: return statement outside of function body [E0572] + //~| NOTE: the return is part of this body... [(); return || {}]; - //~^ ERROR return statement outside of function body + //~^ ERROR: return statement outside of function body [E0572] + //~| NOTE: the return is part of this body... [(); return |ice| {}]; - //~^ ERROR return statement outside of function body + //~^ ERROR: return statement outside of function body [E0572] + //~| NOTE: the return is part of this body... [(); return while let Some(n) = Some(0) {}]; - //~^ ERROR return statement outside of function body + //~^ ERROR: return statement outside of function body [E0572] + //~| NOTE: the return is part of this body... } diff --git a/src/test/ui/issues/issue-51714.stderr b/src/test/ui/issues/issue-51714.stderr index 023d9013ab4..514d69c1c7d 100644 --- a/src/test/ui/issues/issue-51714.stderr +++ b/src/test/ui/issues/issue-51714.stderr @@ -1,26 +1,62 @@ error[E0572]: return statement outside of function body - --> $DIR/issue-51714.rs:2:14 + --> $DIR/issue-51714.rs:6:14 | -LL | |_: [_; return || {}] | {}; - | ^^^^^^^^^^^^ +LL | / fn main() { +LL | | +LL | | +LL | | +LL | | +LL | | |_: [_; return || {}] | {}; + | | ^^^^^^^^^^^^ the return is part of this body... +... | +LL | | +LL | | } + | |_- ...not the enclosing function body error[E0572]: return statement outside of function body - --> $DIR/issue-51714.rs:5:10 + --> $DIR/issue-51714.rs:10:10 | -LL | [(); return || {}]; - | ^^^^^^^^^^^^ +LL | / fn main() { +LL | | +LL | | +LL | | +... | +LL | | [(); return || {}]; + | | ^^^^^^^^^^^^ the return is part of this body... +... | +LL | | +LL | | } + | |_- ...not the enclosing function body error[E0572]: return statement outside of function body - --> $DIR/issue-51714.rs:8:10 + --> $DIR/issue-51714.rs:14:10 | -LL | [(); return |ice| {}]; - | ^^^^^^^^^^^^^^^ +LL | / fn main() { +LL | | +LL | | +LL | | +... | +LL | | [(); return |ice| {}]; + | | ^^^^^^^^^^^^^^^ the return is part of this body... +... | +LL | | +LL | | } + | |_- ...not the enclosing function body error[E0572]: return statement outside of function body - --> $DIR/issue-51714.rs:11:10 + --> $DIR/issue-51714.rs:18:10 | -LL | [(); return while let Some(n) = Some(0) {}]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / fn main() { +LL | | +LL | | +LL | | +... | +LL | | [(); return while let Some(n) = Some(0) {}]; + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the return is part of this body... +LL | | +LL | | +LL | | } + | |_- ...not the enclosing function body error: aborting due to 4 previous errors 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 new file mode 100644 index 00000000000..23cc9f0512c --- /dev/null +++ b/src/test/ui/return/issue-86188-return-not-in-fn-body.rs @@ -0,0 +1,22 @@ +// Due to a compiler bug, if a return occurs outside of a function body +// (e.g. in an AnonConst body), the return value expression would not be +// type-checked, leading to an ICE. This test checks that the ICE no +// longer happens, and that an appropriate error message is issued that +// also explains why the return is considered "outside of a function body" +// if it seems to be inside one, as in the main function below. + +const C: [(); 42] = { + [(); return || { + //~^ ERROR: return statement outside of function body [E0572] + let tx; + }] +}; + +fn main() { +//~^ NOTE: ...not the enclosing function body + [(); return || { + //~^ ERROR: return statement outside of function body [E0572] + //~| NOTE: the return is part of this body... + let tx; + }]; +} 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 new file mode 100644 index 00000000000..9275cb91dd3 --- /dev/null +++ b/src/test/ui/return/issue-86188-return-not-in-fn-body.stderr @@ -0,0 +1,28 @@ +error[E0572]: return statement outside of function body + --> $DIR/issue-86188-return-not-in-fn-body.rs:9:10 + | +LL | [(); return || { + | __________^ +LL | | +LL | | let tx; +LL | | }] + | |_____^ + +error[E0572]: return statement outside of function body + --> $DIR/issue-86188-return-not-in-fn-body.rs:17:10 + | +LL | / fn main() { +LL | | +LL | | [(); return || { + | |__________^ +LL | || +LL | || +LL | || let tx; +LL | || }]; + | ||_____^ the return is part of this body... +LL | | } + | |_- ...not the enclosing function body + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0572`. diff --git a/src/test/ui/return/return-match-array-const.rs b/src/test/ui/return/return-match-array-const.rs index f21eac37c17..b619a4d57f9 100644 --- a/src/test/ui/return/return-match-array-const.rs +++ b/src/test/ui/return/return-match-array-const.rs @@ -1,10 +1,19 @@ fn main() { +//~^ NOTE: not the enclosing function body +//~| NOTE: not the enclosing function body +//~| NOTE: not the enclosing function body [(); return match 0 { n => n }]; - //~^ ERROR: return statement outside of function body + //~^ ERROR: return statement outside of function body [E0572] + //~| NOTE: the return is part of this body... [(); return match 0 { 0 => 0 }]; - //~^ ERROR: return statement outside of function body + //~^ ERROR: return statement outside of function body [E0572] + //~| NOTE: the return is part of this body... [(); return match () { 'a' => 0, _ => 0 }]; - //~^ ERROR: return statement outside of function body + //~^ ERROR: return statement outside of function body [E0572] + //~| NOTE: the return is part of this body... + //~| ERROR: mismatched types [E0308] + //~| NOTE: expected `()`, found `char` + //~| NOTE: this expression has type `()` } diff --git a/src/test/ui/return/return-match-array-const.stderr b/src/test/ui/return/return-match-array-const.stderr index 8e801e3fbb7..85a733adfee 100644 --- a/src/test/ui/return/return-match-array-const.stderr +++ b/src/test/ui/return/return-match-array-const.stderr @@ -1,21 +1,56 @@ -error[E0572]: return statement outside of function body - --> $DIR/return-match-array-const.rs:2:10 - | -LL | [(); return match 0 { n => n }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0572]: return statement outside of function body --> $DIR/return-match-array-const.rs:5:10 | -LL | [(); return match 0 { 0 => 0 }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / fn main() { +LL | | +LL | | +LL | | +LL | | [(); return match 0 { n => n }]; + | | ^^^^^^^^^^^^^^^^^^^^^^^^^ the return is part of this body... +... | +LL | | +LL | | } + | |_- ...not the enclosing function body error[E0572]: return statement outside of function body - --> $DIR/return-match-array-const.rs:8:10 + --> $DIR/return-match-array-const.rs:9:10 + | +LL | / fn main() { +LL | | +LL | | +LL | | +... | +LL | | [(); return match 0 { 0 => 0 }]; + | | ^^^^^^^^^^^^^^^^^^^^^^^^^ the return is part of this body... +... | +LL | | +LL | | } + | |_- ...not the enclosing function body + +error[E0572]: return statement outside of function body + --> $DIR/return-match-array-const.rs:13:10 + | +LL | / fn main() { +LL | | +LL | | +LL | | +... | +LL | | [(); return match () { 'a' => 0, _ => 0 }]; + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the return is part of this body... +... | +LL | | +LL | | } + | |_- ...not the enclosing function body + +error[E0308]: mismatched types + --> $DIR/return-match-array-const.rs:13:28 | LL | [(); return match () { 'a' => 0, _ => 0 }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- ^^^ expected `()`, found `char` + | | + | this expression has type `()` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0572`. +Some errors have detailed explanations: E0308, E0572. +For more information about an error, try `rustc --explain E0308`.