1
Fork 0

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:
Yuki Okushi 2021-06-29 00:26:54 +09:00 committed by GitHub
commit 4afdef07d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 206 additions and 32 deletions

View file

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

View file

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