| author | |
| committer | |
| log | df5a8120df640de900667624ad8390394f99521f |
| tree | 0782386cabd0941025d722e462b3ff86001fc96f |
| parent | 7ca53bdfaab59e61c38d0bedb6b16739904f7519 |
| signature | Commit is signed but in an unrecognized format. |
3 files changed, 95 insertions(+), 34 deletions(-)
src/translate_c.zig+24-14| ... | ... | @@ -1219,8 +1219,10 @@ fn transCompoundStmtInline( |
| 1219 | 1219 | const end_it = stmt.body_end(); |
| 1220 | 1220 | while (it != end_it) : (it += 1) { |
| 1221 | 1221 | const result = try transStmt(c, &block.base, it[0], .unused); |
| 1222 | if (result.tag() == .declaration) continue; | |
| 1223 | try block.statements.append(result); | |
| 1222 | switch (result.tag()) { | |
| 1223 | .declaration, .empty_block => {}, | |
| 1224 | else => try block.statements.append(result), | |
| 1225 | } | |
| 1224 | 1226 | } |
| 1225 | 1227 | } |
| 1226 | 1228 | |
| ... | ... | @@ -1395,6 +1397,10 @@ fn transImplicitCastExpr( |
| 1395 | 1397 | .BuiltinFnToFnPtr => { |
| 1396 | 1398 | return transExpr(c, scope, sub_expr, result_used); |
| 1397 | 1399 | }, |
| 1400 | .ToVoid => { | |
| 1401 | // Should only appear in the rhs and lhs of a ConditionalOperator | |
| 1402 | return transExpr(c, scope, sub_expr, .unused); | |
| 1403 | }, | |
| 1398 | 1404 | else => |kind| return fail( |
| 1399 | 1405 | c, |
| 1400 | 1406 | error.UnsupportedTranslation, |
| ... | ... | @@ -2032,10 +2038,8 @@ fn transZeroInitExpr( |
| 2032 | 2038 | typedef_decl.getUnderlyingType().getTypePtr(), |
| 2033 | 2039 | ); |
| 2034 | 2040 | }, |
| 2035 | else => {}, | |
| 2041 | else => return Tag.std_mem_zeroes.create(c.arena, try transType(c, scope, ty, source_loc)), | |
| 2036 | 2042 | } |
| 2037 | ||
| 2038 | return fail(c, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{}); | |
| 2039 | 2043 | } |
| 2040 | 2044 | |
| 2041 | 2045 | fn transImplicitValueInitExpr( |
| ... | ... | @@ -2118,7 +2122,7 @@ fn transDoWhileLoop( |
| 2118 | 2122 | defer cond_scope.deinit(); |
| 2119 | 2123 | const cond = try transBoolExpr(c, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used); |
| 2120 | 2124 | const if_not_break = switch (cond.tag()) { |
| 2121 | .false_literal => Tag.@"break".init(), | |
| 2125 | .false_literal => return transStmt(c, scope, stmt.getBody(), .unused), | |
| 2122 | 2126 | .true_literal => { |
| 2123 | 2127 | const body_node = try transStmt(c, scope, stmt.getBody(), .unused); |
| 2124 | 2128 | return Tag.while_true.create(c.arena, body_node); |
| ... | ... | @@ -2396,8 +2400,10 @@ fn transSwitchProngStmtInline( |
| 2396 | 2400 | }, |
| 2397 | 2401 | else => { |
| 2398 | 2402 | const result = try transStmt(c, &block.base, it[0], .unused); |
| 2399 | if (result.tag() == .declaration) continue; | |
| 2400 | try block.statements.append(result); | |
| 2403 | switch (result.tag()) { | |
| 2404 | .declaration, .empty_block => {}, | |
| 2405 | else => try block.statements.append(result), | |
| 2406 | } | |
| 2401 | 2407 | }, |
| 2402 | 2408 | } |
| 2403 | 2409 | } |
| ... | ... | @@ -2479,8 +2485,10 @@ fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used: |
| 2479 | 2485 | const end_it = comp.body_end(); |
| 2480 | 2486 | while (it != end_it - 1) : (it += 1) { |
| 2481 | 2487 | const result = try transStmt(c, &block_scope.base, it[0], .unused); |
| 2482 | if (result.tag() == .declaration) continue; | |
| 2483 | try block_scope.statements.append(result); | |
| 2488 | switch (result.tag()) { | |
| 2489 | .declaration, .empty_block => {}, | |
| 2490 | else => try block_scope.statements.append(result), | |
| 2491 | } | |
| 2484 | 2492 | } |
| 2485 | 2493 | const break_node = try Tag.break_val.create(c.arena, .{ |
| 2486 | 2494 | .label = block_scope.label, |
| ... | ... | @@ -3126,12 +3134,12 @@ fn transConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.Condi |
| 3126 | 3134 | |
| 3127 | 3135 | const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used); |
| 3128 | 3136 | |
| 3129 | var then_body = try transExpr(c, scope, true_expr, .used); | |
| 3137 | var then_body = try transExpr(c, scope, true_expr, used); | |
| 3130 | 3138 | if (!res_is_bool and isBoolRes(then_body)) { |
| 3131 | 3139 | then_body = try Tag.bool_to_int.create(c.arena, then_body); |
| 3132 | 3140 | } |
| 3133 | 3141 | |
| 3134 | var else_body = try transExpr(c, scope, false_expr, .used); | |
| 3142 | var else_body = try transExpr(c, scope, false_expr, used); | |
| 3135 | 3143 | if (!res_is_bool and isBoolRes(else_body)) { |
| 3136 | 3144 | else_body = try Tag.bool_to_int.create(c.arena, else_body); |
| 3137 | 3145 | } |
| ... | ... | @@ -3141,7 +3149,8 @@ fn transConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.Condi |
| 3141 | 3149 | .then = then_body, |
| 3142 | 3150 | .@"else" = else_body, |
| 3143 | 3151 | }); |
| 3144 | return maybeSuppressResult(c, scope, used, if_node); | |
| 3152 | // Clang inserts ImplicitCast(ToVoid)'s to both rhs and lhs so we don't need to supress the result here. | |
| 3153 | return if_node; | |
| 3145 | 3154 | } |
| 3146 | 3155 | |
| 3147 | 3156 | fn maybeSuppressResult( |
| ... | ... | @@ -4794,7 +4803,8 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 4794 | 4803 | while (true) { |
| 4795 | 4804 | switch (m.next().?) { |
| 4796 | 4805 | .Asterisk => { |
| 4797 | if (m.peek().? == .RParen) { | |
| 4806 | const next = m.peek().?; | |
| 4807 | if (next == .RParen or next == .Nl or next == .Eof) { | |
| 4798 | 4808 | // type *) |
| 4799 | 4809 | |
| 4800 | 4810 | // last token of `node` |
src/translate_c/ast.zig+12-7| ... | ... | @@ -1891,30 +1891,35 @@ fn addSemicolonIfNeeded(c: *Context, node: Node) !void { |
| 1891 | 1891 | .var_decl, .var_simple, .arg_redecl, .alias, .enum_redecl, .block, .empty_block, .block_single, .@"switch" => {}, |
| 1892 | 1892 | .while_true => { |
| 1893 | 1893 | const payload = node.castTag(.while_true).?.data; |
| 1894 | return addSemicolonIfNotBlock(c, payload); | |
| 1894 | return addSemicolonIfNotBlock(c, payload, .yes_if); | |
| 1895 | 1895 | }, |
| 1896 | 1896 | .@"while" => { |
| 1897 | 1897 | const payload = node.castTag(.@"while").?.data; |
| 1898 | return addSemicolonIfNotBlock(c, payload.body); | |
| 1898 | return addSemicolonIfNotBlock(c, payload.body, .yes_if); | |
| 1899 | 1899 | }, |
| 1900 | 1900 | .@"if" => { |
| 1901 | 1901 | const payload = node.castTag(.@"if").?.data; |
| 1902 | 1902 | if (payload.@"else") |some| |
| 1903 | return addSemicolonIfNotBlock(c, some); | |
| 1904 | return addSemicolonIfNotBlock(c, payload.then); | |
| 1903 | return addSemicolonIfNotBlock(c, some, .no_if); | |
| 1904 | return addSemicolonIfNotBlock(c, payload.then, .no_if); | |
| 1905 | 1905 | }, |
| 1906 | 1906 | else => _ = try c.addToken(.semicolon, ";"), |
| 1907 | 1907 | } |
| 1908 | 1908 | } |
| 1909 | 1909 | |
| 1910 | fn addSemicolonIfNotBlock(c: *Context, node: Node) !void { | |
| 1910 | fn addSemicolonIfNotBlock(c: *Context, node: Node, if_needs_semicolon: enum{ yes_if, no_if}) !void { | |
| 1911 | 1911 | switch (node.tag()) { |
| 1912 | 1912 | .block, .empty_block, .block_single => {}, |
| 1913 | 1913 | .@"if" => { |
| 1914 | if (if_needs_semicolon == .yes_if) { | |
| 1915 | _ = try c.addToken(.semicolon, ";"); | |
| 1916 | return; | |
| 1917 | } | |
| 1918 | ||
| 1914 | 1919 | const payload = node.castTag(.@"if").?.data; |
| 1915 | 1920 | if (payload.@"else") |some| |
| 1916 | return addSemicolonIfNotBlock(c, some); | |
| 1917 | return addSemicolonIfNotBlock(c, payload.then); | |
| 1921 | return addSemicolonIfNotBlock(c, some, .no_if); | |
| 1922 | return addSemicolonIfNotBlock(c, payload.then, .no_if); | |
| 1918 | 1923 | }, |
| 1919 | 1924 | else => _ = try c.addToken(.semicolon, ";"), |
| 1920 | 1925 | } |
test/translate_c.zig+59-13| ... | ... | @@ -3,6 +3,62 @@ const std = @import("std"); |
| 3 | 3 | const CrossTarget = std.zig.CrossTarget; |
| 4 | 4 | |
| 5 | 5 | pub fn addCases(cases: *tests.TranslateCContext) void { |
| 6 | cases.add("if as while stmt has semicolon", | |
| 7 | \\void foo() { | |
| 8 | \\ while (1) if (1) { | |
| 9 | \\ int a = 1; | |
| 10 | \\ } else { | |
| 11 | \\ int b = 2; | |
| 12 | \\ } | |
| 13 | \\} | |
| 14 | , &[_][]const u8{ | |
| 15 | \\pub export fn foo() void { | |
| 16 | \\ while (true) if (true) { | |
| 17 | \\ var a: c_int = 1; | |
| 18 | \\ } else { | |
| 19 | \\ var b: c_int = 2; | |
| 20 | \\ }; | |
| 21 | \\} | |
| 22 | }); | |
| 23 | ||
| 24 | cases.add("conditional operator cast to void", | |
| 25 | \\int bar(); | |
| 26 | \\void foo() { | |
| 27 | \\ int a; | |
| 28 | \\ a ? a = 2 : bar(); | |
| 29 | \\} | |
| 30 | , &[_][]const u8{ | |
| 31 | \\pub extern fn bar(...) c_int; | |
| 32 | \\pub export fn foo() void { | |
| 33 | \\ var a: c_int = undefined; | |
| 34 | \\ if (a != 0) a = 2 else _ = bar(); | |
| 35 | \\} | |
| 36 | }); | |
| 37 | ||
| 38 | cases.add("struct in struct init to zero", | |
| 39 | \\struct Foo { | |
| 40 | \\ int a; | |
| 41 | \\ struct Bar { | |
| 42 | \\ int a; | |
| 43 | \\ } b; | |
| 44 | \\} a = {}; | |
| 45 | \\#define PTR void * | |
| 46 | , &[_][]const u8{ | |
| 47 | \\pub const struct_Bar = extern struct { | |
| 48 | \\ a: c_int, | |
| 49 | \\}; | |
| 50 | \\pub const struct_Foo = extern struct { | |
| 51 | \\ a: c_int, | |
| 52 | \\ b: struct_Bar, | |
| 53 | \\}; | |
| 54 | \\pub export var a: struct_Foo = struct_Foo{ | |
| 55 | \\ .a = 0, | |
| 56 | \\ .b = @import("std").mem.zeroes(struct_Bar), | |
| 57 | \\}; | |
| 58 | , | |
| 59 | \\pub const PTR = ?*c_void; | |
| 60 | }); | |
| 61 | ||
| 6 | 62 | cases.add("scoped enum", |
| 7 | 63 | \\void foo() { |
| 8 | 64 | \\	enum Foo { |
| ... | ... | @@ -330,9 +386,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 330 | 386 | \\pub export fn foo() void { |
| 331 | 387 | \\ while (false) while (false) {}; |
| 332 | 388 | \\ while (true) while (false) {}; |
| 333 | \\ while (true) while (true) { | |
| 334 | \\ break; | |
| 335 | \\ }; | |
| 389 | \\ while (true) {} | |
| 336 | 390 | \\} |
| 337 | 391 | }); |
| 338 | 392 | |
| ... | ... | @@ -1044,13 +1098,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1044 | 1098 | \\ ;;;;; |
| 1045 | 1099 | \\} |
| 1046 | 1100 | , &[_][]const u8{ |
| 1047 | \\pub export fn foo() void { | |
| 1048 | \\ {} | |
| 1049 | \\ {} | |
| 1050 | \\ {} | |
| 1051 | \\ {} | |
| 1052 | \\ {} | |
| 1053 | \\} | |
| 1101 | \\pub export fn foo() void {} | |
| 1054 | 1102 | }); |
| 1055 | 1103 | |
| 1056 | 1104 | if (std.Target.current.os.tag != .windows) { |
| ... | ... | @@ -3050,9 +3098,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3050 | 3098 | \\} |
| 3051 | 3099 | , &[_][]const u8{ |
| 3052 | 3100 | \\pub fn foo() callconv(.C) void { |
| 3053 | \\ if (true) while (true) { | |
| 3054 | \\ break; | |
| 3055 | \\ }; | |
| 3101 | \\ if (true) {} | |
| 3056 | 3102 | \\} |
| 3057 | 3103 | }); |
| 3058 | 3104 |