From 050fef3c236e67cf425331e51063c6194421e8ac Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Mon, 4 Jul 2022 21:42:28 +0300 Subject: [PATCH] translate-c: do not try to get rid of do while loop It might contain breaks and continues. Closes #11994 --- src/translate_c.zig | 19 +++++++-------- test/translate_c.zig | 55 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/translate_c.zig b/src/translate_c.zig index 306f5d3ea1..641f589c41 100644 --- a/src/translate_c.zig +++ b/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); } diff --git a/test/translate_c.zig b/test/translate_c.zig index f5748f0659..b8d39ff797 100644 --- a/test/translate_c.zig +++ b/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; + \\ }; \\} });