diff --git a/releasenotes.md b/releasenotes.md index f27b7b24a..9ceabef40 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -45,6 +45,7 @@ - Fix several issues relating to multi-level inference like `int[*][*]` #2505 - `$for int $a = 1; $a < 2; $a++` would not parse. - Fix lambda-in-macro visibility, where lambdas would sometimes not correctly link if used through a macro. +- Dead code analysis with labelled `if` did not work properly. ### Stdlib changes - Added generic `InterfaceList` to store a list of values that implement a specific interface diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index d5a39b8cf..cedd7a120 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -1989,20 +1989,23 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement) SCOPE_START_WITH_LABEL(statement->if_stmt.flow.label); if (result == COND_FALSE) context->active_scope.is_dead = true; success = success && sema_analyse_statement(context, then); - then_jump = context->active_scope.end_jump.active; + then_jump = context->active_scope.end_jump.active && !(statement->if_stmt.flow.label && statement->if_stmt.flow.has_break); SCOPE_END; if (!success) goto END; else_jump = false; if (statement->if_stmt.else_body) { + bool store_break = statement->if_stmt.flow.has_break; + statement->if_stmt.flow.has_break = false; SCOPE_START_WITH_LABEL(statement->if_stmt.flow.label); if (result == COND_TRUE) context->active_scope.is_dead = true; sema_remove_unwraps_from_try(context, cond); sema_unwrappable_from_catch_in_else(context, cond); success = success && sema_analyse_statement(context, else_body); - else_jump = context->active_scope.end_jump.active; + else_jump = context->active_scope.end_jump.active && !(statement->if_stmt.flow.label && statement->if_stmt.flow.has_break); SCOPE_END; + statement->if_stmt.flow.has_break |= store_break; } END: @@ -2022,6 +2025,7 @@ END: } if (then_jump && else_jump && !statement->flow.has_break) { + SET_JUMP_END(context, statement); } else if (then_jump && result == COND_TRUE) diff --git a/test/test_suite/statements/foreach_with_only_ref.c3t b/test/test_suite/statements/foreach_with_only_ref.c3t index 4513e2f7b..0ce5553c7 100644 --- a/test/test_suite/statements/foreach_with_only_ref.c3t +++ b/test/test_suite/statements/foreach_with_only_ref.c3t @@ -1,3 +1,4 @@ +// #target: macos-x64 module test; import std; diff --git a/test/test_suite/statements/if_break.c3t b/test/test_suite/statements/if_break.c3t new file mode 100644 index 000000000..43be78da4 --- /dev/null +++ b/test/test_suite/statements/if_break.c3t @@ -0,0 +1,81 @@ +// #target: macos-x64 +module test; +int a; +fn void test() +{ + + if LABEL: (false) + { + a += 1; + } + else if (true) + { + a += 2; + break LABEL; + } + else + { + a += 3; + } + + a *= 4; +} + +fn void main() +{ + if LABEL: (true) + { + a += 1; + break LABEL; + } + else if (true) + { + a += 2; + } + else + { + a += 3; + } + + a *= 4; +} + +/* #expect: test.ll + +define void @test.test() #0 { +entry: + br label %if.else + +if.else: ; preds = %entry + br label %if.then + +if.then: ; preds = %if.else + %0 = load i32, ptr @test.a, align 4 + %add = add i32 %0, 2 + store i32 %add, ptr @test.a, align 4 + br label %if.exit + +if.exit: ; preds = %if.then + %1 = load i32, ptr @test.a, align 4 + %mul = mul i32 %1, 4 + store i32 %mul, ptr @test.a, align 4 + ret void +} + +; Function Attrs: nounwind uwtable +define void @test.main() #0 { +entry: + br label %if.then + +if.then: ; preds = %entry + %0 = load i32, ptr @test.a, align 4 + %add = add i32 %0, 1 + store i32 %add, ptr @test.a, align 4 + br label %if.exit + +if.exit: ; preds = %if.then + %1 = load i32, ptr @test.a, align 4 + %mul = mul i32 %1, 4 + store i32 %mul, ptr @test.a, align 4 + ret void +}