| author | |
| committer | |
| log | 050fef3c236e67cf425331e51063c6194421e8ac |
| tree | 3b3d2c04f54d8b9b497161ce91802c69fa53fb79 |
| parent | 314ce5465dfdc9f4d1e2d178704b47666d541fc4 |
It might contain breaks and continues.
Closes #119942 files changed, 63 insertions(+), 11 deletions(-)
src/translate_c.zig+10-9| ... | @@ -2945,7 +2945,6 @@ fn transDoWhileLoop( | ... | @@ -2945,7 +2945,6 @@ fn transDoWhileLoop( |
| 2945 | defer cond_scope.deinit(); | 2945 | defer cond_scope.deinit(); |
| 2946 | const cond = try transBoolExpr(c, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used); | 2946 | const cond = try transBoolExpr(c, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used); |
| 2947 | const if_not_break = switch (cond.tag()) { | 2947 | const if_not_break = switch (cond.tag()) { |
| 2948 | .false_literal => return transStmt(c, scope, stmt.getBody(), .unused), | ||
| 2949 | .true_literal => { | 2948 | .true_literal => { |
| 2950 | const body_node = try maybeBlockify(c, scope, stmt.getBody()); | 2949 | const body_node = try maybeBlockify(c, scope, stmt.getBody()); |
| 2951 | return Tag.while_true.create(c.arena, body_node); | 2950 | return Tag.while_true.create(c.arena, body_node); |
| ... | @@ -2953,7 +2952,11 @@ fn transDoWhileLoop( | ... | @@ -2953,7 +2952,11 @@ fn transDoWhileLoop( |
| 2953 | else => try Tag.if_not_break.create(c.arena, cond), | 2952 | else => try Tag.if_not_break.create(c.arena, cond), |
| 2954 | }; | 2953 | }; |
| 2955 | 2954 | ||
| 2956 | const body_node = if (stmt.getBody().getStmtClass() == .CompoundStmtClass) blk: { | 2955 | var body_node = try transStmt(c, &loop_scope, stmt.getBody(), .unused); |
| 2956 | if (body_node.isNoreturn(true)) { | ||
| 2957 | // The body node ends in a noreturn statement. Simply put it in a while (true) | ||
| 2958 | // in case it contains breaks or continues. | ||
| 2959 | } else if (stmt.getBody().getStmtClass() == .CompoundStmtClass) { | ||
| 2957 | // there's already a block in C, so we'll append our condition to it. | 2960 | // there's already a block in C, so we'll append our condition to it. |
| 2958 | // c: do { | 2961 | // c: do { |
| 2959 | // c: a; | 2962 | // c: a; |
| ... | @@ -2964,12 +2967,10 @@ fn transDoWhileLoop( | ... | @@ -2964,12 +2967,10 @@ fn transDoWhileLoop( |
| 2964 | // zig: b; | 2967 | // zig: b; |
| 2965 | // zig: if (!cond) break; | 2968 | // zig: if (!cond) break; |
| 2966 | // zig: } | 2969 | // zig: } |
| 2967 | const node = try transStmt(c, &loop_scope, stmt.getBody(), .unused); | 2970 | const block = body_node.castTag(.block).?; |
| 2968 | const block = node.castTag(.block).?; | ||
| 2969 | block.data.stmts.len += 1; // This is safe since we reserve one extra space in Scope.Block.complete. | 2971 | block.data.stmts.len += 1; // This is safe since we reserve one extra space in Scope.Block.complete. |
| 2970 | block.data.stmts[block.data.stmts.len - 1] = if_not_break; | 2972 | block.data.stmts[block.data.stmts.len - 1] = if_not_break; |
| 2971 | break :blk node; | 2973 | } else { |
| 2972 | } else blk: { | ||
| 2973 | // the C statement is without a block, so we need to create a block to contain it. | 2974 | // the C statement is without a block, so we need to create a block to contain it. |
| 2974 | // c: do | 2975 | // c: do |
| 2975 | // c: a; | 2976 | // c: a; |
| ... | @@ -2979,10 +2980,10 @@ fn transDoWhileLoop( | ... | @@ -2979,10 +2980,10 @@ fn transDoWhileLoop( |
| 2979 | // zig: if (!cond) break; | 2980 | // zig: if (!cond) break; |
| 2980 | // zig: } | 2981 | // zig: } |
| 2981 | const statements = try c.arena.alloc(Node, 2); | 2982 | const statements = try c.arena.alloc(Node, 2); |
| 2982 | statements[0] = try transStmt(c, &loop_scope, stmt.getBody(), .unused); | 2983 | statements[0] = body_node; |
| 2983 | statements[1] = if_not_break; | 2984 | statements[1] = if_not_break; |
| 2984 | break :blk try Tag.block.create(c.arena, .{ .label = null, .stmts = statements }); | 2985 | body_node = try Tag.block.create(c.arena, .{ .label = null, .stmts = statements }); |
| 2985 | }; | 2986 | } |
| 2986 | return Tag.while_true.create(c.arena, body_node); | 2987 | return Tag.while_true.create(c.arena, body_node); |
| 2987 | } | 2988 | } |
| 2988 | 2989 |
test/translate_c.zig+53-2| ... | @@ -6,6 +6,53 @@ const CrossTarget = std.zig.CrossTarget; | ... | @@ -6,6 +6,53 @@ const CrossTarget = std.zig.CrossTarget; |
| 6 | pub fn addCases(cases: *tests.TranslateCContext) void { | 6 | pub fn addCases(cases: *tests.TranslateCContext) void { |
| 7 | const default_enum_type = if (builtin.abi == .msvc) "c_int" else "c_uint"; | 7 | const default_enum_type = if (builtin.abi == .msvc) "c_int" else "c_uint"; |
| 8 | 8 | ||
| 9 | cases.add("do while with breaks", | ||
| 10 | \\void foo(int a) { | ||
| 11 | \\ do { | ||
| 12 | \\ if (a) break; | ||
| 13 | \\ } while (4); | ||
| 14 | \\ do { | ||
| 15 | \\ if (a) break; | ||
| 16 | \\ } while (0); | ||
| 17 | \\ do { | ||
| 18 | \\ if (a) break; | ||
| 19 | \\ } while (a); | ||
| 20 | \\ do { | ||
| 21 | \\ break; | ||
| 22 | \\ } while (3); | ||
| 23 | \\ do { | ||
| 24 | \\ break; | ||
| 25 | \\ } while (0); | ||
| 26 | \\ do { | ||
| 27 | \\ break; | ||
| 28 | \\ } while (a); | ||
| 29 | \\} | ||
| 30 | , &[_][]const u8{ | ||
| 31 | \\pub export fn foo(arg_a: c_int) void { | ||
| 32 | \\ var a = arg_a; | ||
| 33 | \\ while (true) { | ||
| 34 | \\ if (a != 0) break; | ||
| 35 | \\ } | ||
| 36 | \\ while (true) { | ||
| 37 | \\ if (a != 0) break; | ||
| 38 | \\ if (!false) break; | ||
| 39 | \\ } | ||
| 40 | \\ while (true) { | ||
| 41 | \\ if (a != 0) break; | ||
| 42 | \\ if (!(a != 0)) break; | ||
| 43 | \\ } | ||
| 44 | \\ while (true) { | ||
| 45 | \\ break; | ||
| 46 | \\ } | ||
| 47 | \\ while (true) { | ||
| 48 | \\ break; | ||
| 49 | \\ } | ||
| 50 | \\ while (true) { | ||
| 51 | \\ break; | ||
| 52 | \\ } | ||
| 53 | \\} | ||
| 54 | }); | ||
| 55 | |||
| 9 | cases.add("variables check for opaque demotion", | 56 | cases.add("variables check for opaque demotion", |
| 10 | \\struct A { | 57 | \\struct A { |
| 11 | \\ _Atomic int a; | 58 | \\ _Atomic int a; |
| ... | @@ -441,7 +488,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -441,7 +488,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 441 | \\pub export fn foo() void { | 488 | \\pub export fn foo() void { |
| 442 | \\ while (false) while (false) {}; | 489 | \\ while (false) while (false) {}; |
| 443 | \\ while (true) while (false) {}; | 490 | \\ while (true) while (false) {}; |
| 444 | \\ while (true) {} | 491 | \\ while (true) while (true) { |
| 492 | \\ if (!false) break; | ||
| 493 | \\ }; | ||
| 445 | \\} | 494 | \\} |
| 446 | }); | 495 | }); |
| 447 | 496 | ||
| ... | @@ -3229,7 +3278,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -3229,7 +3278,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3229 | \\} | 3278 | \\} |
| 3230 | , &[_][]const u8{ | 3279 | , &[_][]const u8{ |
| 3231 | \\pub fn foo() callconv(.C) void { | 3280 | \\pub fn foo() callconv(.C) void { |
| 3232 | \\ if (true) {} | 3281 | \\ if (true) while (true) { |
| 3282 | \\ if (!false) break; | ||
| 3283 | \\ }; | ||
| 3233 | \\} | 3284 | \\} |
| 3234 | }); | 3285 | }); |
| 3235 | 3286 |