translate-c: do not try to get rid of do while loop

It might contain breaks and continues.

Closes #11994
This commit is contained in:
Veikka Tuominen
2022-07-04 21:42:28 +03:00
parent 314ce5465d
commit 050fef3c23
2 changed files with 63 additions and 11 deletions

View File

@@ -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);
}

View File

@@ -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;
\\ };
\\}
});