| author | |
| committer | |
| log | e761e0ac18aa1eab22b9547d702067910ed82c4a |
| tree | 2051a37e060386eab8b52152b6f478bc6e54945a |
| parent | 36a33c99e3bc0825ada2ce1b374c32b4d6dee6b0 |
This allows `break` statements to be directly translated from the original C.
Add a break statement as the last statement of the while loop to ensure we
don't have an infinite loop if no breaks / returns are hit in the switch.
Fixes #83873 files changed, 109 insertions(+), 40 deletions(-)
src/translate_c.zig+25-8| ... | @@ -2357,7 +2357,6 @@ fn transInitListExprVector( | ... | @@ -2357,7 +2357,6 @@ fn transInitListExprVector( |
| 2357 | expr: *const clang.InitListExpr, | 2357 | expr: *const clang.InitListExpr, |
| 2358 | ty: *const clang.Type, | 2358 | ty: *const clang.Type, |
| 2359 | ) TransError!Node { | 2359 | ) TransError!Node { |
| 2360 | |||
| 2361 | const qt = getExprQualType(c, @ptrCast(*const clang.Expr, expr)); | 2360 | const qt = getExprQualType(c, @ptrCast(*const clang.Expr, expr)); |
| 2362 | const vector_type = try transQualType(c, scope, qt, loc); | 2361 | const vector_type = try transQualType(c, scope, qt, loc); |
| 2363 | const init_count = expr.getNumInits(); | 2362 | const init_count = expr.getNumInits(); |
| ... | @@ -2700,9 +2699,19 @@ fn transSwitch( | ... | @@ -2700,9 +2699,19 @@ fn transSwitch( |
| 2700 | scope: *Scope, | 2699 | scope: *Scope, |
| 2701 | stmt: *const clang.SwitchStmt, | 2700 | stmt: *const clang.SwitchStmt, |
| 2702 | ) TransError!Node { | 2701 | ) TransError!Node { |
| 2702 | var loop_scope = Scope{ | ||
| 2703 | .parent = scope, | ||
| 2704 | .id = .loop, | ||
| 2705 | }; | ||
| 2706 | |||
| 2707 | var block_scope = try Scope.Block.init(c, &loop_scope, false); | ||
| 2708 | defer block_scope.deinit(); | ||
| 2709 | |||
| 2710 | const base_scope = &block_scope.base; | ||
| 2711 | |||
| 2703 | var cond_scope = Scope.Condition{ | 2712 | var cond_scope = Scope.Condition{ |
| 2704 | .base = .{ | 2713 | .base = .{ |
| 2705 | .parent = scope, | 2714 | .parent = base_scope, |
| 2706 | .id = .condition, | 2715 | .id = .condition, |
| 2707 | }, | 2716 | }, |
| 2708 | }; | 2717 | }; |
| ... | @@ -2725,8 +2734,8 @@ fn transSwitch( | ... | @@ -2725,8 +2734,8 @@ fn transSwitch( |
| 2725 | .CaseStmtClass => { | 2734 | .CaseStmtClass => { |
| 2726 | var items = std.ArrayList(Node).init(c.gpa); | 2735 | var items = std.ArrayList(Node).init(c.gpa); |
| 2727 | defer items.deinit(); | 2736 | defer items.deinit(); |
| 2728 | const sub = try transCaseStmt(c, scope, it[0], &items); | 2737 | const sub = try transCaseStmt(c, base_scope, it[0], &items); |
| 2729 | const res = try transSwitchProngStmt(c, scope, sub, it, end_it); | 2738 | const res = try transSwitchProngStmt(c, base_scope, sub, it, end_it); |
| 2730 | 2739 | ||
| 2731 | if (items.items.len == 0) { | 2740 | if (items.items.len == 0) { |
| 2732 | has_default = true; | 2741 | has_default = true; |
| ... | @@ -2751,7 +2760,7 @@ fn transSwitch( | ... | @@ -2751,7 +2760,7 @@ fn transSwitch( |
| 2751 | else => break, | 2760 | else => break, |
| 2752 | }; | 2761 | }; |
| 2753 | 2762 | ||
| 2754 | const res = try transSwitchProngStmt(c, scope, sub, it, end_it); | 2763 | const res = try transSwitchProngStmt(c, base_scope, sub, it, end_it); |
| 2755 | 2764 | ||
| 2756 | const switch_else = try Tag.switch_else.create(c.arena, res); | 2765 | const switch_else = try Tag.switch_else.create(c.arena, res); |
| 2757 | try cases.append(switch_else); | 2766 | try cases.append(switch_else); |
| ... | @@ -2765,10 +2774,15 @@ fn transSwitch( | ... | @@ -2765,10 +2774,15 @@ fn transSwitch( |
| 2765 | try cases.append(else_prong); | 2774 | try cases.append(else_prong); |
| 2766 | } | 2775 | } |
| 2767 | 2776 | ||
| 2768 | return Tag.@"switch".create(c.arena, .{ | 2777 | const switch_node = try Tag.@"switch".create(c.arena, .{ |
| 2769 | .cond = switch_expr, | 2778 | .cond = switch_expr, |
| 2770 | .cases = try c.arena.dupe(Node, cases.items), | 2779 | .cases = try c.arena.dupe(Node, cases.items), |
| 2771 | }); | 2780 | }); |
| 2781 | try block_scope.statements.append(switch_node); | ||
| 2782 | try block_scope.statements.append(Tag.@"break".init()); | ||
| 2783 | const while_body = try block_scope.complete(c); | ||
| 2784 | |||
| 2785 | return Tag.while_true.create(c.arena, while_body); | ||
| 2772 | } | 2786 | } |
| 2773 | 2787 | ||
| 2774 | /// Collects all items for this case, returns the first statement after the labels. | 2788 | /// Collects all items for this case, returns the first statement after the labels. |
| ... | @@ -2818,7 +2832,7 @@ fn transSwitchProngStmt( | ... | @@ -2818,7 +2832,7 @@ fn transSwitchProngStmt( |
| 2818 | parent_end_it: clang.CompoundStmt.ConstBodyIterator, | 2832 | parent_end_it: clang.CompoundStmt.ConstBodyIterator, |
| 2819 | ) TransError!Node { | 2833 | ) TransError!Node { |
| 2820 | switch (stmt.getStmtClass()) { | 2834 | switch (stmt.getStmtClass()) { |
| 2821 | .BreakStmtClass => return Tag.empty_block.init(), | 2835 | .BreakStmtClass => return Tag.@"break".init(), |
| 2822 | .ReturnStmtClass => return transStmt(c, scope, stmt, .unused), | 2836 | .ReturnStmtClass => return transStmt(c, scope, stmt, .unused), |
| 2823 | .CaseStmtClass, .DefaultStmtClass => unreachable, | 2837 | .CaseStmtClass, .DefaultStmtClass => unreachable, |
| 2824 | else => { | 2838 | else => { |
| ... | @@ -2847,7 +2861,10 @@ fn transSwitchProngStmtInline( | ... | @@ -2847,7 +2861,10 @@ fn transSwitchProngStmtInline( |
| 2847 | try block.statements.append(result); | 2861 | try block.statements.append(result); |
| 2848 | return; | 2862 | return; |
| 2849 | }, | 2863 | }, |
| 2850 | .BreakStmtClass => return, | 2864 | .BreakStmtClass => { |
| 2865 | try block.statements.append(Tag.@"break".init()); | ||
| 2866 | return; | ||
| 2867 | }, | ||
| 2851 | .CaseStmtClass => { | 2868 | .CaseStmtClass => { |
| 2852 | var sub = @ptrCast(*const clang.CaseStmt, it[0]).getSubStmt(); | 2869 | var sub = @ptrCast(*const clang.CaseStmt, it[0]).getSubStmt(); |
| 2853 | while (true) switch (sub.getStmtClass()) { | 2870 | while (true) switch (sub.getStmtClass()) { |
test/run_translated_c.zig+43| ... | @@ -1410,4 +1410,47 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { | ... | @@ -1410,4 +1410,47 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 1410 | \\} | 1410 | \\} |
| 1411 | , ""); | 1411 | , ""); |
| 1412 | 1412 | ||
| 1413 | cases.add("break from switch statement. Issue #8387", | ||
| 1414 | \\#include <stdlib.h> | ||
| 1415 | \\int switcher(int x) { | ||
| 1416 | \\ switch (x) { | ||
| 1417 | \\ case 0: // no braces | ||
| 1418 | \\ x += 1; | ||
| 1419 | \\ break; | ||
| 1420 | \\ case 1: // conditional break | ||
| 1421 | \\ if (x == 1) { | ||
| 1422 | \\ x += 1; | ||
| 1423 | \\ break; | ||
| 1424 | \\ } | ||
| 1425 | \\ x += 100; | ||
| 1426 | \\ case 2: { // braces with fallthrough | ||
| 1427 | \\ x += 1; | ||
| 1428 | \\ } | ||
| 1429 | \\ case 3: // fallthrough to return statement | ||
| 1430 | \\ x += 1; | ||
| 1431 | \\ case 42: { // random out of order case | ||
| 1432 | \\ x += 1; | ||
| 1433 | \\ return x; | ||
| 1434 | \\ } | ||
| 1435 | \\ case 4: { // break within braces | ||
| 1436 | \\ x += 1; | ||
| 1437 | \\ break; | ||
| 1438 | \\ } | ||
| 1439 | \\ case 5: | ||
| 1440 | \\ x += 1; // fallthrough to default | ||
| 1441 | \\ default: | ||
| 1442 | \\ x += 1; | ||
| 1443 | \\ } | ||
| 1444 | \\ return x; | ||
| 1445 | \\} | ||
| 1446 | \\int main(void) { | ||
| 1447 | \\ int expected[] = {1, 2, 5, 5, 5, 7, 7}; | ||
| 1448 | \\ for (int i = 0; i < sizeof(expected) / sizeof(int); i++) { | ||
| 1449 | \\ int res = switcher(i); | ||
| 1450 | \\ if (res != expected[i]) abort(); | ||
| 1451 | \\ } | ||
| 1452 | \\ if (switcher(42) != 43) abort(); | ||
| 1453 | \\ return 0; | ||
| 1454 | \\} | ||
| 1455 | , ""); | ||
| 1413 | } | 1456 | } |
test/translate_c.zig+41-32| ... | @@ -2072,40 +2072,49 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -2072,40 +2072,49 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2072 | \\pub export fn switch_fn(arg_i: c_int) void { | 2072 | \\pub export fn switch_fn(arg_i: c_int) void { |
| 2073 | \\ var i = arg_i; | 2073 | \\ var i = arg_i; |
| 2074 | \\ var res: c_int = 0; | 2074 | \\ var res: c_int = 0; |
| 2075 | \\ switch (i) { | 2075 | \\ while (true) { |
| 2076 | \\ @as(c_int, 0) => { | 2076 | \\ switch (i) { |
| 2077 | \\ res = 1; | 2077 | \\ @as(c_int, 0) => { |
| 2078 | \\ res = 2; | 2078 | \\ res = 1; |
| 2079 | \\ res = @as(c_int, 3) * i; | 2079 | \\ res = 2; |
| 2080 | \\ }, | 2080 | \\ res = @as(c_int, 3) * i; |
| 2081 | \\ @as(c_int, 1)...@as(c_int, 3) => { | ||
| 2082 | \\ res = 2; | ||
| 2083 | \\ res = @as(c_int, 3) * i; | ||
| 2084 | \\ }, | ||
| 2085 | \\ else => { | ||
| 2086 | \\ res = @as(c_int, 3) * i; | ||
| 2087 | \\ }, | ||
| 2088 | \\ @as(c_int, 7) => { | ||
| 2089 | \\ { | ||
| 2090 | \\ res = 7; | ||
| 2091 | \\ break; | 2081 | \\ break; |
| 2092 | \\ } | 2082 | \\ }, |
| 2093 | \\ }, | 2083 | \\ @as(c_int, 1)...@as(c_int, 3) => { |
| 2094 | \\ @as(c_int, 4), @as(c_int, 5) => { | 2084 | \\ res = 2; |
| 2095 | \\ res = 69; | 2085 | \\ res = @as(c_int, 3) * i; |
| 2096 | \\ { | 2086 | \\ break; |
| 2097 | \\ res = 5; | 2087 | \\ }, |
| 2088 | \\ else => { | ||
| 2089 | \\ res = @as(c_int, 3) * i; | ||
| 2090 | \\ break; | ||
| 2091 | \\ }, | ||
| 2092 | \\ @as(c_int, 7) => { | ||
| 2093 | \\ { | ||
| 2094 | \\ res = 7; | ||
| 2095 | \\ break; | ||
| 2096 | \\ } | ||
| 2097 | \\ }, | ||
| 2098 | \\ @as(c_int, 4), @as(c_int, 5) => { | ||
| 2099 | \\ res = 69; | ||
| 2100 | \\ { | ||
| 2101 | \\ res = 5; | ||
| 2102 | \\ return; | ||
| 2103 | \\ } | ||
| 2104 | \\ }, | ||
| 2105 | \\ @as(c_int, 6) => { | ||
| 2106 | \\ while (true) { | ||
| 2107 | \\ switch (res) { | ||
| 2108 | \\ @as(c_int, 9) => break, | ||
| 2109 | \\ else => {}, | ||
| 2110 | \\ } | ||
| 2111 | \\ break; | ||
| 2112 | \\ } | ||
| 2113 | \\ res = 1; | ||
| 2098 | \\ return; | 2114 | \\ return; |
| 2099 | \\ } | 2115 | \\ }, |
| 2100 | \\ }, | 2116 | \\ } |
| 2101 | \\ @as(c_int, 6) => { | 2117 | \\ break; |
| 2102 | \\ switch (res) { | ||
| 2103 | \\ @as(c_int, 9) => {}, | ||
| 2104 | \\ else => {}, | ||
| 2105 | \\ } | ||
| 2106 | \\ res = 1; | ||
| 2107 | \\ return; | ||
| 2108 | \\ }, | ||
| 2109 | \\ } | 2118 | \\ } |
| 2110 | \\} | 2119 | \\} |
| 2111 | }); | 2120 | }); |