Skip to content

Commit 4afdef0

Browse files
authored
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 ```
2 parents 17ea490 + bdddaeb commit 4afdef0

8 files changed

+204
-30
lines changed

compiler/rustc_typeck/src/check/expr.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
675675
expr: &'tcx hir::Expr<'tcx>,
676676
) -> Ty<'tcx> {
677677
if self.ret_coercion.is_none() {
678-
self.tcx.sess.emit_err(ReturnStmtOutsideOfFnBody { span: expr.span });
678+
let mut err = ReturnStmtOutsideOfFnBody {
679+
span: expr.span,
680+
encl_body_span: None,
681+
encl_fn_span: None,
682+
};
683+
684+
let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id);
685+
let encl_item = self.tcx.hir().expect_item(encl_item_id);
686+
687+
if let hir::ItemKind::Fn(..) = encl_item.kind {
688+
// We are inside a function body, so reporting "return statement
689+
// outside of function body" needs an explanation.
690+
691+
let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id);
692+
693+
// If this didn't hold, we would not have to report an error in
694+
// the first place.
695+
assert_ne!(encl_item_id, encl_body_owner_id);
696+
697+
let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id);
698+
let encl_body = self.tcx.hir().body(encl_body_id);
699+
700+
err.encl_body_span = Some(encl_body.value.span);
701+
err.encl_fn_span = Some(encl_item.span);
702+
}
703+
704+
self.tcx.sess.emit_err(err);
705+
706+
if let Some(e) = expr_opt {
707+
// We still have to type-check `e` (issue #86188), but calling
708+
// `check_return_expr` only works inside fn bodies.
709+
self.check_expr(e);
710+
}
679711
} else if let Some(e) = expr_opt {
680712
if self.ret_coercion_span.get().is_none() {
681713
self.ret_coercion_span.set(Some(e.span));

compiler/rustc_typeck/src/errors.rs

+4
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ pub struct TypeofReservedKeywordUsed {
147147
pub struct ReturnStmtOutsideOfFnBody {
148148
#[message = "return statement outside of function body"]
149149
pub span: Span,
150+
#[label = "the return is part of this body..."]
151+
pub encl_body_span: Option<Span>,
152+
#[label = "...not the enclosing function body"]
153+
pub encl_fn_span: Option<Span>,
150154
}
151155

152156
#[derive(SessionDiagnostic)]

src/test/ui/issues/issue-51714.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
fn main() {
2+
//~^ NOTE: not the enclosing function body
3+
//~| NOTE: not the enclosing function body
4+
//~| NOTE: not the enclosing function body
5+
//~| NOTE: not the enclosing function body
26
|_: [_; return || {}] | {};
3-
//~^ ERROR return statement outside of function body
7+
//~^ ERROR: return statement outside of function body [E0572]
8+
//~| NOTE: the return is part of this body...
49

510
[(); return || {}];
6-
//~^ ERROR return statement outside of function body
11+
//~^ ERROR: return statement outside of function body [E0572]
12+
//~| NOTE: the return is part of this body...
713

814
[(); return |ice| {}];
9-
//~^ ERROR return statement outside of function body
15+
//~^ ERROR: return statement outside of function body [E0572]
16+
//~| NOTE: the return is part of this body...
1017

1118
[(); return while let Some(n) = Some(0) {}];
12-
//~^ ERROR return statement outside of function body
19+
//~^ ERROR: return statement outside of function body [E0572]
20+
//~| NOTE: the return is part of this body...
1321
}

src/test/ui/issues/issue-51714.stderr

+48-12
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,62 @@
11
error[E0572]: return statement outside of function body
2-
--> $DIR/issue-51714.rs:2:14
2+
--> $DIR/issue-51714.rs:6:14
33
|
4-
LL | |_: [_; return || {}] | {};
5-
| ^^^^^^^^^^^^
4+
LL | / fn main() {
5+
LL | |
6+
LL | |
7+
LL | |
8+
LL | |
9+
LL | | |_: [_; return || {}] | {};
10+
| | ^^^^^^^^^^^^ the return is part of this body...
11+
... |
12+
LL | |
13+
LL | | }
14+
| |_- ...not the enclosing function body
615

716
error[E0572]: return statement outside of function body
8-
--> $DIR/issue-51714.rs:5:10
17+
--> $DIR/issue-51714.rs:10:10
918
|
10-
LL | [(); return || {}];
11-
| ^^^^^^^^^^^^
19+
LL | / fn main() {
20+
LL | |
21+
LL | |
22+
LL | |
23+
... |
24+
LL | | [(); return || {}];
25+
| | ^^^^^^^^^^^^ the return is part of this body...
26+
... |
27+
LL | |
28+
LL | | }
29+
| |_- ...not the enclosing function body
1230

1331
error[E0572]: return statement outside of function body
14-
--> $DIR/issue-51714.rs:8:10
32+
--> $DIR/issue-51714.rs:14:10
1533
|
16-
LL | [(); return |ice| {}];
17-
| ^^^^^^^^^^^^^^^
34+
LL | / fn main() {
35+
LL | |
36+
LL | |
37+
LL | |
38+
... |
39+
LL | | [(); return |ice| {}];
40+
| | ^^^^^^^^^^^^^^^ the return is part of this body...
41+
... |
42+
LL | |
43+
LL | | }
44+
| |_- ...not the enclosing function body
1845

1946
error[E0572]: return statement outside of function body
20-
--> $DIR/issue-51714.rs:11:10
47+
--> $DIR/issue-51714.rs:18:10
2148
|
22-
LL | [(); return while let Some(n) = Some(0) {}];
23-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49+
LL | / fn main() {
50+
LL | |
51+
LL | |
52+
LL | |
53+
... |
54+
LL | | [(); return while let Some(n) = Some(0) {}];
55+
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the return is part of this body...
56+
LL | |
57+
LL | |
58+
LL | | }
59+
| |_- ...not the enclosing function body
2460

2561
error: aborting due to 4 previous errors
2662

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Due to a compiler bug, if a return occurs outside of a function body
2+
// (e.g. in an AnonConst body), the return value expression would not be
3+
// type-checked, leading to an ICE. This test checks that the ICE no
4+
// longer happens, and that an appropriate error message is issued that
5+
// also explains why the return is considered "outside of a function body"
6+
// if it seems to be inside one, as in the main function below.
7+
8+
const C: [(); 42] = {
9+
[(); return || {
10+
//~^ ERROR: return statement outside of function body [E0572]
11+
let tx;
12+
}]
13+
};
14+
15+
fn main() {
16+
//~^ NOTE: ...not the enclosing function body
17+
[(); return || {
18+
//~^ ERROR: return statement outside of function body [E0572]
19+
//~| NOTE: the return is part of this body...
20+
let tx;
21+
}];
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error[E0572]: return statement outside of function body
2+
--> $DIR/issue-86188-return-not-in-fn-body.rs:9:10
3+
|
4+
LL | [(); return || {
5+
| __________^
6+
LL | |
7+
LL | | let tx;
8+
LL | | }]
9+
| |_____^
10+
11+
error[E0572]: return statement outside of function body
12+
--> $DIR/issue-86188-return-not-in-fn-body.rs:17:10
13+
|
14+
LL | / fn main() {
15+
LL | |
16+
LL | | [(); return || {
17+
| |__________^
18+
LL | ||
19+
LL | ||
20+
LL | || let tx;
21+
LL | || }];
22+
| ||_____^ the return is part of this body...
23+
LL | | }
24+
| |_- ...not the enclosing function body
25+
26+
error: aborting due to 2 previous errors
27+
28+
For more information about this error, try `rustc --explain E0572`.
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
fn main() {
2+
//~^ NOTE: not the enclosing function body
3+
//~| NOTE: not the enclosing function body
4+
//~| NOTE: not the enclosing function body
25
[(); return match 0 { n => n }];
3-
//~^ ERROR: return statement outside of function body
6+
//~^ ERROR: return statement outside of function body [E0572]
7+
//~| NOTE: the return is part of this body...
48

59
[(); return match 0 { 0 => 0 }];
6-
//~^ ERROR: return statement outside of function body
10+
//~^ ERROR: return statement outside of function body [E0572]
11+
//~| NOTE: the return is part of this body...
712

813
[(); return match () { 'a' => 0, _ => 0 }];
9-
//~^ ERROR: return statement outside of function body
14+
//~^ ERROR: return statement outside of function body [E0572]
15+
//~| NOTE: the return is part of this body...
16+
//~| ERROR: mismatched types [E0308]
17+
//~| NOTE: expected `()`, found `char`
18+
//~| NOTE: this expression has type `()`
1019
}
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,56 @@
11
error[E0572]: return statement outside of function body
2-
--> $DIR/return-match-array-const.rs:2:10
2+
--> $DIR/return-match-array-const.rs:5:10
33
|
4-
LL | [(); return match 0 { n => n }];
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^
4+
LL | / fn main() {
5+
LL | |
6+
LL | |
7+
LL | |
8+
LL | | [(); return match 0 { n => n }];
9+
| | ^^^^^^^^^^^^^^^^^^^^^^^^^ the return is part of this body...
10+
... |
11+
LL | |
12+
LL | | }
13+
| |_- ...not the enclosing function body
614

715
error[E0572]: return statement outside of function body
8-
--> $DIR/return-match-array-const.rs:5:10
16+
--> $DIR/return-match-array-const.rs:9:10
917
|
10-
LL | [(); return match 0 { 0 => 0 }];
11-
| ^^^^^^^^^^^^^^^^^^^^^^^^^
18+
LL | / fn main() {
19+
LL | |
20+
LL | |
21+
LL | |
22+
... |
23+
LL | | [(); return match 0 { 0 => 0 }];
24+
| | ^^^^^^^^^^^^^^^^^^^^^^^^^ the return is part of this body...
25+
... |
26+
LL | |
27+
LL | | }
28+
| |_- ...not the enclosing function body
1229

1330
error[E0572]: return statement outside of function body
14-
--> $DIR/return-match-array-const.rs:8:10
31+
--> $DIR/return-match-array-const.rs:13:10
32+
|
33+
LL | / fn main() {
34+
LL | |
35+
LL | |
36+
LL | |
37+
... |
38+
LL | | [(); return match () { 'a' => 0, _ => 0 }];
39+
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the return is part of this body...
40+
... |
41+
LL | |
42+
LL | | }
43+
| |_- ...not the enclosing function body
44+
45+
error[E0308]: mismatched types
46+
--> $DIR/return-match-array-const.rs:13:28
1547
|
1648
LL | [(); return match () { 'a' => 0, _ => 0 }];
17-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49+
| -- ^^^ expected `()`, found `char`
50+
| |
51+
| this expression has type `()`
1852

19-
error: aborting due to 3 previous errors
53+
error: aborting due to 4 previous errors
2054

21-
For more information about this error, try `rustc --explain E0572`.
55+
Some errors have detailed explanations: E0308, E0572.
56+
For more information about an error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)