Commit e761e0ac18
Changed files (3)
src/translate_c.zig
@@ -2357,7 +2357,6 @@ fn transInitListExprVector(
expr: *const clang.InitListExpr,
ty: *const clang.Type,
) TransError!Node {
-
const qt = getExprQualType(c, @ptrCast(*const clang.Expr, expr));
const vector_type = try transQualType(c, scope, qt, loc);
const init_count = expr.getNumInits();
@@ -2700,9 +2699,19 @@ fn transSwitch(
scope: *Scope,
stmt: *const clang.SwitchStmt,
) TransError!Node {
+ var loop_scope = Scope{
+ .parent = scope,
+ .id = .loop,
+ };
+
+ var block_scope = try Scope.Block.init(c, &loop_scope, false);
+ defer block_scope.deinit();
+
+ const base_scope = &block_scope.base;
+
var cond_scope = Scope.Condition{
.base = .{
- .parent = scope,
+ .parent = base_scope,
.id = .condition,
},
};
@@ -2725,8 +2734,8 @@ fn transSwitch(
.CaseStmtClass => {
var items = std.ArrayList(Node).init(c.gpa);
defer items.deinit();
- const sub = try transCaseStmt(c, scope, it[0], &items);
- const res = try transSwitchProngStmt(c, scope, sub, it, end_it);
+ const sub = try transCaseStmt(c, base_scope, it[0], &items);
+ const res = try transSwitchProngStmt(c, base_scope, sub, it, end_it);
if (items.items.len == 0) {
has_default = true;
@@ -2751,7 +2760,7 @@ fn transSwitch(
else => break,
};
- const res = try transSwitchProngStmt(c, scope, sub, it, end_it);
+ const res = try transSwitchProngStmt(c, base_scope, sub, it, end_it);
const switch_else = try Tag.switch_else.create(c.arena, res);
try cases.append(switch_else);
@@ -2765,10 +2774,15 @@ fn transSwitch(
try cases.append(else_prong);
}
- return Tag.@"switch".create(c.arena, .{
+ const switch_node = try Tag.@"switch".create(c.arena, .{
.cond = switch_expr,
.cases = try c.arena.dupe(Node, cases.items),
});
+ try block_scope.statements.append(switch_node);
+ try block_scope.statements.append(Tag.@"break".init());
+ const while_body = try block_scope.complete(c);
+
+ return Tag.while_true.create(c.arena, while_body);
}
/// Collects all items for this case, returns the first statement after the labels.
@@ -2818,7 +2832,7 @@ fn transSwitchProngStmt(
parent_end_it: clang.CompoundStmt.ConstBodyIterator,
) TransError!Node {
switch (stmt.getStmtClass()) {
- .BreakStmtClass => return Tag.empty_block.init(),
+ .BreakStmtClass => return Tag.@"break".init(),
.ReturnStmtClass => return transStmt(c, scope, stmt, .unused),
.CaseStmtClass, .DefaultStmtClass => unreachable,
else => {
@@ -2847,7 +2861,10 @@ fn transSwitchProngStmtInline(
try block.statements.append(result);
return;
},
- .BreakStmtClass => return,
+ .BreakStmtClass => {
+ try block.statements.append(Tag.@"break".init());
+ return;
+ },
.CaseStmtClass => {
var sub = @ptrCast(*const clang.CaseStmt, it[0]).getSubStmt();
while (true) switch (sub.getStmtClass()) {
test/run_translated_c.zig
@@ -1410,4 +1410,47 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\}
, "");
+ cases.add("break from switch statement. Issue #8387",
+ \\#include <stdlib.h>
+ \\int switcher(int x) {
+ \\ switch (x) {
+ \\ case 0: // no braces
+ \\ x += 1;
+ \\ break;
+ \\ case 1: // conditional break
+ \\ if (x == 1) {
+ \\ x += 1;
+ \\ break;
+ \\ }
+ \\ x += 100;
+ \\ case 2: { // braces with fallthrough
+ \\ x += 1;
+ \\ }
+ \\ case 3: // fallthrough to return statement
+ \\ x += 1;
+ \\ case 42: { // random out of order case
+ \\ x += 1;
+ \\ return x;
+ \\ }
+ \\ case 4: { // break within braces
+ \\ x += 1;
+ \\ break;
+ \\ }
+ \\ case 5:
+ \\ x += 1; // fallthrough to default
+ \\ default:
+ \\ x += 1;
+ \\ }
+ \\ return x;
+ \\}
+ \\int main(void) {
+ \\ int expected[] = {1, 2, 5, 5, 5, 7, 7};
+ \\ for (int i = 0; i < sizeof(expected) / sizeof(int); i++) {
+ \\ int res = switcher(i);
+ \\ if (res != expected[i]) abort();
+ \\ }
+ \\ if (switcher(42) != 43) abort();
+ \\ return 0;
+ \\}
+ , "");
}
test/translate_c.zig
@@ -2072,40 +2072,49 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub export fn switch_fn(arg_i: c_int) void {
\\ var i = arg_i;
\\ var res: c_int = 0;
- \\ switch (i) {
- \\ @as(c_int, 0) => {
- \\ res = 1;
- \\ res = 2;
- \\ res = @as(c_int, 3) * i;
- \\ },
- \\ @as(c_int, 1)...@as(c_int, 3) => {
- \\ res = 2;
- \\ res = @as(c_int, 3) * i;
- \\ },
- \\ else => {
- \\ res = @as(c_int, 3) * i;
- \\ },
- \\ @as(c_int, 7) => {
- \\ {
- \\ res = 7;
+ \\ while (true) {
+ \\ switch (i) {
+ \\ @as(c_int, 0) => {
+ \\ res = 1;
+ \\ res = 2;
+ \\ res = @as(c_int, 3) * i;
\\ break;
- \\ }
- \\ },
- \\ @as(c_int, 4), @as(c_int, 5) => {
- \\ res = 69;
- \\ {
- \\ res = 5;
+ \\ },
+ \\ @as(c_int, 1)...@as(c_int, 3) => {
+ \\ res = 2;
+ \\ res = @as(c_int, 3) * i;
+ \\ break;
+ \\ },
+ \\ else => {
+ \\ res = @as(c_int, 3) * i;
+ \\ break;
+ \\ },
+ \\ @as(c_int, 7) => {
+ \\ {
+ \\ res = 7;
+ \\ break;
+ \\ }
+ \\ },
+ \\ @as(c_int, 4), @as(c_int, 5) => {
+ \\ res = 69;
+ \\ {
+ \\ res = 5;
+ \\ return;
+ \\ }
+ \\ },
+ \\ @as(c_int, 6) => {
+ \\ while (true) {
+ \\ switch (res) {
+ \\ @as(c_int, 9) => break,
+ \\ else => {},
+ \\ }
+ \\ break;
+ \\ }
+ \\ res = 1;
\\ return;
- \\ }
- \\ },
- \\ @as(c_int, 6) => {
- \\ switch (res) {
- \\ @as(c_int, 9) => {},
- \\ else => {},
- \\ }
- \\ res = 1;
- \\ return;
- \\ },
+ \\ },
+ \\ }
+ \\ break;
\\ }
\\}
});