authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-17 23:18:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-09-24 20:01:17-07:00
log1bdcdbd996a73a7270d6668fca8893b4fc701280
tree5328f197817106c0d77370bd6b2706901b94ef35
parentf49a54745ba67a4226cbe706727fb6817b64b1aa

delete all the translate-c tests

the ziglang/translate-c package has its own test suite, so these are redundant

55 files changed, 21 insertions(+), 6900 deletions(-)

build.zig+20-28
......@@ -90,8 +90,6 @@ pub fn build(b: *std.Build) !void {
9090 const skip_libc = b.option(bool, "skip-libc", "Main test suite skips tests that link libc") orelse false;
9191 const skip_single_threaded = b.option(bool, "skip-single-threaded", "Main test suite skips tests that are single-threaded") orelse false;
9292 const skip_compile_errors = b.option(bool, "skip-compile-errors", "Main test suite skips compile error tests") orelse false;
93 const skip_translate_c = b.option(bool, "skip-translate-c", "Main test suite skips translate-c tests") orelse false;
94 const skip_run_translated_c = b.option(bool, "skip-run-translated-c", "Main test suite skips run-translated-c tests") orelse skip_translate_c;
9593 const skip_freebsd = b.option(bool, "skip-freebsd", "Main test suite skips targets with freebsd OS") orelse false;
9694 const skip_netbsd = b.option(bool, "skip-netbsd", "Main test suite skips targets with netbsd OS") orelse false;
9795 const skip_windows = b.option(bool, "skip-windows", "Main test suite skips targets with windows OS") orelse false;
......@@ -416,7 +414,7 @@ pub fn build(b: *std.Build) !void {
416414 test_step.dependOn(check_fmt);
417415
418416 const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
419 try tests.addCases(b, test_cases_step, target, .{
417 try tests.addCases(b, test_cases_step, .{
420418 .test_filters = test_filters,
421419 .test_target_filters = test_target_filters,
422420 .skip_compile_errors = skip_compile_errors,
......@@ -428,9 +426,6 @@ pub fn build(b: *std.Build) !void {
428426 .skip_linux = skip_linux,
429427 .skip_llvm = skip_llvm,
430428 .skip_libc = skip_libc,
431 }, .{
432 .skip_translate_c = skip_translate_c,
433 .skip_run_translated_c = skip_run_translated_c,
434429 }, .{
435430 .enable_llvm = enable_llvm,
436431 .llvm_has_m68k = llvm_has_m68k,
......@@ -465,27 +460,25 @@ pub fn build(b: *std.Build) !void {
465460 .max_rss = 4000000000,
466461 }));
467462
468 if (!skip_translate_c) {
469 test_modules_step.dependOn(tests.addModuleTests(b, .{
470 .test_filters = test_filters,
471 .test_target_filters = test_target_filters,
472 .test_extra_targets = test_extra_targets,
473 .root_src = "test/c_import.zig",
474 .name = "c-import",
475 .desc = "Run the @cImport tests",
476 .optimize_modes = optimization_modes,
477 .include_paths = &.{"test/c_import"},
478 .skip_single_threaded = true,
479 .skip_non_native = skip_non_native,
480 .skip_freebsd = skip_freebsd,
481 .skip_netbsd = skip_netbsd,
482 .skip_windows = skip_windows,
483 .skip_macos = skip_macos,
484 .skip_linux = skip_linux,
485 .skip_llvm = skip_llvm,
486 .skip_libc = skip_libc,
487 }));
488 }
463 test_modules_step.dependOn(tests.addModuleTests(b, .{
464 .test_filters = test_filters,
465 .test_target_filters = test_target_filters,
466 .test_extra_targets = test_extra_targets,
467 .root_src = "test/c_import.zig",
468 .name = "c-import",
469 .desc = "Run the @cImport tests",
470 .optimize_modes = optimization_modes,
471 .include_paths = &.{"test/c_import"},
472 .skip_single_threaded = true,
473 .skip_non_native = skip_non_native,
474 .skip_freebsd = skip_freebsd,
475 .skip_netbsd = skip_netbsd,
476 .skip_windows = skip_windows,
477 .skip_macos = skip_macos,
478 .skip_linux = skip_linux,
479 .skip_llvm = skip_llvm,
480 .skip_libc = skip_libc,
481 }));
489482
490483 test_modules_step.dependOn(tests.addModuleTests(b, .{
491484 .test_filters = test_filters,
......@@ -577,7 +570,6 @@ pub fn build(b: *std.Build) !void {
577570 enable_macos_sdk,
578571 enable_ios_sdk,
579572 enable_symlinks_windows,
580 skip_translate_c,
581573 ));
582574 test_step.dependOn(tests.addCAbiTests(b, .{
583575 .test_target_filters = test_target_filters,
test/cases/README.md-27
......@@ -22,33 +22,6 @@ This will do `zig run` on the code and expect exit code 0.
2222// run
2323```
2424
25## Translate-c
26
27If you want to test translating C code to Zig use `translate-c`:
28
29```c
30// translate-c
31// c_frontend=aro,clang
32// target=x86_64-linux
33//
34// pub const foo = 1;
35// pub const immediately_after_foo = 2;
36//
37// pub const somewhere_else_in_the_file = 3:
38```
39
40## Run Translated C
41
42If you want to test translating C code to Zig and then executing it use `run-translated-c`:
43
44```c
45// run-translated-c
46// c_frontend=aro,clang
47// target=x86_64-linux
48//
49// Hello world!
50```
51
5225## Incremental Compilation
5326
5427Make multiple files that have ".", and then an integer, before the ".zig"
test/cases/run_translated_c/compound_assignments_with_implicit_casts.c deleted-20
......@@ -1,20 +0,0 @@
1int main() {
2 int i = 2;
3 float f = 3.2f;
4
5 i += 1.7;
6 if (i != 3) return 1;
7 i += f;
8 if (i != 6) return 2;
9
10
11 f += 2UL;
12 if (f <= 5.1999 || f >= 5.2001) return 3;
13 f += i;
14 if (f <= 11.1999 || f >= 11.2001) return 4;
15
16 return 0;
17}
18
19// run-translated-c
20// c_frontend=clang
test/cases/run_translated_c/compound_assignments_with_pointer_arithmetic.c deleted-21
......@@ -1,21 +0,0 @@
1int main() {
2 const char *s = "forgreatjustice";
3 unsigned int add = 1;
4
5 s += add;
6 if (*s != 'o') return 1;
7
8 s += 1UL;
9 if (*s != 'r') return 2;
10
11 const char *s2 = (s += add);
12 if (*s2 != 'g') return 3;
13
14 s2 -= add;
15 if (*s2 != 'r') return 4;
16
17 return 0;
18}
19
20// run-translated-c
21// c_frontend=clang
test/cases/run_translated_c/dereference address of.c deleted-11
......@@ -1,11 +0,0 @@
1#include <stdlib.h>
2int main(void) {
3 int i = 0;
4 *&i = 42;
5 if (i != 42) abort();
6 return 0;
7}
8
9// run-translated-c
10// c_frontend=clang
11// link_libc=true
test/cases/run_translated_c/explicit_cast_bool_from_float.c deleted-10
......@@ -1,10 +0,0 @@
1#include <stdbool.h>
2
3int main() {
4 float f = 2.0f;
5 bool b = (bool) f;
6 return 0;
7}
8
9// run-translated-c
10// c_frontend=clang
test/cases/run_translated_c/extern_typedef_variables_in_functions.c deleted-22
......@@ -1,22 +0,0 @@
1const int ev = 40;
2
3static int func(void)
4{
5 typedef int test_type_t;
6 extern const test_type_t ev;
7 // Ensure mangled name is also being used for conditions and loops, see #20828
8 if (ev == 0);
9 while (ev == 0);
10 do; while (ev == 0);
11 return ev + 2;
12}
13
14int main()
15{
16 if (func() != 42)
17 return 1;
18 return 0;
19}
20
21// run-translated-c
22// c_frontend=clang
test/cases/run_translated_c/float_from_bool_expr_cast.c deleted-8
......@@ -1,8 +0,0 @@
1int main() {
2 float f = (float)(10.0f > 1.0f);
3 return 0;
4}
5
6// run-translated-c
7// c_frontend=clang
8//
test/cases/run_translated_c/sub_scope_extern_local_var_ref.c deleted-23
......@@ -1,23 +0,0 @@
1#include <stdlib.h>
2int a = 42;
3int foo(int bar) {
4 extern int a;
5 if (bar) {
6 return a;
7 }
8 return 0;
9}
10int main() {
11 int result1 = foo(0);
12 if (result1 != 0) abort();
13 int result2 = foo(1);
14 if (result2 != 42) abort();
15 a = 100;
16 int result3 = foo(1);
17 if (result3 != 100) abort();
18 return 0;
19}
20
21// run-translated-c
22// c_frontend=clang
23// link_libc=true
test/cases/translate_c/_Static_assert.c deleted-7
......@@ -1,7 +0,0 @@
1_Static_assert(1 == 1, "");
2
3// translate-c
4// target=x86_64-linux
5// c_frontend=aro
6//
7// tmp.c:1:1: warning: ignoring _Static_assert declaration
test/cases/translate_c/align() attribute.c deleted-17
......@@ -1,17 +0,0 @@
1__attribute__ ((aligned(128)))
2extern char my_array[16];
3__attribute__ ((aligned(128)))
4void my_fn(void) { }
5void other_fn(void) {
6 char ARR[16] __attribute__ ((aligned (16)));
7}
8
9// translate-c
10// c_frontend=clang
11//
12// pub extern var my_array: [16]u8 align(128);
13// pub export fn my_fn() align(128) void {}
14// pub export fn other_fn() void {
15// var ARR: [16]u8 align(16) = undefined;
16// _ = &ARR;
17// }
test/cases/translate_c/assert_with_strlit.c deleted-8
......@@ -1,8 +0,0 @@
1
2void assert(int x) {}
3#define FOO assert(0 && "error message")
4
5// translate-c
6// c_frontend=clang
7//
8// pub const FOO = assert((@as(c_int, 0) != 0) and (@intFromPtr("error message") != 0));
test/cases/translate_c/atomic types.c deleted-8
......@@ -1,8 +0,0 @@
1typedef _Atomic(int) AtomicInt;
2
3// translate-c
4// target=x86_64-linux
5// c_frontend=aro
6//
7// tmp.c:1:22: warning: unsupported type: '_Atomic(int)'
8// pub const AtomicInt = @compileError("unable to resolve typedef child type");
test/cases/translate_c/c_keywords_as_macro_function_parameters.c deleted-82
......@@ -1,82 +0,0 @@
1#define GUARDED_INT_ADDITION(int) ((int) + 1)
2
3#define UNGUARDED_INT_SUBTRACTION(int) (int - 2)
4
5#define GUARDED_INT_MULTIPLY(int) ((int) * 3)
6
7#define UNGUARDED_INT_DIVIDE(int) (int / 4)
8
9#define WRAPPED_RETURN(return) ((return) % 2)
10
11#define UNWRAPPED_RETURN(return) (return ^ 0x7F)
12
13#define WITH_TWO_PARAMETERS(signed, x) ((signed) + (x) + 9)
14
15#define GUARDED_ALIGNOF(_Alignof) ((_Alignof) & 0x55)
16
17#define UNGUARDED_ALIGNOF(_Alignof) (_Alignof | 0x80)
18
19#define GUARDED_SIZEOF(sizeof) ((sizeof) == 64)
20
21#define UNGUARDED_SIZEOF(sizeof) (sizeof < 64)
22
23#define SIZEOF(x) ((int)sizeof(x))
24
25#define SIZEOF2(x) ((int)sizeof x)
26
27// translate-c
28// c_frontend=clang
29//
30// pub inline fn GUARDED_INT_ADDITION(int: anytype) @TypeOf(int + @as(c_int, 1)) {
31// _ = &int;
32// return int + @as(c_int, 1);
33// }
34// pub inline fn UNGUARDED_INT_SUBTRACTION(int: anytype) @TypeOf(int - @as(c_int, 2)) {
35// _ = &int;
36// return int - @as(c_int, 2);
37// }
38// pub inline fn GUARDED_INT_MULTIPLY(int: anytype) @TypeOf(int * @as(c_int, 3)) {
39// _ = &int;
40// return int * @as(c_int, 3);
41// }
42// pub inline fn UNGUARDED_INT_DIVIDE(int: anytype) @TypeOf(@import("std").zig.c_translation.MacroArithmetic.div(int, @as(c_int, 4))) {
43// _ = &int;
44// return @import("std").zig.c_translation.MacroArithmetic.div(int, @as(c_int, 4));
45// }
46// pub inline fn WRAPPED_RETURN(@"return": anytype) @TypeOf(@import("std").zig.c_translation.MacroArithmetic.rem(@"return", @as(c_int, 2))) {
47// _ = &@"return";
48// return @import("std").zig.c_translation.MacroArithmetic.rem(@"return", @as(c_int, 2));
49// }
50// pub inline fn UNWRAPPED_RETURN(@"return": anytype) @TypeOf(@"return" ^ @as(c_int, 0x7F)) {
51// _ = &@"return";
52// return @"return" ^ @as(c_int, 0x7F);
53// }
54// pub inline fn WITH_TWO_PARAMETERS(signed: anytype, x: anytype) @TypeOf((signed + x) + @as(c_int, 9)) {
55// _ = &signed;
56// _ = &x;
57// return (signed + x) + @as(c_int, 9);
58// }
59// pub inline fn GUARDED_ALIGNOF(_Alignof: anytype) @TypeOf(_Alignof & @as(c_int, 0x55)) {
60// _ = &_Alignof;
61// return _Alignof & @as(c_int, 0x55);
62// }
63// pub inline fn UNGUARDED_ALIGNOF(_Alignof: anytype) @TypeOf(_Alignof | @as(c_int, 0x80)) {
64// _ = &_Alignof;
65// return _Alignof | @as(c_int, 0x80);
66// }
67// pub inline fn GUARDED_SIZEOF(sizeof: anytype) @TypeOf(sizeof == @as(c_int, 64)) {
68// _ = &sizeof;
69// return sizeof == @as(c_int, 64);
70// }
71// pub inline fn UNGUARDED_SIZEOF(sizeof: anytype) @TypeOf(sizeof < @as(c_int, 64)) {
72// _ = &sizeof;
73// return sizeof < @as(c_int, 64);
74// }
75// pub inline fn SIZEOF(x: anytype) c_int {
76// _ = &x;
77// return @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.sizeof(x));
78// }
79// pub inline fn SIZEOF2(x: anytype) c_int {
80// _ = &x;
81// return @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.sizeof(x));
82// }
test/cases/translate_c/circular_struct_definitions.c deleted-20
......@@ -1,20 +0,0 @@
1struct Bar;
2
3struct Foo {
4 struct Bar *next;
5};
6
7struct Bar {
8 struct Foo *next;
9};
10
11// translate-c
12// c_frontend=clang
13//
14// pub const struct_Bar = extern struct {
15// next: [*c]struct_Foo = @import("std").mem.zeroes([*c]struct_Foo),
16// };
17//
18// pub const struct_Foo = extern struct {
19// next: [*c]struct_Bar = @import("std").mem.zeroes([*c]struct_Bar),
20// };
test/cases/translate_c/continue_from_while.c deleted-14
......@@ -1,14 +0,0 @@
1void foo() {
2 for (;;) {
3 continue;
4 }
5}
6
7// translate-c
8// c_frontend=clang
9//
10// pub export fn foo() void {
11// while (true) {
12// continue;
13// }
14// }
test/cases/translate_c/double_define_struct.c deleted-25
......@@ -1,25 +0,0 @@
1typedef struct Bar Bar;
2typedef struct Foo Foo;
3
4struct Foo {
5 Foo *a;
6};
7
8struct Bar {
9 Foo *a;
10};
11
12// translate-c
13// c_frontend=clang
14//
15// pub const struct_Foo = extern struct {
16// a: [*c]Foo = @import("std").mem.zeroes([*c]Foo),
17// };
18//
19// pub const Foo = struct_Foo;
20//
21// pub const struct_Bar = extern struct {
22// a: [*c]Foo = @import("std").mem.zeroes([*c]Foo),
23// };
24//
25// pub const Bar = struct_Bar;
test/cases/translate_c/empty declaration.c deleted-6
......@@ -1,6 +0,0 @@
1;
2
3// translate-c
4// c_frontend=clang,aro
5//
6//
\ No newline at end of file
test/cases/translate_c/empty union initializer list.c deleted-20
......@@ -1,20 +0,0 @@
1union U {
2 int x;
3 long y;
4};
5
6void foo(void) {
7 union U u = {};
8}
9// translate-c
10// target=x86_64-linux
11// c_frontend=clang
12//
13// pub const union_U = extern union {
14// x: c_int,
15// y: c_long,
16// };
17// pub export fn foo() void {
18// var u: union_U = @import("std").mem.zeroes(union_U);
19// _ = &u;
20// }
test/cases/translate_c/enums msvc.c deleted-16
......@@ -1,16 +0,0 @@
1enum Foo {
2 FooA = 2,
3 FooB = 5,
4 Foo1,
5};
6
7// translate-c
8// target=x86_64-windows-msvc
9// c_frontend=clang
10//
11// pub const FooA: c_int = 2;
12// pub const FooB: c_int = 5;
13// pub const Foo1: c_int = 6;
14// pub const enum_Foo = c_int;
15//
16// pub const Foo = enum_Foo;
test/cases/translate_c/enums.c deleted-16
......@@ -1,16 +0,0 @@
1enum Foo {
2 FooA = 2,
3 FooB = 5,
4 Foo1,
5};
6
7// translate-c
8// target=x86_64-linux
9// c_frontend=clang,aro
10//
11// pub const FooA: c_int = 2;
12// pub const FooB: c_int = 5;
13// pub const Foo1: c_int = 6;
14// pub const enum_Foo = c_uint;
15//
16// pub const Foo = enum_Foo;
test/cases/translate_c/field_access_is_grouped_if_necessary.c deleted-18
......@@ -1,18 +0,0 @@
1unsigned long foo(unsigned long x) {
2 return ((union{unsigned long _x}){x})._x;
3}
4
5// translate-c
6// c_frontend=clang
7//
8// pub export fn foo(arg_x: c_ulong) c_ulong {
9// var x = arg_x;
10// _ = &x;
11// const union_unnamed_1 = extern union {
12// _x: c_ulong,
13// };
14// _ = &union_unnamed_1;
15// return (union_unnamed_1{
16// ._x = x,
17// })._x;
18// }
test/cases/translate_c/function prototype with parenthesis.c deleted-10
......@@ -1,10 +0,0 @@
1void (f0) (void *L);
2void ((f1)) (void *L);
3void (((f2))) (void *L);
4
5// translate-c
6// c_frontend=clang,aro
7//
8// pub extern fn f0(L: ?*anyopaque) void;
9// pub extern fn f1(L: ?*anyopaque) void;
10// pub extern fn f2(L: ?*anyopaque) void;
test/cases/translate_c/global_struct_whose_default_name_conflicts_with_global_is_mangled.c deleted-15
......@@ -1,15 +0,0 @@
1struct foo {
2 int x;
3};
4const char *struct_foo = "hello world";
5
6// translate-c
7// c_frontend=clang
8//
9// pub const struct_foo_1 = extern struct {
10// x: c_int = @import("std").mem.zeroes(c_int),
11// };
12//
13// pub const foo = struct_foo_1;
14//
15// pub export var struct_foo: [*c]const u8 = "hello world";
test/cases/translate_c/large_packed_struct.c deleted-20
......@@ -1,20 +0,0 @@
1struct __attribute__((packed)) bar {
2 short a;
3 float b;
4 double c;
5 short x;
6 float y;
7 double z;
8};
9
10// translate-c
11// c_frontend=aro,clang
12//
13// pub const struct_bar = extern struct {
14// a: c_short align(1) = @import("std").mem.zeroes(c_short),
15// b: f32 align(1) = @import("std").mem.zeroes(f32),
16// c: f64 align(1) = @import("std").mem.zeroes(f64),
17// x: c_short align(1) = @import("std").mem.zeroes(c_short),
18// y: f32 align(1) = @import("std").mem.zeroes(f32),
19// z: f64 align(1) = @import("std").mem.zeroes(f64),
20// };
test/cases/translate_c/macro_calling_convention.c deleted-9
......@@ -1,9 +0,0 @@
1#define SYSV_ABI __attribute__((sysv_abi))
2void SYSV_ABI foo(void);
3
4
5// translate-c
6// c_frontend=clang
7// target=x86_64-windows
8//
9// pub extern fn foo() callconv(.{ .x86_64_sysv = .{} }) void;
test/cases/translate_c/macro_function_string_concat.c deleted-11
......@@ -1,11 +0,0 @@
1#define bar() ""
2#define FOO bar() "," bar()
3
4// translate-c
5// target=x86_64-linux
6// c_frontend=clang
7//
8// pub inline fn bar() @TypeOf("") {
9// return "";
10// }
11// pub const FOO = bar() ++ "," ++ bar();
test/cases/translate_c/macro_referencing_var.c deleted-21
......@@ -1,21 +0,0 @@
1extern float foo;
2#define FOO_TWICE foo * 2.0f
3#define FOO_NEGATIVE -foo
4
5#define BAR 10.0f
6#define BAR_TWICE BAR * 2.0f
7
8// translate-c
9// c_frontend=clang
10//
11// pub extern var foo: f32;
12//
13// pub inline fn FOO_TWICE() @TypeOf(foo * @as(f32, 2.0)) {
14// return foo * @as(f32, 2.0);
15// }
16//
17// pub inline fn FOO_NEGATIVE() @TypeOf(-foo) {
18// return -foo;
19// }
20// pub const BAR = @as(f32, 10.0);
21// pub const BAR_TWICE = BAR * @as(f32, 2.0);
test/cases/translate_c/noreturn attribute.c deleted-6
......@@ -1,6 +0,0 @@
1void foo(void) __attribute__((noreturn));
2
3// translate-c
4// c_frontend=aro,clang
5//
6// pub extern fn foo() noreturn;
test/cases/translate_c/packed_union_nested_unpacked.c deleted-25
......@@ -1,25 +0,0 @@
1// NOTE: The nested struct is *not* packed/aligned,
2// even though the parent struct is
3// this is consistent with GCC docs
4union Foo{
5 short x;
6 double y;
7 struct {
8 int b;
9 } z;
10} __attribute__((packed));
11
12// translate-c
13// c_frontend=aro,clang
14//
15// const struct_unnamed_1 = extern struct {
16// b: c_int = @import("std").mem.zeroes(c_int),
17// };
18//
19// pub const union_Foo = extern union {
20// x: c_short align(1),
21// y: f64 align(1),
22// z: struct_unnamed_1 align(1),
23// };
24//
25// pub const Foo = union_Foo;
test/cases/translate_c/packed_union_simple.c deleted-14
......@@ -1,14 +0,0 @@
1union Foo {
2 short x;
3 double y;
4} __attribute__((packed));
5
6// translate-c
7// c_frontend=aro,clang
8//
9// pub const union_Foo = extern union {
10// x: c_short align(1),
11// y: f64 align(1),
12// };
13//
14// pub const Foo = union_Foo;
test/cases/translate_c/pointer_to_struct_demoted_opaque_due_to_bit_fields.c deleted-15
......@@ -1,15 +0,0 @@
1struct Foo {
2 unsigned int: 1;
3};
4struct Bar {
5 struct Foo *foo;
6};
7
8// translate-c
9// c_frontend=clang
10//
11// pub const struct_Foo = opaque {};
12//
13// pub const struct_Bar = extern struct {
14// foo: ?*struct_Foo = @import("std").mem.zeroes(?*struct_Foo),
15// };
test/cases/translate_c/qualified_struct_and_enum.c deleted-25
......@@ -1,25 +0,0 @@
1struct Foo {
2 int x;
3 int y;
4};
5enum Bar {
6 BarA,
7 BarB,
8};
9void func(struct Foo *a, enum Bar **b);
10
11// translate-c
12// c_frontend=clang
13// target=x86_64-linux,x86_64-macos
14//
15// pub const struct_Foo = extern struct {
16// x: c_int = @import("std").mem.zeroes(c_int),
17// y: c_int = @import("std").mem.zeroes(c_int),
18// };
19// pub const BarA: c_int = 0;
20// pub const BarB: c_int = 1;
21// pub const enum_Bar = c_uint;
22// pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
23//
24// pub const Foo = struct_Foo;
25// pub const Bar = enum_Bar;
test/cases/translate_c/qualified_struct_and_enum_msvc.c deleted-25
......@@ -1,25 +0,0 @@
1struct Foo {
2 int x;
3 int y;
4};
5enum Bar {
6 BarA,
7 BarB,
8};
9void func(struct Foo *a, enum Bar **b);
10
11// translate-c
12// c_frontend=clang
13// target=x86_64-windows-msvc
14//
15// pub const struct_Foo = extern struct {
16// x: c_int = @import("std").mem.zeroes(c_int),
17// y: c_int = @import("std").mem.zeroes(c_int),
18// };
19// pub const BarA: c_int = 0;
20// pub const BarB: c_int = 1;
21// pub const enum_Bar = c_int;
22// pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
23//
24// pub const Foo = struct_Foo;
25// pub const Bar = enum_Bar;
test/cases/translate_c/scoped_record.c deleted-49
......@@ -1,49 +0,0 @@
1void foo() {
2 struct Foo {
3 int A;
4 int B;
5 int C;
6 };
7 struct Foo a = {0};
8 {
9 struct Foo {
10 int A;
11 int B;
12 int C;
13 };
14 struct Foo a = {0};
15 }
16}
17
18// translate-c
19// c_frontend=clang
20//
21// pub export fn foo() void {
22// const struct_Foo = extern struct {
23// A: c_int = @import("std").mem.zeroes(c_int),
24// B: c_int = @import("std").mem.zeroes(c_int),
25// C: c_int = @import("std").mem.zeroes(c_int),
26// };
27// _ = &struct_Foo;
28// var a: struct_Foo = struct_Foo{
29// .A = @as(c_int, 0),
30// .B = 0,
31// .C = 0,
32// };
33// _ = &a;
34// {
35// const struct_Foo_1 = extern struct {
36// A: c_int = @import("std").mem.zeroes(c_int),
37// B: c_int = @import("std").mem.zeroes(c_int),
38// C: c_int = @import("std").mem.zeroes(c_int),
39// };
40// _ = &struct_Foo_1;
41// var a_2: struct_Foo_1 = struct_Foo_1{
42// .A = @as(c_int, 0),
43// .B = 0,
44// .C = 0,
45// };
46// _ = &a_2;
47// }
48// }
49
test/cases/translate_c/simple function prototypes.c deleted-8
......@@ -1,8 +0,0 @@
1void __attribute__((noreturn)) foo(void);
2int bar(void);
3
4// translate-c
5// c_frontend=clang,aro
6//
7// pub extern fn foo() noreturn;
8// pub extern fn bar() c_int;
test/cases/translate_c/simple_struct.c deleted-12
......@@ -1,12 +0,0 @@
1struct Foo {
2 int x;
3};
4
5// translate-c
6// c_frontend=aro,clang
7//
8// const struct_Foo = extern struct {
9// x: c_int = @import("std").mem.zeroes(c_int),
10// };
11//
12// pub const Foo = struct_Foo;
test/cases/translate_c/simple_union.c deleted-12
......@@ -1,12 +0,0 @@
1union Foo {
2 int x;
3};
4
5// translate-c
6// c_frontend=aro,clang
7//
8// pub const union_Foo = extern union {
9// x: c_int,
10// };
11//
12// pub const Foo = union_Foo;
test/cases/translate_c/static empty struct.c deleted-17
......@@ -1,17 +0,0 @@
1struct empty_struct {};
2
3static inline void foo() {
4 static struct empty_struct bar = {};
5}
6
7// translate-c
8// target=x86_64-linux
9// c_frontend=clang
10//
11// pub const struct_empty_struct = extern struct {};
12// pub fn foo() callconv(.c) void {
13// const bar = struct {
14// var static: struct_empty_struct = @import("std").mem.zeroes(struct_empty_struct);
15// };
16// _ = &bar;
17// }
test/cases/translate_c/strlit_as_bool.c deleted-8
......@@ -1,8 +0,0 @@
1void foo() { if(0 && "error message") {} }
2
3// translate-c
4// c_frontend=clang
5//
6// pub export fn foo() void {
7// if (false and (@intFromPtr("error message") != 0)) {}
8// }
test/cases/translate_c/struct prototype used in func.c deleted-10
......@@ -1,10 +0,0 @@
1struct Foo;
2struct Foo *some_func(struct Foo *foo, int x);
3
4// translate-c
5// c_frontend=clang,aro
6//
7// pub const struct_Foo = opaque {};
8// pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;
9//
10// pub const Foo = struct_Foo;
test/cases/translate_c/struct_in_struct_init_to_zero.c deleted-24
......@@ -1,24 +0,0 @@
1struct Foo {
2 int a;
3 struct Bar {
4 int a;
5 } b;
6} a = {};
7#define PTR void *
8
9// translate-c
10// c_frontend=clang
11//
12// pub const struct_Bar_1 = extern struct {
13// a: c_int = @import("std").mem.zeroes(c_int),
14// };
15// pub const struct_Foo = extern struct {
16// a: c_int = @import("std").mem.zeroes(c_int),
17// b: struct_Bar_1 = @import("std").mem.zeroes(struct_Bar_1),
18// };
19// pub export var a: struct_Foo = struct_Foo{
20// .a = 0,
21// .b = @import("std").mem.zeroes(struct_Bar_1),
22// };
23//
24// pub const PTR = ?*anyopaque;
test/cases/translate_c/struct_with_aligned_fields.c deleted-10
......@@ -1,10 +0,0 @@
1struct foo {
2 __attribute__((aligned(4))) short bar;
3};
4
5// translate-c
6// c_frontend=aro,clang
7//
8// pub const struct_foo = extern struct {
9// bar: c_short align(4) = @import("std").mem.zeroes(c_short),
10// };
test/cases/translate_c/struct_with_invalid_field_alignment.c deleted-35
......@@ -1,35 +0,0 @@
1// The aligned attribute cannot decrease the alignment of a field. The packed attribute is required
2// for decreasing the alignment. gcc and clang will compile these structs without error
3// (and possibly without warning), but checking the alignment will reveal a different value than
4// what was requested. This is consistent with the gcc documentation on type attributes.
5//
6// This test is currently broken for the clang frontend. See issue #19307.
7
8struct foo {
9 __attribute__((aligned(1)))int x;
10};
11
12struct bar {
13 __attribute__((aligned(2)))float y;
14};
15
16struct baz {
17 __attribute__((aligned(4)))double z;
18};
19
20// translate-c
21// c_frontend=aro
22// target=x86_64-linux
23//
24// pub const struct_foo = extern struct {
25// x: c_int = @import("std").mem.zeroes(c_int),
26// };
27//
28// pub const struct_bar = extern struct {
29// y: f32 = @import("std").mem.zeroes(f32),
30// };
31//
32// pub const struct_baz = extern struct {
33// z: f64 = @import("std").mem.zeroes(f64),
34// };
35//
test/cases/translate_c/type_referenced_struct.c deleted-19
......@@ -1,19 +0,0 @@
1// When clang uses the <arch>-windows-none, triple it behaves as MSVC and
2// interprets the inner `struct Bar` as an anonymous structure
3struct Foo {
4 struct Bar{
5 int b;
6 };
7 struct Bar c;
8};
9
10// translate-c
11// c_frontend=aro,clang
12// target=x86_64-linux-gnu
13//
14// pub const struct_Bar_1 = extern struct {
15// b: c_int = @import("std").mem.zeroes(c_int),
16// };
17// pub const struct_Foo = extern struct {
18// c: struct_Bar_1 = @import("std").mem.zeroes(struct_Bar_1),
19// };
test/cases/translate_c/union_initializer.c deleted-22
......@@ -1,22 +0,0 @@
1union { int x; char c[4]; }
2 ua = {1},
3 ub = {.c={'a','b','b','a'}};
4
5// translate-c
6// c_frontend=clang
7//
8// const union_unnamed_1 = extern union {
9// x: c_int,
10// c: [4]u8,
11// };
12// pub export var ua: union_unnamed_1 = union_unnamed_1{
13// .x = @as(c_int, 1),
14// };
15// pub export var ub: union_unnamed_1 = union_unnamed_1{
16// .c = [4]u8{
17// 'a',
18// 'b',
19// 'b',
20// 'a',
21// },
22// };
test/cases/translate_c/union_struct_forward_decl.c deleted-37
......@@ -1,37 +0,0 @@
1struct A;
2union B;
3enum C;
4
5struct A {
6 short x;
7 double y;
8};
9
10union B {
11 short x;
12 double y;
13};
14
15struct Foo {
16 struct A a;
17 union B b;
18};
19
20
21// translate-c
22// c_frontend=aro,clang
23//
24// pub const struct_A = extern struct {
25// x: c_short = @import("std").mem.zeroes(c_short),
26// y: f64 = @import("std").mem.zeroes(f64),
27// };
28//
29// pub const union_B = extern union {
30// x: c_short,
31// y: f64,
32// };
33//
34// pub const struct_Foo = extern struct {
35// a: struct_A = @import("std").mem.zeroes(struct_A),
36// b: union_B = @import("std").mem.zeroes(union_B),
37// };
test/cases/translate_c/unnamed_fields_have_predictable_names.c deleted-22
......@@ -1,22 +0,0 @@
1struct a {
2 struct { int x; };
3};
4struct b {
5 struct { int y; };
6};
7
8// translate-c
9// c_frontend=aro,clang
10//
11// const struct_unnamed_1 = extern struct {
12// x: c_int = @import("std").mem.zeroes(c_int),
13// };
14// pub const struct_a = extern struct {
15// unnamed_0: struct_unnamed_1 = @import("std").mem.zeroes(struct_unnamed_1),
16// };
17// const struct_unnamed_2 = extern struct {
18// y: c_int = @import("std").mem.zeroes(c_int),
19// };
20// pub const struct_b = extern struct {
21// unnamed_0: struct_unnamed_2 = @import("std").mem.zeroes(struct_unnamed_2),
22// };
test/cases/translate_c/void_pointer_subtraction.c deleted-16
......@@ -1,16 +0,0 @@
1#include <stddef.h>
2ptrdiff_t sub_ptr(void *a, void *b) {
3 return a - b;
4}
5
6// translate-c
7// c_frontend=clang
8// target=x86_64-linux
9//
10// pub export fn sub_ptr(arg_a: ?*anyopaque, arg_b: ?*anyopaque) ptrdiff_t {
11// var a = arg_a;
12// _ = &a;
13// var b = arg_b;
14// _ = &b;
15// return @as(c_long, @bitCast(@intFromPtr(a) -% @intFromPtr(b)));
16// }
test/cases/translate_c/zero_width_field_alignment.c deleted-18
......@@ -1,18 +0,0 @@
1struct __attribute__((packed)) foo {
2 int x;
3 struct {};
4 float y;
5 union {};
6};
7
8// translate-c
9// c_frontend=aro
10//
11// const struct_unnamed_1 = extern struct {};
12// const union_unnamed_2 = extern union {};
13// pub const struct_foo = extern struct {
14// x: c_int align(1) = @import("std").mem.zeroes(c_int),
15// unnamed_0: struct_unnamed_1 align(1) = @import("std").mem.zeroes(struct_unnamed_1),
16// y: f32 align(1) = @import("std").mem.zeroes(f32),
17// unnamed_1: union_unnamed_2 align(1) = @import("std").mem.zeroes(union_unnamed_2),
18// };
test/cases/translate_c/zig_keywords_in_c_code.c deleted-12
......@@ -1,12 +0,0 @@
1struct comptime {
2 int defer;
3};
4
5// translate-c
6// c_frontend=aro,clang
7//
8// pub const struct_comptime = extern struct {
9// @"defer": c_int = @import("std").mem.zeroes(c_int),
10// };
11//
12// pub const @"comptime" = struct_comptime;
test/run_translated_c.zig deleted-1825
......@@ -1,1825 +0,0 @@
1const std = @import("std");
2const tests = @import("tests.zig");
3const nl = if (@import("builtin").os.tag == .windows) "\r\n" else "\n";
4
5// *********************************************************
6// * *
7// * DO NOT ADD NEW CASES HERE *
8// * instead add a file to test/cases/run_translated_c *
9// * *
10// *********************************************************
11
12pub fn addCases(cases: *tests.RunTranslatedCContext) void {
13 cases.add("division of floating literals",
14 \\#define _NO_CRT_STDIO_INLINE 1
15 \\#include <stdio.h>
16 \\#define PI 3.14159265358979323846f
17 \\#define DEG2RAD (PI/180.0f)
18 \\int main(void) {
19 \\ printf("DEG2RAD is: %f\n", DEG2RAD);
20 \\ return 0;
21 \\}
22 , "DEG2RAD is: 0.017453" ++ nl);
23
24 cases.add("use global scope for record/enum/typedef type translation if needed",
25 \\void bar(void);
26 \\void baz(void);
27 \\struct foo { int x; };
28 \\void bar() {
29 \\ struct foo tmp;
30 \\}
31 \\
32 \\void baz() {
33 \\ struct foo tmp;
34 \\}
35 \\
36 \\int main(void) {
37 \\ bar();
38 \\ baz();
39 \\ return 0;
40 \\}
41 , "");
42
43 cases.add("failed macros are only declared once",
44 \\#define FOO =
45 \\#define FOO =
46 \\#define PtrToPtr64(p) ((void *POINTER_64) p)
47 \\#define STRUC_ALIGNED_STACK_COPY(t,s) ((CONST t *)(s))
48 \\#define bar = 0x
49 \\#define baz = 0b
50 \\int main(void) {}
51 , "");
52
53 cases.add("parenthesized string literal",
54 \\void foo(const char *s) {}
55 \\int main(void) {
56 \\ foo(("bar"));
57 \\}
58 , "");
59
60 cases.add("variable shadowing type type",
61 \\#include <stdlib.h>
62 \\int main() {
63 \\ int type = 1;
64 \\ if (type != 1) abort();
65 \\}
66 , "");
67
68 cases.add("assignment as expression",
69 \\#include <stdlib.h>
70 \\int main() {
71 \\ int a, b, c, d = 5;
72 \\ int e = a = b = c = d;
73 \\ if (e != 5) abort();
74 \\}
75 , "");
76
77 cases.add("static variable in block scope",
78 \\#include <stdlib.h>
79 \\int foo() {
80 \\ static int bar;
81 \\ bar += 1;
82 \\ return bar;
83 \\}
84 \\int main() {
85 \\ foo();
86 \\ foo();
87 \\ if (foo() != 3) abort();
88 \\}
89 , "");
90
91 cases.add("array initializer",
92 \\#include <stdlib.h>
93 \\int main(int argc, char **argv) {
94 \\ int a0[4] = {1};
95 \\ int a1[4] = {1,2,3,4};
96 \\ int s0 = 0, s1 = 0;
97 \\ for (int i = 0; i < 4; i++) {
98 \\ s0 += a0[i];
99 \\ s1 += a1[i];
100 \\ }
101 \\ if (s0 != 1) abort();
102 \\ if (s1 != 10) abort();
103 \\}
104 , "");
105
106 cases.add("forward declarations",
107 \\#include <stdlib.h>
108 \\int foo(int);
109 \\int foo(int x) { return x + 1; }
110 \\int main(int argc, char **argv) {
111 \\ if (foo(2) != 3) abort();
112 \\ return 0;
113 \\}
114 , "");
115
116 cases.add("typedef and function pointer",
117 \\#include <stdlib.h>
118 \\typedef struct _Foo Foo;
119 \\typedef int Ret;
120 \\typedef int Param;
121 \\struct _Foo { Ret (*func)(Param p); };
122 \\static Ret add1(Param p) {
123 \\ return p + 1;
124 \\}
125 \\int main(int argc, char **argv) {
126 \\ Foo strct = { .func = add1 };
127 \\ if (strct.func(16) != 17) abort();
128 \\ return 0;
129 \\}
130 , "");
131
132 cases.add("ternary operator",
133 \\#include <stdlib.h>
134 \\static int cnt = 0;
135 \\int foo() { cnt++; return 42; }
136 \\int main(int argc, char **argv) {
137 \\ short q = 3;
138 \\ signed char z0 = q?:1;
139 \\ if (z0 != 3) abort();
140 \\ int z1 = 3?:1;
141 \\ if (z1 != 3) abort();
142 \\ int z2 = foo()?:-1;
143 \\ if (z2 != 42) abort();
144 \\ if (cnt != 1) abort();
145 \\ return 0;
146 \\}
147 , "");
148
149 cases.add("switch case",
150 \\#include <stdlib.h>
151 \\int lottery(unsigned int x) {
152 \\ switch (x) {
153 \\ case 3: return 0;
154 \\ case -1: return 3;
155 \\ case 8 ... 10: return x;
156 \\ default: return -1;
157 \\ }
158 \\}
159 \\int main(int argc, char **argv) {
160 \\ if (lottery(2) != -1) abort();
161 \\ if (lottery(3) != 0) abort();
162 \\ if (lottery(-1) != 3) abort();
163 \\ if (lottery(9) != 9) abort();
164 \\ return 0;
165 \\}
166 , "");
167
168 cases.add("boolean values and expressions",
169 \\#include <stdlib.h>
170 \\static const _Bool false_val = 0;
171 \\static const _Bool true_val = 1;
172 \\void foo(int x, int y) {
173 \\ _Bool r = x < y;
174 \\ if (!r) abort();
175 \\ _Bool self = foo;
176 \\ if (self == false_val) abort();
177 \\ if (((r) ? 'a' : 'b') != 'a') abort();
178 \\}
179 \\int main(int argc, char **argv) {
180 \\ foo(2, 5);
181 \\ if (false_val == true_val) abort();
182 \\ return 0;
183 \\}
184 , "");
185
186 cases.add("hello world",
187 \\#define _NO_CRT_STDIO_INLINE 1
188 \\#include <stdio.h>
189 \\int main(int argc, char **argv) {
190 \\ printf("hello, world!\n");
191 \\ return 0;
192 \\}
193 , "hello, world!" ++ nl);
194
195 cases.add("anon struct init",
196 \\#include <stdlib.h>
197 \\struct {int a; int b;} x = {1, 2};
198 \\int main(int argc, char **argv) {
199 \\ x.a += 2;
200 \\ x.b += 1;
201 \\ if (x.a != 3) abort();
202 \\ if (x.b != 3) abort();
203 \\ return 0;
204 \\}
205 , "");
206
207 cases.add("casting away const and volatile",
208 \\void foo(int *a) {}
209 \\void bar(const int *a) {
210 \\ foo((int *)a);
211 \\}
212 \\void baz(volatile int *a) {
213 \\ foo((int *)a);
214 \\}
215 \\int main(int argc, char **argv) {
216 \\ int a = 0;
217 \\ bar((const int *)&a);
218 \\ baz((volatile int *)&a);
219 \\ return 0;
220 \\}
221 , "");
222
223 cases.add("anonymous struct & unions",
224 \\#include <stdlib.h>
225 \\#include <stdint.h>
226 \\static struct { struct { uint16_t x, y; }; } x = { 1 };
227 \\static struct { union { uint32_t x; uint8_t y; }; } y = { 0x55AA55AA };
228 \\int main(int argc, char **argv) {
229 \\ if (x.x != 1) abort();
230 \\ if (x.y != 0) abort();
231 \\ if (y.x != 0x55AA55AA) abort();
232 \\ if (y.y != 0xAA) abort();
233 \\ return 0;
234 \\}
235 , "");
236
237 cases.add("array to pointer decay",
238 \\#include <stdlib.h>
239 \\int main(int argc, char **argv) {
240 \\ char data[3] = {'a','b','c'};
241 \\ if (2[data] != data[2]) abort();
242 \\ if ("abc"[1] != data[1]) abort();
243 \\ char *as_ptr = data;
244 \\ if (2[as_ptr] != as_ptr[2]) abort();
245 \\ if ("abc"[1] != as_ptr[1]) abort();
246 \\ return 0;
247 \\}
248 , "");
249
250 cases.add("struct initializer - packed",
251 \\#define _NO_CRT_STDIO_INLINE 1
252 \\#include <stdint.h>
253 \\#include <stdlib.h>
254 \\struct s {uint8_t x,y;
255 \\ uint32_t z;} __attribute__((packed)) s0 = {1, 2};
256 \\int main() {
257 \\ /* sizeof nor offsetof currently supported */
258 \\ if (((intptr_t)&s0.z - (intptr_t)&s0.x) != 2) abort();
259 \\ return 0;
260 \\}
261 , "");
262
263 cases.add("cast signed array index to unsigned",
264 \\#include <stdlib.h>
265 \\int main(int argc, char **argv) {
266 \\ int a[10], i = 0;
267 \\ a[i] = 0;
268 \\ if (a[i] != 0) abort();
269 \\ return 0;
270 \\}
271 , "");
272
273 cases.add("cast long long array index to unsigned",
274 \\#include <stdlib.h>
275 \\int main(int argc, char **argv) {
276 \\ long long a[10], i = 0;
277 \\ a[i] = 0;
278 \\ if (a[i] != 0) abort();
279 \\ return 0;
280 \\}
281 , "");
282
283 cases.add("case boolean expression converted to int",
284 \\#include <stdlib.h>
285 \\int main(int argc, char **argv) {
286 \\ int value = 1 + 2 * 3 + 4 * 5 + 6 << 7 | 8 == 9;
287 \\ if (value != 4224) abort();
288 \\ return 0;
289 \\}
290 , "");
291
292 cases.add("case boolean expression on left converted to int",
293 \\#include <stdlib.h>
294 \\int main(int argc, char **argv) {
295 \\ int value = 8 == 9 | 1 + 2 * 3 + 4 * 5 + 6 << 7;
296 \\ if (value != 4224) abort();
297 \\ return 0;
298 \\}
299 , "");
300
301 cases.add("case boolean and operator+ converts bool to int",
302 \\#include <stdlib.h>
303 \\int main(int argc, char **argv) {
304 \\ int value = (8 == 9) + 3;
305 \\ int value2 = 3 + (8 == 9);
306 \\ if (value != value2) abort();
307 \\ return 0;
308 \\}
309 , "");
310
311 cases.add("case boolean and operator<",
312 \\#include <stdlib.h>
313 \\int main(int argc, char **argv) {
314 \\ int value = (8 == 9) < 3;
315 \\ if (value == 0) abort();
316 \\ return 0;
317 \\}
318 , "");
319
320 cases.add("case boolean and operator*",
321 \\#include <stdlib.h>
322 \\int main(int argc, char **argv) {
323 \\ int value = (8 == 9) * 3;
324 \\ int value2 = 3 * (9 == 9);
325 \\ if (value != 0) abort();
326 \\ if (value2 == 0) abort();
327 \\ return 0;
328 \\}
329 , "");
330
331 cases.add("scoped typedef",
332 \\int main(int argc, char **argv) {
333 \\ typedef int Foo;
334 \\ typedef Foo Bar;
335 \\ typedef void (*func)(int);
336 \\ typedef int uint32_t;
337 \\ uint32_t a;
338 \\ Foo i;
339 \\ Bar j;
340 \\ return 0;
341 \\}
342 , "");
343
344 cases.add("scoped for loops with shadowing",
345 \\#include <stdlib.h>
346 \\int main() {
347 \\ int count = 0;
348 \\ for (int x = 0; x < 2; x++)
349 \\ for (int x = 0; x < 2; x++)
350 \\ count++;
351 \\
352 \\ if (count != 4) abort();
353 \\ return 0;
354 \\}
355 , "");
356
357 cases.add("array value type casts properly",
358 \\#include <stdlib.h>
359 \\unsigned int choose[53][10];
360 \\static int hash_binary(int k)
361 \\{
362 \\ choose[0][k] = 3;
363 \\ int sum = 0;
364 \\ sum += choose[0][k];
365 \\ return sum;
366 \\}
367 \\
368 \\int main() {
369 \\ int s = hash_binary(4);
370 \\ if (s != 3) abort();
371 \\ return 0;
372 \\}
373 , "");
374
375 cases.add("array value type casts properly use +=",
376 \\#include <stdlib.h>
377 \\static int hash_binary(int k)
378 \\{
379 \\ unsigned int choose[1][1] = {{3}};
380 \\ int sum = -1;
381 \\ int prev = 0;
382 \\ prev = sum += choose[0][0];
383 \\ if (sum != 2) abort();
384 \\ return sum + prev;
385 \\}
386 \\
387 \\int main() {
388 \\ int x = hash_binary(4);
389 \\ if (x != 4) abort();
390 \\ return 0;
391 \\}
392 , "");
393
394 cases.add("ensure array casts outside +=",
395 \\#include <stdlib.h>
396 \\static int hash_binary(int k)
397 \\{
398 \\ unsigned int choose[3] = {1, 2, 3};
399 \\ int sum = -2;
400 \\ int prev = sum + choose[k];
401 \\ if (prev != 0) abort();
402 \\ return sum + prev;
403 \\}
404 \\
405 \\int main() {
406 \\ int x = hash_binary(1);
407 \\ if (x != -2) abort();
408 \\ return 0;
409 \\}
410 , "");
411
412 cases.add("array cast int to uint",
413 \\#include <stdlib.h>
414 \\static unsigned int hash_binary(int k)
415 \\{
416 \\ int choose[3] = {-1, -2, 3};
417 \\ unsigned int sum = 2;
418 \\ sum += choose[k];
419 \\ return sum;
420 \\}
421 \\
422 \\int main() {
423 \\ unsigned int x = hash_binary(1);
424 \\ if (x != 0) abort();
425 \\ return 0;
426 \\}
427 , "");
428
429 cases.add("assign enum to uint, no explicit cast",
430 \\#include <stdlib.h>
431 \\typedef enum {
432 \\ ENUM_0 = 0,
433 \\ ENUM_1 = 1,
434 \\} my_enum_t;
435 \\
436 \\int main() {
437 \\ my_enum_t val = ENUM_1;
438 \\ unsigned int x = val;
439 \\ if (x != 1) abort();
440 \\ return 0;
441 \\}
442 , "");
443
444 cases.add("assign enum to int",
445 \\#include <stdlib.h>
446 \\typedef enum {
447 \\ ENUM_0 = 0,
448 \\ ENUM_1 = 1,
449 \\} my_enum_t;
450 \\
451 \\int main() {
452 \\ my_enum_t val = ENUM_1;
453 \\ int x = val;
454 \\ if (x != 1) abort();
455 \\ return 0;
456 \\}
457 , "");
458
459 cases.add("cast enum to smaller uint",
460 \\#include <stdlib.h>
461 \\#include <stdint.h>
462 \\typedef enum {
463 \\ ENUM_0 = 0,
464 \\ ENUM_257 = 257,
465 \\} my_enum_t;
466 \\
467 \\int main() {
468 \\ my_enum_t val = ENUM_257;
469 \\ uint8_t x = (uint8_t)val;
470 \\ if (x != (uint8_t)257) abort();
471 \\ return 0;
472 \\}
473 , "");
474
475 cases.add("cast enum to smaller signed int",
476 \\#include <stdlib.h>
477 \\#include <stdint.h>
478 \\typedef enum {
479 \\ ENUM_0 = 0,
480 \\ ENUM_384 = 384,
481 \\} my_enum_t;
482 \\
483 \\int main() {
484 \\ my_enum_t val = ENUM_384;
485 \\ int8_t x = (int8_t)val;
486 \\ if (x != (int8_t)384) abort();
487 \\ return 0;
488 \\}
489 , "");
490
491 cases.add("cast negative enum to smaller signed int",
492 \\#include <stdlib.h>
493 \\#include <stdint.h>
494 \\typedef enum {
495 \\ ENUM_MINUS_1 = -1,
496 \\ ENUM_384 = 384,
497 \\} my_enum_t;
498 \\
499 \\int main() {
500 \\ my_enum_t val = ENUM_MINUS_1;
501 \\ int8_t x = (int8_t)val;
502 \\ if (x != -1) abort();
503 \\ return 0;
504 \\}
505 , "");
506
507 cases.add("cast negative enum to smaller unsigned int",
508 \\#include <stdlib.h>
509 \\#include <stdint.h>
510 \\typedef enum {
511 \\ ENUM_MINUS_1 = -1,
512 \\ ENUM_384 = 384,
513 \\} my_enum_t;
514 \\
515 \\int main() {
516 \\ my_enum_t val = ENUM_MINUS_1;
517 \\ uint8_t x = (uint8_t)val;
518 \\ if (x != (uint8_t)-1) abort();
519 \\ return 0;
520 \\}
521 , "");
522
523 cases.add("implicit enum cast in boolean expression",
524 \\#include <stdlib.h>
525 \\enum Foo {
526 \\ FooA,
527 \\ FooB,
528 \\ FooC,
529 \\};
530 \\int main() {
531 \\ int a = 0;
532 \\ float b = 0;
533 \\ void *c = 0;
534 \\ enum Foo d = FooA;
535 \\ if (a || d) abort();
536 \\ if (d && b) abort();
537 \\ if (c || d) abort();
538 \\ return 0;
539 \\}
540 , "");
541
542 cases.add("issue #6707 cast builtin call result to opaque struct pointer",
543 \\#include <stdlib.h>
544 \\struct foo* make_foo(void)
545 \\{
546 \\ return (struct foo*)__builtin_strlen("0123456789ABCDEF");
547 \\}
548 \\int main(void) {
549 \\ struct foo *foo_pointer = make_foo();
550 \\ if (foo_pointer != (struct foo*)16) abort();
551 \\ return 0;
552 \\}
553 , "");
554
555 cases.add("C built-ins",
556 \\#include <stdlib.h>
557 \\#include <limits.h>
558 \\#include <stdbool.h>
559 \\#define M_E 2.71828182845904523536
560 \\#define M_PI_2 1.57079632679489661923
561 \\bool check_clz(unsigned int pos) {
562 \\ return (__builtin_clz(1 << pos) == (8 * sizeof(unsigned int) - pos - 1));
563 \\}
564 \\int main(void) {
565 \\ if (__builtin_bswap16(0x0102) != 0x0201) abort();
566 \\ if (__builtin_bswap32(0x01020304) != 0x04030201) abort();
567 \\ if (__builtin_bswap64(0x0102030405060708) != 0x0807060504030201) abort();
568 \\
569 \\ if (__builtin_signbit(0.0) != 0) abort();
570 \\ if (__builtin_signbitf(0.0f) != 0) abort();
571 \\ if (__builtin_signbit(1.0) != 0) abort();
572 \\ if (__builtin_signbitf(1.0f) != 0) abort();
573 \\ if (__builtin_signbit(-1.0) != 1) abort();
574 \\ if (__builtin_signbitf(-1.0f) != 1) abort();
575 \\
576 \\ if (__builtin_popcount(0) != 0) abort();
577 \\ if (__builtin_popcount(0b1) != 1) abort();
578 \\ if (__builtin_popcount(0b11) != 2) abort();
579 \\ if (__builtin_popcount(0b1111) != 4) abort();
580 \\ if (__builtin_popcount(0b11111111) != 8) abort();
581 \\
582 \\ if (__builtin_ctz(0b1) != 0) abort();
583 \\ if (__builtin_ctz(0b10) != 1) abort();
584 \\ if (__builtin_ctz(0b100) != 2) abort();
585 \\ if (__builtin_ctz(0b10000) != 4) abort();
586 \\ if (__builtin_ctz(0b100000000) != 8) abort();
587 \\
588 \\ if (!check_clz(0)) abort();
589 \\ if (!check_clz(1)) abort();
590 \\ if (!check_clz(2)) abort();
591 \\ if (!check_clz(4)) abort();
592 \\ if (!check_clz(8)) abort();
593 \\
594 \\ if (__builtin_sqrt(__builtin_sqrt(__builtin_sqrt(256))) != 2.0) abort();
595 \\ if (__builtin_sqrt(__builtin_sqrt(__builtin_sqrt(256.0))) != 2.0) abort();
596 \\ if (__builtin_sqrt(__builtin_sqrt(__builtin_sqrt(256.0f))) != 2.0) abort();
597 \\ if (__builtin_sqrtf(__builtin_sqrtf(__builtin_sqrtf(256.0f))) != 2.0f) abort();
598 \\
599 \\ if (__builtin_sin(1.0) != -__builtin_sin(-1.0)) abort();
600 \\ if (__builtin_sinf(1.0f) != -__builtin_sinf(-1.0f)) abort();
601 \\ if (__builtin_sin(M_PI_2) != 1.0) abort();
602 \\ if (__builtin_sinf(M_PI_2) != 1.0f) abort();
603 \\
604 \\ if (__builtin_cos(1.0) != __builtin_cos(-1.0)) abort();
605 \\ if (__builtin_cosf(1.0f) != __builtin_cosf(-1.0f)) abort();
606 \\ if (__builtin_cos(0.0) != 1.0) abort();
607 \\ if (__builtin_cosf(0.0f) != 1.0f) abort();
608 \\
609 \\ if (__builtin_exp(0) != 1.0) abort();
610 \\ if (__builtin_fabs(__builtin_exp(1.0) - M_E) > 0.00000001) abort();
611 \\ if (__builtin_exp(0.0f) != 1.0f) abort();
612 \\
613 \\ if (__builtin_exp2(0) != 1.0) abort();
614 \\ if (__builtin_exp2(4.0) != 16.0) abort();
615 \\ if (__builtin_exp2f(0.0f) != 1.0f) abort();
616 \\ if (__builtin_exp2f(4.0f) != 16.0f) abort();
617 \\
618 \\ if (__builtin_log(M_E) != 1.0) abort();
619 \\ if (__builtin_log(1.0) != 0.0) abort();
620 \\ if (__builtin_logf(1.0f) != 0.0f) abort();
621 \\
622 \\ if (__builtin_log2(8.0) != 3.0) abort();
623 \\ if (__builtin_log2(1.0) != 0.0) abort();
624 \\ if (__builtin_log2f(8.0f) != 3.0f) abort();
625 \\ if (__builtin_log2f(1.0f) != 0.0f) abort();
626 \\
627 \\ if (__builtin_log10(1000.0) != 3.0) abort();
628 \\ if (__builtin_log10(1.0) != 0.0) abort();
629 \\ if (__builtin_log10f(1000.0f) != 3.0f) abort();
630 \\ if (__builtin_log10f(1.0f) != 0.0f) abort();
631 \\
632 \\ if (__builtin_fabs(-42.0f) != 42.0) abort();
633 \\ if (__builtin_fabs(-42.0) != 42.0) abort();
634 \\ if (__builtin_fabs(-42) != 42.0) abort();
635 \\ if (__builtin_fabsf(-42.0f) != 42.0f) abort();
636 \\
637 \\ if (__builtin_fabs(-42.0f) != 42.0) abort();
638 \\ if (__builtin_fabs(-42.0) != 42.0) abort();
639 \\ if (__builtin_fabs(-42) != 42.0) abort();
640 \\ if (__builtin_fabsf(-42.0f) != 42.0f) abort();
641 \\
642 \\ if (__builtin_abs(42) != 42) abort();
643 \\ if (__builtin_abs(-42) != 42) abort();
644 \\ if (__builtin_abs(INT_MIN) != INT_MIN) abort();
645 \\
646 \\ if (__builtin_floor(42.9) != 42.0) abort();
647 \\ if (__builtin_floor(-42.9) != -43.0) abort();
648 \\ if (__builtin_floorf(42.9f) != 42.0f) abort();
649 \\ if (__builtin_floorf(-42.9f) != -43.0f) abort();
650 \\
651 \\ if (__builtin_ceil(42.9) != 43.0) abort();
652 \\ if (__builtin_ceil(-42.9) != -42) abort();
653 \\ if (__builtin_ceilf(42.9f) != 43.0f) abort();
654 \\ if (__builtin_ceilf(-42.9f) != -42.0f) abort();
655 \\
656 \\ if (__builtin_trunc(42.9) != 42.0) abort();
657 \\ if (__builtin_truncf(42.9f) != 42.0f) abort();
658 \\ if (__builtin_trunc(-42.9) != -42.0) abort();
659 \\ if (__builtin_truncf(-42.9f) != -42.0f) abort();
660 \\
661 \\ if (__builtin_round(0.5) != 1.0) abort();
662 \\ if (__builtin_round(-0.5) != -1.0) abort();
663 \\ if (__builtin_roundf(0.5f) != 1.0f) abort();
664 \\ if (__builtin_roundf(-0.5f) != -1.0f) abort();
665 \\
666 \\ if (__builtin_strcmp("abc", "abc") != 0) abort();
667 \\ if (__builtin_strcmp("abc", "def") >= 0 ) abort();
668 \\ if (__builtin_strcmp("def", "abc") <= 0) abort();
669 \\
670 \\ if (__builtin_strlen("this is a string") != 16) abort();
671 \\
672 \\ char *s = malloc(6);
673 \\ __builtin_memcpy(s, "hello", 5);
674 \\ s[5] = '\0';
675 \\ if (__builtin_strlen(s) != 5) abort();
676 \\
677 \\ __builtin_memset(s, 42, __builtin_strlen(s));
678 \\ if (s[0] != 42 || s[1] != 42 || s[2] != 42 || s[3] != 42 || s[4] != 42) abort();
679 \\
680 \\ free(s);
681 \\
682 \\ return 0;
683 \\}
684 , "");
685
686 cases.add("function macro that uses builtin",
687 \\#include <stdlib.h>
688 \\#define FOO(x, y) (__builtin_popcount((x)) + __builtin_strlen((y)))
689 \\int main() {
690 \\ if (FOO(7, "hello!") != 9) abort();
691 \\ return 0;
692 \\}
693 , "");
694
695 cases.add("assign bool result to int or char",
696 \\#include <stdlib.h>
697 \\#include <stdbool.h>
698 \\bool foo() { return true; }
699 \\int main() {
700 \\ int x = foo();
701 \\ if (x != 1) abort();
702 \\ signed char c = foo();
703 \\ if (c != 1) abort();
704 \\ return 0;
705 \\}
706 , "");
707
708 cases.add("static K&R-style no prototype function declaration (empty parameter list)",
709 \\#include <stdlib.h>
710 \\static int foo() {
711 \\ return 42;
712 \\}
713 \\int main() {
714 \\ if (foo() != 42) abort();
715 \\ return 0;
716 \\}
717 , "");
718
719 cases.add("K&R-style static function prototype for unused function",
720 \\static int foo();
721 \\int main() {
722 \\ return 0;
723 \\}
724 , "");
725
726 cases.add("K&R-style static function prototype + separate definition",
727 \\#include <stdlib.h>
728 \\static int foo();
729 \\static int foo(int a, int b) {
730 \\ return a + b;
731 \\}
732 \\int main() {
733 \\ if (foo(40, 2) != 42) abort();
734 \\ return 0;
735 \\}
736 , "");
737
738 cases.add("dollar sign in identifiers",
739 \\#include <stdlib.h>
740 \\#define $FOO 2
741 \\#define $foo bar$
742 \\#define $baz($x) ($x + $FOO)
743 \\int $$$(int $x$) { return $x$ + $FOO; }
744 \\int main() {
745 \\ int bar$ = 42;
746 \\ if ($foo != 42) abort();
747 \\ if (bar$ != 42) abort();
748 \\ if ($baz(bar$) != 44) abort();
749 \\ if ($$$(bar$) != 44) abort();
750 \\ return 0;
751 \\}
752 , "");
753
754 cases.add("Cast boolean expression result to int",
755 \\#include <stdlib.h>
756 \\char foo(char c) { return c; }
757 \\int bar(int i) { return i; }
758 \\long baz(long l) { return l; }
759 \\int main() {
760 \\ if (foo(1 == 2)) abort();
761 \\ if (!foo(1 == 1)) abort();
762 \\ if (bar(1 == 2)) abort();
763 \\ if (!bar(1 == 1)) abort();
764 \\ if (baz(1 == 2)) abort();
765 \\ if (!baz(1 == 1)) abort();
766 \\ return 0;
767 \\}
768 , "");
769
770 cases.add("Wide, UTF-16, and UTF-32 character literals",
771 \\#include <wchar.h>
772 \\#include <stdlib.h>
773 \\int main() {
774 \\ wchar_t wc = L'™';
775 \\ int utf16_char = u'™';
776 \\ int utf32_char = U'💯';
777 \\ if (wc != 8482) abort();
778 \\ if (utf16_char != 8482) abort();
779 \\ if (utf32_char != 128175) abort();
780 \\ unsigned char c = wc;
781 \\ if (c != 0x22) abort();
782 \\ c = utf32_char;
783 \\ if (c != 0xaf) abort();
784 \\ return 0;
785 \\}
786 , "");
787
788 cases.add("Variadic function call",
789 \\#define _NO_CRT_STDIO_INLINE 1
790 \\#include <stdio.h>
791 \\int main(void) {
792 \\ printf("%d %d\n", 1, 2);
793 \\ return 0;
794 \\}
795 , "1 2" ++ nl);
796
797 cases.add("multi-character character constant",
798 \\#include <stdlib.h>
799 \\int main(void) {
800 \\ int foo = 'abcd';
801 \\ switch (foo) {
802 \\ case 'abcd': break;
803 \\ default: abort();
804 \\ }
805 \\ return 0;
806 \\}
807 , "");
808
809 cases.add("Array initializers (string literals, incomplete arrays)",
810 \\#include <stdlib.h>
811 \\#include <string.h>
812 \\extern int foo[];
813 \\int global_arr[] = {1, 2, 3};
814 \\char global_string[] = "hello";
815 \\int main(int argc, char *argv[]) {
816 \\ if (global_arr[2] != 3) abort();
817 \\ if (strlen(global_string) != 5) abort();
818 \\ const char *const_str = "hello";
819 \\ if (strcmp(const_str, "hello") != 0) abort();
820 \\ char empty_str[] = "";
821 \\ if (strlen(empty_str) != 0) abort();
822 \\ char hello[] = "hello";
823 \\ if (strlen(hello) != 5 || sizeof(hello) != 6) abort();
824 \\ int empty[] = {};
825 \\ if (sizeof(empty) != 0) abort();
826 \\ int bar[] = {42};
827 \\ if (bar[0] != 42) abort();
828 \\ bar[0] = 43;
829 \\ if (bar[0] != 43) abort();
830 \\ int baz[] = {1, [42] = 123, 456};
831 \\ if (baz[42] != 123 || baz[43] != 456) abort();
832 \\ if (sizeof(baz) != sizeof(int) * 44) abort();
833 \\ const char *const names[] = {"first", "second", "third"};
834 \\ if (strcmp(names[2], "third") != 0) abort();
835 \\ char catted_str[] = "abc" "def";
836 \\ if (strlen(catted_str) != 6 || sizeof(catted_str) != 7) abort();
837 \\ char catted_trunc_str[2] = "abc" "def";
838 \\ if (sizeof(catted_trunc_str) != 2 || catted_trunc_str[0] != 'a' || catted_trunc_str[1] != 'b') abort();
839 \\ char big_array_utf8lit[10] = "💯";
840 \\ if (strcmp(big_array_utf8lit, "💯") != 0 || big_array_utf8lit[9] != 0) abort();
841 \\ return 0;
842 \\}
843 , "");
844
845 cases.add("Wide, UTF-16, and UTF-32 string literals",
846 \\#include <stdlib.h>
847 \\#include <stdint.h>
848 \\#include <wchar.h>
849 \\int main(void) {
850 \\ const wchar_t *wide_str = L"wide";
851 \\ const wchar_t wide_hello[] = L"hello";
852 \\ if (wcslen(wide_str) != 4) abort();
853 \\ if (wcslen(L"literal") != 7) abort();
854 \\ if (wcscmp(wide_hello, L"hello") != 0) abort();
855 \\
856 \\ const uint16_t *u16_str = u"wide";
857 \\ const uint16_t u16_hello[] = u"hello";
858 \\ if (u16_str[3] != u'e' || u16_str[4] != 0) abort();
859 \\ if (u16_hello[4] != u'o' || u16_hello[5] != 0) abort();
860 \\
861 \\ const uint32_t *u32_str = U"wide";
862 \\ const uint32_t u32_hello[] = U"hello";
863 \\ if (u32_str[3] != U'e' || u32_str[4] != 0) abort();
864 \\ if (u32_hello[4] != U'o' || u32_hello[5] != 0) abort();
865 \\ return 0;
866 \\}
867 , "");
868
869 cases.add("Address of function is no-op",
870 \\#include <stdlib.h>
871 \\#include <stdbool.h>
872 \\typedef int (*myfunc)(int);
873 \\int a(int arg) { return arg + 1;}
874 \\int b(int arg) { return arg + 2;}
875 \\int caller(myfunc fn, int arg) {
876 \\ return fn(arg);
877 \\}
878 \\int main() {
879 \\ myfunc arr[3] = {&a, &b, a};
880 \\ myfunc foo = a;
881 \\ myfunc bar = &(a);
882 \\ if (foo != bar) abort();
883 \\ if (arr[0] == arr[1]) abort();
884 \\ if (arr[0] != arr[2]) abort();
885 \\ if (caller(b, 40) != 42) abort();
886 \\ if (caller(&b, 40) != 42) abort();
887 \\ return 0;
888 \\}
889 , "");
890
891 cases.add("Obscure ways of calling functions; issue #4124",
892 \\#include <stdlib.h>
893 \\static int add(int a, int b) {
894 \\ return a + b;
895 \\}
896 \\typedef int (*adder)(int, int);
897 \\typedef void (*funcptr)(void);
898 \\int main() {
899 \\ if ((add)(1, 2) != 3) abort();
900 \\ if ((&add)(1, 2) != 3) abort();
901 \\ if (add(3, 1) != 4) abort();
902 \\ if ((*add)(2, 3) != 5) abort();
903 \\ if ((**add)(7, -1) != 6) abort();
904 \\ if ((***add)(-2, 9) != 7) abort();
905 \\
906 \\ int (*ptr)(int a, int b);
907 \\ ptr = add;
908 \\
909 \\ if (ptr(1, 2) != 3) abort();
910 \\ if ((*ptr)(3, 1) != 4) abort();
911 \\ if ((**ptr)(2, 3) != 5) abort();
912 \\ if ((***ptr)(7, -1) != 6) abort();
913 \\ if ((****ptr)(-2, 9) != 7) abort();
914 \\
915 \\ funcptr addr1 = (funcptr)(add);
916 \\ funcptr addr2 = (funcptr)(&add);
917 \\
918 \\ if (addr1 != addr2) abort();
919 \\ if (((int(*)(int, int))addr1)(1, 2) != 3) abort();
920 \\ if (((adder)addr2)(1, 2) != 3) abort();
921 \\ return 0;
922 \\}
923 , "");
924
925 cases.add("Return boolean expression as int; issue #6215",
926 \\#include <stdlib.h>
927 \\#include <stdbool.h>
928 \\bool actual_bool(void) { return 4 - 1 < 4;}
929 \\char char_bool_ret(void) { return 0 || 1; }
930 \\short short_bool_ret(void) { return 0 < 1; }
931 \\int int_bool_ret(void) { return 1 && 1; }
932 \\long long_bool_ret(void) { return !(0 > 1); }
933 \\static int GLOBAL = 1;
934 \\int nested_scopes(int a, int b) {
935 \\ if (a == 1) {
936 \\ int target = 1;
937 \\ return b == target;
938 \\ } else {
939 \\ int target = 2;
940 \\ if (b == target) {
941 \\ return GLOBAL == 1;
942 \\ }
943 \\ return target == 2;
944 \\ }
945 \\}
946 \\int main(void) {
947 \\ if (!actual_bool()) abort();
948 \\ if (!char_bool_ret()) abort();
949 \\ if (!short_bool_ret()) abort();
950 \\ if (!int_bool_ret()) abort();
951 \\ if (!long_bool_ret()) abort();
952 \\ if (!nested_scopes(1, 1)) abort();
953 \\ if (nested_scopes(1, 2)) abort();
954 \\ if (!nested_scopes(0, 2)) abort();
955 \\ if (!nested_scopes(0, 3)) abort();
956 \\ return 1 != 1;
957 \\}
958 , "");
959
960 cases.add("Comma operator should create new scope; issue #7989",
961 \\#include <stdlib.h>
962 \\#include <stdio.h>
963 \\int main(void) {
964 \\ if (1 || (abort(), 1)) {}
965 \\ if (0 && (1, printf("do not print\n"))) {}
966 \\ int x = 0;
967 \\ x = (x = 3, 4, x + 1);
968 \\ if (x != 4) abort();
969 \\ return 0;
970 \\}
971 , "");
972
973 cases.add("Use correct break label for statement expression in nested scope",
974 \\#include <stdlib.h>
975 \\int main(void) {
976 \\ int x = ({1, ({2; 3;});});
977 \\ if (x != 3) abort();
978 \\ return 0;
979 \\}
980 , "");
981
982 cases.add("pointer difference: scalar array w/ size truncation or negative result. Issue #7216",
983 \\#include <stdlib.h>
984 \\#include <stddef.h>
985 \\#define SIZE 10
986 \\int main() {
987 \\ int foo[SIZE];
988 \\ int *start = &foo[0];
989 \\ int *one_past_end = start + SIZE;
990 \\ ptrdiff_t diff = one_past_end - start;
991 \\ char diff_char = one_past_end - start;
992 \\ if (diff != SIZE || diff_char != SIZE) abort();
993 \\ diff = start - one_past_end;
994 \\ if (diff != -SIZE) abort();
995 \\ if (one_past_end - foo != SIZE) abort();
996 \\ if ((one_past_end - 1) - foo != SIZE - 1) abort();
997 \\ if ((start + 1) - foo != 1) abort();
998 \\ return 0;
999 \\}
1000 , "");
1001
1002 // C standard: if the expression P points either to an element of an array object or one
1003 // past the last element of an array object, and the expression Q points to the last
1004 // element of the same array object, the expression ((Q)+1)-(P) has the same value as
1005 // ((Q)-(P))+1 and as -((P)-((Q)+1)), and has the value zero if the expression P points
1006 // one past the last element of the array object, even though the expression (Q)+1
1007 // does not point to an element of the array object
1008 cases.add("pointer difference: C standard edge case",
1009 \\#include <stdlib.h>
1010 \\#include <stddef.h>
1011 \\#define SIZE 10
1012 \\int main() {
1013 \\ int foo[SIZE];
1014 \\ int *start = &foo[0];
1015 \\ int *P = start + SIZE;
1016 \\ int *Q = &foo[SIZE - 1];
1017 \\ if ((Q + 1) - P != 0) abort();
1018 \\ if ((Q + 1) - P != (Q - P) + 1) abort();
1019 \\ if ((Q + 1) - P != -(P - (Q + 1))) abort();
1020 \\ return 0;
1021 \\}
1022 , "");
1023
1024 cases.add("pointer difference: unary operators",
1025 \\#include <stdlib.h>
1026 \\int main() {
1027 \\ int foo[10];
1028 \\ int *x = &foo[1];
1029 \\ const int *y = &foo[5];
1030 \\ if (y - x++ != 4) abort();
1031 \\ if (y - x != 3) abort();
1032 \\ if (y - ++x != 2) abort();
1033 \\ if (y - x-- != 2) abort();
1034 \\ if (y - x != 3) abort();
1035 \\ if (y - --x != 4) abort();
1036 \\ if (y - &foo[0] != 5) abort();
1037 \\ return 0;
1038 \\}
1039 , "");
1040
1041 cases.add("pointer difference: struct array with padding",
1042 \\#include <stdlib.h>
1043 \\#include <stddef.h>
1044 \\#define SIZE 10
1045 \\typedef struct my_struct {
1046 \\ int x;
1047 \\ char c;
1048 \\ int y;
1049 \\} my_struct_t;
1050 \\int main() {
1051 \\ my_struct_t foo[SIZE];
1052 \\ my_struct_t *start = &foo[0];
1053 \\ my_struct_t *one_past_end = start + SIZE;
1054 \\ ptrdiff_t diff = one_past_end - start;
1055 \\ int diff_int = one_past_end - start;
1056 \\ if (diff != SIZE || diff_int != SIZE) abort();
1057 \\ diff = start - one_past_end;
1058 \\ if (diff != -SIZE) abort();
1059 \\ return 0;
1060 \\}
1061 , "");
1062
1063 cases.add("pointer difference: array of function pointers",
1064 \\#include <stdlib.h>
1065 \\int a(void) { return 1;}
1066 \\int b(void) { return 2;}
1067 \\int c(void) { return 3;}
1068 \\typedef int (*myfunc)(void);
1069 \\int main() {
1070 \\ myfunc arr[] = {a, b, c, a, b, c};
1071 \\ myfunc *f1 = &arr[1];
1072 \\ myfunc *f4 = &arr[4];
1073 \\ if (f4 - f1 != 3) abort();
1074 \\ return 0;
1075 \\}
1076 , "");
1077
1078 cases.add("typeof operator",
1079 \\#include <stdlib.h>
1080 \\static int FOO = 42;
1081 \\typedef typeof(FOO) foo_type;
1082 \\typeof(foo_type) myfunc(typeof(FOO) x) { return (typeof(FOO)) x; }
1083 \\int main(void) {
1084 \\ int x = FOO;
1085 \\ typeof(x) y = x;
1086 \\ foo_type z = y;
1087 \\ if (x != y) abort();
1088 \\ if (myfunc(z) != x) abort();
1089 \\
1090 \\ const char *my_string = "bar";
1091 \\ typeof (typeof (my_string)[4]) string_arr = {"a","b","c","d"};
1092 \\ if (string_arr[0][0] != 'a' || string_arr[3][0] != 'd') abort();
1093 \\ return 0;
1094 \\}
1095 , "");
1096
1097 cases.add("offsetof",
1098 \\#include <stddef.h>
1099 \\#include <stdlib.h>
1100 \\#define container_of(ptr, type, member) ({ \
1101 \\ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
1102 \\ (type *)( (char *)__mptr - offsetof(type,member) );})
1103 \\typedef struct {
1104 \\ int i;
1105 \\ struct { int x; char y; int z; } s;
1106 \\ float f;
1107 \\} container;
1108 \\int main(void) {
1109 \\ if (offsetof(container, i) != 0) abort();
1110 \\ if (offsetof(container, s) <= offsetof(container, i)) abort();
1111 \\ if (offsetof(container, f) <= offsetof(container, s)) abort();
1112 \\
1113 \\ container my_container;
1114 \\ typeof(my_container.s) *inner_member_pointer = &my_container.s;
1115 \\ float *float_member_pointer = &my_container.f;
1116 \\ int *anon_member_pointer = &my_container.s.z;
1117 \\ container *my_container_p;
1118 \\
1119 \\ my_container_p = container_of(inner_member_pointer, container, s);
1120 \\ if (my_container_p != &my_container) abort();
1121 \\
1122 \\ my_container_p = container_of(float_member_pointer, container, f);
1123 \\ if (my_container_p != &my_container) abort();
1124 \\
1125 \\ if (container_of(anon_member_pointer, typeof(my_container.s), z) != inner_member_pointer) abort();
1126 \\ return 0;
1127 \\}
1128 , "");
1129
1130 cases.add("handle assert.h",
1131 \\#include <assert.h>
1132 \\int main() {
1133 \\ int x = 1;
1134 \\ int *xp = &x;
1135 \\ assert(1);
1136 \\ assert(x != 0);
1137 \\ assert(xp);
1138 \\ assert(*xp);
1139 \\ return 0;
1140 \\}
1141 , "");
1142
1143 cases.add("NDEBUG disables assert",
1144 \\#define NDEBUG
1145 \\#include <assert.h>
1146 \\int main() {
1147 \\ assert(0);
1148 \\ assert(NULL);
1149 \\ return 0;
1150 \\}
1151 , "");
1152
1153 cases.add("pointer arithmetic with signed operand",
1154 \\#include <stdlib.h>
1155 \\int main() {
1156 \\ int array[10];
1157 \\ int *x = &array[5];
1158 \\ int *y;
1159 \\ int idx = 0;
1160 \\ y = x + ++idx;
1161 \\ if (y != x + 1 || y != &array[6]) abort();
1162 \\ y = idx + x;
1163 \\ if (y != x + 1 || y != &array[6]) abort();
1164 \\ y = x - idx;
1165 \\ if (y != x - 1 || y != &array[4]) abort();
1166 \\
1167 \\ idx = 0;
1168 \\ y = --idx + x;
1169 \\ if (y != x - 1 || y != &array[4]) abort();
1170 \\ y = idx + x;
1171 \\ if (y != x - 1 || y != &array[4]) abort();
1172 \\ y = x - idx;
1173 \\ if (y != x + 1 || y != &array[6]) abort();
1174 \\
1175 \\ idx = 1;
1176 \\ x += idx;
1177 \\ if (x != &array[6]) abort();
1178 \\ x -= idx;
1179 \\ if (x != &array[5]) abort();
1180 \\ y = (x += idx);
1181 \\ if (y != x || y != &array[6]) abort();
1182 \\ y = (x -= idx);
1183 \\ if (y != x || y != &array[5]) abort();
1184 \\
1185 \\ if (array + idx != &array[1] || array + 1 != &array[1]) abort();
1186 \\ idx = -1;
1187 \\ if (array - idx != &array[1]) abort();
1188 \\
1189 \\ return 0;
1190 \\}
1191 , "");
1192
1193 cases.add("Compound literals",
1194 \\#include <stdlib.h>
1195 \\struct Foo {
1196 \\ int a;
1197 \\ char b[2];
1198 \\ float c;
1199 \\};
1200 \\int main() {
1201 \\ struct Foo foo;
1202 \\ int x = 1, y = 2;
1203 \\ foo = (struct Foo) {x + y, {'a', 'b'}, 42.0f};
1204 \\ if (foo.a != x + y || foo.b[0] != 'a' || foo.b[1] != 'b' || foo.c != 42.0f) abort();
1205 \\ return 0;
1206 \\}
1207 , "");
1208
1209 cases.add("Generic selections",
1210 \\#include <stdlib.h>
1211 \\#include <string.h>
1212 \\#include <stdint.h>
1213 \\#define my_generic_fn(X) _Generic((X), \
1214 \\ int: abs, \
1215 \\ char *: strlen, \
1216 \\ size_t: malloc, \
1217 \\ default: free \
1218 \\)(X)
1219 \\#define my_generic_val(X) _Generic((X), \
1220 \\ int: 1, \
1221 \\ const char *: "bar" \
1222 \\)
1223 \\int main(void) {
1224 \\ if (my_generic_val(100) != 1) abort();
1225 \\
1226 \\ const char *foo = "foo";
1227 \\ const char *bar = my_generic_val(foo);
1228 \\ if (strcmp(bar, "bar") != 0) abort();
1229 \\
1230 \\ if (my_generic_fn(-42) != 42) abort();
1231 \\ if (my_generic_fn("hello") != 5) abort();
1232 \\
1233 \\ size_t size = 8192;
1234 \\ uint8_t *mem = my_generic_fn(size);
1235 \\ memset(mem, 42, size);
1236 \\ if (mem[size - 1] != 42) abort();
1237 \\ my_generic_fn(mem);
1238 \\
1239 \\ return 0;
1240 \\}
1241 , "");
1242
1243 // See __builtin_alloca_with_align comment in std.zig.c_builtins
1244 cases.add("use of unimplemented builtin in unused function does not prevent compilation",
1245 \\#include <stdlib.h>
1246 \\void unused() {
1247 \\ __builtin_alloca_with_align(1, 8);
1248 \\}
1249 \\int main(void) {
1250 \\ if (__builtin_sqrt(1.0) != 1.0) abort();
1251 \\ return 0;
1252 \\}
1253 , "");
1254
1255 cases.add("convert single-statement bodies into blocks for if/else/for/while. issue #8159",
1256 \\#include <stdlib.h>
1257 \\int foo() { return 1; }
1258 \\int main(void) {
1259 \\ int i = 0;
1260 \\ if (i == 0) if (i == 0) if (i != 0) i = 1;
1261 \\ if (i != 0) i = 1; else if (i == 0) if (i == 0) i += 1;
1262 \\ for (; i < 10;) for (; i < 10;) i++;
1263 \\ while (i == 100) while (i == 100) foo();
1264 \\ if (0) do do "string"; while(1); while(1);
1265 \\ return 0;
1266 \\}
1267 , "");
1268
1269 cases.add("cast RHS of compound assignment if necessary, unused result",
1270 \\#include <stdlib.h>
1271 \\int main(void) {
1272 \\ signed short val = -1;
1273 \\ val += 1; if (val != 0) abort();
1274 \\ val -= 1; if (val != -1) abort();
1275 \\ val *= 2; if (val != -2) abort();
1276 \\ val /= 2; if (val != -1) abort();
1277 \\ val %= 2; if (val != -1) abort();
1278 \\ val <<= 1; if (val != -2) abort();
1279 \\ val >>= 1; if (val != -1) abort();
1280 \\ val += 100000000; // compile error if @truncate() not inserted
1281 \\ unsigned short uval = 1;
1282 \\ uval += 1; if (uval != 2) abort();
1283 \\ uval -= 1; if (uval != 1) abort();
1284 \\ uval *= 2; if (uval != 2) abort();
1285 \\ uval /= 2; if (uval != 1) abort();
1286 \\ uval %= 2; if (uval != 1) abort();
1287 \\ uval <<= 1; if (uval != 2) abort();
1288 \\ uval >>= 1; if (uval != 1) abort();
1289 \\ uval += 100000000; // compile error if @truncate() not inserted
1290 \\}
1291 , "");
1292
1293 cases.add("cast RHS of compound assignment if necessary, used result",
1294 \\#include <stdlib.h>
1295 \\int main(void) {
1296 \\ signed short foo;
1297 \\ signed short val = -1;
1298 \\ foo = (val += 1); if (foo != 0) abort();
1299 \\ foo = (val -= 1); if (foo != -1) abort();
1300 \\ foo = (val *= 2); if (foo != -2) abort();
1301 \\ foo = (val /= 2); if (foo != -1) abort();
1302 \\ foo = (val %= 2); if (foo != -1) abort();
1303 \\ foo = (val <<= 1); if (foo != -2) abort();
1304 \\ foo = (val >>= 1); if (foo != -1) abort();
1305 \\ foo = (val += 100000000); // compile error if @truncate() not inserted
1306 \\ unsigned short ufoo;
1307 \\ unsigned short uval = 1;
1308 \\ ufoo = (uval += 1); if (ufoo != 2) abort();
1309 \\ ufoo = (uval -= 1); if (ufoo != 1) abort();
1310 \\ ufoo = (uval *= 2); if (ufoo != 2) abort();
1311 \\ ufoo = (uval /= 2); if (ufoo != 1) abort();
1312 \\ ufoo = (uval %= 2); if (ufoo != 1) abort();
1313 \\ ufoo = (uval <<= 1); if (ufoo != 2) abort();
1314 \\ ufoo = (uval >>= 1); if (ufoo != 1) abort();
1315 \\ ufoo = (uval += 100000000); // compile error if @truncate() not inserted
1316 \\}
1317 , "");
1318
1319 cases.add("break from switch statement. Issue #8387",
1320 \\#include <stdlib.h>
1321 \\int switcher(int x) {
1322 \\ switch (x) {
1323 \\ case 0: // no braces
1324 \\ x += 1;
1325 \\ break;
1326 \\ case 1: // conditional break
1327 \\ if (x == 1) {
1328 \\ x += 1;
1329 \\ break;
1330 \\ }
1331 \\ x += 100;
1332 \\ case 2: { // braces with fallthrough
1333 \\ x += 1;
1334 \\ }
1335 \\ case 3: // fallthrough to return statement
1336 \\ x += 1;
1337 \\ case 42: { // random out of order case
1338 \\ x += 1;
1339 \\ return x;
1340 \\ }
1341 \\ case 4: { // break within braces
1342 \\ x += 1;
1343 \\ break;
1344 \\ }
1345 \\ case 5:
1346 \\ x += 1; // fallthrough to default
1347 \\ default:
1348 \\ x += 1;
1349 \\ }
1350 \\ return x;
1351 \\}
1352 \\int main(void) {
1353 \\ int expected[] = {1, 2, 5, 5, 5, 7, 7};
1354 \\ for (int i = 0; i < sizeof(expected) / sizeof(int); i++) {
1355 \\ int res = switcher(i);
1356 \\ if (res != expected[i]) abort();
1357 \\ }
1358 \\ if (switcher(42) != 43) abort();
1359 \\ return 0;
1360 \\}
1361 , "");
1362
1363 cases.add("Cast to enum from larger integral type. Issue #6011",
1364 \\#include <stdint.h>
1365 \\#include <stdlib.h>
1366 \\enum Foo { A, B, C };
1367 \\static inline enum Foo do_stuff(void) {
1368 \\ int64_t i = 1;
1369 \\ return (enum Foo)i;
1370 \\}
1371 \\int main(void) {
1372 \\ if (do_stuff() != B) abort();
1373 \\ return 0;
1374 \\}
1375 , "");
1376
1377 cases.add("Render array LHS as grouped node if necessary",
1378 \\#include <stdlib.h>
1379 \\int main(void) {
1380 \\ int arr[] = {40, 41, 42, 43};
1381 \\ if ((arr + 1)[1] != 42) abort();
1382 \\ return 0;
1383 \\}
1384 , "");
1385
1386 cases.add("typedef with multiple names",
1387 \\#include <stdlib.h>
1388 \\typedef struct {
1389 \\ char field;
1390 \\} a_t, b_t;
1391 \\
1392 \\int main(void) {
1393 \\ a_t a = { .field = 42 };
1394 \\ b_t b = a;
1395 \\ if (b.field != 42) abort();
1396 \\ return 0;
1397 \\}
1398 , "");
1399
1400 cases.add("__cleanup__ attribute",
1401 \\#include <stdlib.h>
1402 \\static int cleanup_count = 0;
1403 \\void clean_up(int *final_value) {
1404 \\ if (*final_value != cleanup_count++) abort();
1405 \\}
1406 \\void doit(void) {
1407 \\ int a __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 2;
1408 \\ int b __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 1;
1409 \\ int c __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 0;
1410 \\}
1411 \\int main(void) {
1412 \\ doit();
1413 \\ if (cleanup_count != 3) abort();
1414 \\ return 0;
1415 \\}
1416 , "");
1417
1418 cases.add("enum used as boolean expression",
1419 \\#include <stdlib.h>
1420 \\enum FOO {BAR, BAZ};
1421 \\int main(void) {
1422 \\ enum FOO x = BAR;
1423 \\ if (x) abort();
1424 \\ if (!BAZ) abort();
1425 \\ return 0;
1426 \\}
1427 , "");
1428
1429 cases.add("Flexible arrays",
1430 \\#include <stdlib.h>
1431 \\#include <stdint.h>
1432 \\typedef struct { char foo; int bar; } ITEM;
1433 \\typedef struct { size_t count; ITEM items[]; } ITEM_LIST;
1434 \\typedef struct { unsigned char count; int items[]; } INT_LIST;
1435 \\#define SIZE 10
1436 \\int main(void) {
1437 \\ ITEM_LIST *list = malloc(sizeof(ITEM_LIST) + SIZE * sizeof(ITEM));
1438 \\ for (int i = 0; i < SIZE; i++) list->items[i] = (ITEM) {.foo = i, .bar = i + 1};
1439 \\ const ITEM_LIST *const c_list = list;
1440 \\ for (int i = 0; i < SIZE; i++) if (c_list->items[i].foo != i || c_list->items[i].bar != i + 1) abort();
1441 \\ INT_LIST *int_list = malloc(sizeof(INT_LIST) + SIZE * sizeof(int));
1442 \\ for (int i = 0; i < SIZE; i++) int_list->items[i] = i;
1443 \\ const INT_LIST *const c_int_list = int_list;
1444 \\ const int *const ints = int_list->items;
1445 \\ for (int i = 0; i < SIZE; i++) if (ints[i] != i) abort();
1446 \\ return 0;
1447 \\}
1448 , "");
1449
1450 cases.add("Flexible array with typedefed flexible item, issue #16838",
1451 \\#include <stdlib.h>
1452 \\#include <assert.h>
1453 \\typedef int MARKER[0];
1454 \\typedef struct { int x; MARKER y; } Flexible;
1455 \\#define SIZE 10
1456 \\int main(void) {
1457 \\ Flexible *flex = malloc(sizeof(Flexible) + SIZE * sizeof(int));
1458 \\ for (int i = 0; i < SIZE; i++) {
1459 \\ flex->y[i] = i;
1460 \\ }
1461 \\ for (int i = 0; i < SIZE; i++) {
1462 \\ assert(flex->y[i] == i);
1463 \\ }
1464 \\ return 0;
1465 \\}
1466 , "");
1467
1468 cases.add("enum with value that fits in c_uint but not c_int, issue #8003",
1469 \\#include <stdlib.h>
1470 \\enum my_enum {
1471 \\ FORCE_UINT = 0xffffffff
1472 \\};
1473 \\int main(void) {
1474 \\ if(FORCE_UINT != 0xffffffff) abort();
1475 \\}
1476 , "");
1477
1478 cases.add("block-scope static variable shadows function parameter. Issue #8208",
1479 \\#include <stdlib.h>
1480 \\int func1(int foo) { return foo + 1; }
1481 \\int func2(void) {
1482 \\ static int foo = 5;
1483 \\ return foo++;
1484 \\}
1485 \\int main(void) {
1486 \\ if (func1(42) != 43) abort();
1487 \\ if (func2() != 5) abort();
1488 \\ if (func2() != 6) abort();
1489 \\ return 0;
1490 \\}
1491 , "");
1492
1493 cases.add("nested same-name static locals",
1494 \\#include <stdlib.h>
1495 \\int func(int val) {
1496 \\ static int foo;
1497 \\ if (foo != val) abort();
1498 \\ {
1499 \\ foo += 1;
1500 \\ static int foo = 2;
1501 \\ if (foo != val + 2) abort();
1502 \\ foo += 1;
1503 \\ }
1504 \\ return foo;
1505 \\}
1506 \\int main(void) {
1507 \\ int foo = 1;
1508 \\ if (func(0) != 1) abort();
1509 \\ if (func(1) != 2) abort();
1510 \\ if (func(2) != 3) abort();
1511 \\ if (foo != 1) abort();
1512 \\ return 0;
1513 \\}
1514 , "");
1515
1516 cases.add("Enum constants are assigned correct type. Issue #9153",
1517 \\enum A { A0, A1=0xFFFFFFFF };
1518 \\enum B { B0=-1, B1=0xFFFFFFFF };
1519 \\enum C { C0=-1, C1=0 };
1520 \\enum D { D0, D1=0xFFFFFFFFFFL };
1521 \\enum E { E0=-1, E1=0xFFFFFFFFFFL };
1522 \\int main(void) {
1523 \\ signed char a0 = A0, a1 = A1;
1524 \\ signed char b0 = B0, b1 = B1;
1525 \\ signed char c0 = C0, c1 = C1;
1526 \\ signed char d0 = D0, d1 = D1;
1527 \\ signed char e0 = E0, e1 = E1;
1528 \\ return 0;
1529 \\}
1530 , "");
1531
1532 cases.add("Enum constant matches enum name; multiple enumerations with same value",
1533 \\#include <stdlib.h>
1534 \\enum FOO {
1535 \\ FOO = 1,
1536 \\ BAR = 2,
1537 \\ BAZ = 1,
1538 \\};
1539 \\int main(void) {
1540 \\ enum FOO x = BAZ;
1541 \\ if (x != 1) abort();
1542 \\ if (x != BAZ) abort();
1543 \\ if (x != FOO) abort();
1544 \\}
1545 , "");
1546
1547 cases.add("Scoped enums",
1548 \\#include <stdlib.h>
1549 \\int main(void) {
1550 \\ enum Foo { A, B, C };
1551 \\ enum Foo a = B;
1552 \\ if (a != B) abort();
1553 \\ if (a != 1) abort();
1554 \\ {
1555 \\ enum Foo { A = 5, B = 6, C = 7 };
1556 \\ enum Foo a = B;
1557 \\ if (a != B) abort();
1558 \\ if (a != 6) abort();
1559 \\ }
1560 \\ if (a != B) abort();
1561 \\ if (a != 1) abort();
1562 \\}
1563 , "");
1564
1565 cases.add("Underscore identifiers",
1566 \\#include <stdlib.h>
1567 \\int _ = 10;
1568 \\typedef struct { int _; } S;
1569 \\int main(void) {
1570 \\ if (_ != 10) abort();
1571 \\ S foo = { ._ = _ };
1572 \\ if (foo._ != _) abort();
1573 \\ return 0;
1574 \\}
1575 , "");
1576
1577 cases.add("__builtin_choose_expr (unchosen expression is not evaluated)",
1578 \\#include <stdlib.h>
1579 \\int main(void) {
1580 \\ int x = 0.0;
1581 \\ int y = 0.0;
1582 \\ int res;
1583 \\ res = __builtin_choose_expr(1, 1, x / y);
1584 \\ if (res != 1) abort();
1585 \\ res = __builtin_choose_expr(0, x / y, 2);
1586 \\ if (res != 2) abort();
1587 \\ return 0;
1588 \\}
1589 , "");
1590
1591 // TODO: add isnan check for long double once bitfield support is added
1592 // (needed for x86_64-windows-gnu)
1593 // TODO: add isinf check for long double once std.math.isInf supports c_longdouble
1594 cases.add("NAN and INFINITY",
1595 \\#include <math.h>
1596 \\#include <stdint.h>
1597 \\#include <stdlib.h>
1598 \\union uf { uint32_t u; float f; };
1599 \\#define CHECK_NAN(STR, VAL) { \
1600 \\ union uf unpack = {.f = __builtin_nanf(STR)}; \
1601 \\ if (!isnan(unpack.f)) abort(); \
1602 \\ if (unpack.u != VAL) abort(); \
1603 \\}
1604 \\int main(void) {
1605 \\ float f_nan = NAN;
1606 \\ if (!isnan(f_nan)) abort();
1607 \\ double d_nan = NAN;
1608 \\ if (!isnan(d_nan)) abort();
1609 \\ CHECK_NAN("0", 0x7FC00000);
1610 \\ CHECK_NAN("", 0x7FC00000);
1611 \\ CHECK_NAN("1", 0x7FC00001);
1612 \\ CHECK_NAN("0x7FC00000", 0x7FC00000);
1613 \\ CHECK_NAN("0x7FC0000F", 0x7FC0000F);
1614 \\ CHECK_NAN("0x7FC000F0", 0x7FC000F0);
1615 \\ CHECK_NAN("0x7FC00F00", 0x7FC00F00);
1616 \\ CHECK_NAN("0x7FC0F000", 0x7FC0F000);
1617 \\ CHECK_NAN("0x7FCF0000", 0x7FCF0000);
1618 \\ CHECK_NAN("0xFFFFFFFF", 0x7FFFFFFF);
1619 \\ float f_inf = INFINITY;
1620 \\ if (!isinf(f_inf)) abort();
1621 \\ double d_inf = INFINITY;
1622 \\ if (!isinf(d_inf)) abort();
1623 \\ return 0;
1624 \\}
1625 , "");
1626
1627 cases.add("signed array subscript. Issue #8556",
1628 \\#include <stdint.h>
1629 \\#include <stdlib.h>
1630 \\#define TEST_NEGATIVE(type) { type x = -1; if (ptr[x] != 42) abort(); }
1631 \\#define TEST_UNSIGNED(type) { type x = 2; if (arr[x] != 42) abort(); }
1632 \\int main(void) {
1633 \\ int arr[] = {40, 41, 42, 43};
1634 \\ int *ptr = arr + 3;
1635 \\ if (ptr[-1] != 42) abort();
1636 \\ TEST_NEGATIVE(int);
1637 \\ TEST_NEGATIVE(long);
1638 \\ TEST_NEGATIVE(long long);
1639 \\ TEST_NEGATIVE(int64_t);
1640 \\ TEST_NEGATIVE(__int128);
1641 \\ TEST_UNSIGNED(unsigned);
1642 \\ TEST_UNSIGNED(unsigned long);
1643 \\ TEST_UNSIGNED(unsigned long long);
1644 \\ TEST_UNSIGNED(uint64_t);
1645 \\ TEST_UNSIGNED(size_t);
1646 \\ TEST_UNSIGNED(unsigned __int128);
1647 \\ return 0;
1648 \\}
1649 , "");
1650
1651 cases.add("Ensure side-effects only evaluated once for signed array indices",
1652 \\#include <stdlib.h>
1653 \\int main(void) {
1654 \\ int foo[] = {1, 2, 3, 4};
1655 \\ int *p = foo;
1656 \\ int idx = 1;
1657 \\ if ((++p)[--idx] != 2) abort();
1658 \\ if (p != foo + 1) abort();
1659 \\ if (idx != 0) abort();
1660 \\ if ((p++)[idx++] != 2) abort();
1661 \\ if (p != foo + 2) abort();
1662 \\ if (idx != 1) abort();
1663 \\ return 0;
1664 \\}
1665 , "");
1666
1667 cases.add("Allow non-const char* string literals. Issue #9126",
1668 \\#include <stdlib.h>
1669 \\int func(char *x) { return x[0]; }
1670 \\struct S { char *member; };
1671 \\struct S global_struct = { .member = "global" };
1672 \\char *g = "global";
1673 \\int main(void) {
1674 \\ if (g[0] != 'g') abort();
1675 \\ if (global_struct.member[0] != 'g') abort();
1676 \\ char *string = "hello";
1677 \\ if (string[0] != 'h') abort();
1678 \\ struct S s = {.member = "hello"};
1679 \\ if (s.member[0] != 'h') abort();
1680 \\ if (func("foo") != 'f') abort();
1681 \\ return 0;
1682 \\}
1683 , "");
1684
1685 cases.add("Ensure while loop under an if doesn't steal the else. Issue #9953",
1686 \\#include <stdio.h>
1687 \\void doWork(int id) { }
1688 \\int reallyDelete(int id) { printf("deleted %d\n", id); return 1; }
1689 \\int process(int id, int n, int delete) {
1690 \\ if(!delete)
1691 \\ while(n-- > 0) doWork(id);
1692 \\ else
1693 \\ return reallyDelete(id);
1694 \\ return 0;
1695 \\}
1696 \\int main(void) {
1697 \\ process(99, 3, 0);
1698 \\ return 0;
1699 \\}
1700 , "");
1701
1702 cases.add("Remainder operator with negative integers. Issue #10176",
1703 \\#include <stdlib.h>
1704 \\int main(void) {
1705 \\ int denominator = -2;
1706 \\ int numerator = 5;
1707 \\ if (numerator % denominator != 1) abort();
1708 \\ numerator = -5; denominator = 2;
1709 \\ if (numerator % denominator != -1) abort();
1710 \\ return 0;
1711 \\}
1712 , "");
1713
1714 cases.add("Boolean expression coerced to int. Issue #10175",
1715 \\#include <stdlib.h>
1716 \\int sign(int v) {
1717 \\ return -(v < 0);
1718 \\}
1719 \\int main(void) {
1720 \\ if (sign(-5) != -1) abort();
1721 \\ if (sign(5) != 0) abort();
1722 \\ if (sign(0) != 0) abort();
1723 \\ return 0;
1724 \\}
1725 , "");
1726
1727 cases.add("Typedef'ed void used as return type. Issue #10356",
1728 \\typedef void V;
1729 \\V foo(V *f) {}
1730 \\int main(void) {
1731 \\ int x = 0;
1732 \\ foo(&x);
1733 \\ return 0;
1734 \\}
1735 , "");
1736
1737 cases.add("Zero-initialization of global union. Issue #10797",
1738 \\#include <stdlib.h>
1739 \\union U { int x; double y; };
1740 \\union U u;
1741 \\int main(void) {
1742 \\ if (u.x != 0) abort();
1743 \\ return 0;
1744 \\}
1745 , "");
1746
1747 cases.add("Cast-to-union. Issue #10955",
1748 \\#include <stdlib.h>
1749 \\struct S { int x; };
1750 \\union U {
1751 \\ long l;
1752 \\ double d;
1753 \\ struct S s;
1754 \\};
1755 \\union U bar(union U u) { return u; }
1756 \\int main(void) {
1757 \\ union U u = (union U) 42L;
1758 \\ if (u.l != 42L) abort();
1759 \\ u = (union U) 2.0;
1760 \\ if (u.d != 2.0) abort();
1761 \\ u = bar((union U)4.0);
1762 \\ if (u.d != 4.0) abort();
1763 \\ u = (union U)(struct S){ .x = 5 };
1764 \\ if (u.s.x != 5) abort();
1765 \\ return 0;
1766 \\}
1767 , "");
1768
1769 cases.add("Nested comma operator in macro. Issue #11040",
1770 \\#include <stdlib.h>
1771 \\#define FOO (1, (2, 3))
1772 \\int main(void) {
1773 \\ int x = FOO;
1774 \\ if (x != 3) abort();
1775 \\ return 0;
1776 \\}
1777 , "");
1778
1779 // The C standard does not require function pointers to be convertible to any integer type.
1780 // However, POSIX requires that function pointers have the same representation as `void *`
1781 // so that dlsym() can work
1782 cases.add("Function to integral",
1783 \\#include <stdint.h>
1784 \\int main(void) {
1785 \\#if defined(__UINTPTR_MAX__) && __has_include(<unistd.h>)
1786 \\ uintptr_t x = (uintptr_t)main;
1787 \\#endif
1788 \\ return 0;
1789 \\}
1790 , "");
1791
1792 cases.add("Closure over local in typeof",
1793 \\#include <stdlib.h>
1794 \\int main(void) {
1795 \\ int x = 123;
1796 \\ union { typeof(x) val; } u = { x };
1797 \\ if (u.val != 123) abort();
1798 \\ return 0;
1799 \\}
1800 , "");
1801
1802 cases.add("struct without global declaration does not conflict with local variable name",
1803 \\#include <stdlib.h>
1804 \\static void foo(struct foobar *unused) {}
1805 \\int main(void) {
1806 \\ int struct_foobar = 123;
1807 \\ if (struct_foobar != 123) abort();
1808 \\ int foobar = 456;
1809 \\ if (foobar != 456) abort();
1810 \\ return 0;
1811 \\}
1812 , "");
1813
1814 cases.add("struct without global declaration does not conflict with global variable name",
1815 \\#include <stdlib.h>
1816 \\static void foo(struct foobar *unused) {}
1817 \\static int struct_foobar = 123;
1818 \\static int foobar = 456;
1819 \\int main(void) {
1820 \\ if (struct_foobar != 123) abort();
1821 \\ if (foobar != 456) abort();
1822 \\ return 0;
1823 \\}
1824 , "");
1825}
test/src/Cases.zig+1-145
......@@ -9,7 +9,6 @@ const ArrayList = std.ArrayList;
99gpa: Allocator,
1010arena: Allocator,
1111cases: std.array_list.Managed(Case),
12translate: std.array_list.Managed(Translate),
1312
1413pub const IncrementalCase = struct {
1514 base_path: []const u8,
......@@ -127,25 +126,6 @@ pub const Case = struct {
127126 }
128127};
129128
130pub const Translate = struct {
131 /// The name of the test case. This is shown if a test fails, and
132 /// otherwise ignored.
133 name: []const u8,
134
135 input: [:0]const u8,
136 target: std.Build.ResolvedTarget,
137 link_libc: bool,
138 c_frontend: CFrontend,
139 kind: union(enum) {
140 /// Translate the input, run it and check that it
141 /// outputs the expected text.
142 run: []const u8,
143 /// Translate the input and check that it contains
144 /// the expected lines of code.
145 translate: []const []const u8,
146 },
147};
148
149129pub fn addExe(
150130 ctx: *Cases,
151131 name: []const u8,
......@@ -374,7 +354,6 @@ fn addFromDirInner(
374354
375355 const backends = try manifest.getConfigForKeyAlloc(ctx.arena, "backend", Backend);
376356 const targets = try manifest.getConfigForKeyAlloc(ctx.arena, "target", std.Target.Query);
377 const c_frontends = try manifest.getConfigForKeyAlloc(ctx.arena, "c_frontend", CFrontend);
378357 const is_test = try manifest.getConfigForKeyAssertSingle("is_test", bool);
379358 const link_libc = try manifest.getConfigForKeyAssertSingle("link_libc", bool);
380359 const output_mode = try manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode);
......@@ -384,39 +363,6 @@ fn addFromDirInner(
384363 const emit_bin = try manifest.getConfigForKeyAssertSingle("emit_bin", bool);
385364 const imports = try manifest.getConfigForKeyAlloc(ctx.arena, "imports", []const u8);
386365
387 if (manifest.type == .translate_c) {
388 for (c_frontends) |c_frontend| {
389 for (targets) |target_query| {
390 const output = try manifest.trailingLinesSplit(ctx.arena);
391 try ctx.translate.append(.{
392 .name = try caseNameFromPath(ctx.arena, filename),
393 .c_frontend = c_frontend,
394 .target = b.resolveTargetQuery(target_query),
395 .link_libc = link_libc,
396 .input = src,
397 .kind = .{ .translate = output },
398 });
399 }
400 }
401 continue;
402 }
403 if (manifest.type == .run_translated_c) {
404 for (c_frontends) |c_frontend| {
405 for (targets) |target_query| {
406 const output = try manifest.trailingSplit(ctx.arena);
407 try ctx.translate.append(.{
408 .name = try caseNameFromPath(ctx.arena, filename),
409 .c_frontend = c_frontend,
410 .target = b.resolveTargetQuery(target_query),
411 .link_libc = link_libc,
412 .input = src,
413 .kind = .{ .run = output },
414 });
415 }
416 }
417 continue;
418 }
419
420366 var cases = std.array_list.Managed(usize).init(ctx.arena);
421367
422368 // Cross-product to get all possible test combinations
......@@ -484,101 +430,11 @@ fn addFromDirInner(
484430pub fn init(gpa: Allocator, arena: Allocator) Cases {
485431 return .{
486432 .gpa = gpa,
487 .cases = std.array_list.Managed(Case).init(gpa),
488 .translate = std.array_list.Managed(Translate).init(gpa),
433 .cases = .init(gpa),
489434 .arena = arena,
490435 };
491436}
492437
493pub const TranslateCOptions = struct {
494 skip_translate_c: bool = false,
495 skip_run_translated_c: bool = false,
496};
497pub fn lowerToTranslateCSteps(
498 self: *Cases,
499 b: *std.Build,
500 parent_step: *std.Build.Step,
501 test_filters: []const []const u8,
502 test_target_filters: []const []const u8,
503 target: std.Build.ResolvedTarget,
504 translate_c_options: TranslateCOptions,
505) void {
506 const tests = @import("../tests.zig");
507 const test_translate_c_step = b.step("test-translate-c", "Run the C translation tests");
508 if (!translate_c_options.skip_translate_c) {
509 tests.addTranslateCTests(b, test_translate_c_step, test_filters, test_target_filters);
510 parent_step.dependOn(test_translate_c_step);
511 }
512
513 const test_run_translated_c_step = b.step("test-run-translated-c", "Run the Run-Translated-C tests");
514 if (!translate_c_options.skip_run_translated_c) {
515 tests.addRunTranslatedCTests(b, test_run_translated_c_step, test_filters, target);
516 parent_step.dependOn(test_run_translated_c_step);
517 }
518
519 for (self.translate.items) |case| switch (case.kind) {
520 .run => |output| {
521 if (translate_c_options.skip_run_translated_c) continue;
522 const annotated_case_name = b.fmt("run-translated-c {s}", .{case.name});
523 for (test_filters) |test_filter| {
524 if (std.mem.indexOf(u8, annotated_case_name, test_filter)) |_| break;
525 } else if (test_filters.len > 0) continue;
526 if (!std.process.can_spawn) {
527 std.debug.print("Unable to spawn child processes on {s}, skipping test.\n", .{@tagName(builtin.os.tag)});
528 continue; // Pass test.
529 }
530
531 const write_src = b.addWriteFiles();
532 const file_source = write_src.add("tmp.c", case.input);
533
534 const translate_c = b.addTranslateC(.{
535 .root_source_file = file_source,
536 .optimize = .Debug,
537 .target = case.target,
538 .link_libc = case.link_libc,
539 .use_clang = case.c_frontend == .clang,
540 });
541 translate_c.step.name = b.fmt("{s} translate-c", .{annotated_case_name});
542
543 const run_exe = b.addExecutable(.{
544 .name = "translated_c",
545 .root_module = translate_c.createModule(),
546 });
547 run_exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});
548 run_exe.root_module.link_libc = true;
549 const run = b.addRunArtifact(run_exe);
550 run.step.name = b.fmt("{s} run", .{annotated_case_name});
551 run.expectStdOutEqual(output);
552 run.skip_foreign_checks = true;
553
554 test_run_translated_c_step.dependOn(&run.step);
555 },
556 .translate => |output| {
557 if (translate_c_options.skip_translate_c) continue;
558 const annotated_case_name = b.fmt("zig translate-c {s}", .{case.name});
559 for (test_filters) |test_filter| {
560 if (std.mem.indexOf(u8, annotated_case_name, test_filter)) |_| break;
561 } else if (test_filters.len > 0) continue;
562
563 const write_src = b.addWriteFiles();
564 const file_source = write_src.add("tmp.c", case.input);
565
566 const translate_c = b.addTranslateC(.{
567 .root_source_file = file_source,
568 .optimize = .Debug,
569 .target = case.target,
570 .link_libc = case.link_libc,
571 .use_clang = case.c_frontend == .clang,
572 });
573 translate_c.step.name = b.fmt("{s} translate-c", .{annotated_case_name});
574
575 const check_file = translate_c.addCheckFile(output);
576 check_file.step.name = b.fmt("{s} CheckFile", .{annotated_case_name});
577 test_translate_c_step.dependOn(&check_file.step);
578 },
579 };
580}
581
582438pub const CaseTestOptions = struct {
583439 test_filters: []const []const u8,
584440 test_target_filters: []const []const u8,
test/tests.zig-53
......@@ -7,14 +7,10 @@ const Step = std.Build.Step;
77
88// Cases
99const stack_traces = @import("stack_traces.zig");
10const translate_c = @import("translate_c.zig");
11const run_translated_c = @import("run_translated_c.zig");
1210const llvm_ir = @import("llvm_ir.zig");
1311const libc = @import("libc.zig");
1412
1513// Implementations
16pub const TranslateCContext = @import("src/TranslateC.zig");
17pub const RunTranslatedCContext = @import("src/RunTranslatedC.zig");
1814pub const StackTracesContext = @import("src/StackTrace.zig");
1915pub const DebuggerContext = @import("src/Debugger.zig");
2016pub const LlvmIrContext = @import("src/LlvmIr.zig");
......@@ -1901,7 +1897,6 @@ pub fn addStandaloneTests(
19011897 enable_macos_sdk: bool,
19021898 enable_ios_sdk: bool,
19031899 enable_symlinks_windows: bool,
1904 skip_translate_c: bool,
19051900) *Step {
19061901 const step = b.step("test-standalone", "Run the standalone tests");
19071902 if (compilerHasPackageManager(b)) {
......@@ -1914,7 +1909,6 @@ pub fn addStandaloneTests(
19141909 .simple_skip_release_safe = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseSafe) == null,
19151910 .simple_skip_release_fast = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseFast) == null,
19161911 .simple_skip_release_small = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseSmall) == null,
1917 .skip_translate_c = skip_translate_c,
19181912 });
19191913 const test_cases_dep_step = test_cases_dep.builder.default_step;
19201914 test_cases_dep_step.name = b.dupe(test_cases_dep_name);
......@@ -2155,42 +2149,6 @@ pub fn addCliTests(b: *std.Build) *Step {
21552149 return step;
21562150}
21572151
2158pub fn addTranslateCTests(
2159 b: *std.Build,
2160 parent_step: *std.Build.Step,
2161 test_filters: []const []const u8,
2162 test_target_filters: []const []const u8,
2163) void {
2164 const cases = b.allocator.create(TranslateCContext) catch @panic("OOM");
2165 cases.* = TranslateCContext{
2166 .b = b,
2167 .step = parent_step,
2168 .test_index = 0,
2169 .test_filters = test_filters,
2170 .test_target_filters = test_target_filters,
2171 };
2172
2173 translate_c.addCases(cases);
2174}
2175
2176pub fn addRunTranslatedCTests(
2177 b: *std.Build,
2178 parent_step: *std.Build.Step,
2179 test_filters: []const []const u8,
2180 target: std.Build.ResolvedTarget,
2181) void {
2182 const cases = b.allocator.create(RunTranslatedCContext) catch @panic("OOM");
2183 cases.* = .{
2184 .b = b,
2185 .step = parent_step,
2186 .test_index = 0,
2187 .test_filters = test_filters,
2188 .target = target,
2189 };
2190
2191 run_translated_c.addCases(cases);
2192}
2193
21942152const ModuleTestOptions = struct {
21952153 test_filters: []const []const u8,
21962154 test_target_filters: []const []const u8,
......@@ -2558,9 +2516,7 @@ pub fn addCAbiTests(b: *std.Build, options: CAbiTestOptions) *Step {
25582516pub fn addCases(
25592517 b: *std.Build,
25602518 parent_step: *Step,
2561 target: std.Build.ResolvedTarget,
25622519 case_test_options: @import("src/Cases.zig").CaseTestOptions,
2563 translate_c_options: @import("src/Cases.zig").TranslateCOptions,
25642520 build_options: @import("cases.zig").BuildOptions,
25652521) !void {
25662522 const arena = b.allocator;
......@@ -2574,15 +2530,6 @@ pub fn addCases(
25742530 cases.addFromDir(dir, b);
25752531 try @import("cases.zig").addCases(&cases, build_options, b);
25762532
2577 cases.lowerToTranslateCSteps(
2578 b,
2579 parent_step,
2580 case_test_options.test_filters,
2581 case_test_options.test_target_filters,
2582 target,
2583 translate_c_options,
2584 );
2585
25862533 cases.lowerToBuildSteps(
25872534 b,
25882535 parent_step,
test/translate_c.zig deleted-3923
......@@ -1,3923 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const tests = @import("tests.zig");
4
5// ********************************************************
6// * *
7// * DO NOT ADD NEW CASES HERE *
8// * instead add a file to test/cases/translate_c *
9// * *
10// ********************************************************
11
12pub fn addCases(cases: *tests.TranslateCContext) void {
13 const default_enum_type = if (builtin.abi == .msvc) "c_int" else "c_uint";
14
15 cases.add("do while with breaks",
16 \\void foo(int a) {
17 \\ do {
18 \\ if (a) break;
19 \\ } while (4);
20 \\ do {
21 \\ if (a) break;
22 \\ } while (0);
23 \\ do {
24 \\ if (a) break;
25 \\ } while (a);
26 \\ do {
27 \\ break;
28 \\ } while (3);
29 \\ do {
30 \\ break;
31 \\ } while (0);
32 \\ do {
33 \\ break;
34 \\ } while (a);
35 \\}
36 , &[_][]const u8{
37 \\pub export fn foo(arg_a: c_int) void {
38 \\ var a = arg_a;
39 \\ _ = &a;
40 \\ while (true) {
41 \\ if (a != 0) break;
42 \\ }
43 \\ while (true) {
44 \\ if (a != 0) break;
45 \\ if (!false) break;
46 \\ }
47 \\ while (true) {
48 \\ if (a != 0) break;
49 \\ if (!(a != 0)) break;
50 \\ }
51 \\ while (true) {
52 \\ break;
53 \\ }
54 \\ while (true) {
55 \\ break;
56 \\ }
57 \\ while (true) {
58 \\ break;
59 \\ }
60 \\}
61 });
62
63 cases.add("variables check for opaque demotion",
64 \\struct A {
65 \\ _Atomic int a;
66 \\} a;
67 \\int main(void) {
68 \\ struct A a;
69 \\}
70 , &[_][]const u8{
71 \\pub const struct_A = opaque {};
72 \\pub const a = @compileError("non-extern variable has opaque type");
73 ,
74 \\pub extern fn main() c_int;
75 });
76
77 cases.add("unnamed child types of typedef receive typedef's name",
78 \\typedef enum {
79 \\ FooA,
80 \\ FooB,
81 \\} Foo;
82 \\typedef struct {
83 \\ int a, b;
84 \\} Bar;
85 , &[_][]const u8{
86 \\pub const FooA: c_int = 0;
87 \\pub const FooB: c_int = 1;
88 \\pub const Foo =
89 ++ " " ++ default_enum_type ++
90 \\;
91 \\pub const Bar = extern struct {
92 \\ a: c_int = @import("std").mem.zeroes(c_int),
93 \\ b: c_int = @import("std").mem.zeroes(c_int),
94 \\};
95 });
96
97 cases.add("if as while stmt has semicolon",
98 \\void foo() {
99 \\ while (1) if (1) {
100 \\ int a = 1;
101 \\ } else {
102 \\ int b = 2;
103 \\ }
104 \\ if (1) if (1) {}
105 \\}
106 , &[_][]const u8{
107 \\pub export fn foo() void {
108 \\ while (true) if (true) {
109 \\ var a: c_int = 1;
110 \\ _ = &a;
111 \\ } else {
112 \\ var b: c_int = 2;
113 \\ _ = &b;
114 \\ };
115 \\ if (true) if (true) {};
116 \\}
117 });
118
119 cases.add("conditional operator cast to void",
120 \\int bar();
121 \\void foo() {
122 \\ int a;
123 \\ a ? a = 2 : bar();
124 \\}
125 , &[_][]const u8{
126 \\pub extern fn bar(...) c_int;
127 \\pub export fn foo() void {
128 \\ var a: c_int = undefined;
129 \\ _ = &a;
130 \\ if (a != 0) a = 2 else _ = bar();
131 \\}
132 });
133
134 cases.add("scoped typedef",
135 \\void foo() {
136 \\ typedef union {
137 \\ int A;
138 \\ int B;
139 \\ int C;
140 \\ } Foo;
141 \\ Foo a = {0};
142 \\ {
143 \\ typedef union {
144 \\ int A;
145 \\ int B;
146 \\ int C;
147 \\ } Foo;
148 \\ Foo a = {0};
149 \\ }
150 \\}
151 , &[_][]const u8{
152 \\pub export fn foo() void {
153 \\ const union_unnamed_1 = extern union {
154 \\ A: c_int,
155 \\ B: c_int,
156 \\ C: c_int,
157 \\ };
158 \\ _ = &union_unnamed_1;
159 \\ const Foo = union_unnamed_1;
160 \\ _ = &Foo;
161 \\ var a: Foo = Foo{
162 \\ .A = @as(c_int, 0),
163 \\ };
164 \\ _ = &a;
165 \\ {
166 \\ const union_unnamed_2 = extern union {
167 \\ A: c_int,
168 \\ B: c_int,
169 \\ C: c_int,
170 \\ };
171 \\ _ = &union_unnamed_2;
172 \\ const Foo_1 = union_unnamed_2;
173 \\ _ = &Foo_1;
174 \\ var a_2: Foo_1 = Foo_1{
175 \\ .A = @as(c_int, 0),
176 \\ };
177 \\ _ = &a_2;
178 \\ }
179 \\}
180 });
181
182 cases.add("use cast param as macro fn return type",
183 \\#include <stdint.h>
184 \\#define SYS_BASE_CACHED 0
185 \\#define MEM_PHYSICAL_TO_K0(x) (void*)((uint32_t)(x) + SYS_BASE_CACHED)
186 , &[_][]const u8{
187 \\pub inline fn MEM_PHYSICAL_TO_K0(x: anytype) ?*anyopaque {
188 \\ _ = &x;
189 \\ return @import("std").zig.c_translation.cast(?*anyopaque, @import("std").zig.c_translation.cast(u32, x) + SYS_BASE_CACHED);
190 \\}
191 });
192
193 cases.add("variadic function demoted to extern",
194 \\int foo(int bar, ...) {
195 \\ return 1;
196 \\}
197 , &[_][]const u8{
198 \\warning: TODO unable to translate variadic function, demoted to extern
199 \\pub extern fn foo(bar: c_int, ...) c_int;
200 });
201
202 cases.add("pointer to opaque demoted struct",
203 \\typedef struct {
204 \\ _Atomic int foo;
205 \\} Foo;
206 \\
207 \\typedef struct {
208 \\ Foo *bar;
209 \\} Bar;
210 , &[_][]const u8{
211 \\source.h:1:9: warning: struct demoted to opaque type - unable to translate type of field foo
212 \\pub const Foo = opaque {};
213 \\pub const Bar = extern struct {
214 \\ bar: ?*Foo = @import("std").mem.zeroes(?*Foo),
215 \\};
216 });
217
218 cases.add("macro expressions respect C operator precedence",
219 \\int *foo = 0;
220 \\#define FOO *((foo) + 2)
221 \\#define VALUE (1 + 2 * 3 + 4 * 5 + 6 << 7 | 8 == 9)
222 \\#define _AL_READ3BYTES(p) ((*(unsigned char *)(p)) \
223 \\ | (*((unsigned char *)(p) + 1) << 8) \
224 \\ | (*((unsigned char *)(p) + 2) << 16))
225 , &[_][]const u8{
226 \\pub inline fn FOO() @TypeOf((foo + @as(c_int, 2)).*) {
227 \\ return (foo + @as(c_int, 2)).*;
228 \\}
229 ,
230 \\pub const VALUE = ((((@as(c_int, 1) + (@as(c_int, 2) * @as(c_int, 3))) + (@as(c_int, 4) * @as(c_int, 5))) + @as(c_int, 6)) << @as(c_int, 7)) | @intFromBool(@as(c_int, 8) == @as(c_int, 9));
231 ,
232 \\pub inline fn _AL_READ3BYTES(p: anytype) @TypeOf((@import("std").zig.c_translation.cast([*c]u8, p).* | ((@import("std").zig.c_translation.cast([*c]u8, p) + @as(c_int, 1)).* << @as(c_int, 8))) | ((@import("std").zig.c_translation.cast([*c]u8, p) + @as(c_int, 2)).* << @as(c_int, 16))) {
233 \\ _ = &p;
234 \\ return (@import("std").zig.c_translation.cast([*c]u8, p).* | ((@import("std").zig.c_translation.cast([*c]u8, p) + @as(c_int, 1)).* << @as(c_int, 8))) | ((@import("std").zig.c_translation.cast([*c]u8, p) + @as(c_int, 2)).* << @as(c_int, 16));
235 \\}
236 });
237
238 cases.add("static variable in block scope",
239 \\float bar;
240 \\int foo() {
241 \\ _Thread_local static int bar = 2;
242 \\}
243 , &[_][]const u8{
244 \\pub export var bar: f32 = @import("std").mem.zeroes(f32);
245 \\pub export fn foo() c_int {
246 \\ const bar_1 = struct {
247 \\ threadlocal var static: c_int = 2;
248 \\ };
249 \\ _ = &bar_1;
250 \\ return 0;
251 \\}
252 });
253
254 cases.add("missing return stmt",
255 \\int foo() {}
256 \\int bar() {
257 \\ int a = 2;
258 \\}
259 \\int baz() {
260 \\ return 0;
261 \\}
262 , &[_][]const u8{
263 \\pub export fn foo() c_int {
264 \\ return 0;
265 \\}
266 \\pub export fn bar() c_int {
267 \\ var a: c_int = 2;
268 \\ _ = &a;
269 \\ return 0;
270 \\}
271 \\pub export fn baz() c_int {
272 \\ return 0;
273 \\}
274 });
275
276 cases.add("alignof",
277 \\void main() {
278 \\ int a = _Alignof(int);
279 \\}
280 , &[_][]const u8{
281 \\pub export fn main() void {
282 \\ var a: c_int = @as(c_int, @bitCast(@as(c_uint, @truncate(@alignOf(c_int)))));
283 \\ _ = &a;
284 \\}
285 });
286
287 cases.add("initializer list macro",
288 \\typedef struct Color {
289 \\ unsigned char r;
290 \\ unsigned char g;
291 \\ unsigned char b;
292 \\ unsigned char a;
293 \\} Color;
294 \\#define CLITERAL(type) (type)
295 \\#define LIGHTGRAY CLITERAL(Color){ 200, 200, 200, 255 } // Light Gray
296 \\typedef struct boom_t
297 \\{
298 \\ int i1;
299 \\} boom_t;
300 \\#define FOO ((boom_t){1})
301 \\typedef struct { float x; } MyCStruct;
302 \\#define A(_x) (MyCStruct) { .x = (_x) }
303 \\#define B A(0.f)
304 , &[_][]const u8{
305 \\pub const struct_Color = extern struct {
306 \\ r: u8 = @import("std").mem.zeroes(u8),
307 \\ g: u8 = @import("std").mem.zeroes(u8),
308 \\ b: u8 = @import("std").mem.zeroes(u8),
309 \\ a: u8 = @import("std").mem.zeroes(u8),
310 \\};
311 \\pub const Color = struct_Color;
312 ,
313 \\pub inline fn CLITERAL(@"type": anytype) @TypeOf(@"type") {
314 \\ _ = &@"type";
315 \\ return @"type";
316 \\}
317 ,
318 \\pub const LIGHTGRAY = @import("std").mem.zeroInit(CLITERAL(Color), .{ @as(c_int, 200), @as(c_int, 200), @as(c_int, 200), @as(c_int, 255) });
319 ,
320 \\pub const struct_boom_t = extern struct {
321 \\ i1: c_int = @import("std").mem.zeroes(c_int),
322 \\};
323 \\pub const boom_t = struct_boom_t;
324 ,
325 \\pub const FOO = @import("std").mem.zeroInit(boom_t, .{@as(c_int, 1)});
326 ,
327 \\pub const MyCStruct = extern struct {
328 \\ x: f32 = @import("std").mem.zeroes(f32),
329 \\};
330 ,
331 \\pub inline fn A(_x: anytype) MyCStruct {
332 \\ _ = &_x;
333 \\ return @import("std").mem.zeroInit(MyCStruct, .{
334 \\ .x = _x,
335 \\ });
336 \\}
337 ,
338 \\pub const B = A(@as(f32, 0));
339 });
340
341 cases.add("complex switch",
342 \\int main() {
343 \\ int i = 2;
344 \\ switch (i) {
345 \\ case 0: {
346 \\ case 2:{
347 \\ i += 2;}
348 \\ i += 1;
349 \\ }
350 \\ }
351 \\}
352 , &[_][]const u8{ // TODO properly translate this
353 \\source.h:5:13: warning: TODO complex switch
354 ,
355 \\source.h:1:5: warning: unable to translate function, demoted to extern
356 \\pub extern fn main() c_int;
357 });
358
359 cases.add("correct semicolon after infixop",
360 \\#define _IO_ERR_SEEN 0
361 \\#define __ferror_unlocked_body(_fp) (((_fp)->_flags & _IO_ERR_SEEN) != 0)
362 , &[_][]const u8{
363 \\pub inline fn __ferror_unlocked_body(_fp: anytype) @TypeOf((_fp.*._flags & _IO_ERR_SEEN) != @as(c_int, 0)) {
364 \\ _ = &_fp;
365 \\ return (_fp.*._flags & _IO_ERR_SEEN) != @as(c_int, 0);
366 \\}
367 });
368
369 cases.add("c booleans are just ints",
370 \\#define FOO(x) ((x >= 0) + (x >= 0))
371 \\#define BAR 1 && 2 > 4
372 , &[_][]const u8{
373 \\pub inline fn FOO(x: anytype) @TypeOf(@intFromBool(x >= @as(c_int, 0)) + @intFromBool(x >= @as(c_int, 0))) {
374 \\ _ = &x;
375 \\ return @intFromBool(x >= @as(c_int, 0)) + @intFromBool(x >= @as(c_int, 0));
376 \\}
377 ,
378 \\pub const BAR = (@as(c_int, 1) != 0) and (@as(c_int, 2) > @as(c_int, 4));
379 });
380
381 cases.add("struct with flexible array",
382 \\struct foo { int x; int y[]; };
383 \\struct bar { int x; int y[0]; };
384 , &[_][]const u8{
385 \\pub const struct_foo = extern struct {
386 \\ x: c_int align(4) = @import("std").mem.zeroes(c_int),
387 \\ pub fn y(self: anytype) @import("std").zig.c_translation.FlexibleArrayType(@TypeOf(self), c_int) {
388 \\ const Intermediate = @import("std").zig.c_translation.FlexibleArrayType(@TypeOf(self), u8);
389 \\ const ReturnType = @import("std").zig.c_translation.FlexibleArrayType(@TypeOf(self), c_int);
390 \\ return @as(ReturnType, @ptrCast(@alignCast(@as(Intermediate, @ptrCast(self)) + 4)));
391 \\ }
392 \\};
393 \\pub const struct_bar = extern struct {
394 \\ x: c_int align(4) = @import("std").mem.zeroes(c_int),
395 \\ pub fn y(self: anytype) @import("std").zig.c_translation.FlexibleArrayType(@TypeOf(self), c_int) {
396 \\ const Intermediate = @import("std").zig.c_translation.FlexibleArrayType(@TypeOf(self), u8);
397 \\ const ReturnType = @import("std").zig.c_translation.FlexibleArrayType(@TypeOf(self), c_int);
398 \\ return @as(ReturnType, @ptrCast(@alignCast(@as(Intermediate, @ptrCast(self)) + 4)));
399 \\ }
400 \\};
401 });
402
403 cases.add("nested loops without blocks",
404 \\void foo() {
405 \\ while (0) while (0) {}
406 \\ for (;;) while (0);
407 \\ for (;;) do {} while (0);
408 \\}
409 , &[_][]const u8{
410 \\pub export fn foo() void {
411 \\ while (false) while (false) {};
412 \\ while (true) while (false) {};
413 \\ while (true) while (true) {
414 \\ if (!false) break;
415 \\ };
416 \\}
417 });
418
419 cases.add("macro comma operator",
420 \\#define foo (foo, bar)
421 \\int baz(int x, int y) { return 0; }
422 \\#define bar(x) (&x, +3, 4 == 4, 5 * 6, baz(1, 2), 2 % 2, baz(1,2))
423 , &[_][]const u8{
424 \\pub const foo = blk_1: {
425 \\ _ = &foo;
426 \\ break :blk_1 bar;
427 \\};
428 ,
429 \\pub inline fn bar(x: anytype) @TypeOf(baz(@as(c_int, 1), @as(c_int, 2))) {
430 \\ _ = &x;
431 \\ return blk_1: {
432 \\ _ = &x;
433 \\ _ = @as(c_int, 3);
434 \\ _ = @as(c_int, 4) == @as(c_int, 4);
435 \\ _ = @as(c_int, 5) * @as(c_int, 6);
436 \\ _ = baz(@as(c_int, 1), @as(c_int, 2));
437 \\ _ = @import("std").zig.c_translation.MacroArithmetic.rem(@as(c_int, 2), @as(c_int, 2));
438 \\ break :blk_1 baz(@as(c_int, 1), @as(c_int, 2));
439 \\ };
440 \\}
441 });
442
443 cases.add("macro keyword define",
444 \\#define foo 1
445 \\#define inline 2
446 , &[_][]const u8{
447 \\pub const foo = @as(c_int, 1);
448 ,
449 \\pub const @"inline" = @as(c_int, 2);
450 });
451
452 cases.add("macro line continuation",
453 \\int BAR = 0;
454 \\#define FOO -\
455 \\BAR
456 , &[_][]const u8{
457 \\pub inline fn FOO() @TypeOf(-BAR) {
458 \\ return -BAR;
459 \\}
460 });
461
462 cases.add("struct with atomic field",
463 \\struct arcan_shmif_cont {
464 \\ struct arcan_shmif_page* addr;
465 \\};
466 \\struct arcan_shmif_page {
467 \\ volatile _Atomic int abufused[12];
468 \\};
469 , &[_][]const u8{
470 \\source.h:4:8: warning: struct demoted to opaque type - unable to translate type of field abufused
471 \\pub const struct_arcan_shmif_page = opaque {};
472 \\pub const struct_arcan_shmif_cont = extern struct {
473 \\ addr: ?*struct_arcan_shmif_page = @import("std").mem.zeroes(?*struct_arcan_shmif_page),
474 \\};
475 });
476
477 cases.add("function prototype translated as optional",
478 \\typedef void (*fnptr_ty)(void);
479 \\typedef __attribute__((cdecl)) void (*fnptr_attr_ty)(void);
480 \\struct foo {
481 \\ __attribute__((cdecl)) void (*foo)(void);
482 \\ void (*bar)(void);
483 \\ fnptr_ty baz;
484 \\ fnptr_attr_ty qux;
485 \\};
486 , &[_][]const u8{
487 \\pub const fnptr_ty = ?*const fn () callconv(.c) void;
488 \\pub const fnptr_attr_ty = ?*const fn () callconv(.c) void;
489 \\pub const struct_foo = extern struct {
490 \\ foo: ?*const fn () callconv(.c) void = @import("std").mem.zeroes(?*const fn () callconv(.c) void),
491 \\ bar: ?*const fn () callconv(.c) void = @import("std").mem.zeroes(?*const fn () callconv(.c) void),
492 \\ baz: fnptr_ty = @import("std").mem.zeroes(fnptr_ty),
493 \\ qux: fnptr_attr_ty = @import("std").mem.zeroes(fnptr_attr_ty),
494 \\};
495 });
496
497 cases.add("array initializer w/ typedef",
498 \\typedef unsigned char uuid_t[16];
499 \\static const uuid_t UUID_NULL __attribute__ ((unused)) = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
500 , &[_][]const u8{
501 \\pub const uuid_t = [16]u8;
502 \\pub const UUID_NULL: uuid_t = [16]u8{
503 \\ 0,
504 \\ 0,
505 \\ 0,
506 \\ 0,
507 \\ 0,
508 \\ 0,
509 \\ 0,
510 \\ 0,
511 \\ 0,
512 \\ 0,
513 \\ 0,
514 \\ 0,
515 \\ 0,
516 \\ 0,
517 \\ 0,
518 \\ 0,
519 \\};
520 });
521
522 cases.add("#define hex literal with capital X",
523 \\#define VAL 0XF00D
524 , &[_][]const u8{
525 \\pub const VAL = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xF00D, .hex);
526 });
527
528 cases.add("anonymous struct & unions",
529 \\typedef struct {
530 \\ union {
531 \\ char x;
532 \\ struct { int y; };
533 \\ };
534 \\} outer;
535 \\void foo(outer *x) { x->y = x->x; }
536 , &[_][]const u8{
537 \\const struct_unnamed_2 = extern struct {
538 \\ y: c_int = @import("std").mem.zeroes(c_int),
539 \\};
540 \\const union_unnamed_1 = extern union {
541 \\ x: u8,
542 \\ unnamed_0: struct_unnamed_2,
543 \\};
544 \\pub const outer = extern struct {
545 \\ unnamed_0: union_unnamed_1 = @import("std").mem.zeroes(union_unnamed_1),
546 \\};
547 \\pub export fn foo(arg_x: [*c]outer) void {
548 \\ var x = arg_x;
549 \\ _ = &x;
550 \\ x.*.unnamed_0.unnamed_0.y = @as(c_int, @bitCast(@as(c_uint, x.*.unnamed_0.x)));
551 \\}
552 });
553
554 cases.add("struct initializer - simple",
555 \\typedef struct { int x; } foo;
556 \\struct {double x,y,z;} s0 = {1.2, 1.3};
557 \\struct {int sec,min,hour,day,mon,year;} s1 = {.day=31,12,2014,.sec=30,15,17};
558 \\struct {int x,y;} s2 = {.y = 2, .x=1};
559 \\foo s3 = { 123 };
560 , &[_][]const u8{
561 \\pub const foo = extern struct {
562 \\ x: c_int = @import("std").mem.zeroes(c_int),
563 \\};
564 \\const struct_unnamed_1 = extern struct {
565 \\ x: f64 = @import("std").mem.zeroes(f64),
566 \\ y: f64 = @import("std").mem.zeroes(f64),
567 \\ z: f64 = @import("std").mem.zeroes(f64),
568 \\};
569 \\pub export var s0: struct_unnamed_1 = struct_unnamed_1{
570 \\ .x = 1.2,
571 \\ .y = 1.3,
572 \\ .z = 0,
573 \\};
574 \\const struct_unnamed_2 = extern struct {
575 \\ sec: c_int = @import("std").mem.zeroes(c_int),
576 \\ min: c_int = @import("std").mem.zeroes(c_int),
577 \\ hour: c_int = @import("std").mem.zeroes(c_int),
578 \\ day: c_int = @import("std").mem.zeroes(c_int),
579 \\ mon: c_int = @import("std").mem.zeroes(c_int),
580 \\ year: c_int = @import("std").mem.zeroes(c_int),
581 \\};
582 \\pub export var s1: struct_unnamed_2 = struct_unnamed_2{
583 \\ .sec = @as(c_int, 30),
584 \\ .min = @as(c_int, 15),
585 \\ .hour = @as(c_int, 17),
586 \\ .day = @as(c_int, 31),
587 \\ .mon = @as(c_int, 12),
588 \\ .year = @as(c_int, 2014),
589 \\};
590 \\const struct_unnamed_3 = extern struct {
591 \\ x: c_int = @import("std").mem.zeroes(c_int),
592 \\ y: c_int = @import("std").mem.zeroes(c_int),
593 \\};
594 \\pub export var s2: struct_unnamed_3 = struct_unnamed_3{
595 \\ .x = @as(c_int, 1),
596 \\ .y = @as(c_int, 2),
597 \\};
598 \\pub export var s3: foo = foo{
599 \\ .x = @as(c_int, 123),
600 \\};
601 });
602
603 cases.add("simple ptrCast for casts between opaque types",
604 \\struct opaque;
605 \\struct opaque_2;
606 \\void function(struct opaque *opaque) {
607 \\ struct opaque_2 *cast = (struct opaque_2 *)opaque;
608 \\}
609 , &[_][]const u8{
610 \\pub const struct_opaque = opaque {};
611 \\pub const struct_opaque_2 = opaque {};
612 \\pub export fn function(arg_opaque_1: ?*struct_opaque) void {
613 \\ var opaque_1 = arg_opaque_1;
614 \\ _ = &opaque_1;
615 \\ var cast: ?*struct_opaque_2 = @as(?*struct_opaque_2, @ptrCast(opaque_1));
616 \\ _ = &cast;
617 \\}
618 });
619
620 cases.add("struct initializer - packed",
621 \\struct {int x,y,z;} __attribute__((packed)) s0 = {1, 2};
622 , &[_][]const u8{
623 \\const struct_unnamed_1 = extern struct {
624 \\ x: c_int align(1) = @import("std").mem.zeroes(c_int),
625 \\ y: c_int align(1) = @import("std").mem.zeroes(c_int),
626 \\ z: c_int align(1) = @import("std").mem.zeroes(c_int),
627 \\};
628 \\pub export var s0: struct_unnamed_1 = struct_unnamed_1{
629 \\ .x = @as(c_int, 1),
630 \\ .y = @as(c_int, 2),
631 \\ .z = 0,
632 \\};
633 });
634
635 cases.add("linksection() attribute",
636 \\// Use the "segment,section" format to make this test pass when
637 \\// targeting the mach-o binary format
638 \\__attribute__ ((__section__("NEAR,.data")))
639 \\extern char my_array[16];
640 \\__attribute__ ((__section__("NEAR,.data")))
641 \\void my_fn(void) { }
642 , &[_][]const u8{
643 \\pub extern var my_array: [16]u8 linksection("NEAR,.data");
644 \\pub export fn my_fn() linksection("NEAR,.data") void {}
645 });
646
647 cases.add("simple var decls",
648 \\void foo(void) {
649 \\ int a;
650 \\ char b = 123;
651 \\ const int c;
652 \\ const unsigned d = 440;
653 \\ int e = 10;
654 \\ unsigned int f = 10u;
655 \\}
656 , &[_][]const u8{
657 \\pub export fn foo() void {
658 \\ var a: c_int = undefined;
659 \\ _ = &a;
660 \\ var b: u8 = 123;
661 \\ _ = &b;
662 \\ const c: c_int = undefined;
663 \\ _ = &c;
664 \\ const d: c_uint = @as(c_uint, @bitCast(@as(c_int, 440)));
665 \\ _ = &d;
666 \\ var e: c_int = 10;
667 \\ _ = &e;
668 \\ var f: c_uint = 10;
669 \\ _ = &f;
670 \\}
671 });
672
673 cases.add("ignore result, explicit function arguments",
674 \\void foo(void) {
675 \\ int a;
676 \\ 1;
677 \\ "hey";
678 \\ 1 + 1;
679 \\ 1 - 1;
680 \\ a = 1;
681 \\}
682 , &[_][]const u8{
683 \\pub export fn foo() void {
684 \\ var a: c_int = undefined;
685 \\ _ = &a;
686 \\ _ = @as(c_int, 1);
687 \\ _ = "hey";
688 \\ _ = @as(c_int, 1) + @as(c_int, 1);
689 \\ _ = @as(c_int, 1) - @as(c_int, 1);
690 \\ a = 1;
691 \\}
692 });
693
694 cases.add("function with no prototype",
695 \\int foo() {
696 \\ return 5;
697 \\}
698 , &[_][]const u8{
699 \\pub export fn foo() c_int {
700 \\ return 5;
701 \\}
702 });
703
704 cases.add("variables",
705 \\extern int extern_var;
706 \\static const int int_var = 13;
707 \\int foo;
708 , &[_][]const u8{
709 \\pub extern var extern_var: c_int;
710 \\pub const int_var: c_int = 13;
711 \\pub export var foo: c_int = @import("std").mem.zeroes(c_int);
712 });
713
714 cases.add("const ptr initializer",
715 \\static const char *v0 = "0.0.0";
716 , &[_][]const u8{
717 \\pub var v0: [*c]const u8 = "0.0.0";
718 });
719
720 cases.add("static incomplete array inside function",
721 \\void foo(void) {
722 \\ static const char v2[] = "2.2.2";
723 \\}
724 , &[_][]const u8{
725 \\pub export fn foo() void {
726 \\ const v2 = struct {
727 \\ const static: [5:0]u8 = "2.2.2".*;
728 \\ };
729 \\ _ = &v2;
730 \\}
731 });
732
733 cases.add("simple function definition",
734 \\void foo(void) {}
735 \\static void bar(void) {}
736 , &[_][]const u8{
737 \\pub export fn foo() void {}
738 \\pub fn bar() callconv(.c) void {}
739 });
740
741 cases.add("typedef void",
742 \\typedef void Foo;
743 \\Foo fun(Foo *a);
744 , &[_][]const u8{
745 \\pub const Foo = anyopaque;
746 ,
747 \\pub extern fn fun(a: ?*Foo) void;
748 });
749
750 cases.add("duplicate typedef",
751 \\typedef long foo;
752 \\typedef int bar;
753 \\typedef long foo;
754 \\typedef int baz;
755 , &[_][]const u8{
756 \\pub const foo = c_long;
757 \\pub const bar = c_int;
758 \\pub const baz = c_int;
759 });
760
761 cases.add("casting pointers to ints and ints to pointers",
762 \\void foo(void);
763 \\void bar(void) {
764 \\ void *func_ptr = foo;
765 \\ void (*typed_func_ptr)(void) = (void (*)(void)) (unsigned long) func_ptr;
766 \\}
767 , &[_][]const u8{
768 \\pub extern fn foo() void;
769 \\pub export fn bar() void {
770 \\ var func_ptr: ?*anyopaque = @as(?*anyopaque, @ptrCast(&foo));
771 \\ _ = &func_ptr;
772 \\ var typed_func_ptr: ?*const fn () callconv(.c) void = @as(?*const fn () callconv(.c) void, @ptrFromInt(@as(c_ulong, @intCast(@intFromPtr(func_ptr)))));
773 \\ _ = &typed_func_ptr;
774 \\}
775 });
776
777 cases.add("always_inline attribute",
778 \\__attribute__((always_inline)) int foo() {
779 \\ return 5;
780 \\}
781 , &[_][]const u8{
782 \\pub inline fn foo() c_int {
783 \\ return 5;
784 \\}
785 });
786
787 cases.add("add, sub, mul, div, rem",
788 \\int s() {
789 \\ int a, b, c;
790 \\ c = a + b;
791 \\ c = a - b;
792 \\ c = a * b;
793 \\ c = a / b;
794 \\ c = a % b;
795 \\}
796 \\unsigned u() {
797 \\ unsigned a, b, c;
798 \\ c = a + b;
799 \\ c = a - b;
800 \\ c = a * b;
801 \\ c = a / b;
802 \\ c = a % b;
803 \\}
804 , &[_][]const u8{
805 \\pub export fn s() c_int {
806 \\ var a: c_int = undefined;
807 \\ _ = &a;
808 \\ var b: c_int = undefined;
809 \\ _ = &b;
810 \\ var c: c_int = undefined;
811 \\ _ = &c;
812 \\ c = a + b;
813 \\ c = a - b;
814 \\ c = a * b;
815 \\ c = @divTrunc(a, b);
816 \\ c = @import("std").zig.c_translation.signedRemainder(a, b);
817 \\ return 0;
818 \\}
819 \\pub export fn u() c_uint {
820 \\ var a: c_uint = undefined;
821 \\ _ = &a;
822 \\ var b: c_uint = undefined;
823 \\ _ = &b;
824 \\ var c: c_uint = undefined;
825 \\ _ = &c;
826 \\ c = a +% b;
827 \\ c = a -% b;
828 \\ c = a *% b;
829 \\ c = a / b;
830 \\ c = a % b;
831 \\ return 0;
832 \\}
833 });
834
835 cases.add("typedef of function in struct field",
836 \\typedef void lws_callback_function(void);
837 \\struct Foo {
838 \\ void (*func)(void);
839 \\ lws_callback_function *callback_http;
840 \\};
841 , &[_][]const u8{
842 \\pub const lws_callback_function = fn () callconv(.c) void;
843 \\pub const struct_Foo = extern struct {
844 \\ func: ?*const fn () callconv(.c) void = @import("std").mem.zeroes(?*const fn () callconv(.c) void),
845 \\ callback_http: ?*const lws_callback_function = @import("std").mem.zeroes(?*const lws_callback_function),
846 \\};
847 });
848
849 cases.add("macro with left shift",
850 \\#define REDISMODULE_READ (1<<0)
851 , &[_][]const u8{
852 \\pub const REDISMODULE_READ = @as(c_int, 1) << @as(c_int, 0);
853 });
854
855 cases.add("macro with right shift",
856 \\#define FLASH_SIZE 0x200000UL /* 2 MB */
857 \\#define FLASH_BANK_SIZE (FLASH_SIZE >> 1) /* 1 MB */
858 , &[_][]const u8{
859 \\pub const FLASH_SIZE = @as(c_ulong, 0x200000);
860 ,
861 \\pub const FLASH_BANK_SIZE = FLASH_SIZE >> @as(c_int, 1);
862 });
863
864 cases.add("self referential struct with function pointer",
865 \\struct Foo {
866 \\ void (*derp)(struct Foo *foo);
867 \\};
868 , &[_][]const u8{
869 \\pub const struct_Foo = extern struct {
870 \\ derp: ?*const fn ([*c]struct_Foo) callconv(.c) void = @import("std").mem.zeroes(?*const fn ([*c]struct_Foo) callconv(.c) void),
871 \\};
872 ,
873 \\pub const Foo = struct_Foo;
874 });
875
876 cases.add("#define an unsigned integer literal",
877 \\#define CHANNEL_COUNT 24
878 , &[_][]const u8{
879 \\pub const CHANNEL_COUNT = @as(c_int, 24);
880 });
881
882 cases.add("#define referencing another #define",
883 \\#define THING2 THING1
884 \\#define THING1 1234
885 , &[_][]const u8{
886 \\pub const THING1 = @as(c_int, 1234);
887 ,
888 \\pub const THING2 = THING1;
889 });
890
891 cases.add("#define string",
892 \\#define foo "a string"
893 , &[_][]const u8{
894 \\pub const foo = "a string";
895 });
896
897 cases.add("macro with parens around negative number",
898 \\#define LUA_GLOBALSINDEX (-10002)
899 , &[_][]const u8{
900 \\pub const LUA_GLOBALSINDEX = -@as(c_int, 10002);
901 });
902
903 cases.add(
904 "u integer suffix after 0 (zero) in macro definition",
905 "#define ZERO 0U",
906 &[_][]const u8{
907 "pub const ZERO = @as(c_uint, 0);",
908 },
909 );
910
911 cases.add(
912 "l integer suffix after 0 (zero) in macro definition",
913 "#define ZERO 0L",
914 &[_][]const u8{
915 "pub const ZERO = @as(c_long, 0);",
916 },
917 );
918
919 cases.add(
920 "ul integer suffix after 0 (zero) in macro definition",
921 "#define ZERO 0UL",
922 &[_][]const u8{
923 "pub const ZERO = @as(c_ulong, 0);",
924 },
925 );
926
927 cases.add(
928 "lu integer suffix after 0 (zero) in macro definition",
929 "#define ZERO 0LU",
930 &[_][]const u8{
931 "pub const ZERO = @as(c_ulong, 0);",
932 },
933 );
934
935 cases.add(
936 "ll integer suffix after 0 (zero) in macro definition",
937 "#define ZERO 0LL",
938 &[_][]const u8{
939 "pub const ZERO = @as(c_longlong, 0);",
940 },
941 );
942
943 cases.add(
944 "ull integer suffix after 0 (zero) in macro definition",
945 "#define ZERO 0ULL",
946 &[_][]const u8{
947 "pub const ZERO = @as(c_ulonglong, 0);",
948 },
949 );
950
951 cases.add(
952 "llu integer suffix after 0 (zero) in macro definition",
953 "#define ZERO 0LLU",
954 &[_][]const u8{
955 "pub const ZERO = @as(c_ulonglong, 0);",
956 },
957 );
958
959 cases.add(
960 "bitwise not on u-suffixed 0 (zero) in macro definition",
961 "#define NOT_ZERO (~0U)",
962 &[_][]const u8{
963 "pub const NOT_ZERO = ~@as(c_uint, 0);",
964 },
965 );
966
967 cases.add("float suffixes",
968 \\#define foo 3.14f
969 \\#define bar 16.e-2l
970 \\#define FOO 0.12345
971 \\#define BAR .12345
972 \\#define baz 1e1
973 \\#define BAZ 42e-3f
974 \\#define foobar -73.L
975 \\extern const float my_float = 1.0f;
976 \\extern const double my_double = 1.0;
977 \\extern const long double my_longdouble = 1.0l;
978 \\extern const long double my_extended_precision_longdouble = 1.0000000000000003l;
979 , &([_][]const u8{
980 "pub const foo = @as(f32, 3.14);",
981 "pub const bar = @as(c_longdouble, 16.e-2);",
982 "pub const FOO = @as(f64, 0.12345);",
983 "pub const BAR = @as(f64, 0.12345);",
984 "pub const baz = @as(f64, 1e1);",
985 "pub const BAZ = @as(f32, 42e-3);",
986 "pub const foobar = -@as(c_longdouble, 73);",
987 "pub export const my_float: f32 = 1.0;",
988 "pub export const my_double: f64 = 1.0;",
989 "pub export const my_longdouble: c_longdouble = 1.0;",
990 switch (@bitSizeOf(c_longdouble)) {
991 // TODO implement decimal format for f128 <https://github.com/ziglang/zig/issues/1181>
992 // (so that f80/f128 values not exactly representable as f64 can be emitted in decimal form)
993 80 => "pub export const my_extended_precision_longdouble: c_longdouble = 0x1.000000000000159ep0;",
994 128 => "pub export const my_extended_precision_longdouble: c_longdouble = 0x1.000000000000159e05f1e2674d21p0;",
995 else => "pub export const my_extended_precision_longdouble: c_longdouble = 1.0000000000000002;",
996 },
997 }));
998
999 cases.add("macro defines hexadecimal float",
1000 \\#define FOO 0xf7p38
1001 \\#define BAR -0X8F.BP5F
1002 \\#define FOOBAR 0X0P+0
1003 \\#define BAZ -0x.0a5dp+12
1004 \\#define FOOBAZ 0xfE.P-1l
1005 , &[_][]const u8{
1006 "pub const FOO = @as(f64, 0xf7p38);",
1007 "pub const BAR = -@as(f32, 0x8F.BP5);",
1008 "pub const FOOBAR = @as(f64, 0x0P+0);",
1009 "pub const BAZ = -@as(f64, 0x0.0a5dp+12);",
1010 "pub const FOOBAZ = @as(c_longdouble, 0xfE.P-1);",
1011 });
1012
1013 cases.add("comments",
1014 \\#define foo 1 //foo
1015 \\#define bar /* bar */ 2
1016 , &[_][]const u8{
1017 "pub const foo = @as(c_int, 1);",
1018 "pub const bar = @as(c_int, 2);",
1019 });
1020
1021 cases.add("string prefix",
1022 \\#define foo L"hello"
1023 , &[_][]const u8{
1024 "pub const foo = \"hello\";",
1025 });
1026
1027 cases.add("null statements",
1028 \\void foo(void) {
1029 \\ ;;;;;
1030 \\}
1031 , &[_][]const u8{
1032 \\pub export fn foo() void {}
1033 });
1034
1035 if (builtin.os.tag != .windows) {
1036 // Windows treats this as an enum with type c_int
1037 cases.add("big negative enum init values when C ABI supports long long enums",
1038 \\enum EnumWithInits {
1039 \\ VAL01 = 0,
1040 \\ VAL02 = 1,
1041 \\ VAL03 = 2,
1042 \\ VAL04 = 3,
1043 \\ VAL05 = -1,
1044 \\ VAL06 = -2,
1045 \\ VAL07 = -3,
1046 \\ VAL08 = -4,
1047 \\ VAL09 = VAL02 + VAL08,
1048 \\ VAL10 = -1000012000,
1049 \\ VAL11 = -1000161000,
1050 \\ VAL12 = -1000174001,
1051 \\ VAL13 = VAL09,
1052 \\ VAL14 = VAL10,
1053 \\ VAL15 = VAL11,
1054 \\ VAL16 = VAL13,
1055 \\ VAL17 = (VAL16 - VAL10 + 1),
1056 \\ VAL18 = 0x1000000000000000L,
1057 \\ VAL19 = VAL18 + VAL18 + VAL18 - 1,
1058 \\ VAL20 = VAL19 + VAL19,
1059 \\ VAL21 = VAL20 + 0xFFFFFFFFFFFFFFFF,
1060 \\ VAL22 = 0xFFFFFFFFFFFFFFFF + 1,
1061 \\ VAL23 = 0xFFFFFFFFFFFFFFFF,
1062 \\};
1063 , &[_][]const u8{
1064 \\pub const VAL01: c_longlong = 0;
1065 \\pub const VAL02: c_longlong = 1;
1066 \\pub const VAL03: c_longlong = 2;
1067 \\pub const VAL04: c_longlong = 3;
1068 \\pub const VAL05: c_longlong = -1;
1069 \\pub const VAL06: c_longlong = -2;
1070 \\pub const VAL07: c_longlong = -3;
1071 \\pub const VAL08: c_longlong = -4;
1072 \\pub const VAL09: c_longlong = -3;
1073 \\pub const VAL10: c_longlong = -1000012000;
1074 \\pub const VAL11: c_longlong = -1000161000;
1075 \\pub const VAL12: c_longlong = -1000174001;
1076 \\pub const VAL13: c_longlong = -3;
1077 \\pub const VAL14: c_longlong = -1000012000;
1078 \\pub const VAL15: c_longlong = -1000161000;
1079 \\pub const VAL16: c_longlong = -3;
1080 \\pub const VAL17: c_longlong = 1000011998;
1081 \\pub const VAL18: c_longlong = 1152921504606846976;
1082 \\pub const VAL19: c_longlong = 3458764513820540927;
1083 \\pub const VAL20: c_longlong = 6917529027641081854;
1084 \\pub const VAL21: c_longlong = 6917529027641081853;
1085 \\pub const VAL22: c_longlong = 0;
1086 \\pub const VAL23: c_longlong = -1;
1087 \\pub const enum_EnumWithInits = c_longlong;
1088 });
1089 }
1090
1091 cases.add("predefined expressions",
1092 \\void foo(void) {
1093 \\ __func__;
1094 \\ __FUNCTION__;
1095 \\ __PRETTY_FUNCTION__;
1096 \\}
1097 , &[_][]const u8{
1098 \\pub export fn foo() void {
1099 \\ _ = "foo";
1100 \\ _ = "foo";
1101 \\ _ = "void foo(void)";
1102 \\}
1103 });
1104
1105 cases.add("constant size array",
1106 \\void func(int array[20]);
1107 , &[_][]const u8{
1108 \\pub extern fn func(array: [*c]c_int) void;
1109 });
1110
1111 cases.add("__cdecl doesn't mess up function pointers",
1112 \\void foo(void (__cdecl *fn_ptr)(void));
1113 , &[_][]const u8{
1114 \\pub extern fn foo(fn_ptr: ?*const fn () callconv(.c) void) void;
1115 });
1116
1117 cases.add("void cast",
1118 \\void foo() {
1119 \\ int a;
1120 \\ (void) a;
1121 \\}
1122 , &[_][]const u8{
1123 \\pub export fn foo() void {
1124 \\ var a: c_int = undefined;
1125 \\ _ = &a;
1126 \\ _ = &a;
1127 \\}
1128 });
1129
1130 cases.add("implicit cast to void *",
1131 \\void *foo() {
1132 \\ unsigned short *x;
1133 \\ return x;
1134 \\}
1135 , &[_][]const u8{
1136 \\pub export fn foo() ?*anyopaque {
1137 \\ var x: [*c]c_ushort = undefined;
1138 \\ _ = &x;
1139 \\ return @as(?*anyopaque, @ptrCast(x));
1140 \\}
1141 });
1142
1143 cases.add("null pointer implicit cast",
1144 \\int* foo(void) {
1145 \\ return 0;
1146 \\}
1147 , &[_][]const u8{
1148 \\pub export fn foo() [*c]c_int {
1149 \\ return null;
1150 \\}
1151 });
1152
1153 cases.add("string literal",
1154 \\const char *foo(void) {
1155 \\ return "bar";
1156 \\}
1157 , &[_][]const u8{
1158 \\pub export fn foo() [*c]const u8 {
1159 \\ return "bar";
1160 \\}
1161 });
1162
1163 cases.add("return void",
1164 \\void foo(void) {
1165 \\ return;
1166 \\}
1167 , &[_][]const u8{
1168 \\pub export fn foo() void {
1169 \\ return;
1170 \\}
1171 });
1172
1173 cases.add("for loop",
1174 \\void foo(void) {
1175 \\ for (int i = 0; i; i++) { }
1176 \\}
1177 , &[_][]const u8{
1178 \\pub export fn foo() void {
1179 \\ {
1180 \\ var i: c_int = 0;
1181 \\ _ = &i;
1182 \\ while (i != 0) : (i += 1) {}
1183 \\ }
1184 \\}
1185 });
1186
1187 cases.add("empty for loop",
1188 \\void foo(void) {
1189 \\ for (;;) { }
1190 \\}
1191 , &[_][]const u8{
1192 \\pub export fn foo() void {
1193 \\ while (true) {}
1194 \\}
1195 });
1196
1197 cases.add("for loop with simple init expression",
1198 \\void foo(void) {
1199 \\ int i;
1200 \\ for (i = 3; i; i--) { }
1201 \\}
1202 , &[_][]const u8{
1203 \\pub export fn foo() void {
1204 \\ var i: c_int = undefined;
1205 \\ _ = &i;
1206 \\ {
1207 \\ i = 3;
1208 \\ while (i != 0) : (i -= 1) {}
1209 \\ }
1210 \\}
1211 });
1212
1213 cases.add("break statement",
1214 \\void foo(void) {
1215 \\ for (;;) {
1216 \\ break;
1217 \\ }
1218 \\}
1219 , &[_][]const u8{
1220 \\pub export fn foo() void {
1221 \\ while (true) {
1222 \\ break;
1223 \\ }
1224 \\}
1225 });
1226
1227 cases.add("continue statement",
1228 \\void foo(void) {
1229 \\ for (;;) {
1230 \\ continue;
1231 \\ }
1232 \\}
1233 , &[_][]const u8{
1234 \\pub export fn foo() void {
1235 \\ while (true) {
1236 \\ continue;
1237 \\ }
1238 \\}
1239 });
1240
1241 cases.add("pointer casting",
1242 \\float *ptrcast() {
1243 \\ int *a;
1244 \\ return (float *)a;
1245 \\}
1246 , &[_][]const u8{
1247 \\pub export fn ptrcast() [*c]f32 {
1248 \\ var a: [*c]c_int = undefined;
1249 \\ _ = &a;
1250 \\ return @as([*c]f32, @ptrCast(@alignCast(a)));
1251 \\}
1252 });
1253
1254 cases.add("casting pointer to pointer",
1255 \\float **ptrptrcast() {
1256 \\ int **a;
1257 \\ return (float **)a;
1258 \\}
1259 , &[_][]const u8{
1260 \\pub export fn ptrptrcast() [*c][*c]f32 {
1261 \\ var a: [*c][*c]c_int = undefined;
1262 \\ _ = &a;
1263 \\ return @as([*c][*c]f32, @ptrCast(@alignCast(a)));
1264 \\}
1265 });
1266
1267 cases.add("pointer conversion with different alignment",
1268 \\void test_ptr_cast() {
1269 \\ void *p;
1270 \\ {
1271 \\ char *to_char = (char *)p;
1272 \\ short *to_short = (short *)p;
1273 \\ int *to_int = (int *)p;
1274 \\ long long *to_longlong = (long long *)p;
1275 \\ }
1276 \\ {
1277 \\ char *to_char = p;
1278 \\ short *to_short = p;
1279 \\ int *to_int = p;
1280 \\ long long *to_longlong = p;
1281 \\ }
1282 \\}
1283 , &[_][]const u8{
1284 \\pub export fn test_ptr_cast() void {
1285 \\ var p: ?*anyopaque = undefined;
1286 \\ _ = &p;
1287 \\ {
1288 \\ var to_char: [*c]u8 = @as([*c]u8, @ptrCast(@alignCast(p)));
1289 \\ _ = &to_char;
1290 \\ var to_short: [*c]c_short = @as([*c]c_short, @ptrCast(@alignCast(p)));
1291 \\ _ = &to_short;
1292 \\ var to_int: [*c]c_int = @as([*c]c_int, @ptrCast(@alignCast(p)));
1293 \\ _ = &to_int;
1294 \\ var to_longlong: [*c]c_longlong = @as([*c]c_longlong, @ptrCast(@alignCast(p)));
1295 \\ _ = &to_longlong;
1296 \\ }
1297 \\ {
1298 \\ var to_char: [*c]u8 = @as([*c]u8, @ptrCast(@alignCast(p)));
1299 \\ _ = &to_char;
1300 \\ var to_short: [*c]c_short = @as([*c]c_short, @ptrCast(@alignCast(p)));
1301 \\ _ = &to_short;
1302 \\ var to_int: [*c]c_int = @as([*c]c_int, @ptrCast(@alignCast(p)));
1303 \\ _ = &to_int;
1304 \\ var to_longlong: [*c]c_longlong = @as([*c]c_longlong, @ptrCast(@alignCast(p)));
1305 \\ _ = &to_longlong;
1306 \\ }
1307 \\}
1308 });
1309
1310 cases.add("while on non-bool",
1311 \\int while_none_bool() {
1312 \\ int a;
1313 \\ float b;
1314 \\ void *c;
1315 \\ while (a) return 0;
1316 \\ while (b) return 1;
1317 \\ while (c) return 2;
1318 \\ return 3;
1319 \\}
1320 , &[_][]const u8{
1321 \\pub export fn while_none_bool() c_int {
1322 \\ var a: c_int = undefined;
1323 \\ _ = &a;
1324 \\ var b: f32 = undefined;
1325 \\ _ = &b;
1326 \\ var c: ?*anyopaque = undefined;
1327 \\ _ = &c;
1328 \\ while (a != 0) return 0;
1329 \\ while (b != 0) return 1;
1330 \\ while (c != null) return 2;
1331 \\ return 3;
1332 \\}
1333 });
1334
1335 cases.add("for on non-bool",
1336 \\int for_none_bool() {
1337 \\ int a;
1338 \\ float b;
1339 \\ void *c;
1340 \\ for (;a;) return 0;
1341 \\ for (;b;) return 1;
1342 \\ for (;c;) return 2;
1343 \\ return 3;
1344 \\}
1345 , &[_][]const u8{
1346 \\pub export fn for_none_bool() c_int {
1347 \\ var a: c_int = undefined;
1348 \\ _ = &a;
1349 \\ var b: f32 = undefined;
1350 \\ _ = &b;
1351 \\ var c: ?*anyopaque = undefined;
1352 \\ _ = &c;
1353 \\ while (a != 0) return 0;
1354 \\ while (b != 0) return 1;
1355 \\ while (c != null) return 2;
1356 \\ return 3;
1357 \\}
1358 });
1359
1360 cases.add("bitshift",
1361 \\int foo(void) {
1362 \\ return (1 << 2) >> 1;
1363 \\}
1364 , &[_][]const u8{
1365 \\pub export fn foo() c_int {
1366 \\ return (@as(c_int, 1) << @intCast(2)) >> @intCast(1);
1367 \\}
1368 });
1369
1370 cases.add("sizeof",
1371 \\#include <stddef.h>
1372 \\size_t size_of(void) {
1373 \\ return sizeof(int);
1374 \\}
1375 , &[_][]const u8{
1376 \\pub export fn size_of() usize {
1377 \\ return @sizeOf(c_int);
1378 \\}
1379 });
1380
1381 cases.add("normal deref",
1382 \\void foo() {
1383 \\ int *x;
1384 \\ *x = 1;
1385 \\}
1386 , &[_][]const u8{
1387 \\pub export fn foo() void {
1388 \\ var x: [*c]c_int = undefined;
1389 \\ _ = &x;
1390 \\ x.* = 1;
1391 \\}
1392 });
1393
1394 cases.add("address of operator",
1395 \\int foo(void) {
1396 \\ int x = 1234;
1397 \\ int *ptr = &x;
1398 \\ return *ptr;
1399 \\}
1400 , &[_][]const u8{
1401 \\pub export fn foo() c_int {
1402 \\ var x: c_int = 1234;
1403 \\ _ = &x;
1404 \\ var ptr: [*c]c_int = &x;
1405 \\ _ = &ptr;
1406 \\ return ptr.*;
1407 \\}
1408 });
1409
1410 cases.add("bin not",
1411 \\int foo() {
1412 \\ int x;
1413 \\ return ~x;
1414 \\}
1415 , &[_][]const u8{
1416 \\pub export fn foo() c_int {
1417 \\ var x: c_int = undefined;
1418 \\ _ = &x;
1419 \\ return ~x;
1420 \\}
1421 });
1422
1423 cases.add("bool not",
1424 \\int foo() {
1425 \\ int a;
1426 \\ float b;
1427 \\ void *c;
1428 \\ return !(a == 0);
1429 \\ return !a;
1430 \\ return !b;
1431 \\ return !c;
1432 \\}
1433 , &[_][]const u8{
1434 \\pub export fn foo() c_int {
1435 \\ var a: c_int = undefined;
1436 \\ _ = &a;
1437 \\ var b: f32 = undefined;
1438 \\ _ = &b;
1439 \\ var c: ?*anyopaque = undefined;
1440 \\ _ = &c;
1441 \\ return @intFromBool(!(a == @as(c_int, 0)));
1442 \\ return @intFromBool(!(a != 0));
1443 \\ return @intFromBool(!(b != 0));
1444 \\ return @intFromBool(!(c != null));
1445 \\}
1446 });
1447
1448 cases.add("__extension__ cast",
1449 \\int foo(void) {
1450 \\ return __extension__ 1;
1451 \\}
1452 , &[_][]const u8{
1453 \\pub export fn foo() c_int {
1454 \\ return 1;
1455 \\}
1456 });
1457
1458 if (builtin.os.tag != .windows) {
1459 // sysv_abi not currently supported on windows
1460 cases.add("Macro qualified functions",
1461 \\void __attribute__((sysv_abi)) foo(void);
1462 , &[_][]const u8{
1463 \\pub extern fn foo() void;
1464 });
1465 }
1466
1467 cases.add("Forward-declared enum",
1468 \\extern enum enum_ty my_enum;
1469 \\enum enum_ty { FOO };
1470 , &[_][]const u8{
1471 \\pub const FOO: c_int = 0;
1472 \\pub const enum_enum_ty = c_int;
1473 \\pub extern var my_enum: enum_enum_ty;
1474 });
1475
1476 cases.add("Parameterless function pointers",
1477 \\typedef void (*fn0)();
1478 \\typedef void (*fn1)(char);
1479 , &[_][]const u8{
1480 \\pub const fn0 = ?*const fn (...) callconv(.c) void;
1481 \\pub const fn1 = ?*const fn (u8) callconv(.c) void;
1482 });
1483
1484 cases.addWithTarget("Calling convention", .{
1485 .cpu_arch = .x86,
1486 .os_tag = .linux,
1487 .abi = .none,
1488 },
1489 \\void __attribute__((fastcall)) foo1(float *a);
1490 \\void __attribute__((stdcall)) foo2(float *a);
1491 \\void __attribute__((vectorcall)) foo3(float *a);
1492 \\void __attribute__((cdecl)) foo4(float *a);
1493 \\void __attribute__((thiscall)) foo5(float *a);
1494 , &[_][]const u8{
1495 \\pub extern fn foo1(a: [*c]f32) callconv(.{ .x86_fastcall = .{} }) void;
1496 \\pub extern fn foo2(a: [*c]f32) callconv(.{ .x86_stdcall = .{} }) void;
1497 \\pub extern fn foo3(a: [*c]f32) callconv(.{ .x86_vectorcall = .{} }) void;
1498 \\pub extern fn foo4(a: [*c]f32) void;
1499 \\pub extern fn foo5(a: [*c]f32) callconv(.{ .x86_thiscall = .{} }) void;
1500 });
1501
1502 cases.addWithTarget("Calling convention", std.Target.Query.parse(.{
1503 .arch_os_abi = "arm-linux-none",
1504 .cpu_features = "generic+v8_5a",
1505 }) catch unreachable,
1506 \\void __attribute__((pcs("aapcs"))) foo1(float *a);
1507 \\void __attribute__((pcs("aapcs-vfp"))) foo2(float *a);
1508 , &[_][]const u8{
1509 \\pub extern fn foo1(a: [*c]f32) callconv(.{ .arm_aapcs = .{} }) void;
1510 \\pub extern fn foo2(a: [*c]f32) callconv(.{ .arm_aapcs_vfp = .{} }) void;
1511 });
1512
1513 cases.addWithTarget("Calling convention", std.Target.Query.parse(.{
1514 .arch_os_abi = "aarch64-linux-none",
1515 .cpu_features = "generic+v8_5a",
1516 }) catch unreachable,
1517 \\void __attribute__((aarch64_vector_pcs)) foo1(float *a);
1518 , &[_][]const u8{
1519 \\pub extern fn foo1(a: [*c]f32) callconv(.{ .aarch64_vfabi = .{} }) void;
1520 });
1521
1522 cases.add("Parameterless function prototypes",
1523 \\void a() {}
1524 \\void b(void) {}
1525 \\void c();
1526 \\void d(void);
1527 \\static void e() {}
1528 \\static void f(void) {}
1529 \\static void g();
1530 \\static void h(void);
1531 , &[_][]const u8{
1532 \\pub export fn a() void {}
1533 \\pub export fn b() void {}
1534 \\pub extern fn c(...) void;
1535 \\pub extern fn d() void;
1536 \\pub fn e() callconv(.c) void {}
1537 \\pub fn f() callconv(.c) void {}
1538 \\pub extern fn g() void;
1539 \\pub extern fn h() void;
1540 });
1541
1542 cases.add("variable declarations",
1543 \\extern char arr0[] = "hello";
1544 \\static char arr1[] = "hello";
1545 \\char arr2[] = "hello";
1546 , &[_][]const u8{
1547 \\pub export var arr0: [5:0]u8 = "hello".*;
1548 \\pub var arr1: [5:0]u8 = "hello".*;
1549 \\pub export var arr2: [5:0]u8 = "hello".*;
1550 });
1551
1552 cases.add("array initializer expr",
1553 \\static void foo(void){
1554 \\ char arr[10] ={1};
1555 \\ char *arr1[10] ={0};
1556 \\}
1557 , &[_][]const u8{
1558 \\pub fn foo() callconv(.c) void {
1559 \\ var arr: [10]u8 = [1]u8{
1560 \\ 1,
1561 \\ } ++ [1]u8{0} ** 9;
1562 \\ _ = &arr;
1563 \\ var arr1: [10][*c]u8 = [1][*c]u8{
1564 \\ null,
1565 \\ } ++ [1][*c]u8{null} ** 9;
1566 \\ _ = &arr1;
1567 \\}
1568 });
1569
1570 cases.add("enums",
1571 \\typedef enum {
1572 \\ a,
1573 \\ b,
1574 \\ c,
1575 \\} d;
1576 \\enum {
1577 \\ e,
1578 \\ f = 4,
1579 \\ g,
1580 \\} h = e;
1581 \\struct Baz {
1582 \\ enum {
1583 \\ i,
1584 \\ j,
1585 \\ k,
1586 \\ } l;
1587 \\ d m;
1588 \\};
1589 \\enum i {
1590 \\ n,
1591 \\ o,
1592 \\ p,
1593 \\};
1594 , &[_][]const u8{
1595 \\pub const a: c_int = 0;
1596 \\pub const b: c_int = 1;
1597 \\pub const c: c_int = 2;
1598 \\pub const d =
1599 ++ " " ++ default_enum_type ++
1600 \\;
1601 \\pub const e: c_int = 0;
1602 \\pub const f: c_int = 4;
1603 \\pub const g: c_int = 5;
1604 \\const enum_unnamed_1 =
1605 ++ " " ++ default_enum_type ++
1606 \\;
1607 \\pub export var h: enum_unnamed_1 = @as(c_uint, @bitCast(e));
1608 \\pub const i: c_int = 0;
1609 \\pub const j: c_int = 1;
1610 \\pub const k: c_int = 2;
1611 \\const enum_unnamed_2 =
1612 ++ " " ++ default_enum_type ++
1613 \\;
1614 \\pub const struct_Baz = extern struct {
1615 \\ l: enum_unnamed_2 = @import("std").mem.zeroes(enum_unnamed_2),
1616 \\ m: d = @import("std").mem.zeroes(d),
1617 \\};
1618 \\pub const n: c_int = 0;
1619 \\pub const o: c_int = 1;
1620 \\pub const p: c_int = 2;
1621 \\pub const enum_i =
1622 ++ " " ++ default_enum_type ++
1623 \\;
1624 ,
1625 "pub const Baz = struct_Baz;",
1626 });
1627
1628 cases.add("#define a char literal",
1629 \\#define A_CHAR 'a'
1630 , &[_][]const u8{
1631 \\pub const A_CHAR = 'a';
1632 });
1633
1634 cases.add("comment after integer literal",
1635 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1636 , &[_][]const u8{
1637 \\pub const SDL_INIT_VIDEO = @as(c_int, 0x00000020);
1638 });
1639
1640 cases.add("u integer suffix after hex literal",
1641 \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1642 , &[_][]const u8{
1643 \\pub const SDL_INIT_VIDEO = @as(c_uint, 0x00000020);
1644 });
1645
1646 cases.add("l integer suffix after hex literal",
1647 \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1648 , &[_][]const u8{
1649 \\pub const SDL_INIT_VIDEO = @as(c_long, 0x00000020);
1650 });
1651
1652 cases.add("ul integer suffix after hex literal",
1653 \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1654 , &[_][]const u8{
1655 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020);
1656 });
1657
1658 cases.add("lu integer suffix after hex literal",
1659 \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1660 , &[_][]const u8{
1661 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020);
1662 });
1663
1664 cases.add("ll integer suffix after hex literal",
1665 \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1666 , &[_][]const u8{
1667 \\pub const SDL_INIT_VIDEO = @as(c_longlong, 0x00000020);
1668 });
1669
1670 cases.add("ull integer suffix after hex literal",
1671 \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1672 , &[_][]const u8{
1673 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020);
1674 });
1675
1676 cases.add("llu integer suffix after hex literal",
1677 \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1678 , &[_][]const u8{
1679 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020);
1680 });
1681
1682 cases.add("generate inline func for #define global extern fn",
1683 \\extern void (*fn_ptr)(void);
1684 \\#define foo fn_ptr
1685 \\
1686 \\extern char (*fn_ptr2)(int, float);
1687 \\#define bar fn_ptr2
1688 , &[_][]const u8{
1689 \\pub extern var fn_ptr: ?*const fn () callconv(.c) void;
1690 ,
1691 \\pub inline fn foo() void {
1692 \\ return fn_ptr.?();
1693 \\}
1694 ,
1695 \\pub extern var fn_ptr2: ?*const fn (c_int, f32) callconv(.c) u8;
1696 ,
1697 \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 {
1698 \\ return fn_ptr2.?(arg_1, arg_2);
1699 \\}
1700 });
1701
1702 cases.add("macros with field targets",
1703 \\typedef unsigned int GLbitfield;
1704 \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask);
1705 \\typedef void(*OpenGLProc)(void);
1706 \\union OpenGLProcs {
1707 \\ OpenGLProc ptr[1];
1708 \\ struct {
1709 \\ PFNGLCLEARPROC Clear;
1710 \\ } gl;
1711 \\};
1712 \\extern union OpenGLProcs glProcs;
1713 \\#define glClearUnion glProcs.gl.Clear
1714 \\#define glClearPFN PFNGLCLEARPROC
1715 , &[_][]const u8{
1716 \\pub const GLbitfield = c_uint;
1717 \\pub const PFNGLCLEARPROC = ?*const fn (GLbitfield) callconv(.c) void;
1718 \\pub const OpenGLProc = ?*const fn () callconv(.c) void;
1719 \\const struct_unnamed_1 = extern struct {
1720 \\ Clear: PFNGLCLEARPROC = @import("std").mem.zeroes(PFNGLCLEARPROC),
1721 \\};
1722 \\pub const union_OpenGLProcs = extern union {
1723 \\ ptr: [1]OpenGLProc,
1724 \\ gl: struct_unnamed_1,
1725 \\};
1726 \\pub extern var glProcs: union_OpenGLProcs;
1727 ,
1728 \\pub const glClearPFN = PFNGLCLEARPROC;
1729 ,
1730 \\pub inline fn glClearUnion(arg_2: GLbitfield) void {
1731 \\ return glProcs.gl.Clear.?(arg_2);
1732 \\}
1733 ,
1734 \\pub const OpenGLProcs = union_OpenGLProcs;
1735 });
1736
1737 cases.add("macro pointer cast",
1738 \\#define NRF_GPIO_BASE 0
1739 \\typedef struct { int dummy; } NRF_GPIO_Type;
1740 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
1741 , &[_][]const u8{
1742 \\pub const NRF_GPIO = @import("std").zig.c_translation.cast([*c]NRF_GPIO_Type, NRF_GPIO_BASE);
1743 });
1744
1745 cases.add("basic macro function",
1746 \\extern int c;
1747 \\#define BASIC(c) (c*2)
1748 \\#define FOO(L,b) (L + b)
1749 \\#define BAR() (c*c)
1750 , &[_][]const u8{
1751 \\pub extern var c: c_int;
1752 ,
1753 \\pub inline fn BASIC(c_1: anytype) @TypeOf(c_1 * @as(c_int, 2)) {
1754 \\ _ = &c_1;
1755 \\ return c_1 * @as(c_int, 2);
1756 \\}
1757 ,
1758 \\pub inline fn FOO(L: anytype, b: anytype) @TypeOf(L + b) {
1759 \\ _ = &L;
1760 \\ _ = &b;
1761 \\ return L + b;
1762 \\}
1763 ,
1764 \\pub inline fn BAR() @TypeOf(c * c) {
1765 \\ return c * c;
1766 \\}
1767 });
1768
1769 cases.add("macro defines string literal with hex",
1770 \\#define FOO "aoeu\xab derp"
1771 \\#define FOO2 "aoeu\x0007a derp"
1772 \\#define FOO_CHAR '\xfF'
1773 , &[_][]const u8{
1774 \\pub const FOO = "aoeu\xab derp";
1775 ,
1776 \\pub const FOO2 = "aoeu\x7a derp";
1777 ,
1778 \\pub const FOO_CHAR = '\xff';
1779 });
1780
1781 cases.add("macro add",
1782 \\#define D3_AHB1PERIPH_BASE 0
1783 \\#define PERIPH_BASE (0x40000000UL) /*!< Base address of : AHB/APB Peripherals */
1784 \\#define D3_APB1PERIPH_BASE (PERIPH_BASE + 0x18000000UL)
1785 \\#define RCC_BASE (D3_AHB1PERIPH_BASE + 0x4400UL)
1786 , &[_][]const u8{
1787 \\pub const PERIPH_BASE = @as(c_ulong, 0x40000000);
1788 ,
1789 \\pub const D3_APB1PERIPH_BASE = PERIPH_BASE + @as(c_ulong, 0x18000000);
1790 ,
1791 \\pub const RCC_BASE = D3_AHB1PERIPH_BASE + @as(c_ulong, 0x4400);
1792 });
1793
1794 cases.add("variable aliasing",
1795 \\static long a = 2;
1796 \\static long b = 2;
1797 \\static int c = 4;
1798 \\void foo(char c) {
1799 \\ int a;
1800 \\ char b = 123;
1801 \\ b = (char) a;
1802 \\ {
1803 \\ int d = 5;
1804 \\ }
1805 \\ unsigned d = 440;
1806 \\}
1807 , &[_][]const u8{
1808 \\pub var a: c_long = 2;
1809 \\pub var b: c_long = 2;
1810 \\pub var c: c_int = 4;
1811 \\pub export fn foo(arg_c_1: u8) void {
1812 \\ var c_1 = arg_c_1;
1813 \\ _ = &c_1;
1814 \\ var a_2: c_int = undefined;
1815 \\ _ = &a_2;
1816 \\ var b_3: u8 = 123;
1817 \\ _ = &b_3;
1818 \\ b_3 = @as(u8, @bitCast(@as(i8, @truncate(a_2))));
1819 \\ {
1820 \\ var d: c_int = 5;
1821 \\ _ = &d;
1822 \\ }
1823 \\ var d: c_uint = @as(c_uint, @bitCast(@as(c_int, 440)));
1824 \\ _ = &d;
1825 \\}
1826 });
1827
1828 cases.add("comma operator",
1829 \\int foo() {
1830 \\ 2, 4;
1831 \\ return 2, 4, 6;
1832 \\}
1833 , &[_][]const u8{
1834 \\pub export fn foo() c_int {
1835 \\ _ = blk: {
1836 \\ _ = @as(c_int, 2);
1837 \\ break :blk @as(c_int, 4);
1838 \\ };
1839 \\ return blk: {
1840 \\ _ = blk_1: {
1841 \\ _ = @as(c_int, 2);
1842 \\ break :blk_1 @as(c_int, 4);
1843 \\ };
1844 \\ break :blk @as(c_int, 6);
1845 \\ };
1846 \\}
1847 });
1848
1849 cases.add("worst-case assign",
1850 \\void foo() {
1851 \\ int a;
1852 \\ int b;
1853 \\ a = b = 2;
1854 \\}
1855 , &[_][]const u8{
1856 \\pub export fn foo() void {
1857 \\ var a: c_int = undefined;
1858 \\ _ = &a;
1859 \\ var b: c_int = undefined;
1860 \\ _ = &b;
1861 \\ a = blk: {
1862 \\ const tmp = @as(c_int, 2);
1863 \\ b = tmp;
1864 \\ break :blk tmp;
1865 \\ };
1866 \\}
1867 });
1868
1869 cases.add("while loops",
1870 \\int foo() {
1871 \\ int a = 5;
1872 \\ while (2)
1873 \\ a = 2;
1874 \\ while (4) {
1875 \\ int a = 4;
1876 \\ a = 9;
1877 \\ return 6, a;
1878 \\ }
1879 \\ do {
1880 \\ int a = 2;
1881 \\ a = 12;
1882 \\ } while (4);
1883 \\ do
1884 \\ a = 7;
1885 \\ while (4);
1886 \\}
1887 , &[_][]const u8{
1888 \\pub export fn foo() c_int {
1889 \\ var a: c_int = 5;
1890 \\ _ = &a;
1891 \\ while (true) {
1892 \\ a = 2;
1893 \\ }
1894 \\ while (true) {
1895 \\ var a_1: c_int = 4;
1896 \\ _ = &a_1;
1897 \\ a_1 = 9;
1898 \\ return blk: {
1899 \\ _ = @as(c_int, 6);
1900 \\ break :blk a_1;
1901 \\ };
1902 \\ }
1903 \\ while (true) {
1904 \\ var a_1: c_int = 2;
1905 \\ _ = &a_1;
1906 \\ a_1 = 12;
1907 \\ }
1908 \\ while (true) {
1909 \\ a = 7;
1910 \\ }
1911 \\ return 0;
1912 \\}
1913 });
1914
1915 cases.add("for loops",
1916 \\void foo() {
1917 \\ for (int i = 2, b = 4; i + 2; i = 2) {
1918 \\ int a = 2;
1919 \\ a = 6, 5, 7;
1920 \\ }
1921 \\ char i = 2;
1922 \\}
1923 , &[_][]const u8{
1924 \\pub export fn foo() void {
1925 \\ {
1926 \\ var i: c_int = 2;
1927 \\ _ = &i;
1928 \\ var b: c_int = 4;
1929 \\ _ = &b;
1930 \\ while ((i + @as(c_int, 2)) != 0) : (i = 2) {
1931 \\ var a: c_int = 2;
1932 \\ _ = &a;
1933 \\ _ = blk: {
1934 \\ _ = blk_1: {
1935 \\ a = 6;
1936 \\ break :blk_1 @as(c_int, 5);
1937 \\ };
1938 \\ break :blk @as(c_int, 7);
1939 \\ };
1940 \\ }
1941 \\ }
1942 \\ var i: u8 = 2;
1943 \\ _ = &i;
1944 \\}
1945 });
1946
1947 cases.add("shadowing primitive types",
1948 \\unsigned anyerror = 2;
1949 \\#define noreturn _Noreturn
1950 \\typedef enum {
1951 \\ f32,
1952 \\ u32,
1953 \\} BadEnum;
1954 , &[_][]const u8{
1955 \\pub export var @"anyerror": c_uint = 2;
1956 ,
1957 \\pub const @"noreturn" = @compileError("unable to translate C expr: unexpected token '_Noreturn'");
1958 ,
1959 \\pub const @"f32": c_int = 0;
1960 \\pub const @"u32": c_int = 1;
1961 \\pub const BadEnum = c_uint;
1962 });
1963
1964 cases.add("floats",
1965 \\float a = 3.1415;
1966 \\double b = 3.1415;
1967 \\int c = 3.1415;
1968 \\double d = 3;
1969 , &[_][]const u8{
1970 \\pub export var a: f32 = @as(f32, @floatCast(3.1415));
1971 \\pub export var b: f64 = 3.1415;
1972 \\pub export var c: c_int = @as(c_int, @intFromFloat(3.1415));
1973 \\pub export var d: f64 = 3;
1974 });
1975
1976 cases.add("conditional operator",
1977 \\int bar(void) {
1978 \\ if (2 ? 5 : 5 ? 4 : 6) 2;
1979 \\ return 2 ? 5 : 5 ? 4 : 6;
1980 \\}
1981 , &[_][]const u8{
1982 \\pub export fn bar() c_int {
1983 \\ if ((if (true) @as(c_int, 5) else if (true) @as(c_int, 4) else @as(c_int, 6)) != 0) {
1984 \\ _ = @as(c_int, 2);
1985 \\ }
1986 \\ return if (true) @as(c_int, 5) else if (true) @as(c_int, 4) else @as(c_int, 6);
1987 \\}
1988 });
1989
1990 cases.add("switch on int",
1991 \\void switch_fn(int i) {
1992 \\ int res = 0;
1993 \\ switch (i) {
1994 \\ case 0:
1995 \\ res = 1;
1996 \\ case 1 ... 3:
1997 \\ res = 2;
1998 \\ default:
1999 \\ res = 3 * i;
2000 \\ break;
2001 \\ break;
2002 \\ case 7: {
2003 \\ res = 7;
2004 \\ break;
2005 \\ }
2006 \\ case 4:
2007 \\ case 5:
2008 \\ res = 69;
2009 \\ {
2010 \\ res = 5;
2011 \\ return;
2012 \\ }
2013 \\ case 6:
2014 \\ switch (res) {
2015 \\ case 9: break;
2016 \\ }
2017 \\ res = 1;
2018 \\ return;
2019 \\ }
2020 \\}
2021 , &[_][]const u8{
2022 \\pub export fn switch_fn(arg_i: c_int) void {
2023 \\ var i = arg_i;
2024 \\ _ = &i;
2025 \\ var res: c_int = 0;
2026 \\ _ = &res;
2027 \\ while (true) {
2028 \\ switch (i) {
2029 \\ @as(c_int, 0) => {
2030 \\ res = 1;
2031 \\ res = 2;
2032 \\ res = @as(c_int, 3) * i;
2033 \\ break;
2034 \\ },
2035 \\ @as(c_int, 1)...@as(c_int, 3) => {
2036 \\ res = 2;
2037 \\ res = @as(c_int, 3) * i;
2038 \\ break;
2039 \\ },
2040 \\ else => {
2041 \\ res = @as(c_int, 3) * i;
2042 \\ break;
2043 \\ },
2044 \\ @as(c_int, 7) => {
2045 \\ {
2046 \\ res = 7;
2047 \\ break;
2048 \\ }
2049 \\ },
2050 \\ @as(c_int, 4), @as(c_int, 5) => {
2051 \\ res = 69;
2052 \\ {
2053 \\ res = 5;
2054 \\ return;
2055 \\ }
2056 \\ },
2057 \\ @as(c_int, 6) => {
2058 \\ while (true) {
2059 \\ switch (res) {
2060 \\ @as(c_int, 9) => break,
2061 \\ else => {},
2062 \\ }
2063 \\ break;
2064 \\ }
2065 \\ res = 1;
2066 \\ return;
2067 \\ },
2068 \\ }
2069 \\ break;
2070 \\ }
2071 \\}
2072 });
2073 cases.add("undefined array global",
2074 \\int array[100] = {};
2075 , &[_][]const u8{
2076 \\pub export var array: [100]c_int = [1]c_int{0} ** 100;
2077 });
2078
2079 cases.add("restrict -> noalias",
2080 \\void foo(void *restrict bar, void *restrict);
2081 , &[_][]const u8{
2082 \\pub extern fn foo(noalias bar: ?*anyopaque, noalias ?*anyopaque) void;
2083 });
2084
2085 cases.add("assign",
2086 \\void max(int a) {
2087 \\ int tmp;
2088 \\ tmp = a;
2089 \\ a = tmp;
2090 \\}
2091 , &[_][]const u8{
2092 \\pub export fn max(arg_a: c_int) void {
2093 \\ var a = arg_a;
2094 \\ _ = &a;
2095 \\ var tmp: c_int = undefined;
2096 \\ _ = &tmp;
2097 \\ tmp = a;
2098 \\ a = tmp;
2099 \\}
2100 });
2101
2102 cases.add("chaining assign",
2103 \\void max(int a) {
2104 \\ int b, c;
2105 \\ c = b = a;
2106 \\}
2107 , &[_][]const u8{
2108 \\pub export fn max(arg_a: c_int) void {
2109 \\ var a = arg_a;
2110 \\ _ = &a;
2111 \\ var b: c_int = undefined;
2112 \\ _ = &b;
2113 \\ var c: c_int = undefined;
2114 \\ _ = &c;
2115 \\ c = blk: {
2116 \\ const tmp = a;
2117 \\ b = tmp;
2118 \\ break :blk tmp;
2119 \\ };
2120 \\}
2121 });
2122
2123 cases.add("anonymous enum",
2124 \\enum {
2125 \\ One,
2126 \\ Two,
2127 \\};
2128 , &[_][]const u8{
2129 \\pub const One: c_int = 0;
2130 \\pub const Two: c_int = 1;
2131 \\const enum_unnamed_1 =
2132 ++ " " ++ default_enum_type ++
2133 \\;
2134 });
2135
2136 cases.add("c style cast",
2137 \\int int_from_float(float a) {
2138 \\ return (int)a;
2139 \\}
2140 , &[_][]const u8{
2141 \\pub export fn int_from_float(arg_a: f32) c_int {
2142 \\ var a = arg_a;
2143 \\ _ = &a;
2144 \\ return @as(c_int, @intFromFloat(a));
2145 \\}
2146 });
2147
2148 cases.add("escape sequences",
2149 \\const char *escapes() {
2150 \\char a = '\'',
2151 \\ b = '\\',
2152 \\ c = '\a',
2153 \\ d = '\b',
2154 \\ e = '\f',
2155 \\ f = '\n',
2156 \\ g = '\r',
2157 \\ h = '\t',
2158 \\ i = '\v',
2159 \\ j = '\0',
2160 \\ k = '\"';
2161 \\ return "\'\\\a\b\f\n\r\t\v\0\"";
2162 \\}
2163 \\
2164 , &[_][]const u8{
2165 \\pub export fn escapes() [*c]const u8 {
2166 \\ var a: u8 = '\'';
2167 \\ _ = &a;
2168 \\ var b: u8 = '\\';
2169 \\ _ = &b;
2170 \\ var c: u8 = '\x07';
2171 \\ _ = &c;
2172 \\ var d: u8 = '\x08';
2173 \\ _ = &d;
2174 \\ var e: u8 = '\x0c';
2175 \\ _ = &e;
2176 \\ var f: u8 = '\n';
2177 \\ _ = &f;
2178 \\ var g: u8 = '\r';
2179 \\ _ = &g;
2180 \\ var h: u8 = '\t';
2181 \\ _ = &h;
2182 \\ var i: u8 = '\x0b';
2183 \\ _ = &i;
2184 \\ var j: u8 = '\x00';
2185 \\ _ = &j;
2186 \\ var k: u8 = '"';
2187 \\ _ = &k;
2188 \\ return "'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
2189 \\}
2190 });
2191
2192 cases.add("do loop",
2193 \\void foo(void) {
2194 \\ int a = 2;
2195 \\ do {
2196 \\ a = a - 1;
2197 \\ } while (a);
2198 \\
2199 \\ int b = 2;
2200 \\ do
2201 \\ b = b -1;
2202 \\ while (b);
2203 \\}
2204 , &[_][]const u8{
2205 \\pub export fn foo() void {
2206 \\ var a: c_int = 2;
2207 \\ _ = &a;
2208 \\ while (true) {
2209 \\ a = a - @as(c_int, 1);
2210 \\ if (!(a != 0)) break;
2211 \\ }
2212 \\ var b: c_int = 2;
2213 \\ _ = &b;
2214 \\ while (true) {
2215 \\ b = b - @as(c_int, 1);
2216 \\ if (!(b != 0)) break;
2217 \\ }
2218 \\}
2219 });
2220
2221 cases.add("logical and, logical or, on non-bool values, extra parens",
2222 \\enum Foo {
2223 \\ FooA,
2224 \\ FooB,
2225 \\ FooC,
2226 \\};
2227 \\typedef int SomeTypedef;
2228 \\int and_or_non_bool(int a, float b, void *c) {
2229 \\ enum Foo d = FooA;
2230 \\ int e = (a && b);
2231 \\ int f = (b && c);
2232 \\ int g = (a && c);
2233 \\ int h = (a || b);
2234 \\ int i = (b || c);
2235 \\ int j = (a || c);
2236 \\ int k = (a || (int)d);
2237 \\ int l = ((int)d && b);
2238 \\ int m = (c || (unsigned int)d);
2239 \\ SomeTypedef td = 44;
2240 \\ int o = (td || b);
2241 \\ int p = (c && td);
2242 \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
2243 \\}
2244 , &[_][]const u8{
2245 \\pub const FooA: c_int = 0;
2246 \\pub const FooB: c_int = 1;
2247 \\pub const FooC: c_int = 2;
2248 \\pub const enum_Foo =
2249 ++ " " ++ default_enum_type ++
2250 \\;
2251 \\pub const SomeTypedef = c_int;
2252 \\pub export fn and_or_non_bool(arg_a: c_int, arg_b: f32, arg_c: ?*anyopaque) c_int {
2253 \\ var a = arg_a;
2254 \\ _ = &a;
2255 \\ var b = arg_b;
2256 \\ _ = &b;
2257 \\ var c = arg_c;
2258 \\ _ = &c;
2259 \\ var d: enum_Foo = @as(c_uint, @bitCast(FooA));
2260 \\ _ = &d;
2261 \\ var e: c_int = @intFromBool((a != 0) and (b != 0));
2262 \\ _ = &e;
2263 \\ var f: c_int = @intFromBool((b != 0) and (c != null));
2264 \\ _ = &f;
2265 \\ var g: c_int = @intFromBool((a != 0) and (c != null));
2266 \\ _ = &g;
2267 \\ var h: c_int = @intFromBool((a != 0) or (b != 0));
2268 \\ _ = &h;
2269 \\ var i: c_int = @intFromBool((b != 0) or (c != null));
2270 \\ _ = &i;
2271 \\ var j: c_int = @intFromBool((a != 0) or (c != null));
2272 \\ _ = &j;
2273 \\ var k: c_int = @intFromBool((a != 0) or (@as(c_int, @bitCast(d)) != 0));
2274 \\ _ = &k;
2275 \\ var l: c_int = @intFromBool((@as(c_int, @bitCast(d)) != 0) and (b != 0));
2276 \\ _ = &l;
2277 \\ var m: c_int = @intFromBool((c != null) or (d != 0));
2278 \\ _ = &m;
2279 \\ var td: SomeTypedef = 44;
2280 \\ _ = &td;
2281 \\ var o: c_int = @intFromBool((td != 0) or (b != 0));
2282 \\ _ = &o;
2283 \\ var p: c_int = @intFromBool((c != null) and (td != 0));
2284 \\ _ = &p;
2285 \\ return (((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p;
2286 \\}
2287 ,
2288 \\pub const Foo = enum_Foo;
2289 });
2290
2291 cases.add("bitwise binary operators, simpler parens",
2292 \\int max(int a, int b) {
2293 \\ return (a & b) ^ (a | b);
2294 \\}
2295 , &[_][]const u8{
2296 \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int {
2297 \\ var a = arg_a;
2298 \\ _ = &a;
2299 \\ var b = arg_b;
2300 \\ _ = &b;
2301 \\ return (a & b) ^ (a | b);
2302 \\}
2303 });
2304
2305 cases.add("comparison operators (no if)", // TODO Come up with less contrived tests? Make sure to cover all these comparisons.
2306 \\int test_comparisons(int a, int b) {
2307 \\ int c = (a < b);
2308 \\ int d = (a > b);
2309 \\ int e = (a <= b);
2310 \\ int f = (a >= b);
2311 \\ int g = (c < d);
2312 \\ int h = (e < f);
2313 \\ int i = (g < h);
2314 \\ return i;
2315 \\}
2316 , &[_][]const u8{
2317 \\pub export fn test_comparisons(arg_a: c_int, arg_b: c_int) c_int {
2318 \\ var a = arg_a;
2319 \\ _ = &a;
2320 \\ var b = arg_b;
2321 \\ _ = &b;
2322 \\ var c: c_int = @intFromBool(a < b);
2323 \\ _ = &c;
2324 \\ var d: c_int = @intFromBool(a > b);
2325 \\ _ = &d;
2326 \\ var e: c_int = @intFromBool(a <= b);
2327 \\ _ = &e;
2328 \\ var f: c_int = @intFromBool(a >= b);
2329 \\ _ = &f;
2330 \\ var g: c_int = @intFromBool(c < d);
2331 \\ _ = &g;
2332 \\ var h: c_int = @intFromBool(e < f);
2333 \\ _ = &h;
2334 \\ var i: c_int = @intFromBool(g < h);
2335 \\ _ = &i;
2336 \\ return i;
2337 \\}
2338 });
2339
2340 cases.add("==, !=",
2341 \\int max(int a, int b) {
2342 \\ if (a == b)
2343 \\ return a;
2344 \\ if (a != b)
2345 \\ return b;
2346 \\ return a;
2347 \\}
2348 , &[_][]const u8{
2349 \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int {
2350 \\ var a = arg_a;
2351 \\ _ = &a;
2352 \\ var b = arg_b;
2353 \\ _ = &b;
2354 \\ if (a == b) return a;
2355 \\ if (a != b) return b;
2356 \\ return a;
2357 \\}
2358 });
2359
2360 cases.add("typedeffed bool expression",
2361 \\typedef char* yes;
2362 \\void foo(void) {
2363 \\ yes a;
2364 \\ if (a) 2;
2365 \\}
2366 , &[_][]const u8{
2367 \\pub const yes = [*c]u8;
2368 \\pub export fn foo() void {
2369 \\ var a: yes = undefined;
2370 \\ _ = &a;
2371 \\ if (a != null) {
2372 \\ _ = @as(c_int, 2);
2373 \\ }
2374 \\}
2375 });
2376
2377 cases.add("statement expression",
2378 \\int foo(void) {
2379 \\ return ({
2380 \\ int a = 1;
2381 \\ a;
2382 \\ a;
2383 \\ });
2384 \\}
2385 , &[_][]const u8{
2386 \\pub export fn foo() c_int {
2387 \\ return blk: {
2388 \\ var a: c_int = 1;
2389 \\ _ = &a;
2390 \\ _ = &a;
2391 \\ break :blk a;
2392 \\ };
2393 \\}
2394 });
2395
2396 cases.add("field access expression",
2397 \\#define ARROW a->b
2398 \\#define DOT a.b
2399 \\extern struct Foo {
2400 \\ int b;
2401 \\}a;
2402 \\float b = 2.0f;
2403 \\void foo(void) {
2404 \\ struct Foo *c;
2405 \\ a.b;
2406 \\ c->b;
2407 \\}
2408 , &[_][]const u8{
2409 \\pub const struct_Foo = extern struct {
2410 \\ b: c_int = @import("std").mem.zeroes(c_int),
2411 \\};
2412 \\pub extern var a: struct_Foo;
2413 \\pub export var b: f32 = 2.0;
2414 \\pub export fn foo() void {
2415 \\ var c: [*c]struct_Foo = undefined;
2416 \\ _ = &c;
2417 \\ _ = a.b;
2418 \\ _ = c.*.b;
2419 \\}
2420 ,
2421 \\pub inline fn ARROW() @TypeOf(a.*.b) {
2422 \\ return a.*.b;
2423 \\}
2424 ,
2425 \\pub inline fn DOT() @TypeOf(a.b) {
2426 \\ return a.b;
2427 \\}
2428 });
2429
2430 cases.add("array access",
2431 \\#define ACCESS array[2]
2432 \\int array[100] = {};
2433 \\int foo(int index) {
2434 \\ return array[index];
2435 \\}
2436 , &[_][]const u8{
2437 \\pub export var array: [100]c_int = [1]c_int{0} ** 100;
2438 \\pub export fn foo(arg_index: c_int) c_int {
2439 \\ var index = arg_index;
2440 \\ _ = &index;
2441 \\ return array[@as(c_uint, @intCast(index))];
2442 \\}
2443 ,
2444 \\pub inline fn ACCESS() @TypeOf(array[@as(usize, @intCast(@as(c_int, 2)))]) {
2445 \\ return array[@as(usize, @intCast(@as(c_int, 2)))];
2446 \\}
2447 });
2448
2449 cases.add("cast signed array index to unsigned",
2450 \\void foo() {
2451 \\ int a[10], i = 0;
2452 \\ a[i] = 0;
2453 \\}
2454 , &[_][]const u8{
2455 \\pub export fn foo() void {
2456 \\ var a: [10]c_int = undefined;
2457 \\ _ = &a;
2458 \\ var i: c_int = 0;
2459 \\ _ = &i;
2460 \\ a[@as(c_uint, @intCast(i))] = 0;
2461 \\}
2462 });
2463
2464 cases.add("long long array index cast to usize",
2465 \\void foo() {
2466 \\ long long a[10], i = 0;
2467 \\ a[i] = 0;
2468 \\}
2469 , &[_][]const u8{
2470 \\pub export fn foo() void {
2471 \\ var a: [10]c_longlong = undefined;
2472 \\ _ = &a;
2473 \\ var i: c_longlong = 0;
2474 \\ _ = &i;
2475 \\ a[@as(usize, @intCast(i))] = 0;
2476 \\}
2477 });
2478
2479 cases.add("unsigned array index skips cast",
2480 \\void foo() {
2481 \\ unsigned int a[10], i = 0;
2482 \\ a[i] = 0;
2483 \\}
2484 , &[_][]const u8{
2485 \\pub export fn foo() void {
2486 \\ var a: [10]c_uint = undefined;
2487 \\ _ = &a;
2488 \\ var i: c_uint = 0;
2489 \\ _ = &i;
2490 \\ a[i] = 0;
2491 \\}
2492 });
2493
2494 cases.add("macro call",
2495 \\#define CALL(arg) bar(arg)
2496 \\int bar(int x) { return x; }
2497 , &[_][]const u8{
2498 \\pub inline fn CALL(arg: anytype) @TypeOf(bar(arg)) {
2499 \\ _ = &arg;
2500 \\ return bar(arg);
2501 \\}
2502 });
2503
2504 cases.add("macro call with no args",
2505 \\#define CALL(arg) bar()
2506 \\int bar(void) { return 0; }
2507 , &[_][]const u8{
2508 \\pub inline fn CALL(arg: anytype) @TypeOf(bar()) {
2509 \\ _ = &arg;
2510 \\ return bar();
2511 \\}
2512 });
2513
2514 cases.add("logical and, logical or",
2515 \\int max(int a, int b) {
2516 \\ if (a < b || a == b)
2517 \\ return b;
2518 \\ if (a >= b && a == b)
2519 \\ return a;
2520 \\ return a;
2521 \\}
2522 , &[_][]const u8{
2523 \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int {
2524 \\ var a = arg_a;
2525 \\ _ = &a;
2526 \\ var b = arg_b;
2527 \\ _ = &b;
2528 \\ if ((a < b) or (a == b)) return b;
2529 \\ if ((a >= b) and (a == b)) return a;
2530 \\ return a;
2531 \\}
2532 });
2533
2534 cases.add("simple if statement",
2535 \\int max(int a, int b) {
2536 \\ if (a < b)
2537 \\ return b;
2538 \\
2539 \\ if (a < b)
2540 \\ return b;
2541 \\ else
2542 \\ return a;
2543 \\
2544 \\ if (a < b) ; else ;
2545 \\}
2546 , &[_][]const u8{
2547 \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int {
2548 \\ var a = arg_a;
2549 \\ _ = &a;
2550 \\ var b = arg_b;
2551 \\ _ = &b;
2552 \\ if (a < b) return b;
2553 \\ if (a < b) return b else return a;
2554 \\ if (a < b) {} else {}
2555 \\ return 0;
2556 \\}
2557 });
2558
2559 cases.add("if statements",
2560 \\void foo() {
2561 \\ if (2) {
2562 \\ int a = 2;
2563 \\ }
2564 \\ if (2, 5) {
2565 \\ int a = 2;
2566 \\ }
2567 \\}
2568 , &[_][]const u8{
2569 \\pub export fn foo() void {
2570 \\ if (true) {
2571 \\ var a: c_int = 2;
2572 \\ _ = &a;
2573 \\ }
2574 \\ if ((blk: {
2575 \\ _ = @as(c_int, 2);
2576 \\ break :blk @as(c_int, 5);
2577 \\ }) != 0) {
2578 \\ var a: c_int = 2;
2579 \\ _ = &a;
2580 \\ }
2581 \\}
2582 });
2583
2584 cases.add("if on non-bool",
2585 \\enum SomeEnum { A, B, C };
2586 \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
2587 \\ if (a) return 0;
2588 \\ if (b) return 1;
2589 \\ if (c) return 2;
2590 \\ if (d) return 3;
2591 \\ return 4;
2592 \\}
2593 , &[_][]const u8{
2594 \\pub const A: c_int = 0;
2595 \\pub const B: c_int = 1;
2596 \\pub const C: c_int = 2;
2597 \\pub const enum_SomeEnum =
2598 ++ " " ++ default_enum_type ++
2599 \\;
2600 \\pub export fn if_none_bool(arg_a: c_int, arg_b: f32, arg_c: ?*anyopaque, arg_d: enum_SomeEnum) c_int {
2601 \\ var a = arg_a;
2602 \\ _ = &a;
2603 \\ var b = arg_b;
2604 \\ _ = &b;
2605 \\ var c = arg_c;
2606 \\ _ = &c;
2607 \\ var d = arg_d;
2608 \\ _ = &d;
2609 \\ if (a != 0) return 0;
2610 \\ if (b != 0) return 1;
2611 \\ if (c != null) return 2;
2612 \\ if (d != 0) return 3;
2613 \\ return 4;
2614 \\}
2615 });
2616
2617 cases.add("simple data types",
2618 \\#include <stdint.h>
2619 \\int foo(char a, unsigned char b, signed char c);
2620 \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype
2621 \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d);
2622 \\void baz(int8_t a, int16_t b, int32_t c, int64_t d);
2623 , &[_][]const u8{
2624 \\pub extern fn foo(a: u8, b: u8, c: i8) c_int;
2625 \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void;
2626 \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void;
2627 });
2628
2629 cases.add("simple function",
2630 \\int abs(int a) {
2631 \\ return a < 0 ? -a : a;
2632 \\}
2633 , &[_][]const u8{
2634 \\pub export fn abs(arg_a: c_int) c_int {
2635 \\ var a = arg_a;
2636 \\ _ = &a;
2637 \\ return if (a < @as(c_int, 0)) -a else a;
2638 \\}
2639 });
2640
2641 cases.add("post increment",
2642 \\unsigned foo1(unsigned a) {
2643 \\ a++;
2644 \\ return a;
2645 \\}
2646 \\int foo2(int a) {
2647 \\ a++;
2648 \\ return a;
2649 \\}
2650 \\int *foo3(int *a) {
2651 \\ a++;
2652 \\ return a;
2653 \\}
2654 , &[_][]const u8{
2655 \\pub export fn foo1(arg_a: c_uint) c_uint {
2656 \\ var a = arg_a;
2657 \\ _ = &a;
2658 \\ a +%= 1;
2659 \\ return a;
2660 \\}
2661 \\pub export fn foo2(arg_a: c_int) c_int {
2662 \\ var a = arg_a;
2663 \\ _ = &a;
2664 \\ a += 1;
2665 \\ return a;
2666 \\}
2667 \\pub export fn foo3(arg_a: [*c]c_int) [*c]c_int {
2668 \\ var a = arg_a;
2669 \\ _ = &a;
2670 \\ a += 1;
2671 \\ return a;
2672 \\}
2673 });
2674
2675 cases.add("deref function pointer",
2676 \\void foo(void) {}
2677 \\int baz(void) { return 0; }
2678 \\void bar(void) {
2679 \\ void(*f)(void) = foo;
2680 \\ int(*b)(void) = baz;
2681 \\ f();
2682 \\ (*(f))();
2683 \\ foo();
2684 \\ b();
2685 \\ (*(b))();
2686 \\ baz();
2687 \\}
2688 , &[_][]const u8{
2689 \\pub export fn foo() void {}
2690 \\pub export fn baz() c_int {
2691 \\ return 0;
2692 \\}
2693 \\pub export fn bar() void {
2694 \\ var f: ?*const fn () callconv(.c) void = &foo;
2695 \\ _ = &f;
2696 \\ var b: ?*const fn () callconv(.c) c_int = &baz;
2697 \\ _ = &b;
2698 \\ f.?();
2699 \\ f.?();
2700 \\ foo();
2701 \\ _ = b.?();
2702 \\ _ = b.?();
2703 \\ _ = baz();
2704 \\}
2705 });
2706
2707 cases.add("pre increment/decrement",
2708 \\void foo(void) {
2709 \\ int i = 0;
2710 \\ unsigned u = 0;
2711 \\ ++i;
2712 \\ --i;
2713 \\ ++u;
2714 \\ --u;
2715 \\ i = ++i;
2716 \\ i = --i;
2717 \\ u = ++u;
2718 \\ u = --u;
2719 \\}
2720 , &[_][]const u8{
2721 \\pub export fn foo() void {
2722 \\ var i: c_int = 0;
2723 \\ _ = &i;
2724 \\ var u: c_uint = 0;
2725 \\ _ = &u;
2726 \\ i += 1;
2727 \\ i -= 1;
2728 \\ u +%= 1;
2729 \\ u -%= 1;
2730 \\ i = blk: {
2731 \\ const ref = &i;
2732 \\ ref.* += 1;
2733 \\ break :blk ref.*;
2734 \\ };
2735 \\ i = blk: {
2736 \\ const ref = &i;
2737 \\ ref.* -= 1;
2738 \\ break :blk ref.*;
2739 \\ };
2740 \\ u = blk: {
2741 \\ const ref = &u;
2742 \\ ref.* +%= 1;
2743 \\ break :blk ref.*;
2744 \\ };
2745 \\ u = blk: {
2746 \\ const ref = &u;
2747 \\ ref.* -%= 1;
2748 \\ break :blk ref.*;
2749 \\ };
2750 \\}
2751 });
2752
2753 cases.add("shift right assign",
2754 \\int log2(unsigned a) {
2755 \\ int i = 0;
2756 \\ while (a > 0) {
2757 \\ a >>= 1;
2758 \\ }
2759 \\ return i;
2760 \\}
2761 , &[_][]const u8{
2762 \\pub export fn log2(arg_a: c_uint) c_int {
2763 \\ var a = arg_a;
2764 \\ _ = &a;
2765 \\ var i: c_int = 0;
2766 \\ _ = &i;
2767 \\ while (a > @as(c_uint, @bitCast(@as(c_int, 0)))) {
2768 \\ a >>= @intCast(@as(c_int, 1));
2769 \\ }
2770 \\ return i;
2771 \\}
2772 });
2773
2774 cases.add("shift right assign with a fixed size type",
2775 \\#include <stdint.h>
2776 \\int log2(uint32_t a) {
2777 \\ int i = 0;
2778 \\ while (a > 0) {
2779 \\ a >>= 1;
2780 \\ }
2781 \\ return i;
2782 \\}
2783 , &[_][]const u8{
2784 \\pub export fn log2(arg_a: u32) c_int {
2785 \\ var a = arg_a;
2786 \\ _ = &a;
2787 \\ var i: c_int = 0;
2788 \\ _ = &i;
2789 \\ while (a > @as(u32, @bitCast(@as(c_int, 0)))) {
2790 \\ a >>= @intCast(@as(c_int, 1));
2791 \\ }
2792 \\ return i;
2793 \\}
2794 });
2795
2796 cases.add("compound assignment operators",
2797 \\void foo(void) {
2798 \\ int a = 0;
2799 \\ unsigned b = 0;
2800 \\ a += (a += 1);
2801 \\ a -= (a -= 1);
2802 \\ a *= (a *= 1);
2803 \\ a &= (a &= 1);
2804 \\ a |= (a |= 1);
2805 \\ a ^= (a ^= 1);
2806 \\ a >>= (a >>= 1);
2807 \\ a <<= (a <<= 1);
2808 \\ a /= (a /= 1);
2809 \\ a %= (a %= 1);
2810 \\ b /= (b /= 1);
2811 \\ b %= (b %= 1);
2812 \\}
2813 , &[_][]const u8{
2814 \\pub export fn foo() void {
2815 \\ var a: c_int = 0;
2816 \\ _ = &a;
2817 \\ var b: c_uint = 0;
2818 \\ _ = &b;
2819 \\ a += blk: {
2820 \\ const ref = &a;
2821 \\ ref.* += @as(c_int, 1);
2822 \\ break :blk ref.*;
2823 \\ };
2824 \\ a -= blk: {
2825 \\ const ref = &a;
2826 \\ ref.* -= @as(c_int, 1);
2827 \\ break :blk ref.*;
2828 \\ };
2829 \\ a *= blk: {
2830 \\ const ref = &a;
2831 \\ ref.* *= @as(c_int, 1);
2832 \\ break :blk ref.*;
2833 \\ };
2834 \\ a &= blk: {
2835 \\ const ref = &a;
2836 \\ ref.* &= @as(c_int, 1);
2837 \\ break :blk ref.*;
2838 \\ };
2839 \\ a |= blk: {
2840 \\ const ref = &a;
2841 \\ ref.* |= @as(c_int, 1);
2842 \\ break :blk ref.*;
2843 \\ };
2844 \\ a ^= blk: {
2845 \\ const ref = &a;
2846 \\ ref.* ^= @as(c_int, 1);
2847 \\ break :blk ref.*;
2848 \\ };
2849 \\ a >>= @intCast(blk: {
2850 \\ const ref = &a;
2851 \\ ref.* >>= @intCast(@as(c_int, 1));
2852 \\ break :blk ref.*;
2853 \\ });
2854 \\ a <<= @intCast(blk: {
2855 \\ const ref = &a;
2856 \\ ref.* <<= @intCast(@as(c_int, 1));
2857 \\ break :blk ref.*;
2858 \\ });
2859 \\ a = @divTrunc(a, blk: {
2860 \\ const ref = &a;
2861 \\ ref.* = @divTrunc(ref.*, @as(c_int, 1));
2862 \\ break :blk ref.*;
2863 \\ });
2864 \\ a = @import("std").zig.c_translation.signedRemainder(a, blk: {
2865 \\ const ref = &a;
2866 \\ ref.* = @import("std").zig.c_translation.signedRemainder(ref.*, @as(c_int, 1));
2867 \\ break :blk ref.*;
2868 \\ });
2869 \\ b /= blk: {
2870 \\ const ref = &b;
2871 \\ ref.* /= @as(c_uint, @bitCast(@as(c_int, 1)));
2872 \\ break :blk ref.*;
2873 \\ };
2874 \\ b %= blk: {
2875 \\ const ref = &b;
2876 \\ ref.* %= @as(c_uint, @bitCast(@as(c_int, 1)));
2877 \\ break :blk ref.*;
2878 \\ };
2879 \\}
2880 });
2881
2882 cases.add("compound assignment operators unsigned",
2883 \\void foo(void) {
2884 \\ unsigned a = 0;
2885 \\ a += (a += 1);
2886 \\ a -= (a -= 1);
2887 \\ a *= (a *= 1);
2888 \\ a &= (a &= 1);
2889 \\ a |= (a |= 1);
2890 \\ a ^= (a ^= 1);
2891 \\ a >>= (a >>= 1);
2892 \\ a <<= (a <<= 1);
2893 \\}
2894 , &[_][]const u8{
2895 \\pub export fn foo() void {
2896 \\ var a: c_uint = 0;
2897 \\ _ = &a;
2898 \\ a +%= blk: {
2899 \\ const ref = &a;
2900 \\ ref.* +%= @as(c_uint, @bitCast(@as(c_int, 1)));
2901 \\ break :blk ref.*;
2902 \\ };
2903 \\ a -%= blk: {
2904 \\ const ref = &a;
2905 \\ ref.* -%= @as(c_uint, @bitCast(@as(c_int, 1)));
2906 \\ break :blk ref.*;
2907 \\ };
2908 \\ a *%= blk: {
2909 \\ const ref = &a;
2910 \\ ref.* *%= @as(c_uint, @bitCast(@as(c_int, 1)));
2911 \\ break :blk ref.*;
2912 \\ };
2913 \\ a &= blk: {
2914 \\ const ref = &a;
2915 \\ ref.* &= @as(c_uint, @bitCast(@as(c_int, 1)));
2916 \\ break :blk ref.*;
2917 \\ };
2918 \\ a |= blk: {
2919 \\ const ref = &a;
2920 \\ ref.* |= @as(c_uint, @bitCast(@as(c_int, 1)));
2921 \\ break :blk ref.*;
2922 \\ };
2923 \\ a ^= blk: {
2924 \\ const ref = &a;
2925 \\ ref.* ^= @as(c_uint, @bitCast(@as(c_int, 1)));
2926 \\ break :blk ref.*;
2927 \\ };
2928 \\ a >>= @intCast(blk: {
2929 \\ const ref = &a;
2930 \\ ref.* >>= @intCast(@as(c_int, 1));
2931 \\ break :blk ref.*;
2932 \\ });
2933 \\ a <<= @intCast(blk: {
2934 \\ const ref = &a;
2935 \\ ref.* <<= @intCast(@as(c_int, 1));
2936 \\ break :blk ref.*;
2937 \\ });
2938 \\}
2939 });
2940
2941 cases.add("post increment/decrement",
2942 \\void foo(void) {
2943 \\ int i = 0;
2944 \\ unsigned u = 0;
2945 \\ i++;
2946 \\ i--;
2947 \\ u++;
2948 \\ u--;
2949 \\ i = i++;
2950 \\ i = i--;
2951 \\ u = u++;
2952 \\ u = u--;
2953 \\}
2954 , &[_][]const u8{
2955 \\pub export fn foo() void {
2956 \\ var i: c_int = 0;
2957 \\ _ = &i;
2958 \\ var u: c_uint = 0;
2959 \\ _ = &u;
2960 \\ i += 1;
2961 \\ i -= 1;
2962 \\ u +%= 1;
2963 \\ u -%= 1;
2964 \\ i = blk: {
2965 \\ const ref = &i;
2966 \\ const tmp = ref.*;
2967 \\ ref.* += 1;
2968 \\ break :blk tmp;
2969 \\ };
2970 \\ i = blk: {
2971 \\ const ref = &i;
2972 \\ const tmp = ref.*;
2973 \\ ref.* -= 1;
2974 \\ break :blk tmp;
2975 \\ };
2976 \\ u = blk: {
2977 \\ const ref = &u;
2978 \\ const tmp = ref.*;
2979 \\ ref.* +%= 1;
2980 \\ break :blk tmp;
2981 \\ };
2982 \\ u = blk: {
2983 \\ const ref = &u;
2984 \\ const tmp = ref.*;
2985 \\ ref.* -%= 1;
2986 \\ break :blk tmp;
2987 \\ };
2988 \\}
2989 });
2990
2991 cases.add("implicit casts",
2992 \\#include <stdbool.h>
2993 \\
2994 \\void fn_int(int x);
2995 \\void fn_f32(float x);
2996 \\void fn_f64(double x);
2997 \\void fn_char(char x);
2998 \\void fn_bool(bool x);
2999 \\void fn_ptr(void *x);
3000 \\
3001 \\void call() {
3002 \\ fn_int(3.0f);
3003 \\ fn_int(3.0);
3004 \\ fn_int('ABCD');
3005 \\ fn_f32(3);
3006 \\ fn_f64(3);
3007 \\ fn_char('3');
3008 \\ fn_char('\x1');
3009 \\ fn_char(0);
3010 \\ fn_f32(3.0f);
3011 \\ fn_f64(3.0);
3012 \\ fn_bool(123);
3013 \\ fn_bool(0);
3014 \\ fn_bool(&fn_int);
3015 \\ fn_int((int)&fn_int);
3016 \\ fn_ptr((void *)42);
3017 \\}
3018 , &[_][]const u8{
3019 \\pub extern fn fn_int(x: c_int) void;
3020 \\pub extern fn fn_f32(x: f32) void;
3021 \\pub extern fn fn_f64(x: f64) void;
3022 \\pub extern fn fn_char(x: u8) void;
3023 \\pub extern fn fn_bool(x: bool) void;
3024 \\pub extern fn fn_ptr(x: ?*anyopaque) void;
3025 \\pub export fn call() void {
3026 \\ fn_int(@as(c_int, @intFromFloat(3.0)));
3027 \\ fn_int(@as(c_int, @intFromFloat(3.0)));
3028 \\ fn_int(@as(c_int, 1094861636));
3029 \\ fn_f32(@as(f32, @floatFromInt(@as(c_int, 3))));
3030 \\ fn_f64(@as(f64, @floatFromInt(@as(c_int, 3))));
3031 \\ fn_char(@as(u8, @bitCast(@as(i8, @truncate(@as(c_int, '3'))))));
3032 \\ fn_char(@as(u8, @bitCast(@as(i8, @truncate(@as(c_int, '\x01'))))));
3033 \\ fn_char(@as(u8, @bitCast(@as(i8, @truncate(@as(c_int, 0))))));
3034 \\ fn_f32(3.0);
3035 \\ fn_f64(3.0);
3036 \\ fn_bool(@as(c_int, 123) != 0);
3037 \\ fn_bool(@as(c_int, 0) != 0);
3038 \\ fn_bool(@intFromPtr(&fn_int) != 0);
3039 \\ fn_int(@as(c_int, @intCast(@intFromPtr(&fn_int))));
3040 \\ fn_ptr(@as(?*anyopaque, @ptrFromInt(@as(c_int, 42))));
3041 \\}
3042 });
3043
3044 cases.add("function call",
3045 \\static void bar(void) { }
3046 \\void foo(int *(baz)(void)) {
3047 \\ bar();
3048 \\ baz();
3049 \\}
3050 , &[_][]const u8{
3051 \\pub fn bar() callconv(.c) void {}
3052 \\pub export fn foo(arg_baz: ?*const fn () callconv(.c) [*c]c_int) void {
3053 \\ var baz = arg_baz;
3054 \\ _ = &baz;
3055 \\ bar();
3056 \\ _ = baz.?();
3057 \\}
3058 });
3059
3060 cases.add("macro defines string literal with octal",
3061 \\#define FOO "aoeu\023 derp"
3062 \\#define FOO2 "aoeu\0234 derp"
3063 \\#define FOO_CHAR '\077'
3064 , &[_][]const u8{
3065 \\pub const FOO = "aoeu\x13 derp";
3066 ,
3067 \\pub const FOO2 = "aoeu\x134 derp";
3068 ,
3069 \\pub const FOO_CHAR = '\x3f';
3070 });
3071
3072 cases.add("macro cast",
3073 \\#include <stdint.h>
3074 \\int baz(void *arg) { return 0; }
3075 \\#define FOO(bar) baz((void *)(baz))
3076 \\#define BAR (void*) a
3077 \\#define BAZ (uint32_t)(2)
3078 \\#define a 2
3079 , &[_][]const u8{
3080 \\pub inline fn FOO(bar: anytype) @TypeOf(baz(@import("std").zig.c_translation.cast(?*anyopaque, baz))) {
3081 \\ _ = &bar;
3082 \\ return baz(@import("std").zig.c_translation.cast(?*anyopaque, baz));
3083 \\}
3084 ,
3085 \\pub const BAR = @import("std").zig.c_translation.cast(?*anyopaque, a);
3086 ,
3087 \\pub const BAZ = @import("std").zig.c_translation.cast(u32, @as(c_int, 2));
3088 });
3089
3090 cases.add("macro with cast to unsigned short, long, and long long",
3091 \\#define CURLAUTH_BASIC_BUT_USHORT ((unsigned short) 1)
3092 \\#define CURLAUTH_BASIC ((unsigned long) 1)
3093 \\#define CURLAUTH_BASIC_BUT_ULONGLONG ((unsigned long long) 1)
3094 , &[_][]const u8{
3095 \\pub const CURLAUTH_BASIC_BUT_USHORT = @import("std").zig.c_translation.cast(c_ushort, @as(c_int, 1));
3096 \\pub const CURLAUTH_BASIC = @import("std").zig.c_translation.cast(c_ulong, @as(c_int, 1));
3097 \\pub const CURLAUTH_BASIC_BUT_ULONGLONG = @import("std").zig.c_translation.cast(c_ulonglong, @as(c_int, 1));
3098 });
3099
3100 cases.add("macro conditional operator",
3101 \\ int a, b, c;
3102 \\#define FOO a ? b : c
3103 , &[_][]const u8{
3104 \\pub inline fn FOO() @TypeOf(if (a) b else c) {
3105 \\ return if (a) b else c;
3106 \\}
3107 });
3108
3109 cases.add("do while as expr",
3110 \\static void foo(void) {
3111 \\ if (1)
3112 \\ do {} while (0);
3113 \\}
3114 , &[_][]const u8{
3115 \\pub fn foo() callconv(.c) void {
3116 \\ if (true) while (true) {
3117 \\ if (!false) break;
3118 \\ };
3119 \\}
3120 });
3121
3122 cases.add("macro comparisons",
3123 \\#define MIN(a, b) ((b) < (a) ? (b) : (a))
3124 \\#define MAX(a, b) ((b) > (a) ? (b) : (a))
3125 , &[_][]const u8{
3126 \\pub inline fn MIN(a: anytype, b: anytype) @TypeOf(if (b < a) b else a) {
3127 \\ _ = &a;
3128 \\ _ = &b;
3129 \\ return if (b < a) b else a;
3130 \\}
3131 ,
3132 \\pub inline fn MAX(a: anytype, b: anytype) @TypeOf(if (b > a) b else a) {
3133 \\ _ = &a;
3134 \\ _ = &b;
3135 \\ return if (b > a) b else a;
3136 \\}
3137 });
3138
3139 cases.add("nested assignment",
3140 \\int foo(int *p, int x) {
3141 \\ return *p++ = x;
3142 \\}
3143 , &[_][]const u8{
3144 \\pub export fn foo(arg_p: [*c]c_int, arg_x: c_int) c_int {
3145 \\ var p = arg_p;
3146 \\ _ = &p;
3147 \\ var x = arg_x;
3148 \\ _ = &x;
3149 \\ return blk: {
3150 \\ const tmp = x;
3151 \\ (blk_1: {
3152 \\ const ref = &p;
3153 \\ const tmp_2 = ref.*;
3154 \\ ref.* += 1;
3155 \\ break :blk_1 tmp_2;
3156 \\ }).* = tmp;
3157 \\ break :blk tmp;
3158 \\ };
3159 \\}
3160 });
3161
3162 cases.add("widening and truncating integer casting to different signedness",
3163 \\unsigned long foo(void) {
3164 \\ return -1;
3165 \\}
3166 \\unsigned short bar(long x) {
3167 \\ return x;
3168 \\}
3169 , &[_][]const u8{
3170 \\pub export fn foo() c_ulong {
3171 \\ return @as(c_ulong, @bitCast(@as(c_long, -@as(c_int, 1))));
3172 \\}
3173 \\pub export fn bar(arg_x: c_long) c_ushort {
3174 \\ var x = arg_x;
3175 \\ _ = &x;
3176 \\ return @as(c_ushort, @bitCast(@as(c_short, @truncate(x))));
3177 \\}
3178 });
3179
3180 cases.add("arg name aliasing decl which comes after",
3181 \\void foo(int bar) {
3182 \\ bar = 2;
3183 \\}
3184 \\int bar = 4;
3185 , &[_][]const u8{
3186 \\pub export fn foo(arg_bar_1: c_int) void {
3187 \\ var bar_1 = arg_bar_1;
3188 \\ _ = &bar_1;
3189 \\ bar_1 = 2;
3190 \\}
3191 \\pub export var bar: c_int = 4;
3192 });
3193
3194 cases.add("arg name aliasing macro which comes after",
3195 \\void foo(int bar) {
3196 \\ bar = 2;
3197 \\}
3198 \\#define bar 4
3199 , &[_][]const u8{
3200 \\pub export fn foo(arg_bar_1: c_int) void {
3201 \\ var bar_1 = arg_bar_1;
3202 \\ _ = &bar_1;
3203 \\ bar_1 = 2;
3204 \\}
3205 ,
3206 \\pub const bar = @as(c_int, 4);
3207 });
3208
3209 cases.add("don't export inline functions",
3210 \\inline void a(void) {}
3211 \\static void b(void) {}
3212 \\void c(void) {}
3213 \\static void foo() {}
3214 , &[_][]const u8{
3215 \\pub fn a() callconv(.c) void {}
3216 \\pub fn b() callconv(.c) void {}
3217 \\pub export fn c() void {}
3218 \\pub fn foo() callconv(.c) void {}
3219 });
3220
3221 cases.add("casting away const and volatile",
3222 \\void foo(int *a) {}
3223 \\void bar(const int *a) {
3224 \\ foo((int *)a);
3225 \\}
3226 \\void baz(volatile int *a) {
3227 \\ foo((int *)a);
3228 \\}
3229 , &[_][]const u8{
3230 \\pub export fn foo(arg_a: [*c]c_int) void {
3231 \\ var a = arg_a;
3232 \\ _ = &a;
3233 \\}
3234 \\pub export fn bar(arg_a: [*c]const c_int) void {
3235 \\ var a = arg_a;
3236 \\ _ = &a;
3237 \\ foo(@as([*c]c_int, @ptrCast(@constCast(@volatileCast(a)))));
3238 \\}
3239 \\pub export fn baz(arg_a: [*c]volatile c_int) void {
3240 \\ var a = arg_a;
3241 \\ _ = &a;
3242 \\ foo(@as([*c]c_int, @ptrCast(@constCast(@volatileCast(a)))));
3243 \\}
3244 });
3245
3246 cases.add("handling of _Bool type",
3247 \\_Bool foo(_Bool x) {
3248 \\ _Bool a = x != 1;
3249 \\ _Bool b = a != 0;
3250 \\ _Bool c = foo;
3251 \\ return foo(c != b);
3252 \\}
3253 , &[_][]const u8{
3254 \\pub export fn foo(arg_x: bool) bool {
3255 \\ var x = arg_x;
3256 \\ _ = &x;
3257 \\ var a: bool = @as(c_int, @intFromBool(x)) != @as(c_int, 1);
3258 \\ _ = &a;
3259 \\ var b: bool = @as(c_int, @intFromBool(a)) != @as(c_int, 0);
3260 \\ _ = &b;
3261 \\ var c: bool = @intFromPtr(&foo) != 0;
3262 \\ _ = &c;
3263 \\ return foo(@as(c_int, @intFromBool(c)) != @as(c_int, @intFromBool(b)));
3264 \\}
3265 });
3266
3267 cases.add("Don't make const parameters mutable",
3268 \\int max(const int x, int y) {
3269 \\ return (x > y) ? x : y;
3270 \\}
3271 , &[_][]const u8{
3272 \\pub export fn max(x: c_int, arg_y: c_int) c_int {
3273 \\ _ = &x;
3274 \\ var y = arg_y;
3275 \\ _ = &y;
3276 \\ return if (x > y) x else y;
3277 \\}
3278 });
3279
3280 cases.add("string concatenation in macros",
3281 \\#define FOO "hello"
3282 \\#define BAR FOO " world"
3283 \\#define BAZ "oh, " FOO
3284 , &[_][]const u8{
3285 \\pub const FOO = "hello";
3286 ,
3287 \\pub const BAR = FOO ++ " world";
3288 ,
3289 \\pub const BAZ = "oh, " ++ FOO;
3290 });
3291
3292 cases.add("string concatenation in macros: two defines",
3293 \\#define FOO "hello"
3294 \\#define BAZ " world"
3295 \\#define BAR FOO BAZ
3296 , &[_][]const u8{
3297 \\pub const FOO = "hello";
3298 ,
3299 \\pub const BAZ = " world";
3300 ,
3301 \\pub const BAR = FOO ++ BAZ;
3302 });
3303
3304 cases.add("string concatenation in macros: two strings",
3305 \\#define FOO "a" "b"
3306 \\#define BAR FOO "c"
3307 , &[_][]const u8{
3308 \\pub const FOO = "a" ++ "b";
3309 ,
3310 \\pub const BAR = FOO ++ "c";
3311 });
3312
3313 cases.add("string concatenation in macros: three strings",
3314 \\#define FOO "a" "b" "c"
3315 , &[_][]const u8{
3316 \\pub const FOO = "a" ++ "b" ++ "c";
3317 });
3318
3319 cases.add("multibyte character literals",
3320 \\#define FOO 'abcd'
3321 , &[_][]const u8{
3322 \\pub const FOO = 0x61626364;
3323 });
3324
3325 cases.add("Make sure casts are grouped",
3326 \\typedef struct
3327 \\{
3328 \\ int i;
3329 \\}
3330 \\*_XPrivDisplay;
3331 \\typedef struct _XDisplay Display;
3332 \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)
3333 \\
3334 , &[_][]const u8{
3335 \\pub inline fn DefaultScreen(dpy: anytype) @TypeOf(@import("std").zig.c_translation.cast(_XPrivDisplay, dpy).*.default_screen) {
3336 \\ _ = &dpy;
3337 \\ return @import("std").zig.c_translation.cast(_XPrivDisplay, dpy).*.default_screen;
3338 \\}
3339 });
3340
3341 cases.add("macro integer literal casts",
3342 \\#define NULL ((void*)0)
3343 \\#define FOO ((int)0x8000)
3344 , &[_][]const u8{
3345 \\pub const NULL = @import("std").zig.c_translation.cast(?*anyopaque, @as(c_int, 0));
3346 ,
3347 \\pub const FOO = @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hex));
3348 });
3349
3350 if (builtin.abi == .msvc) {
3351 cases.add("nameless struct fields",
3352 \\typedef struct NAMED
3353 \\{
3354 \\ long name;
3355 \\} NAMED;
3356 \\
3357 \\typedef struct ONENAMEWITHSTRUCT
3358 \\{
3359 \\ NAMED;
3360 \\ long b;
3361 \\} ONENAMEWITHSTRUCT;
3362 , &[_][]const u8{
3363 \\pub const struct_NAMED = extern struct {
3364 \\ name: c_long = @import("std").mem.zeroes(c_long),
3365 \\};
3366 \\pub const NAMED = struct_NAMED;
3367 \\pub const struct_ONENAMEWITHSTRUCT = extern struct {
3368 \\ unnamed_0: struct_NAMED = = @import("std").mem.zeroes(struct_NAMED),
3369 \\ b: c_long = @import("std").mem.zeroes(c_long),
3370 \\};
3371 });
3372 } else {
3373 cases.add("nameless struct fields",
3374 \\typedef struct NAMED
3375 \\{
3376 \\ long name;
3377 \\} NAMED;
3378 \\
3379 \\typedef struct ONENAMEWITHSTRUCT
3380 \\{
3381 \\ NAMED;
3382 \\ long b;
3383 \\} ONENAMEWITHSTRUCT;
3384 , &[_][]const u8{
3385 \\pub const struct_NAMED = extern struct {
3386 \\ name: c_long = @import("std").mem.zeroes(c_long),
3387 \\};
3388 \\pub const NAMED = struct_NAMED;
3389 \\pub const struct_ONENAMEWITHSTRUCT = extern struct {
3390 \\ b: c_long = @import("std").mem.zeroes(c_long),
3391 \\};
3392 });
3393 }
3394
3395 cases.add("integer literal promotion",
3396 \\#define GUARANTEED_TO_FIT_1 1024
3397 \\#define GUARANTEED_TO_FIT_2 10241024L
3398 \\#define GUARANTEED_TO_FIT_3 20482048LU
3399 \\#define MAY_NEED_PROMOTION_1 10241024
3400 \\#define MAY_NEED_PROMOTION_2 307230723072L
3401 \\#define MAY_NEED_PROMOTION_3 819281928192LU
3402 \\#define MAY_NEED_PROMOTION_HEX 0x80000000
3403 \\#define MAY_NEED_PROMOTION_OCT 020000000000
3404 , &[_][]const u8{
3405 \\pub const GUARANTEED_TO_FIT_1 = @as(c_int, 1024);
3406 \\pub const GUARANTEED_TO_FIT_2 = @as(c_long, 10241024);
3407 \\pub const GUARANTEED_TO_FIT_3 = @as(c_ulong, 20482048);
3408 \\pub const MAY_NEED_PROMOTION_1 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 10241024, .decimal);
3409 \\pub const MAY_NEED_PROMOTION_2 = @import("std").zig.c_translation.promoteIntLiteral(c_long, 307230723072, .decimal);
3410 \\pub const MAY_NEED_PROMOTION_3 = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 819281928192, .decimal);
3411 \\pub const MAY_NEED_PROMOTION_HEX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x80000000, .hex);
3412 \\pub const MAY_NEED_PROMOTION_OCT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0o20000000000, .octal);
3413 });
3414
3415 cases.add("demote un-implemented builtins",
3416 \\#define FOO(X) __builtin_alloca_with_align((X), 8)
3417 , &[_][]const u8{
3418 \\pub const FOO = @compileError("unable to translate macro: undefined identifier `__builtin_alloca_with_align`");
3419 });
3420
3421 cases.add("null sentinel arrays when initialized from string literal. Issue #8256",
3422 \\#include <stdint.h>
3423 \\char zero[0] = "abc";
3424 \\uint32_t zero_w[0] = U"💯💯💯";
3425 \\char empty_incomplete[] = "";
3426 \\uint32_t empty_incomplete_w[] = U"";
3427 \\char empty_constant[100] = "";
3428 \\uint32_t empty_constant_w[100] = U"";
3429 \\char incomplete[] = "abc";
3430 \\uint32_t incomplete_w[] = U"💯💯💯";
3431 \\char truncated[1] = "abc";
3432 \\uint32_t truncated_w[1] = U"💯💯💯";
3433 \\char extend[5] = "a";
3434 \\uint32_t extend_w[5] = U"💯";
3435 \\char no_null[3] = "abc";
3436 \\uint32_t no_null_w[3] = U"💯💯💯";
3437 , &[_][]const u8{
3438 \\pub export var zero: [0]u8 = [0]u8{};
3439 \\pub export var zero_w: [0]u32 = [0]u32{};
3440 \\pub export var empty_incomplete: [1]u8 = [1]u8{0} ** 1;
3441 \\pub export var empty_incomplete_w: [1]u32 = [1]u32{0} ** 1;
3442 \\pub export var empty_constant: [100]u8 = [1]u8{0} ** 100;
3443 \\pub export var empty_constant_w: [100]u32 = [1]u32{0} ** 100;
3444 \\pub export var incomplete: [3:0]u8 = "abc".*;
3445 \\pub export var incomplete_w: [3:0]u32 = [3:0]u32{
3446 \\ '\u{1f4af}',
3447 \\ '\u{1f4af}',
3448 \\ '\u{1f4af}',
3449 \\};
3450 \\pub export var truncated: [1]u8 = "abc"[0..1].*;
3451 \\pub export var truncated_w: [1]u32 = [1]u32{
3452 \\ '\u{1f4af}',
3453 \\};
3454 \\pub export var extend: [5]u8 = "a"[0..1].* ++ [1]u8{0} ** 4;
3455 \\pub export var extend_w: [5]u32 = [1]u32{
3456 \\ '\u{1f4af}',
3457 \\} ++ [1]u32{0} ** 4;
3458 \\pub export var no_null: [3]u8 = "abc".*;
3459 \\pub export var no_null_w: [3]u32 = [3]u32{
3460 \\ '\u{1f4af}',
3461 \\ '\u{1f4af}',
3462 \\ '\u{1f4af}',
3463 \\};
3464 });
3465
3466 cases.add("global assembly",
3467 \\__asm__(".globl func\n\t"
3468 \\ ".type func, @function\n\t"
3469 \\ "func:\n\t"
3470 \\ ".cfi_startproc\n\t"
3471 \\ "movl $42, %eax\n\t"
3472 \\ "ret\n\t"
3473 \\ ".cfi_endproc");
3474 , &[_][]const u8{
3475 \\comptime {
3476 \\ asm (".globl func\n\t.type func, @function\n\tfunc:\n\t.cfi_startproc\n\tmovl $42, %eax\n\tret\n\t.cfi_endproc");
3477 \\}
3478 });
3479
3480 cases.add("Demote function that initializes opaque struct",
3481 \\struct my_struct {
3482 \\ unsigned a: 15;
3483 \\ unsigned: 2;
3484 \\ unsigned b: 15;
3485 \\};
3486 \\void initialize(void) {
3487 \\ struct my_struct S = {.a = 1, .b = 2};
3488 \\}
3489 , &[_][]const u8{
3490 \\warning: local variable has opaque type
3491 ,
3492 \\warning: unable to translate function, demoted to extern
3493 \\pub extern fn initialize() void;
3494 });
3495
3496 cases.add("Demote function that dereferences opaque type",
3497 \\struct my_struct {
3498 \\ unsigned a: 1;
3499 \\};
3500 \\void deref(struct my_struct *s) {
3501 \\ *s;
3502 \\}
3503 , &[_][]const u8{
3504 \\warning: cannot dereference opaque type
3505 ,
3506 \\warning: unable to translate function, demoted to extern
3507 \\pub extern fn deref(arg_s: ?*struct_my_struct) void;
3508 });
3509
3510 cases.add("Demote function that dereference types that contain opaque type",
3511 \\struct inner {
3512 \\ _Atomic int a;
3513 \\};
3514 \\struct outer {
3515 \\ int thing;
3516 \\ struct inner sub_struct;
3517 \\};
3518 \\void deref(struct outer *s) {
3519 \\ *s;
3520 \\}
3521 , &[_][]const u8{
3522 \\pub const struct_inner = opaque {};
3523 ,
3524 \\pub const struct_outer = extern struct {
3525 \\ thing: c_int = @import("std").mem.zeroes(c_int),
3526 \\ sub_struct: struct_inner = @import("std").mem.zeroes(struct_inner),
3527 \\};
3528 ,
3529 \\warning: unable to translate function, demoted to extern
3530 ,
3531 \\pub extern fn deref(arg_s: ?*struct_outer) void;
3532 });
3533
3534 cases.add("Function prototype declared within function",
3535 \\int foo(void) {
3536 \\ extern int bar(int, int);
3537 \\ return bar(1, 2);
3538 \\}
3539 , &[_][]const u8{
3540 \\pub export fn foo() c_int {
3541 \\ const ExternLocal_bar = struct {
3542 \\ pub extern fn bar(c_int, c_int) c_int;
3543 \\ };
3544 \\ _ = &ExternLocal_bar;
3545 \\ return ExternLocal_bar.bar(@as(c_int, 1), @as(c_int, 2));
3546 \\}
3547 });
3548
3549 cases.add("static local variable zero-initialized if no initializer",
3550 \\struct FOO {int x; int y;};
3551 \\int bar(void) {
3552 \\ static struct FOO foo;
3553 \\ return foo.x;
3554 \\}
3555 , &[_][]const u8{
3556 \\pub const struct_FOO = extern struct {
3557 \\ x: c_int = @import("std").mem.zeroes(c_int),
3558 \\ y: c_int = @import("std").mem.zeroes(c_int),
3559 \\};
3560 \\pub export fn bar() c_int {
3561 \\ const foo = struct {
3562 \\ var static: struct_FOO = @import("std").mem.zeroes(struct_FOO);
3563 \\ };
3564 \\ _ = &foo;
3565 \\ return foo.static.x;
3566 \\}
3567 });
3568
3569 cases.add("macro with nontrivial cast",
3570 \\#define MAP_FAILED ((void *) -1)
3571 \\typedef long long LONG_PTR;
3572 \\#define INVALID_HANDLE_VALUE ((void *)(LONG_PTR)-1)
3573 , &[_][]const u8{
3574 \\pub const MAP_FAILED = @import("std").zig.c_translation.cast(?*anyopaque, -@as(c_int, 1));
3575 \\pub const INVALID_HANDLE_VALUE = @import("std").zig.c_translation.cast(?*anyopaque, @import("std").zig.c_translation.cast(LONG_PTR, -@as(c_int, 1)));
3576 });
3577
3578 cases.add("discard unused local variables and function parameters",
3579 \\#define FOO(A, B) (A)
3580 \\int bar(int x, int y) {
3581 \\ return x;
3582 \\}
3583 , &[_][]const u8{
3584 \\pub export fn bar(arg_x: c_int, arg_y: c_int) c_int {
3585 \\ var x = arg_x;
3586 \\ _ = &x;
3587 \\ var y = arg_y;
3588 \\ _ = &y;
3589 \\ return x;
3590 \\}
3591 ,
3592 \\pub inline fn FOO(A: anytype, B: anytype) @TypeOf(A) {
3593 \\ _ = &A;
3594 \\ _ = &B;
3595 \\ return A;
3596 \\}
3597 });
3598
3599 cases.add("Use @ syntax for bare underscore identifier in macro or public symbol",
3600 \\#define FOO _
3601 \\int _ = 42;
3602 , &[_][]const u8{
3603 \\pub inline fn FOO() @TypeOf(@"_") {
3604 \\ return @"_";
3605 \\}
3606 ,
3607 \\pub export var @"_": c_int = 42;
3608 });
3609
3610 cases.add("Macro matching",
3611 \\#define FOO(X) (X ## U)
3612 , &[_][]const u8{
3613 \\pub const FOO = @import("std").zig.c_translation.Macros.U_SUFFIX;
3614 });
3615
3616 cases.add("Simple array access of pointer with non-negative integer constant",
3617 \\void foo(int *p) {
3618 \\ p[0];
3619 \\ p[1];
3620 \\}
3621 , &[_][]const u8{
3622 \\_ = p[@as(c_uint, @intCast(@as(c_int, 0)))];
3623 ,
3624 \\_ = p[@as(c_uint, @intCast(@as(c_int, 1)))];
3625 });
3626
3627 cases.add("Undefined macro identifier",
3628 \\#define FOO BAR
3629 , &[_][]const u8{
3630 \\pub const FOO = @compileError("unable to translate macro: undefined identifier `BAR`");
3631 });
3632
3633 cases.add("Macro redefines builtin",
3634 \\#define FOO __builtin_popcount
3635 , &[_][]const u8{
3636 \\pub const FOO = __builtin_popcount;
3637 });
3638
3639 cases.add("Only consider public decls in `isBuiltinDefined`",
3640 \\#define FOO std
3641 , &[_][]const u8{
3642 \\pub const FOO = @compileError("unable to translate macro: undefined identifier `std`");
3643 });
3644
3645 cases.add("Macro without a value",
3646 \\#define FOO
3647 , &[_][]const u8{
3648 \\pub const FOO = "";
3649 });
3650
3651 cases.add("leading zeroes",
3652 \\#define O_RDONLY 00
3653 \\#define HELLO 000
3654 \\#define ZERO 0
3655 \\#define WORLD 00000123
3656 , &[_][]const u8{
3657 \\pub const O_RDONLY = @as(c_int, 0o0);
3658 \\pub const HELLO = @as(c_int, 0o00);
3659 \\pub const ZERO = @as(c_int, 0);
3660 \\pub const WORLD = @as(c_int, 0o0000123);
3661 });
3662
3663 cases.add("Assign expression from bool to int",
3664 \\void foo(void) {
3665 \\ int a;
3666 \\ if (a = 1 > 0) {}
3667 \\}
3668 , &[_][]const u8{
3669 \\pub export fn foo() void {
3670 \\ var a: c_int = undefined;
3671 \\ _ = &a;
3672 \\ if ((blk: {
3673 \\ const tmp = @intFromBool(@as(c_int, 1) > @as(c_int, 0));
3674 \\ a = tmp;
3675 \\ break :blk tmp;
3676 \\ }) != 0) {}
3677 \\}
3678 });
3679
3680 if (builtin.os.tag == .windows) {
3681 cases.add("Pointer subtraction with typedef",
3682 \\typedef char* S;
3683 \\void foo() {
3684 \\ S a, b;
3685 \\ long long c = a - b;
3686 \\}
3687 , &[_][]const u8{
3688 \\pub export fn foo() void {
3689 \\ var a: S = undefined;
3690 \\ _ = &a;
3691 \\ var b: S = undefined;
3692 \\ _ = &b;
3693 \\ var c: c_longlong = @divExact(@as(c_longlong, @bitCast(@intFromPtr(a) -% @intFromPtr(b))), @sizeOf(u8));
3694 \\ _ = &c;
3695 \\}
3696 });
3697 } else {
3698 cases.add("Pointer subtraction with typedef",
3699 \\typedef char* S;
3700 \\void foo() {
3701 \\ S a, b;
3702 \\ long c = a - b;
3703 \\}
3704 , &[_][]const u8{
3705 \\pub export fn foo() void {
3706 \\ var a: S = undefined;
3707 \\ _ = &a;
3708 \\ var b: S = undefined;
3709 \\ _ = &b;
3710 \\ var c: c_long = @divExact(@as(c_long, @bitCast(@intFromPtr(a) -% @intFromPtr(b))), @sizeOf(u8));
3711 \\ _ = &c;
3712 \\}
3713 });
3714 }
3715
3716 cases.add("extern array of unknown length",
3717 \\extern int foo[];
3718 , &[_][]const u8{
3719 \\const foo: [*c]c_int = @extern([*c]c_int, .{
3720 \\ .name = "foo",
3721 \\});
3722 });
3723
3724 cases.add("string array initializer",
3725 \\static const char foo[] = {"bar"};
3726 , &[_][]const u8{
3727 \\pub const foo: [3:0]u8 = "bar";
3728 });
3729
3730 cases.add("worst-case assign from mangle prefix",
3731 \\void foo() {
3732 \\ int n, tmp = 1;
3733 \\ if (n = tmp) {}
3734 \\}
3735 , &[_][]const u8{
3736 \\pub export fn foo() void {
3737 \\ var n: c_int = undefined;
3738 \\ _ = &n;
3739 \\ var tmp: c_int = 1;
3740 \\ _ = &tmp;
3741 \\ if ((blk: {
3742 \\ const tmp_1 = tmp;
3743 \\ n = tmp_1;
3744 \\ break :blk tmp_1;
3745 \\ }) != 0) {}
3746 \\}
3747 });
3748
3749 cases.add("worst-case assign to mangle prefix",
3750 \\void foo() {
3751 \\ int tmp, n = 1;
3752 \\ if (tmp = n) {}
3753 \\}
3754 , &[_][]const u8{
3755 \\pub export fn foo() void {
3756 \\ var tmp: c_int = undefined;
3757 \\ _ = &tmp;
3758 \\ var n: c_int = 1;
3759 \\ _ = &n;
3760 \\ if ((blk: {
3761 \\ const tmp_1 = n;
3762 \\ tmp = tmp_1;
3763 \\ break :blk tmp_1;
3764 \\ }) != 0) {}
3765 \\}
3766 });
3767
3768 cases.add("worst-case precrement mangle prefix",
3769 \\void foo() {
3770 \\ int n, ref = 1;
3771 \\ if (n = ++ref) {}
3772 \\}
3773 , &[_][]const u8{
3774 \\pub export fn foo() void {
3775 \\ var n: c_int = undefined;
3776 \\ _ = &n;
3777 \\ var ref: c_int = 1;
3778 \\ _ = &ref;
3779 \\ if ((blk: {
3780 \\ const tmp = blk_1: {
3781 \\ const ref_2 = &ref;
3782 \\ ref_2.* += 1;
3783 \\ break :blk_1 ref_2.*;
3784 \\ };
3785 \\ n = tmp;
3786 \\ break :blk tmp;
3787 \\ }) != 0) {}
3788 \\}
3789 });
3790
3791 cases.add("worst-case postcrement mangle prefix",
3792 \\void foo() {
3793 \\ int n, ref = 1;
3794 \\ if (n = ref++) {}
3795 \\}
3796 , &[_][]const u8{
3797 \\pub export fn foo() void {
3798 \\ var n: c_int = undefined;
3799 \\ _ = &n;
3800 \\ var ref: c_int = 1;
3801 \\ _ = &ref;
3802 \\ if ((blk: {
3803 \\ const tmp = blk_1: {
3804 \\ const ref_2 = &ref;
3805 \\ const tmp_3 = ref_2.*;
3806 \\ ref_2.* += 1;
3807 \\ break :blk_1 tmp_3;
3808 \\ };
3809 \\ n = tmp;
3810 \\ break :blk tmp;
3811 \\ }) != 0) {}
3812 \\}
3813 });
3814
3815 cases.add("worst-case compound assign from mangle prefix",
3816 \\void foo() {
3817 \\ int n, ref = 1;
3818 \\ if (n += ref) {}
3819 \\}
3820 , &[_][]const u8{
3821 \\pub export fn foo() void {
3822 \\ var n: c_int = undefined;
3823 \\ _ = &n;
3824 \\ var ref: c_int = 1;
3825 \\ _ = &ref;
3826 \\ if ((blk: {
3827 \\ const ref_1 = &n;
3828 \\ ref_1.* += ref;
3829 \\ break :blk ref_1.*;
3830 \\ }) != 0) {}
3831 \\}
3832 });
3833
3834 cases.add("worst-case compound assign to mangle prefix",
3835 \\void foo() {
3836 \\ int ref, n = 1;
3837 \\ if (ref += n) {}
3838 \\}
3839 , &[_][]const u8{
3840 \\pub export fn foo() void {
3841 \\ var ref: c_int = undefined;
3842 \\ _ = &ref;
3843 \\ var n: c_int = 1;
3844 \\ _ = &n;
3845 \\ if ((blk: {
3846 \\ const ref_1 = &ref;
3847 \\ ref_1.* += n;
3848 \\ break :blk ref_1.*;
3849 \\ }) != 0) {}
3850 \\}
3851 });
3852
3853 cases.add("binary conditional operator where condition is the mangle prefix",
3854 \\void foo() {
3855 \\ int f = 1;
3856 \\ int n, cond_temp = 1;
3857 \\ if (n = (cond_temp)?:(f)) {}
3858 \\}
3859 , &[_][]const u8{
3860 \\pub export fn foo() void {
3861 \\ var f: c_int = 1;
3862 \\ _ = &f;
3863 \\ var n: c_int = undefined;
3864 \\ _ = &n;
3865 \\ var cond_temp: c_int = 1;
3866 \\ _ = &cond_temp;
3867 \\ if ((blk: {
3868 \\ const tmp = blk_1: {
3869 \\ const cond_temp_2 = cond_temp;
3870 \\ break :blk_1 if (cond_temp_2 != 0) cond_temp_2 else f;
3871 \\ };
3872 \\ n = tmp;
3873 \\ break :blk tmp;
3874 \\ }) != 0) {}
3875 \\}
3876 });
3877
3878 cases.add("binary conditional operator where false_expr is the mangle prefix",
3879 \\void foo() {
3880 \\ int cond_temp = 1;
3881 \\ int n, f = 1;
3882 \\ if (n = (f)?:(cond_temp)) {}
3883 \\}
3884 , &[_][]const u8{
3885 \\pub export fn foo() void {
3886 \\ var cond_temp: c_int = 1;
3887 \\ _ = &cond_temp;
3888 \\ var n: c_int = undefined;
3889 \\ _ = &n;
3890 \\ var f: c_int = 1;
3891 \\ _ = &f;
3892 \\ if ((blk: {
3893 \\ const tmp = blk_1: {
3894 \\ const cond_temp_2 = f;
3895 \\ break :blk_1 if (cond_temp_2 != 0) cond_temp_2 else cond_temp;
3896 \\ };
3897 \\ n = tmp;
3898 \\ break :blk tmp;
3899 \\ }) != 0) {}
3900 \\}
3901 });
3902
3903 cases.add("macro using argument as struct name is not translated",
3904 \\#define FOO(x) struct x
3905 , &[_][]const u8{
3906 \\pub const FOO = @compileError("unable to translate macro: untranslatable usage of arg `x`");
3907 });
3908
3909 cases.add("unsupport declare statement at the last of a compound statement which belongs to a statement expr",
3910 \\void somefunc(void) {
3911 \\ int y;
3912 \\ (void)({y=1; _Static_assert(1);});
3913 \\}
3914 , &[_][]const u8{
3915 \\pub export fn somefunc() void {
3916 \\ var y: c_int = undefined;
3917 \\ _ = &y;
3918 \\ _ = blk: {
3919 \\ y = 1;
3920 \\ };
3921 \\}
3922 });
3923}