diff options
| author | Yuki Okushi <jtitor@2k36.org> | 2021-06-29 00:26:54 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-06-29 00:26:54 +0900 |
| commit | 4afdef07d9edb6fab979b01f510a16ffc27a6ab6 (patch) | |
| tree | acbad63401ccc4f8918fd56380c88db9799416c7 | |
| parent | 17ea490310ba7c836c93fe1b7002555b3bea5eb1 (diff) | |
| parent | bdddaebd76cba207b67141e2c362a4fe117bbd34 (diff) | |
| download | rust-4afdef07d9edb6fab979b01f510a16ffc27a6ab6.tar.gz rust-4afdef07d9edb6fab979b01f510a16ffc27a6ab6.zip | |
Rollup merge of #86206 - FabianWolff:issue-86188, r=Mark-Simulacrum
Fix type checking of return expressions outside of function bodies
This pull request fixes #86188. The problem is that the current code for type-checking `return` expressions stops if the `return` occurs outside of a function body, while the correct behavior is to continue type-checking the return value expression (otherwise an ICE happens later on because variables declared in the return value expression don't have a type).
Also, I have noticed that it is sometimes not obvious why a `return` is outside of a function body; for instance, in the example from #86188 (which currently causes an ICE):
```rust
fn main() {
[(); return || {
let tx;
}]
}
```
I have changed the error message to also explain why the `return` is considered outside of the function body:
```
error[E0572]: return statement outside of function body
--> ice0.rs:2:10
|
1 | / fn main() {
2 | | [(); return || {
| |__________^
3 | || let tx;
4 | || }]
| ||_____^ the return is part of this body...
5 | | }
| |_- ...not the enclosing function body
```
| -rw-r--r-- | compiler/rustc_typeck/src/check/expr.rs | 34 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/errors.rs | 4 | ||||
| -rw-r--r-- | src/test/ui/issues/issue-51714.rs | 16 | ||||
| -rw-r--r-- | src/test/ui/issues/issue-51714.stderr | 60 | ||||
| -rw-r--r-- | src/test/ui/return/issue-86188-return-not-in-fn-body.rs | 22 | ||||
| -rw-r--r-- | src/test/ui/return/issue-86188-return-not-in-fn-body.stderr | 28 | ||||
| -rw-r--r-- | src/test/ui/return/return-match-array-const.rs | 15 | ||||
| -rw-r--r-- | src/test/ui/return/return-match-array-const.stderr | 55 |
8 files changed, 204 insertions, 30 deletions
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<Span>, + #[label = "...not the enclosing function body"] + pub encl_fn_span: Option<Span>, } #[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 + --> $DIR/return-match-array-const.rs:5:10 | -LL | [(); return match 0 { n => n }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +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:5:10 + --> $DIR/return-match-array-const.rs:9:10 | -LL | [(); return match 0 { 0 => 0 }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +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:8:10 + --> $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`. |
