Skip to content

Commit 9177a39

Browse files
authored
Unrolled build for rust-lang#141317
Rollup merge of rust-lang#141317 - dianne:continue-liveness-ice-fix, r=compiler-errors typeck: catch `continue`s pointing to blocks This taints the typeck results with errors if a `continue` is found not pointing to a loop. A few things were going wrong here. First, since this wasn't caught in typeck, we'd end up building the THIR and then running liveness lints on ill-formed HIR. Since liveness assumes all `continue`s point to loops, it wasn't setting a live node for the `continue`'s destination. There was a fallback for if it couldn't retrieve that live node, but it was faulty; it would create a new live node to represent an erroneous state after the analysis's RWU table had already been built. This would ICE if the new live node was used in operations, such as merging results from the arms of a match. I've removed this error-recovery since it was buggy, and we should really catch bad labels before liveness. I've also replaced an outdated comment about when liveness lints are run. At this point, I think the call to `check_liveness` could be moved elsewhere, but if it can be run when the typeck results are tainted by errors, it'll need some slight refactoring so it can bail out in that case. In lieu of that, I've added an assert. Fixes rust-lang#113379 Fixes rust-lang#121623
2 parents bbd3a5a + ed01a20 commit 9177a39

File tree

9 files changed

+113
-29
lines changed

9 files changed

+113
-29
lines changed

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -532,14 +532,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
532532
ExprKind::Break(destination, ref expr_opt) => {
533533
self.check_expr_break(destination, expr_opt.as_deref(), expr)
534534
}
535-
ExprKind::Continue(destination) => {
536-
if destination.target_id.is_ok() {
537-
tcx.types.never
538-
} else {
539-
// There was an error; make type-check fail.
540-
Ty::new_misc_error(tcx)
541-
}
542-
}
535+
ExprKind::Continue(destination) => self.check_expr_continue(destination, expr),
543536
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
544537
ExprKind::Become(call) => self.check_expr_become(call, expr),
545538
ExprKind::Let(let_expr) => self.check_expr_let(let_expr, expr.hir_id),
@@ -989,6 +982,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
989982
}
990983
}
991984

985+
fn check_expr_continue(
986+
&self,
987+
destination: hir::Destination,
988+
expr: &'tcx hir::Expr<'tcx>,
989+
) -> Ty<'tcx> {
990+
if let Ok(target_id) = destination.target_id {
991+
if let hir::Node::Expr(hir::Expr { kind: ExprKind::Loop(..), .. }) =
992+
self.tcx.hir_node(target_id)
993+
{
994+
self.tcx.types.never
995+
} else {
996+
// Liveness linting assumes `continue`s all point to loops. We'll report an error
997+
// in `check_mod_loops`, but make sure we don't run liveness (#113379, #121623).
998+
let guar = self.dcx().span_delayed_bug(
999+
expr.span,
1000+
"found `continue` not pointing to loop, but no error reported",
1001+
);
1002+
Ty::new_error(self.tcx, guar)
1003+
}
1004+
} else {
1005+
// There was an error; make type-check fail.
1006+
Ty::new_misc_error(self.tcx)
1007+
}
1008+
}
1009+
9921010
fn check_expr_return(
9931011
&self,
9941012
expr_opt: Option<&'tcx hir::Expr<'tcx>>,

compiler/rustc_mir_build/src/builder/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
6666
}
6767
};
6868

69-
// this must run before MIR dump, because
70-
// "not all control paths return a value" is reported here.
69+
// Checking liveness after building the THIR ensures there were no typeck errors.
7170
//
7271
// maybe move the check to a MIR pass?
7372
tcx.ensure_ok().check_liveness(def);

compiler/rustc_passes/src/liveness.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ enum LiveNodeKind {
122122
VarDefNode(Span, HirId),
123123
ClosureNode,
124124
ExitNode,
125-
ErrNode,
126125
}
127126

128127
fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
@@ -133,7 +132,6 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
133132
VarDefNode(s, _) => format!("Var def node [{}]", sm.span_to_diagnostic_string(s)),
134133
ClosureNode => "Closure node".to_owned(),
135134
ExitNode => "Exit node".to_owned(),
136-
ErrNode => "Error node".to_owned(),
137135
}
138136
}
139137

@@ -492,6 +490,9 @@ struct Liveness<'a, 'tcx> {
492490
impl<'a, 'tcx> Liveness<'a, 'tcx> {
493491
fn new(ir: &'a mut IrMaps<'tcx>, body_owner: LocalDefId) -> Liveness<'a, 'tcx> {
494492
let typeck_results = ir.tcx.typeck(body_owner);
493+
// Liveness linting runs after building the THIR. We make several assumptions based on
494+
// typeck succeeding, e.g. that breaks and continues are well-formed.
495+
assert!(typeck_results.tainted_by_errors.is_none());
495496
// FIXME(#132279): we're in a body here.
496497
let typing_env = ty::TypingEnv::non_body_analysis(ir.tcx, body_owner);
497498
let closure_min_captures = typeck_results.closure_min_captures.get(&body_owner);
@@ -976,8 +977,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
976977
// Now that we know the label we're going to,
977978
// look it up in the continue loop nodes table
978979
self.cont_ln.get(&sc).cloned().unwrap_or_else(|| {
979-
self.ir.tcx.dcx().span_delayed_bug(expr.span, "continue to unknown label");
980-
self.ir.add_live_node(ErrNode)
980+
// Liveness linting happens after building the THIR. Bad labels should already
981+
// have been caught.
982+
span_bug!(expr.span, "continue to unknown label");
981983
})
982984
}
983985

tests/crashes/113379.rs

Lines changed: 0 additions & 7 deletions
This file was deleted.

tests/crashes/121623.rs

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//! Regression test for ICE #113379. Liveness linting assumes that `continue`s all point to loops.
2+
//! This tests that if a `continue` points to a block, we don't run liveness lints.
3+
4+
async fn f999() -> Vec<usize> {
5+
//~^ ERROR `async fn` is not permitted in Rust 2015
6+
'b: {
7+
//~^ ERROR mismatched types
8+
continue 'b;
9+
//~^ ERROR `continue` pointing to a labeled block
10+
}
11+
}
12+
//~^ ERROR `main` function not found
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error[E0670]: `async fn` is not permitted in Rust 2015
2+
--> $DIR/continue-pointing-to-block-ice-113379.rs:4:1
3+
|
4+
LL | async fn f999() -> Vec<usize> {
5+
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
6+
|
7+
= help: pass `--edition 2024` to `rustc`
8+
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
9+
10+
error[E0601]: `main` function not found in crate `continue_pointing_to_block_ice_113379`
11+
--> $DIR/continue-pointing-to-block-ice-113379.rs:11:2
12+
|
13+
LL | }
14+
| ^ consider adding a `main` function to `$DIR/continue-pointing-to-block-ice-113379.rs`
15+
16+
error[E0696]: `continue` pointing to a labeled block
17+
--> $DIR/continue-pointing-to-block-ice-113379.rs:8:9
18+
|
19+
LL | / 'b: {
20+
LL | |
21+
LL | | continue 'b;
22+
| | ^^^^^^^^^^^ labeled blocks cannot be `continue`'d
23+
LL | |
24+
LL | | }
25+
| |_____- labeled block the `continue` points to
26+
27+
error[E0308]: mismatched types
28+
--> $DIR/continue-pointing-to-block-ice-113379.rs:6:5
29+
|
30+
LL | / 'b: {
31+
LL | |
32+
LL | | continue 'b;
33+
LL | |
34+
LL | | }
35+
| |_____^ expected `Vec<usize>`, found `()`
36+
|
37+
= note: expected struct `Vec<usize>`
38+
found unit type `()`
39+
40+
error: aborting due to 4 previous errors
41+
42+
Some errors have detailed explanations: E0308, E0601, E0670, E0696.
43+
For more information about an error, try `rustc --explain E0308`.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//! Regression test for ICE #121623. Liveness linting assumes that `continue`s all point to loops.
2+
//! This tests that if a `continue` points to a block, we don't run liveness lints.
3+
4+
fn main() {
5+
match () {
6+
_ => 'b: {
7+
continue 'b;
8+
//~^ ERROR `continue` pointing to a labeled block
9+
}
10+
}
11+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0696]: `continue` pointing to a labeled block
2+
--> $DIR/continue-pointing-to-block-ice-121623.rs:7:13
3+
|
4+
LL | _ => 'b: {
5+
| ______________-
6+
LL | | continue 'b;
7+
| | ^^^^^^^^^^^ labeled blocks cannot be `continue`'d
8+
LL | |
9+
LL | | }
10+
| |_________- labeled block the `continue` points to
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0696`.

0 commit comments

Comments
 (0)