Commit df5a8120df

Veikka Tuominen <git@vexu.eu>
2021-02-18 20:34:31
translate-c: small miscellaneous improvements
1 parent 7ca53bd
Changed files (3)
src/translate_c/ast.zig
@@ -1891,30 +1891,35 @@ fn addSemicolonIfNeeded(c: *Context, node: Node) !void {
         .var_decl, .var_simple, .arg_redecl, .alias, .enum_redecl, .block, .empty_block, .block_single, .@"switch" => {},
         .while_true => {
             const payload = node.castTag(.while_true).?.data;
-            return addSemicolonIfNotBlock(c, payload);
+            return addSemicolonIfNotBlock(c, payload, .yes_if);
         },
         .@"while" => {
             const payload = node.castTag(.@"while").?.data;
-            return addSemicolonIfNotBlock(c, payload.body);
+            return addSemicolonIfNotBlock(c, payload.body, .yes_if);
         },
         .@"if" => {
             const payload = node.castTag(.@"if").?.data;
             if (payload.@"else") |some|
-                return addSemicolonIfNotBlock(c, some);
-            return addSemicolonIfNotBlock(c, payload.then);
+                return addSemicolonIfNotBlock(c, some, .no_if);
+            return addSemicolonIfNotBlock(c, payload.then, .no_if);
         },
         else => _ = try c.addToken(.semicolon, ";"),
     }
 }
 
-fn addSemicolonIfNotBlock(c: *Context, node: Node) !void {
+fn addSemicolonIfNotBlock(c: *Context, node: Node, if_needs_semicolon: enum{ yes_if, no_if}) !void {
     switch (node.tag()) {
         .block, .empty_block, .block_single => {},
         .@"if" => {
+            if (if_needs_semicolon == .yes_if) {
+                _ = try c.addToken(.semicolon, ";");
+                return;
+            }
+
             const payload = node.castTag(.@"if").?.data;
             if (payload.@"else") |some|
-                return addSemicolonIfNotBlock(c, some);
-            return addSemicolonIfNotBlock(c, payload.then);
+                return addSemicolonIfNotBlock(c, some, .no_if);
+            return addSemicolonIfNotBlock(c, payload.then, .no_if);
         },
         else => _ = try c.addToken(.semicolon, ";"),
     }
src/translate_c.zig
@@ -1219,8 +1219,10 @@ fn transCompoundStmtInline(
     const end_it = stmt.body_end();
     while (it != end_it) : (it += 1) {
         const result = try transStmt(c, &block.base, it[0], .unused);
-        if (result.tag() == .declaration) continue;
-        try block.statements.append(result);
+        switch (result.tag()) {
+            .declaration, .empty_block => {},
+            else => try block.statements.append(result),
+        }
     }
 }
 
@@ -1395,6 +1397,10 @@ fn transImplicitCastExpr(
         .BuiltinFnToFnPtr => {
             return transExpr(c, scope, sub_expr, result_used);
         },
+        .ToVoid => {
+            // Should only appear in the rhs and lhs of a ConditionalOperator
+            return transExpr(c, scope, sub_expr, .unused);
+        },
         else => |kind| return fail(
             c,
             error.UnsupportedTranslation,
@@ -2032,10 +2038,8 @@ fn transZeroInitExpr(
                 typedef_decl.getUnderlyingType().getTypePtr(),
             );
         },
-        else => {},
+        else => return Tag.std_mem_zeroes.create(c.arena, try transType(c, scope, ty, source_loc)),
     }
-
-    return fail(c, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{});
 }
 
 fn transImplicitValueInitExpr(
@@ -2118,7 +2122,7 @@ 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 => Tag.@"break".init(),
+        .false_literal => return transStmt(c, scope, stmt.getBody(), .unused),
         .true_literal => {
             const body_node = try transStmt(c, scope, stmt.getBody(), .unused);
             return Tag.while_true.create(c.arena, body_node);
@@ -2396,8 +2400,10 @@ fn transSwitchProngStmtInline(
             },
             else => {
                 const result = try transStmt(c, &block.base, it[0], .unused);
-                if (result.tag() == .declaration) continue;
-                try block.statements.append(result);
+                switch (result.tag()) {
+                    .declaration, .empty_block => {},
+                    else => try block.statements.append(result),
+                }
             },
         }
     }
@@ -2479,8 +2485,10 @@ fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used:
     const end_it = comp.body_end();
     while (it != end_it - 1) : (it += 1) {
         const result = try transStmt(c, &block_scope.base, it[0], .unused);
-        if (result.tag() == .declaration) continue;
-        try block_scope.statements.append(result);
+        switch (result.tag()) {
+            .declaration, .empty_block => {},
+            else => try block_scope.statements.append(result),
+        }
     }
     const break_node = try Tag.break_val.create(c.arena, .{
         .label = block_scope.label,
@@ -3126,12 +3134,12 @@ fn transConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.Condi
 
     const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used);
 
-    var then_body = try transExpr(c, scope, true_expr, .used);
+    var then_body = try transExpr(c, scope, true_expr, used);
     if (!res_is_bool and isBoolRes(then_body)) {
         then_body = try Tag.bool_to_int.create(c.arena, then_body);
     }
 
-    var else_body = try transExpr(c, scope, false_expr, .used);
+    var else_body = try transExpr(c, scope, false_expr, used);
     if (!res_is_bool and isBoolRes(else_body)) {
         else_body = try Tag.bool_to_int.create(c.arena, else_body);
     }
@@ -3141,7 +3149,8 @@ fn transConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.Condi
         .then = then_body,
         .@"else" = else_body,
     });
-    return maybeSuppressResult(c, scope, used, if_node);
+    // Clang inserts ImplicitCast(ToVoid)'s to both rhs and lhs so we don't need to supress the result here.
+    return if_node;
 }
 
 fn maybeSuppressResult(
@@ -4794,7 +4803,8 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
     while (true) {
         switch (m.next().?) {
             .Asterisk => {
-                if (m.peek().? == .RParen) {
+                const next = m.peek().?;
+                if (next == .RParen or next == .Nl or next == .Eof) {
                     // type *)
 
                     // last token of `node`
test/translate_c.zig
@@ -3,6 +3,62 @@ const std = @import("std");
 const CrossTarget = std.zig.CrossTarget;
 
 pub fn addCases(cases: *tests.TranslateCContext) void {
+    cases.add("if as while stmt has semicolon",
+        \\void foo() {
+        \\    while (1) if (1) {
+        \\        int a = 1;
+        \\    } else {
+        \\        int b = 2;
+        \\    }
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    while (true) if (true) {
+        \\        var a: c_int = 1;
+        \\    } else {
+        \\        var b: c_int = 2;
+        \\    };
+        \\}
+    });
+
+    cases.add("conditional operator cast to void",
+        \\int bar();
+        \\void foo() {
+        \\    int a;
+        \\    a ? a = 2 : bar();
+        \\}
+    , &[_][]const u8{
+        \\pub extern fn bar(...) c_int;
+        \\pub export fn foo() void {
+        \\    var a: c_int = undefined;
+        \\    if (a != 0) a = 2 else _ = bar();
+        \\}
+    });
+
+    cases.add("struct in struct init to zero",
+        \\struct Foo {
+        \\    int a;
+        \\    struct Bar {
+        \\        int a;
+        \\    } b;
+        \\} a = {};
+        \\#define PTR void *
+    , &[_][]const u8{
+        \\pub const struct_Bar = extern struct {
+        \\    a: c_int,
+        \\};
+        \\pub const struct_Foo = extern struct {
+        \\    a: c_int,
+        \\    b: struct_Bar,
+        \\};
+        \\pub export var a: struct_Foo = struct_Foo{
+        \\    .a = 0,
+        \\    .b = @import("std").mem.zeroes(struct_Bar),
+        \\};
+        ,
+        \\pub const PTR = ?*c_void;
+    });
+
     cases.add("scoped enum",
         \\void foo() {
         \\	enum Foo {
@@ -330,9 +386,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub export fn foo() void {
         \\    while (false) while (false) {};
         \\    while (true) while (false) {};
-        \\    while (true) while (true) {
-        \\        break;
-        \\    };
+        \\    while (true) {}
         \\}
     });
 
@@ -1044,13 +1098,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    ;;;;;
         \\}
     , &[_][]const u8{
-        \\pub export fn foo() void {
-        \\    {}
-        \\    {}
-        \\    {}
-        \\    {}
-        \\    {}
-        \\}
+        \\pub export fn foo() void {}
     });
 
     if (std.Target.current.os.tag != .windows) {
@@ -3050,9 +3098,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     , &[_][]const u8{
         \\pub fn foo() callconv(.C) void {
-        \\    if (true) while (true) {
-        \\        break;
-        \\    };
+        \\    if (true) {}
         \\}
     });