Commit 050fef3c23

Veikka Tuominen <git@vexu.eu>
2022-07-04 20:42:28
translate-c: do not try to get rid of do while loop
It might contain breaks and continues. Closes #11994
1 parent 314ce54
Changed files (2)
src/translate_c.zig
@@ -2945,7 +2945,6 @@ fn transDoWhileLoop(
     defer cond_scope.deinit();
     const cond = try transBoolExpr(c, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used);
     const if_not_break = switch (cond.tag()) {
-        .false_literal => return transStmt(c, scope, stmt.getBody(), .unused),
         .true_literal => {
             const body_node = try maybeBlockify(c, scope, stmt.getBody());
             return Tag.while_true.create(c.arena, body_node);
@@ -2953,7 +2952,11 @@ fn transDoWhileLoop(
         else => try Tag.if_not_break.create(c.arena, cond),
     };
 
-    const body_node = if (stmt.getBody().getStmtClass() == .CompoundStmtClass) blk: {
+    var body_node = try transStmt(c, &loop_scope, stmt.getBody(), .unused);
+    if (body_node.isNoreturn(true)) {
+        // The body node ends in a noreturn statement. Simply put it in a while (true)
+        // in case it contains breaks or continues.
+    } else if (stmt.getBody().getStmtClass() == .CompoundStmtClass) {
         // there's already a block in C, so we'll append our condition to it.
         // c: do {
         // c:   a;
@@ -2964,12 +2967,10 @@ fn transDoWhileLoop(
         // zig:   b;
         // zig:   if (!cond) break;
         // zig: }
-        const node = try transStmt(c, &loop_scope, stmt.getBody(), .unused);
-        const block = node.castTag(.block).?;
+        const block = body_node.castTag(.block).?;
         block.data.stmts.len += 1; // This is safe since we reserve one extra space in Scope.Block.complete.
         block.data.stmts[block.data.stmts.len - 1] = if_not_break;
-        break :blk node;
-    } else blk: {
+    } else {
         // the C statement is without a block, so we need to create a block to contain it.
         // c: do
         // c:   a;
@@ -2979,10 +2980,10 @@ fn transDoWhileLoop(
         // zig:   if (!cond) break;
         // zig: }
         const statements = try c.arena.alloc(Node, 2);
-        statements[0] = try transStmt(c, &loop_scope, stmt.getBody(), .unused);
+        statements[0] = body_node;
         statements[1] = if_not_break;
-        break :blk try Tag.block.create(c.arena, .{ .label = null, .stmts = statements });
-    };
+        body_node = try Tag.block.create(c.arena, .{ .label = null, .stmts = statements });
+    }
     return Tag.while_true.create(c.arena, body_node);
 }
 
test/translate_c.zig
@@ -6,6 +6,53 @@ const CrossTarget = std.zig.CrossTarget;
 pub fn addCases(cases: *tests.TranslateCContext) void {
     const default_enum_type = if (builtin.abi == .msvc) "c_int" else "c_uint";
 
+    cases.add("do while with breaks",
+        \\void foo(int a) {
+        \\    do {
+        \\        if (a) break;
+        \\    } while (4);
+        \\    do {
+        \\        if (a) break;
+        \\    } while (0);
+        \\    do {
+        \\        if (a) break;
+        \\    } while (a);
+        \\    do {
+        \\        break;
+        \\    } while (3);
+        \\    do {
+        \\        break;
+        \\    } while (0);
+        \\    do {
+        \\        break;
+        \\    } while (a);
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo(arg_a: c_int) void {
+        \\    var a = arg_a;
+        \\    while (true) {
+        \\        if (a != 0) break;
+        \\    }
+        \\    while (true) {
+        \\        if (a != 0) break;
+        \\        if (!false) break;
+        \\    }
+        \\    while (true) {
+        \\        if (a != 0) break;
+        \\        if (!(a != 0)) break;
+        \\    }
+        \\    while (true) {
+        \\        break;
+        \\    }
+        \\    while (true) {
+        \\        break;
+        \\    }
+        \\    while (true) {
+        \\        break;
+        \\    }
+        \\}
+    });
+
     cases.add("variables check for opaque demotion",
         \\struct A {
         \\    _Atomic int a;
@@ -441,7 +488,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub export fn foo() void {
         \\    while (false) while (false) {};
         \\    while (true) while (false) {};
-        \\    while (true) {}
+        \\    while (true) while (true) {
+        \\        if (!false) break;
+        \\    };
         \\}
     });
 
@@ -3229,7 +3278,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     , &[_][]const u8{
         \\pub fn foo() callconv(.C) void {
-        \\    if (true) {}
+        \\    if (true) while (true) {
+        \\        if (!false) break;
+        \\    };
         \\}
     });