Commit 6d7025d0c5

Vexu <git@vexu.eu>
2019-12-17 22:28:13
translate-c-2 various fixes to get more tests passing
1 parent a6960b8
Changed files (3)
src-self-hosted/clang.zig
@@ -793,16 +793,16 @@ pub extern fn ZigClangInitListExpr_getInit(self: ?*const struct_ZigClangInitList
 pub extern fn ZigClangInitListExpr_getArrayFiller(self: ?*const struct_ZigClangInitListExpr) *const ZigClangExpr;
 pub extern fn ZigClangInitListExpr_getNumInits(self: ?*const struct_ZigClangInitListExpr) c_uint;
 pub extern fn ZigClangAPValue_getKind(self: ?*const struct_ZigClangAPValue) ZigClangAPValueKind;
-pub extern fn ZigClangAPValue_getInt(self: ?*const struct_ZigClangAPValue) ?*const struct_ZigClangAPSInt;
+pub extern fn ZigClangAPValue_getInt(self: ?*const struct_ZigClangAPValue) *const struct_ZigClangAPSInt;
 pub extern fn ZigClangAPValue_getArrayInitializedElts(self: ?*const struct_ZigClangAPValue) c_uint;
 pub extern fn ZigClangAPValue_getArraySize(self: ?*const struct_ZigClangAPValue) c_uint;
 pub extern fn ZigClangAPValue_getLValueBase(self: ?*const struct_ZigClangAPValue) struct_ZigClangAPValueLValueBase;
-pub extern fn ZigClangAPSInt_isSigned(self: ?*const struct_ZigClangAPSInt) bool;
-pub extern fn ZigClangAPSInt_isNegative(self: ?*const struct_ZigClangAPSInt) bool;
-pub extern fn ZigClangAPSInt_negate(self: ?*const struct_ZigClangAPSInt) ?*const struct_ZigClangAPSInt;
-pub extern fn ZigClangAPSInt_free(self: ?*const struct_ZigClangAPSInt) void;
-pub extern fn ZigClangAPSInt_getRawData(self: ?*const struct_ZigClangAPSInt) [*:0]const u64;
-pub extern fn ZigClangAPSInt_getNumWords(self: ?*const struct_ZigClangAPSInt) c_uint;
+pub extern fn ZigClangAPSInt_isSigned(self: *const struct_ZigClangAPSInt) bool;
+pub extern fn ZigClangAPSInt_isNegative(self: *const struct_ZigClangAPSInt) bool;
+pub extern fn ZigClangAPSInt_negate(self: *const struct_ZigClangAPSInt) *const struct_ZigClangAPSInt;
+pub extern fn ZigClangAPSInt_free(self: *const struct_ZigClangAPSInt) void;
+pub extern fn ZigClangAPSInt_getRawData(self: *const struct_ZigClangAPSInt) [*:0]const u64;
+pub extern fn ZigClangAPSInt_getNumWords(self: *const struct_ZigClangAPSInt) c_uint;
 
 pub extern fn ZigClangAPInt_getLimitedValue(self: *const struct_ZigClangAPInt, limit: u64) u64;
 pub extern fn ZigClangAPValueLValueBase_dyn_cast_Expr(self: struct_ZigClangAPValueLValueBase) ?*const struct_ZigClangExpr;
@@ -1074,3 +1074,6 @@ pub extern fn ZigClangCaseStmt_getSubStmt(*const ZigClangCaseStmt) *const ZigCla
 pub extern fn ZigClangDefaultStmt_getSubStmt(*const ZigClangDefaultStmt) *const ZigClangStmt;
 
 pub extern fn ZigClangExpr_EvaluateAsConstantExpr(*const ZigClangExpr, *ZigClangExprEvalResult, ZigClangExpr_ConstExprUsage, *const ZigClangASTContext) bool;
+
+pub extern fn ZigClangPredefinedExpr_getFunctionName(*const ZigClangPredefinedExpr) *const ZigClangStringLiteral;
+
src-self-hosted/translate_c.zig
@@ -861,6 +861,7 @@ fn transStmt(
         .CaseStmtClass => return transCase(rp, scope, @ptrCast(*const ZigClangCaseStmt, stmt)),
         .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const ZigClangDefaultStmt, stmt)),
         .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used),
+        .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const ZigClangPredefinedExpr, stmt), result_used),
         else => {
             return revertAndWarn(
                 rp,
@@ -1748,6 +1749,10 @@ fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangExpr,
     return maybeSuppressResult(rp, scope, used, try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&result.Val)));
 }
 
+fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangPredefinedExpr, used: ResultUsed) TransError!*ast.Node {
+    return transStringLiteral(rp, scope, ZigClangPredefinedExpr_getFunctionName(expr), used);
+}
+
 fn transCPtrCast(
     rp: RestorePoint,
     loc: ZigClangSourceLocation,
@@ -2191,11 +2196,17 @@ fn transCreateNodePtrType(
     return node;
 }
 
-fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {
-    const num_limbs = ZigClangAPSInt_getNumWords(int.?);
+fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
+    const num_limbs = ZigClangAPSInt_getNumWords(int);
+    var aps_int = int;
+    const is_negative = ZigClangAPSInt_isSigned(int) and ZigClangAPSInt_isNegative(int);
+    if (is_negative)
+        aps_int = ZigClangAPSInt_negate(aps_int);
     var big = try std.math.big.Int.initCapacity(c.a(), num_limbs);
+    if (is_negative)
+        big.negate();
     defer big.deinit();
-    const data = ZigClangAPSInt_getRawData(int.?);
+    const data = ZigClangAPSInt_getRawData(aps_int);
     var i: @TypeOf(num_limbs) = 0;
     while (i < num_limbs) : (i += 1) big.limbs[i] = data[i];
     const str = big.toString(c.a(), 10) catch |err| switch (err) {
@@ -2207,6 +2218,8 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {
     node.* = .{
         .token = token,
     };
+    if (is_negative)
+        ZigClangAPSInt_free(aps_int);
     return &node.base;
 }
 
@@ -2803,7 +2816,7 @@ fn finishTransFnProto(
                 const param = ZigClangFunctionDecl_getParamDecl(fn_decl.?, @intCast(c_uint, i));
                 var param_name: []const u8 = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param)));
                 if (param_name.len < 1)
-                    param_name = "arg"[0..];
+                    param_name = try std.fmt.allocPrint(rp.c.a(), "arg_{}", .{rp.c.getMangle()});
                 const checked_param_name = if (try scope.createAlias(rp.c, param_name)) |a| blk: {
                     try fndef_scope.params.push(.{ .name = param_name, .alias = a });
                     break :blk a;
test/translate_c.zig
@@ -426,6 +426,180 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         },
     );
 
+    cases.addC_both("null statements",
+        \\void foo(void) {
+        \\    ;;;;;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    {}
+        \\    {}
+        \\    {}
+        \\    {}
+        \\    {}
+        \\}
+    });
+
+    if (builtin.os != builtin.Os.windows) {
+        // Windows treats this as an enum with type c_int
+        cases.add_both("big negative enum init values when C ABI supports long long enums",
+            \\enum EnumWithInits {
+            \\    VAL01 = 0,
+            \\    VAL02 = 1,
+            \\    VAL03 = 2,
+            \\    VAL04 = 3,
+            \\    VAL05 = -1,
+            \\    VAL06 = -2,
+            \\    VAL07 = -3,
+            \\    VAL08 = -4,
+            \\    VAL09 = VAL02 + VAL08,
+            \\    VAL10 = -1000012000,
+            \\    VAL11 = -1000161000,
+            \\    VAL12 = -1000174001,
+            \\    VAL13 = VAL09,
+            \\    VAL14 = VAL10,
+            \\    VAL15 = VAL11,
+            \\    VAL16 = VAL13,
+            \\    VAL17 = (VAL16 - VAL10 + 1),
+            \\    VAL18 = 0x1000000000000000L,
+            \\    VAL19 = VAL18 + VAL18 + VAL18 - 1,
+            \\    VAL20 = VAL19 + VAL19,
+            \\    VAL21 = VAL20 + 0xFFFFFFFFFFFFFFFF,
+            \\    VAL22 = 0xFFFFFFFFFFFFFFFF + 1,
+            \\    VAL23 = 0xFFFFFFFFFFFFFFFF,
+            \\};
+        , &[_][]const u8{
+            \\pub const enum_EnumWithInits = extern enum(c_longlong) {
+            \\    VAL01 = 0,
+            \\    VAL02 = 1,
+            \\    VAL03 = 2,
+            \\    VAL04 = 3,
+            \\    VAL05 = -1,
+            \\    VAL06 = -2,
+            \\    VAL07 = -3,
+            \\    VAL08 = -4,
+            \\    VAL09 = -3,
+            \\    VAL10 = -1000012000,
+            \\    VAL11 = -1000161000,
+            \\    VAL12 = -1000174001,
+            \\    VAL13 = -3,
+            \\    VAL14 = -1000012000,
+            \\    VAL15 = -1000161000,
+            \\    VAL16 = -3,
+            \\    VAL17 = 1000011998,
+            \\    VAL18 = 1152921504606846976,
+            \\    VAL19 = 3458764513820540927,
+            \\    VAL20 = 6917529027641081854,
+            \\    VAL21 = 6917529027641081853,
+            \\    VAL22 = 0,
+            \\    VAL23 = -1,
+            \\};
+        });
+    }
+
+    cases.addC_both("predefined expressions",
+        \\void foo(void) {
+        \\    __func__;
+        \\    __FUNCTION__;
+        \\    __PRETTY_FUNCTION__;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    _ = "foo";
+        \\    _ = "foo";
+        \\    _ = "void foo(void)";
+        \\}
+    });
+
+    cases.addC_both("ignore result, no function arguments",
+        \\void foo() {
+        \\    int a;
+        \\    1;
+        \\    "hey";
+        \\    1 + 1;
+        \\    1 - 1;
+        \\    a = 1;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    var a: c_int = undefined;
+        \\    _ = 1;
+        \\    _ = "hey";
+        \\    _ = (1 + 1);
+        \\    _ = (1 - 1);
+        \\    a = 1;
+        \\}
+    });
+
+    cases.add_2("qualified struct and enum",
+        \\struct Foo {
+        \\    int x;
+        \\    int y;
+        \\};
+        \\enum Bar {
+        \\    BarA,
+        \\    BarB,
+        \\};
+        \\void func(struct Foo *a, enum Bar **b);
+    , &[_][]const u8{
+        \\pub const struct_Foo = extern struct {
+        \\    x: c_int,
+        \\    y: c_int,
+        \\};
+        \\pub const BarA = enum_Bar.A;
+        \\pub const BarB = enum_Bar.B;
+        \\pub const enum_Bar = extern enum {
+        \\    A,
+        \\    B,
+        \\};
+        \\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
+    ,
+        \\pub const Foo = struct_Foo;
+        \\pub const Bar = enum_Bar;
+    });
+
+    cases.add_both("constant size array",
+        \\void func(int array[20]);
+    , &[_][]const u8{
+        \\pub extern fn func(array: [*c]c_int) void;
+    });
+
+    cases.add_both("__cdecl doesn't mess up function pointers",
+        \\void foo(void (__cdecl *fn_ptr)(void));
+    , &[_][]const u8{
+        \\pub extern fn foo(fn_ptr: ?extern fn () void) void;
+    });
+
+    cases.addC_both("void cast",
+        \\void foo(int a) {
+        \\    (void) a;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo(a: c_int) void {
+        \\    _ = a;
+        \\}
+    });
+
+    cases.addC_both("implicit cast to void *",
+        \\void *foo(unsigned short *x) {
+        \\    return x;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo(x: [*c]c_ushort) ?*c_void {
+        \\    return @ptrCast(?*c_void, x);
+        \\}
+    });
+
+    cases.addC_both("null pointer implicit cast",
+        \\int* foo(void) {
+        \\    return 0;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() [*c]c_int {
+        \\    return null;
+        \\}
+    });
+
     /////////////// Cases that pass for only stage2 ////////////////
 
     cases.add_2("Parameterless function prototypes",
@@ -904,145 +1078,75 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\};
     });
 
-    /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
-
-    if (builtin.os != builtin.Os.windows) {
-        // Windows treats this as an enum with type c_int
-        cases.add("big negative enum init values when C ABI supports long long enums",
-            \\enum EnumWithInits {
-            \\    VAL01 = 0,
-            \\    VAL02 = 1,
-            \\    VAL03 = 2,
-            \\    VAL04 = 3,
-            \\    VAL05 = -1,
-            \\    VAL06 = -2,
-            \\    VAL07 = -3,
-            \\    VAL08 = -4,
-            \\    VAL09 = VAL02 + VAL08,
-            \\    VAL10 = -1000012000,
-            \\    VAL11 = -1000161000,
-            \\    VAL12 = -1000174001,
-            \\    VAL13 = VAL09,
-            \\    VAL14 = VAL10,
-            \\    VAL15 = VAL11,
-            \\    VAL16 = VAL13,
-            \\    VAL17 = (VAL16 - VAL10 + 1),
-            \\    VAL18 = 0x1000000000000000L,
-            \\    VAL19 = VAL18 + VAL18 + VAL18 - 1,
-            \\    VAL20 = VAL19 + VAL19,
-            \\    VAL21 = VAL20 + 0xFFFFFFFFFFFFFFFF,
-            \\    VAL22 = 0xFFFFFFFFFFFFFFFF + 1,
-            \\    VAL23 = 0xFFFFFFFFFFFFFFFF,
-            \\};
-        , &[_][]const u8{
-            \\pub const enum_EnumWithInits = extern enum(c_longlong) {
-            \\    VAL01 = 0,
-            \\    VAL02 = 1,
-            \\    VAL03 = 2,
-            \\    VAL04 = 3,
-            \\    VAL05 = -1,
-            \\    VAL06 = -2,
-            \\    VAL07 = -3,
-            \\    VAL08 = -4,
-            \\    VAL09 = -3,
-            \\    VAL10 = -1000012000,
-            \\    VAL11 = -1000161000,
-            \\    VAL12 = -1000174001,
-            \\    VAL13 = -3,
-            \\    VAL14 = -1000012000,
-            \\    VAL15 = -1000161000,
-            \\    VAL16 = -3,
-            \\    VAL17 = 1000011998,
-            \\    VAL18 = 1152921504606846976,
-            \\    VAL19 = 3458764513820540927,
-            \\    VAL20 = 6917529027641081854,
-            \\    VAL21 = 6917529027641081853,
-            \\    VAL22 = 0,
-            \\    VAL23 = -1,
-            \\};
-        });
-    }
-
-    cases.add("predefined expressions",
-        \\void foo(void) {
-        \\    __func__;
-        \\    __FUNCTION__;
-        \\    __PRETTY_FUNCTION__;
-        \\}
+    cases.add_2("undefined array global",
+        \\int array[100] = {};
     , &[_][]const u8{
-        \\pub fn foo() void {
-        \\    _ = "foo";
-        \\    _ = "foo";
-        \\    _ = "void foo(void)";
-        \\}
+        \\pub export var array: [100]c_int = .{0} ** 100;
     });
 
-    cases.add("ignore result, no function arguments",
-        \\void foo() {
-        \\    int a;
-        \\    1;
-        \\    "hey";
-        \\    1 + 1;
-        \\    1 - 1;
-        \\    a = 1;
-        \\}
+    cases.add_2("restrict -> noalias",
+        \\void foo(void *restrict bar, void *restrict);
     , &[_][]const u8{
-        \\pub fn foo() void {
-        \\    var a: c_int = undefined;
-        \\    _ = 1;
-        \\    _ = "hey";
-        \\    _ = (1 + 1);
-        \\    _ = (1 - 1);
-        \\    a = 1;
-        \\}
+        \\pub extern fn foo(noalias bar: ?*c_void, noalias arg_1: ?*c_void) void;
     });
 
-    cases.add("for loop with var init but empty body",
-        \\void foo(void) {
-        \\    for (int x = 0; x < 10; x++);
+    cases.add_2("assign",
+        \\int max(int a) {
+        \\    int tmp;
+        \\    tmp = a;
+        \\    a = tmp;
         \\}
     , &[_][]const u8{
-        \\pub fn foo() void {
-        \\    {
-        \\        var x: c_int = 0;
-        \\        while (x < 10) : (x += 1) {}
-        \\    }
+        \\pub export fn max(a: c_int) c_int {
+        \\    var tmp: c_int = undefined;
+        \\    tmp = a;
+        \\    a = tmp;
         \\}
     });
 
-    cases.add("do while with empty body",
-        \\void foo(void) {
-        \\    do ; while (1);
+    cases.add_2("chaining assign",
+        \\void max(int a) {
+        \\    int b, c;
+        \\    c = b = a;
         \\}
-    , &[_][]const u8{ // TODO this should be if (1 != 0) break
-        \\pub fn foo() void {
-        \\    while (true) {
-        \\        {}
-        \\        if (!1) break;
-        \\    }
+    , &[_][]const u8{
+        \\pub export fn max(a: c_int) void {
+        \\    var b: c_int = undefined;
+        \\    var c: c_int = undefined;
+        \\    c = blk: {
+        \\        const _tmp_1 = a;
+        \\        b = _tmp_1;
+        \\        break :blk _tmp_1;
+        \\    };
         \\}
     });
 
-    cases.add("for with empty body",
-        \\void foo(void) {
-        \\    for (;;);
-        \\}
+    cases.add_2("anonymous enum",
+        \\enum {
+        \\    One,
+        \\    Two,
+        \\};
     , &[_][]const u8{
-        \\pub fn foo() void {
-        \\    while (true) {}
-        \\}
+        \\pub const One = enum_unnamed_1.One;
+        \\pub const Two = enum_unnamed_1.Two;
+        \\pub const enum_unnamed_1 = extern enum {
+        \\    One,
+        \\    Two,
+        \\};
     });
 
-    cases.add("while with empty body",
-        \\void foo(void) {
-        \\    while (1);
+    cases.add_2("c style cast",
+        \\int float_to_int(float a) {
+        \\    return (int)a;
         \\}
     , &[_][]const u8{
-        \\pub fn foo() void {
-        \\    while (1 != 0) {}
+        \\pub export fn float_to_int(a: f32) c_int {
+        \\    return @floatToInt(c_int, a);
         \\}
     });
 
+    /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
+
     cases.addAllowWarnings("simple data types",
         \\#include <stdint.h>
         \\int foo(char a, unsigned char b, signed char c);
@@ -1067,56 +1171,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add("restrict -> noalias",
-        \\void foo(void *restrict bar, void *restrict);
-    , &[_][]const u8{
-        \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;
-    });
-
-    cases.add("qualified struct and enum",
-        \\struct Foo {
-        \\    int x;
-        \\    int y;
-        \\};
-        \\enum Bar {
-        \\    BarA,
-        \\    BarB,
-        \\};
-        \\void func(struct Foo *a, enum Bar **b);
-    , &[_][]const u8{
-        \\pub const struct_Foo = extern struct {
-        \\    x: c_int,
-        \\    y: c_int,
-        \\};
-    ,
-        \\pub const enum_Bar = extern enum {
-        \\    A,
-        \\    B,
-        \\};
-    ,
-        \\pub const BarA = enum_Bar.A;
-    ,
-        \\pub const BarB = enum_Bar.B;
-    ,
-        \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void;
-    ,
-        \\pub const Foo = struct_Foo;
-    ,
-        \\pub const Bar = enum_Bar;
-    });
-
-    cases.add("constant size array",
-        \\void func(int array[20]);
-    , &[_][]const u8{
-        \\pub extern fn func(array: [*c]c_int) void;
-    });
-
-    cases.add("__cdecl doesn't mess up function pointers",
-        \\void foo(void (__cdecl *fn_ptr)(void));
-    , &[_][]const u8{
-        \\pub extern fn foo(fn_ptr: ?extern fn () void) void;
-    });
-
     cases.add("macro defines string literal with hex",
         \\#define FOO "aoeu\xab derp"
         \\#define FOO2 "aoeu\x0007a derp"
@@ -1247,54 +1301,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     cases.addC("logical and, logical or on none bool values",
         \\int and_or_none_bool(int a, float b, void *c) {
         \\    if (a && b) return 0;
-        \\    if (b && c) return 1;
-        \\    if (a && c) return 2;
-        \\    if (a || b) return 3;
-        \\    if (b || c) return 4;
-        \\    if (a || c) return 5;
-        \\    return 6;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
-        \\    if ((a != 0) and (b != 0)) return 0;
-        \\    if ((b != 0) and (c != null)) return 1;
-        \\    if ((a != 0) and (c != null)) return 2;
-        \\    if ((a != 0) or (b != 0)) return 3;
-        \\    if ((b != 0) or (c != null)) return 4;
-        \\    if ((a != 0) or (c != null)) return 5;
-        \\    return 6;
-        \\}
-    });
-
-    cases.addC("assign",
-        \\int max(int a) {
-        \\    int tmp;
-        \\    tmp = a;
-        \\    a = tmp;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn max(_arg_a: c_int) c_int {
-        \\    var a = _arg_a;
-        \\    var tmp: c_int = undefined;
-        \\    tmp = a;
-        \\    a = tmp;
-        \\}
-    });
-
-    cases.addC("chaining assign",
-        \\void max(int a) {
-        \\    int b, c;
-        \\    c = b = a;
+        \\    if (b && c) return 1;
+        \\    if (a && c) return 2;
+        \\    if (a || b) return 3;
+        \\    if (b || c) return 4;
+        \\    if (a || c) return 5;
+        \\    return 6;
         \\}
     , &[_][]const u8{
-        \\pub export fn max(a: c_int) void {
-        \\    var b: c_int = undefined;
-        \\    var c: c_int = undefined;
-        \\    c = (x: {
-        \\        const _tmp = a;
-        \\        b = _tmp;
-        \\        break :x _tmp;
-        \\    });
+        \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
+        \\    if ((a != 0) and (b != 0)) return 0;
+        \\    if ((b != 0) and (c != null)) return 1;
+        \\    if ((a != 0) and (c != null)) return 2;
+        \\    if ((a != 0) or (b != 0)) return 3;
+        \\    if ((b != 0) or (c != null)) return 4;
+        \\    if ((a != 0) or (c != null)) return 5;
+        \\    return 6;
         \\}
     });
 
@@ -1318,16 +1340,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add("anonymous enum",
-        \\enum {
-        \\    One,
-        \\    Two,
-        \\};
-    , &[_][]const u8{
-        \\pub const One = 0;
-        \\pub const Two = 1;
-    });
-
     cases.addC("function call",
         \\static void bar(void) { }
         \\static int baz(void) { return 0; }
@@ -1362,26 +1374,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.addC("null statements",
-        \\void foo(void) {
-        \\    ;;;;;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn foo() void {
-        \\    {}
-        \\    {}
-        \\    {}
-        \\    {}
-        \\    {}
-        \\}
-    });
-
-    cases.add("undefined array global",
-        \\int array[100];
-    , &[_][]const u8{
-        \\pub var array: [100]c_int = undefined;
-    });
-
     cases.addC("array access",
         \\int array[100];
         \\int foo(int index) {
@@ -1394,36 +1386,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.addC("c style cast",
-        \\int float_to_int(float a) {
-        \\    return (int)a;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn float_to_int(a: f32) c_int {
-        \\    return @as(c_int, a);
-        \\}
-    });
-
-    cases.addC("void cast",
-        \\void foo(int a) {
-        \\    (void) a;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn foo(a: c_int) void {
-        \\    _ = a;
-        \\}
-    });
-
-    cases.addC("implicit cast to void *",
-        \\void *foo(unsigned short *x) {
-        \\    return x;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn foo(x: [*c]c_ushort) ?*c_void {
-        \\    return @ptrCast(?*c_void, x);
-        \\}
-    });
-
     cases.addC("sizeof",
         \\#include <stddef.h>
         \\size_t size_of(void) {
@@ -1435,29 +1397,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.addC("null pointer implicit cast",
-        \\int* foo(void) {
-        \\    return 0;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn foo() [*c]c_int {
-        \\    return null;
-        \\}
-    });
-
-    cases.addC("comma operator",
-        \\int foo(void) {
-        \\    return 1, 2;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn foo() c_int {
-        \\    return x: {
-        \\        _ = 1;
-        \\        break :x 2;
-        \\    };
-        \\}
-    });
-
     cases.addC("statement expression",
         \\int foo(void) {
         \\    return ({
@@ -2292,4 +2231,159 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    }
         \\}
     });
+
+    cases.add("for loop with var init but empty body",
+        \\void foo(void) {
+        \\    for (int x = 0; x < 10; x++);
+        \\}
+    , &[_][]const u8{
+        \\pub fn foo() void {
+        \\    {
+        \\        var x: c_int = 0;
+        \\        while (x < 10) : (x += 1) {}
+        \\    }
+        \\}
+    });
+
+    cases.add("do while with empty body",
+        \\void foo(void) {
+        \\    do ; while (1);
+        \\}
+    , &[_][]const u8{ // TODO this should be if (1 != 0) break
+        \\pub fn foo() void {
+        \\    while (true) {
+        \\        {}
+        \\        if (!1) break;
+        \\    }
+        \\}
+    });
+
+    cases.add("for with empty body",
+        \\void foo(void) {
+        \\    for (;;);
+        \\}
+    , &[_][]const u8{
+        \\pub fn foo() void {
+        \\    while (true) {}
+        \\}
+    });
+
+    cases.add("while with empty body",
+        \\void foo(void) {
+        \\    while (1);
+        \\}
+    , &[_][]const u8{
+        \\pub fn foo() void {
+        \\    while (1 != 0) {}
+        \\}
+    });
+
+    cases.add("undefined array global",
+        \\int array[100];
+    , &[_][]const u8{
+        \\pub var array: [100]c_int = undefined;
+    });
+
+    cases.add("qualified struct and enum",
+        \\struct Foo {
+        \\    int x;
+        \\    int y;
+        \\};
+        \\enum Bar {
+        \\    BarA,
+        \\    BarB,
+        \\};
+        \\void func(struct Foo *a, enum Bar **b);
+    , &[_][]const u8{
+        \\pub const struct_Foo = extern struct {
+        \\    x: c_int,
+        \\    y: c_int,
+        \\};
+    ,
+        \\pub const enum_Bar = extern enum {
+        \\    A,
+        \\    B,
+        \\};
+    ,
+        \\pub const BarA = enum_Bar.A;
+    ,
+        \\pub const BarB = enum_Bar.B;
+    ,
+        \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void;
+    ,
+        \\pub const Foo = struct_Foo;
+    ,
+        \\pub const Bar = enum_Bar;
+    });
+
+    cases.add("restrict -> noalias",
+        \\void foo(void *restrict bar, void *restrict);
+    , &[_][]const u8{
+        \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;
+    });
+
+    cases.addC("assign",
+        \\int max(int a) {
+        \\    int tmp;
+        \\    tmp = a;
+        \\    a = tmp;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn max(_arg_a: c_int) c_int {
+        \\    var a = _arg_a;
+        \\    var tmp: c_int = undefined;
+        \\    tmp = a;
+        \\    a = tmp;
+        \\}
+    });
+
+    cases.addC("chaining assign",
+        \\void max(int a) {
+        \\    int b, c;
+        \\    c = b = a;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn max(a: c_int) void {
+        \\    var b: c_int = undefined;
+        \\    var c: c_int = undefined;
+        \\    c = (x: {
+        \\        const _tmp = a;
+        \\        b = _tmp;
+        \\        break :x _tmp;
+        \\    });
+        \\}
+    });
+
+    cases.add("anonymous enum",
+        \\enum {
+        \\    One,
+        \\    Two,
+        \\};
+    , &[_][]const u8{
+        \\pub const One = 0;
+        \\pub const Two = 1;
+    });
+
+    cases.addC("c style cast",
+        \\int float_to_int(float a) {
+        \\    return (int)a;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn float_to_int(a: f32) c_int {
+        \\    return @as(c_int, a);
+        \\}
+    });
+
+    cases.addC("comma operator",
+        \\int foo(void) {
+        \\    return 1, 2;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() c_int {
+        \\    return x: {
+        \\        _ = 1;
+        \\        break :x 2;
+        \\    };
+        \\}
+    });
 }