Commit 6d7025d0c5
Changed files (3)
src-self-hosted
test
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;
+ \\ };
+ \\}
+ });
}