diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index 0a627f35352..b89033841f2 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -803,7 +803,18 @@ CompileExpr::visit (HIR::WhileLoopExpr &expr) 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 ()); diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 7885dfcf746..5162cc6f9bb 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -1541,18 +1541,25 @@ void 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 % 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 (); } @@ -1602,7 +1609,6 @@ TypeCheckExpr::visit (HIR::ContinueExpr &expr) "% outside of a loop"); return; } - infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); } diff --git a/gcc/testsuite/rust/compile/issue-3977.rs b/gcc/testsuite/rust/compile/issue-3977.rs new file mode 100644 index 00000000000..ba4de544d44 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3977.rs @@ -0,0 +1,65 @@ +// 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