Commit 050fef3c23
Changed files (2)
test
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;
+ \\ };
\\}
});