Skip to content

Commit bd1e92a

Browse files
committed
Fix ICE with continue/break/return in while condition,Fixes #3977
1 parent 7699f7f commit bd1e92a

File tree

2 files changed

+109
-17
lines changed

2 files changed

+109
-17
lines changed

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

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,24 +1537,44 @@ TypeCheckExpr::visit (HIR::LoopExpr &expr)
15371537
: TyTy::TupleType::get_unit_type ();
15381538
}
15391539

1540-
void
1541-
TypeCheckExpr::visit (HIR::WhileLoopExpr &expr)
1542-
{
1543-
context->push_new_while_loop_context (expr.get_mappings ().get_hirid ());
1544-
1545-
TypeCheckExpr::Resolve (expr.get_predicate_expr ());
1546-
TyTy::BaseType *block_expr = TypeCheckExpr::Resolve (expr.get_loop_block ());
1547-
1548-
if (!block_expr->is_unit ())
1549-
{
1550-
rust_error_at (expr.get_loop_block ().get_locus (),
1551-
"expected %<()%> got %s",
1552-
block_expr->as_string ().c_str ());
1540+
void TypeCheckExpr::visit(HIR::WhileLoopExpr &expr) {
1541+
context->push_new_while_loop_context(expr.get_mappings().get_hirid());
1542+
TyTy::BaseType *predicate_type =
1543+
TypeCheckExpr::Resolve(expr.get_predicate_expr());
1544+
if (predicate_type->get_kind() == TyTy::TypeKind::ERROR) {
1545+
infered = TyTy::TupleType::get_unit_type();
1546+
context->pop_loop_context();
15531547
return;
1554-
}
1555-
1556-
context->pop_loop_context ();
1557-
infered = TyTy::TupleType::get_unit_type ();
1548+
}
1549+
if (predicate_type->get_kind() == TyTy::TypeKind::NEVER) {
1550+
rust_error_at(expr.get_predicate_expr().get_locus(),
1551+
"expected boolean expression in %<while%> condition");
1552+
infered = TyTy::TupleType::get_unit_type();
1553+
context->pop_loop_context();
1554+
return;
1555+
}
1556+
if (predicate_type->get_kind() != TyTy::TypeKind::BOOL) {
1557+
rust_error_at(expr.get_predicate_expr().get_locus(),
1558+
"expected boolean expression in %<while%> condition");
1559+
infered = TyTy::TupleType::get_unit_type();
1560+
context->pop_loop_context();
1561+
return;
1562+
}
1563+
TyTy::BaseType *block_expr = TypeCheckExpr::Resolve(expr.get_loop_block());
1564+
if (!block_expr->is_unit()) {
1565+
rust_error_at(expr.get_loop_block().get_locus(), "expected %<()%> got %s",
1566+
block_expr->as_string().c_str());
1567+
infered = TyTy::TupleType::get_unit_type();
1568+
context->pop_loop_context();
1569+
return;
1570+
}
1571+
if (block_expr->get_kind() == TyTy::TypeKind::ERROR) {
1572+
infered = TyTy::TupleType::get_unit_type();
1573+
context->pop_loop_context();
1574+
return;
1575+
}
1576+
context->pop_loop_context();
1577+
infered = TyTy::TupleType::get_unit_type();
15581578
}
15591579

15601580
void
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)