translate-c-2 various fixes to get more tests passing

This commit is contained in:
Vexu 2019-12-17 23:28:13 +02:00
parent a6960b89ed
commit 6d7025d0c5
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
3 changed files with 423 additions and 313 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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.add_2("undefined array global",
\\int array[100] = {};
, &[_][]const u8{
\\pub export var array: [100]c_int = .{0} ** 100;
});
cases.add_2("restrict -> noalias",
\\void foo(void *restrict bar, void *restrict);
, &[_][]const u8{
\\pub extern fn foo(noalias bar: ?*c_void, noalias arg_1: ?*c_void) void;
});
cases.add_2("assign",
\\int max(int a) {
\\ int tmp;
\\ tmp = a;
\\ a = tmp;
\\}
, &[_][]const u8{
\\pub export fn max(a: c_int) c_int {
\\ var tmp: c_int = undefined;
\\ tmp = a;
\\ a = tmp;
\\}
});
cases.add_2("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 = blk: {
\\ const _tmp_1 = a;
\\ b = _tmp_1;
\\ break :blk _tmp_1;
\\ };
\\}
});
cases.add_2("anonymous enum",
\\enum {
\\ One,
\\ Two,
\\};
, &[_][]const u8{
\\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_2("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 @floatToInt(c_int, a);
\\}
});
/////////////// 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__;
\\}
, &[_][]const u8{
\\pub fn foo() void {
\\ _ = "foo";
\\ _ = "foo";
\\ _ = "void foo(void)";
\\}
});
cases.add("ignore result, no function arguments",
\\void foo() {
\\ int a;
\\ 1;
\\ "hey";
\\ 1 + 1;
\\ 1 - 1;
\\ a = 1;
\\}
, &[_][]const u8{
\\pub fn foo() void {
\\ var a: c_int = undefined;
\\ _ = 1;
\\ _ = "hey";
\\ _ = (1 + 1);
\\ _ = (1 - 1);
\\ a = 1;
\\}
});
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.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"
@ -1266,38 +1320,6 @@ pub fn addCases(cases: *tests.TranslateCContext) 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.addC("shift right assign with a fixed size type",
\\#include <stdint.h>
\\int log2(uint32_t a) {
@ -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;
\\ };
\\}
});
}