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 ```
This commit is contained in:
commit
4afdef07d9
8 changed files with 206 additions and 32 deletions
|
@ -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));
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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...
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
22
src/test/ui/return/issue-86188-return-not-in-fn-body.rs
Normal file
22
src/test/ui/return/issue-86188-return-not-in-fn-body.rs
Normal file
|
@ -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;
|
||||
}];
|
||||
}
|
28
src/test/ui/return/issue-86188-return-not-in-fn-body.stderr
Normal file
28
src/test/ui/return/issue-86188-return-not-in-fn-body.stderr
Normal file
|
@ -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`.
|
|
@ -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 `()`
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
Loading…
Add table
Reference in a new issue