ctx->add_statement (loop_begin_label_decl);
ctx->push_loop_begin_label (loop_begin_label);
- tree condition = CompileExpr::Compile (expr.get_predicate_expr (), ctx);
+ HIR::Expr &predicate = expr.get_predicate_expr ();
+ TyTy::BaseType *predicate_type = nullptr;
+ bool ok
+ = ctx->get_tyctx ()->lookup_type (predicate.get_mappings ().get_hirid (),
+ &predicate_type);
+ rust_assert (ok && predicate_type != nullptr);
+ tree condition = CompileExpr::Compile (predicate, ctx);
+ if (predicate_type->get_kind () == TyTy::TypeKind::NEVER)
+ {
+ ctx->add_statement (condition);
+ condition = boolean_true_node;
+ }
tree exit_condition = fold_build1_loc (expr.get_locus (), TRUTH_NOT_EXPR,
boolean_type_node, condition);
tree exit_expr = Backend::exit_expression (exit_condition, expr.get_locus ());
TypeCheckExpr::visit (HIR::WhileLoopExpr &expr)
{
context->push_new_while_loop_context (expr.get_mappings ().get_hirid ());
-
- TypeCheckExpr::Resolve (expr.get_predicate_expr ());
+ TyTy::BaseType *predicate_type
+ = TypeCheckExpr::Resolve (expr.get_predicate_expr ());
+ if (predicate_type->get_kind () != TyTy::TypeKind::BOOL
+ && predicate_type->get_kind () != TyTy::TypeKind::NEVER)
+ {
+ rust_error_at (expr.get_predicate_expr ().get_locus (),
+ "expected boolean expression in %<while%> condition");
+ context->pop_loop_context ();
+ return;
+ }
TyTy::BaseType *block_expr = TypeCheckExpr::Resolve (expr.get_loop_block ());
-
if (!block_expr->is_unit ())
{
rust_error_at (expr.get_loop_block ().get_locus (),
"expected %<()%> got %s",
block_expr->as_string ().c_str ());
+ context->pop_loop_context ();
return;
}
-
context->pop_loop_context ();
infered = TyTy::TupleType::get_unit_type ();
}
"%<continue%> outside of a loop");
return;
}
-
infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
}
--- /dev/null
+// Test for issue #3977 - ICE with continue/break/return in while condition
+
+fn diverge() -> ! {
+ loop {}
+}
+
+fn test_continue() {
+ loop {
+ while continue {}
+ }
+}
+
+fn test_break() {
+ loop {
+ while break {}
+ }
+}
+
+fn test_return() {
+ loop {
+ while return {}
+ }
+}
+
+fn test_labeled_break() {
+ 'outer: loop {
+ loop {
+ while break 'outer {}
+ }
+ }
+}
+
+fn test_labeled_continue() {
+ 'outer: loop {
+ loop {
+ while continue 'outer {}
+ }
+ }
+}
+
+fn test_complex_if_else() {
+ loop {
+ while if true { continue } else { break } {}
+ }
+}
+
+fn foo() {
+ while diverge() {
+ break
+ }
+ let _x = 5;
+}
+
+fn main() {
+ // Just reference them so they're "used"
+ if false {
+ test_continue();
+ test_break();
+ test_return();
+ test_labeled_break();
+ test_labeled_continue();
+ test_complex_if_else();
+ foo();
+ }
+}
\ No newline at end of file