Skip to content

Commit 32ac8d8

Browse files
committed
Fix ICE with continue/break/return in while condition,Fixes #3977
1 parent c01290e commit 32ac8d8

File tree

2 files changed

+104
-4
lines changed

2 files changed

+104
-4
lines changed

gcc/rust/typecheck/rust-hir-type-check-expr.cc

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,18 +1550,46 @@ void
15501550
TypeCheckExpr::visit (HIR::WhileLoopExpr &expr)
15511551
{
15521552
context->push_new_while_loop_context (expr.get_mappings ().get_hirid ());
1553-
1554-
TypeCheckExpr::Resolve (expr.get_predicate_expr ());
1553+
TyTy::BaseType *predicate_type
1554+
= TypeCheckExpr::Resolve (expr.get_predicate_expr ());
1555+
if (predicate_type->get_kind () == TyTy::TypeKind::ERROR)
1556+
{
1557+
infered = TyTy::TupleType::get_unit_type ();
1558+
context->pop_loop_context ();
1559+
return;
1560+
}
1561+
if (predicate_type->get_kind () == TyTy::TypeKind::NEVER)
1562+
{
1563+
rust_error_at (expr.get_predicate_expr ().get_locus (),
1564+
"expected boolean expression in %<while%> condition");
1565+
infered = TyTy::TupleType::get_unit_type ();
1566+
context->pop_loop_context ();
1567+
return;
1568+
}
1569+
if (predicate_type->get_kind () != TyTy::TypeKind::BOOL)
1570+
{
1571+
rust_error_at (expr.get_predicate_expr ().get_locus (),
1572+
"expected boolean expression in %<while%> condition");
1573+
infered = TyTy::TupleType::get_unit_type ();
1574+
context->pop_loop_context ();
1575+
return;
1576+
}
15551577
TyTy::BaseType *block_expr = TypeCheckExpr::Resolve (expr.get_loop_block ());
1556-
15571578
if (!block_expr->is_unit ())
15581579
{
15591580
rust_error_at (expr.get_loop_block ().get_locus (),
15601581
"expected %<()%> got %s",
15611582
block_expr->as_string ().c_str ());
1583+
infered = TyTy::TupleType::get_unit_type ();
1584+
context->pop_loop_context ();
1585+
return;
1586+
}
1587+
if (block_expr->get_kind () == TyTy::TypeKind::ERROR)
1588+
{
1589+
infered = TyTy::TupleType::get_unit_type ();
1590+
context->pop_loop_context ();
15621591
return;
15631592
}
1564-
15651593
context->pop_loop_context ();
15661594
infered = TyTy::TupleType::get_unit_type ();
15671595
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Test for issue #3977: ICE in fold_convert_loc with diverging expressions in while conditions
2+
// { dg-excess-errors "expected boolean expression" }
3+
4+
fn test_continue() {
5+
loop {
6+
while continue {} // { dg-error "expected boolean expression in 'while' condition" }
7+
}
8+
}
9+
10+
fn test_break() {
11+
loop {
12+
while break {} // { dg-error "expected boolean expression in 'while' condition" }
13+
}
14+
}
15+
16+
fn test_return() {
17+
while return {} // { dg-error "expected boolean expression in 'while' condition" }
18+
}
19+
20+
fn test_return_with_value() {
21+
while return 42 {} // { dg-error "expected boolean expression in 'while' condition" }
22+
}
23+
24+
fn test_infinite_loop() {
25+
while loop {} {} // { dg-error "expected boolean expression in 'while' condition" }
26+
}
27+
28+
fn test_nested_continue() {
29+
loop {
30+
loop {
31+
while continue {} // { dg-error "expected boolean expression in 'while' condition" }
32+
}
33+
}
34+
}
35+
36+
fn test_labeled_break() {
37+
'outer: loop {
38+
while break 'outer {} // { dg-error "expected boolean expression in 'while' condition" }
39+
}
40+
}
41+
42+
fn test_labeled_continue() {
43+
'outer: loop {
44+
while continue 'outer {} // { dg-error "expected boolean expression in 'while' condition" }
45+
}
46+
}
47+
48+
// Valid cases that should NOT error
49+
fn test_valid_boolean() {
50+
while true {}
51+
while false {}
52+
}
53+
54+
fn test_valid_expression() {
55+
let x = 5;
56+
while x > 0 {}
57+
}
58+
59+
fn test_valid_function_call() -> bool {
60+
fn condition() -> bool { true }
61+
while condition() {}
62+
true
63+
}
64+
65+
fn main() {
66+
test_valid_boolean();
67+
test_valid_expression();
68+
test_valid_function_call();
69+
70+
// The error cases would cause compilation to fail
71+
// so they're tested separately
72+
}

0 commit comments

Comments
 (0)