diff --git a/build.zig b/build.zig index e217e9e274..00414c3cad 100644 --- a/build.zig +++ b/build.zig @@ -90,8 +90,6 @@ pub fn build(b: *std.Build) !void { const skip_libc = b.option(bool, "skip-libc", "Main test suite skips tests that link libc") orelse false; const skip_single_threaded = b.option(bool, "skip-single-threaded", "Main test suite skips tests that are single-threaded") orelse false; const skip_compile_errors = b.option(bool, "skip-compile-errors", "Main test suite skips compile error tests") orelse false; - const skip_translate_c = b.option(bool, "skip-translate-c", "Main test suite skips translate-c tests") orelse false; - const skip_run_translated_c = b.option(bool, "skip-run-translated-c", "Main test suite skips run-translated-c tests") orelse skip_translate_c; const skip_freebsd = b.option(bool, "skip-freebsd", "Main test suite skips targets with freebsd OS") orelse false; const skip_netbsd = b.option(bool, "skip-netbsd", "Main test suite skips targets with netbsd OS") orelse false; 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 { test_step.dependOn(check_fmt); const test_cases_step = b.step("test-cases", "Run the main compiler test cases"); - try tests.addCases(b, test_cases_step, target, .{ + try tests.addCases(b, test_cases_step, .{ .test_filters = test_filters, .test_target_filters = test_target_filters, .skip_compile_errors = skip_compile_errors, @@ -428,9 +426,6 @@ pub fn build(b: *std.Build) !void { .skip_linux = skip_linux, .skip_llvm = skip_llvm, .skip_libc = skip_libc, - }, .{ - .skip_translate_c = skip_translate_c, - .skip_run_translated_c = skip_run_translated_c, }, .{ .enable_llvm = enable_llvm, .llvm_has_m68k = llvm_has_m68k, @@ -465,27 +460,25 @@ pub fn build(b: *std.Build) !void { .max_rss = 4000000000, })); - if (!skip_translate_c) { - test_modules_step.dependOn(tests.addModuleTests(b, .{ - .test_filters = test_filters, - .test_target_filters = test_target_filters, - .test_extra_targets = test_extra_targets, - .root_src = "test/c_import.zig", - .name = "c-import", - .desc = "Run the @cImport tests", - .optimize_modes = optimization_modes, - .include_paths = &.{"test/c_import"}, - .skip_single_threaded = true, - .skip_non_native = skip_non_native, - .skip_freebsd = skip_freebsd, - .skip_netbsd = skip_netbsd, - .skip_windows = skip_windows, - .skip_macos = skip_macos, - .skip_linux = skip_linux, - .skip_llvm = skip_llvm, - .skip_libc = skip_libc, - })); - } + test_modules_step.dependOn(tests.addModuleTests(b, .{ + .test_filters = test_filters, + .test_target_filters = test_target_filters, + .test_extra_targets = test_extra_targets, + .root_src = "test/c_import.zig", + .name = "c-import", + .desc = "Run the @cImport tests", + .optimize_modes = optimization_modes, + .include_paths = &.{"test/c_import"}, + .skip_single_threaded = true, + .skip_non_native = skip_non_native, + .skip_freebsd = skip_freebsd, + .skip_netbsd = skip_netbsd, + .skip_windows = skip_windows, + .skip_macos = skip_macos, + .skip_linux = skip_linux, + .skip_llvm = skip_llvm, + .skip_libc = skip_libc, + })); test_modules_step.dependOn(tests.addModuleTests(b, .{ .test_filters = test_filters, @@ -577,7 +570,6 @@ pub fn build(b: *std.Build) !void { enable_macos_sdk, enable_ios_sdk, enable_symlinks_windows, - skip_translate_c, )); test_step.dependOn(tests.addCAbiTests(b, .{ .test_target_filters = test_target_filters, diff --git a/test/cases/README.md b/test/cases/README.md index b746a3fdbf..6f04409b6b 100644 --- a/test/cases/README.md +++ b/test/cases/README.md @@ -22,33 +22,6 @@ This will do `zig run` on the code and expect exit code 0. // run ``` -## Translate-c - -If you want to test translating C code to Zig use `translate-c`: - -```c -// translate-c -// c_frontend=aro,clang -// target=x86_64-linux -// -// pub const foo = 1; -// pub const immediately_after_foo = 2; -// -// pub const somewhere_else_in_the_file = 3: -``` - -## Run Translated C - -If you want to test translating C code to Zig and then executing it use `run-translated-c`: - -```c -// run-translated-c -// c_frontend=aro,clang -// target=x86_64-linux -// -// Hello world! -``` - ## Incremental Compilation Make multiple files that have ".", and then an integer, before the ".zig" diff --git a/test/cases/run_translated_c/compound_assignments_with_implicit_casts.c b/test/cases/run_translated_c/compound_assignments_with_implicit_casts.c deleted file mode 100644 index 79029d4903..0000000000 --- a/test/cases/run_translated_c/compound_assignments_with_implicit_casts.c +++ /dev/null @@ -1,20 +0,0 @@ -int main() { - int i = 2; - float f = 3.2f; - - i += 1.7; - if (i != 3) return 1; - i += f; - if (i != 6) return 2; - - - f += 2UL; - if (f <= 5.1999 || f >= 5.2001) return 3; - f += i; - if (f <= 11.1999 || f >= 11.2001) return 4; - - return 0; -} - -// run-translated-c -// c_frontend=clang diff --git a/test/cases/run_translated_c/compound_assignments_with_pointer_arithmetic.c b/test/cases/run_translated_c/compound_assignments_with_pointer_arithmetic.c deleted file mode 100644 index 2dea669708..0000000000 --- a/test/cases/run_translated_c/compound_assignments_with_pointer_arithmetic.c +++ /dev/null @@ -1,21 +0,0 @@ -int main() { - const char *s = "forgreatjustice"; - unsigned int add = 1; - - s += add; - if (*s != 'o') return 1; - - s += 1UL; - if (*s != 'r') return 2; - - const char *s2 = (s += add); - if (*s2 != 'g') return 3; - - s2 -= add; - if (*s2 != 'r') return 4; - - return 0; -} - -// run-translated-c -// c_frontend=clang diff --git a/test/cases/run_translated_c/dereference address of.c b/test/cases/run_translated_c/dereference address of.c deleted file mode 100644 index 15b9777c7a..0000000000 --- a/test/cases/run_translated_c/dereference address of.c +++ /dev/null @@ -1,11 +0,0 @@ -#include -int main(void) { - int i = 0; - *&i = 42; - if (i != 42) abort(); - return 0; -} - -// run-translated-c -// c_frontend=clang -// link_libc=true diff --git a/test/cases/run_translated_c/explicit_cast_bool_from_float.c b/test/cases/run_translated_c/explicit_cast_bool_from_float.c deleted file mode 100644 index 79bb88cc4b..0000000000 --- a/test/cases/run_translated_c/explicit_cast_bool_from_float.c +++ /dev/null @@ -1,10 +0,0 @@ -#include - -int main() { - float f = 2.0f; - bool b = (bool) f; - return 0; -} - -// run-translated-c -// c_frontend=clang diff --git a/test/cases/run_translated_c/extern_typedef_variables_in_functions.c b/test/cases/run_translated_c/extern_typedef_variables_in_functions.c deleted file mode 100644 index 5b8cf2b195..0000000000 --- a/test/cases/run_translated_c/extern_typedef_variables_in_functions.c +++ /dev/null @@ -1,22 +0,0 @@ -const int ev = 40; - -static int func(void) -{ - typedef int test_type_t; - extern const test_type_t ev; - // Ensure mangled name is also being used for conditions and loops, see #20828 - if (ev == 0); - while (ev == 0); - do; while (ev == 0); - return ev + 2; -} - -int main() -{ - if (func() != 42) - return 1; - return 0; -} - -// run-translated-c -// c_frontend=clang diff --git a/test/cases/run_translated_c/float_from_bool_expr_cast.c b/test/cases/run_translated_c/float_from_bool_expr_cast.c deleted file mode 100644 index 294e5e1d83..0000000000 --- a/test/cases/run_translated_c/float_from_bool_expr_cast.c +++ /dev/null @@ -1,8 +0,0 @@ -int main() { - float f = (float)(10.0f > 1.0f); - return 0; -} - -// run-translated-c -// c_frontend=clang -// diff --git a/test/cases/run_translated_c/sub_scope_extern_local_var_ref.c b/test/cases/run_translated_c/sub_scope_extern_local_var_ref.c deleted file mode 100644 index f3461f8559..0000000000 --- a/test/cases/run_translated_c/sub_scope_extern_local_var_ref.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -int a = 42; -int foo(int bar) { - extern int a; - if (bar) { - return a; - } - return 0; -} -int main() { - int result1 = foo(0); - if (result1 != 0) abort(); - int result2 = foo(1); - if (result2 != 42) abort(); - a = 100; - int result3 = foo(1); - if (result3 != 100) abort(); - return 0; -} - -// run-translated-c -// c_frontend=clang -// link_libc=true diff --git a/test/cases/translate_c/_Static_assert.c b/test/cases/translate_c/_Static_assert.c deleted file mode 100644 index 8ecc639e9d..0000000000 --- a/test/cases/translate_c/_Static_assert.c +++ /dev/null @@ -1,7 +0,0 @@ -_Static_assert(1 == 1, ""); - -// translate-c -// target=x86_64-linux -// c_frontend=aro -// -// tmp.c:1:1: warning: ignoring _Static_assert declaration diff --git a/test/cases/translate_c/align() attribute.c b/test/cases/translate_c/align() attribute.c deleted file mode 100644 index 600e8251fb..0000000000 --- a/test/cases/translate_c/align() attribute.c +++ /dev/null @@ -1,17 +0,0 @@ -__attribute__ ((aligned(128))) -extern char my_array[16]; -__attribute__ ((aligned(128))) -void my_fn(void) { } -void other_fn(void) { - char ARR[16] __attribute__ ((aligned (16))); -} - -// translate-c -// c_frontend=clang -// -// pub extern var my_array: [16]u8 align(128); -// pub export fn my_fn() align(128) void {} -// pub export fn other_fn() void { -// var ARR: [16]u8 align(16) = undefined; -// _ = &ARR; -// } diff --git a/test/cases/translate_c/assert_with_strlit.c b/test/cases/translate_c/assert_with_strlit.c deleted file mode 100644 index 445428bcf1..0000000000 --- a/test/cases/translate_c/assert_with_strlit.c +++ /dev/null @@ -1,8 +0,0 @@ - -void assert(int x) {} -#define FOO assert(0 && "error message") - -// translate-c -// c_frontend=clang -// -// pub const FOO = assert((@as(c_int, 0) != 0) and (@intFromPtr("error message") != 0)); diff --git a/test/cases/translate_c/atomic types.c b/test/cases/translate_c/atomic types.c deleted file mode 100644 index ad1af598c4..0000000000 --- a/test/cases/translate_c/atomic types.c +++ /dev/null @@ -1,8 +0,0 @@ -typedef _Atomic(int) AtomicInt; - -// translate-c -// target=x86_64-linux -// c_frontend=aro -// -// tmp.c:1:22: warning: unsupported type: '_Atomic(int)' -// pub const AtomicInt = @compileError("unable to resolve typedef child type"); diff --git a/test/cases/translate_c/c_keywords_as_macro_function_parameters.c b/test/cases/translate_c/c_keywords_as_macro_function_parameters.c deleted file mode 100644 index 8485909a94..0000000000 --- a/test/cases/translate_c/c_keywords_as_macro_function_parameters.c +++ /dev/null @@ -1,82 +0,0 @@ -#define GUARDED_INT_ADDITION(int) ((int) + 1) - -#define UNGUARDED_INT_SUBTRACTION(int) (int - 2) - -#define GUARDED_INT_MULTIPLY(int) ((int) * 3) - -#define UNGUARDED_INT_DIVIDE(int) (int / 4) - -#define WRAPPED_RETURN(return) ((return) % 2) - -#define UNWRAPPED_RETURN(return) (return ^ 0x7F) - -#define WITH_TWO_PARAMETERS(signed, x) ((signed) + (x) + 9) - -#define GUARDED_ALIGNOF(_Alignof) ((_Alignof) & 0x55) - -#define UNGUARDED_ALIGNOF(_Alignof) (_Alignof | 0x80) - -#define GUARDED_SIZEOF(sizeof) ((sizeof) == 64) - -#define UNGUARDED_SIZEOF(sizeof) (sizeof < 64) - -#define SIZEOF(x) ((int)sizeof(x)) - -#define SIZEOF2(x) ((int)sizeof x) - -// translate-c -// c_frontend=clang -// -// pub inline fn GUARDED_INT_ADDITION(int: anytype) @TypeOf(int + @as(c_int, 1)) { -// _ = ∫ -// return int + @as(c_int, 1); -// } -// pub inline fn UNGUARDED_INT_SUBTRACTION(int: anytype) @TypeOf(int - @as(c_int, 2)) { -// _ = ∫ -// return int - @as(c_int, 2); -// } -// pub inline fn GUARDED_INT_MULTIPLY(int: anytype) @TypeOf(int * @as(c_int, 3)) { -// _ = ∫ -// return int * @as(c_int, 3); -// } -// pub inline fn UNGUARDED_INT_DIVIDE(int: anytype) @TypeOf(@import("std").zig.c_translation.MacroArithmetic.div(int, @as(c_int, 4))) { -// _ = ∫ -// return @import("std").zig.c_translation.MacroArithmetic.div(int, @as(c_int, 4)); -// } -// pub inline fn WRAPPED_RETURN(@"return": anytype) @TypeOf(@import("std").zig.c_translation.MacroArithmetic.rem(@"return", @as(c_int, 2))) { -// _ = &@"return"; -// return @import("std").zig.c_translation.MacroArithmetic.rem(@"return", @as(c_int, 2)); -// } -// pub inline fn UNWRAPPED_RETURN(@"return": anytype) @TypeOf(@"return" ^ @as(c_int, 0x7F)) { -// _ = &@"return"; -// return @"return" ^ @as(c_int, 0x7F); -// } -// pub inline fn WITH_TWO_PARAMETERS(signed: anytype, x: anytype) @TypeOf((signed + x) + @as(c_int, 9)) { -// _ = &signed; -// _ = &x; -// return (signed + x) + @as(c_int, 9); -// } -// pub inline fn GUARDED_ALIGNOF(_Alignof: anytype) @TypeOf(_Alignof & @as(c_int, 0x55)) { -// _ = &_Alignof; -// return _Alignof & @as(c_int, 0x55); -// } -// pub inline fn UNGUARDED_ALIGNOF(_Alignof: anytype) @TypeOf(_Alignof | @as(c_int, 0x80)) { -// _ = &_Alignof; -// return _Alignof | @as(c_int, 0x80); -// } -// pub inline fn GUARDED_SIZEOF(sizeof: anytype) @TypeOf(sizeof == @as(c_int, 64)) { -// _ = &sizeof; -// return sizeof == @as(c_int, 64); -// } -// pub inline fn UNGUARDED_SIZEOF(sizeof: anytype) @TypeOf(sizeof < @as(c_int, 64)) { -// _ = &sizeof; -// return sizeof < @as(c_int, 64); -// } -// pub inline fn SIZEOF(x: anytype) c_int { -// _ = &x; -// return @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.sizeof(x)); -// } -// pub inline fn SIZEOF2(x: anytype) c_int { -// _ = &x; -// return @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.sizeof(x)); -// } diff --git a/test/cases/translate_c/circular_struct_definitions.c b/test/cases/translate_c/circular_struct_definitions.c deleted file mode 100644 index 696066b059..0000000000 --- a/test/cases/translate_c/circular_struct_definitions.c +++ /dev/null @@ -1,20 +0,0 @@ -struct Bar; - -struct Foo { - struct Bar *next; -}; - -struct Bar { - struct Foo *next; -}; - -// translate-c -// c_frontend=clang -// -// pub const struct_Bar = extern struct { -// next: [*c]struct_Foo = @import("std").mem.zeroes([*c]struct_Foo), -// }; -// -// pub const struct_Foo = extern struct { -// next: [*c]struct_Bar = @import("std").mem.zeroes([*c]struct_Bar), -// }; diff --git a/test/cases/translate_c/continue_from_while.c b/test/cases/translate_c/continue_from_while.c deleted file mode 100644 index 2e2237f752..0000000000 --- a/test/cases/translate_c/continue_from_while.c +++ /dev/null @@ -1,14 +0,0 @@ -void foo() { - for (;;) { - continue; - } -} - -// translate-c -// c_frontend=clang -// -// pub export fn foo() void { -// while (true) { -// continue; -// } -// } diff --git a/test/cases/translate_c/double_define_struct.c b/test/cases/translate_c/double_define_struct.c deleted file mode 100644 index e608154d7d..0000000000 --- a/test/cases/translate_c/double_define_struct.c +++ /dev/null @@ -1,25 +0,0 @@ -typedef struct Bar Bar; -typedef struct Foo Foo; - -struct Foo { - Foo *a; -}; - -struct Bar { - Foo *a; -}; - -// translate-c -// c_frontend=clang -// -// pub const struct_Foo = extern struct { -// a: [*c]Foo = @import("std").mem.zeroes([*c]Foo), -// }; -// -// pub const Foo = struct_Foo; -// -// pub const struct_Bar = extern struct { -// a: [*c]Foo = @import("std").mem.zeroes([*c]Foo), -// }; -// -// pub const Bar = struct_Bar; diff --git a/test/cases/translate_c/empty declaration.c b/test/cases/translate_c/empty declaration.c deleted file mode 100644 index 5f19328acf..0000000000 --- a/test/cases/translate_c/empty declaration.c +++ /dev/null @@ -1,6 +0,0 @@ -; - -// translate-c -// c_frontend=clang,aro -// -// \ No newline at end of file diff --git a/test/cases/translate_c/empty union initializer list.c b/test/cases/translate_c/empty union initializer list.c deleted file mode 100644 index 33238d2ed8..0000000000 --- a/test/cases/translate_c/empty union initializer list.c +++ /dev/null @@ -1,20 +0,0 @@ -union U { - int x; - long y; -}; - -void foo(void) { - union U u = {}; -} -// translate-c -// target=x86_64-linux -// c_frontend=clang -// -// pub const union_U = extern union { -// x: c_int, -// y: c_long, -// }; -// pub export fn foo() void { -// var u: union_U = @import("std").mem.zeroes(union_U); -// _ = &u; -// } diff --git a/test/cases/translate_c/enums msvc.c b/test/cases/translate_c/enums msvc.c deleted file mode 100644 index ab7242512f..0000000000 --- a/test/cases/translate_c/enums msvc.c +++ /dev/null @@ -1,16 +0,0 @@ -enum Foo { - FooA = 2, - FooB = 5, - Foo1, -}; - -// translate-c -// target=x86_64-windows-msvc -// c_frontend=clang -// -// pub const FooA: c_int = 2; -// pub const FooB: c_int = 5; -// pub const Foo1: c_int = 6; -// pub const enum_Foo = c_int; -// -// pub const Foo = enum_Foo; diff --git a/test/cases/translate_c/enums.c b/test/cases/translate_c/enums.c deleted file mode 100644 index 528ae60190..0000000000 --- a/test/cases/translate_c/enums.c +++ /dev/null @@ -1,16 +0,0 @@ -enum Foo { - FooA = 2, - FooB = 5, - Foo1, -}; - -// translate-c -// target=x86_64-linux -// c_frontend=clang,aro -// -// pub const FooA: c_int = 2; -// pub const FooB: c_int = 5; -// pub const Foo1: c_int = 6; -// pub const enum_Foo = c_uint; -// -// pub const Foo = enum_Foo; diff --git a/test/cases/translate_c/field_access_is_grouped_if_necessary.c b/test/cases/translate_c/field_access_is_grouped_if_necessary.c deleted file mode 100644 index dc46ab5dd6..0000000000 --- a/test/cases/translate_c/field_access_is_grouped_if_necessary.c +++ /dev/null @@ -1,18 +0,0 @@ -unsigned long foo(unsigned long x) { - return ((union{unsigned long _x}){x})._x; -} - -// translate-c -// c_frontend=clang -// -// pub export fn foo(arg_x: c_ulong) c_ulong { -// var x = arg_x; -// _ = &x; -// const union_unnamed_1 = extern union { -// _x: c_ulong, -// }; -// _ = &union_unnamed_1; -// return (union_unnamed_1{ -// ._x = x, -// })._x; -// } diff --git a/test/cases/translate_c/function prototype with parenthesis.c b/test/cases/translate_c/function prototype with parenthesis.c deleted file mode 100644 index 7b93e3fa93..0000000000 --- a/test/cases/translate_c/function prototype with parenthesis.c +++ /dev/null @@ -1,10 +0,0 @@ -void (f0) (void *L); -void ((f1)) (void *L); -void (((f2))) (void *L); - -// translate-c -// c_frontend=clang,aro -// -// pub extern fn f0(L: ?*anyopaque) void; -// pub extern fn f1(L: ?*anyopaque) void; -// pub extern fn f2(L: ?*anyopaque) void; diff --git a/test/cases/translate_c/global_struct_whose_default_name_conflicts_with_global_is_mangled.c b/test/cases/translate_c/global_struct_whose_default_name_conflicts_with_global_is_mangled.c deleted file mode 100644 index fe06fd88fd..0000000000 --- a/test/cases/translate_c/global_struct_whose_default_name_conflicts_with_global_is_mangled.c +++ /dev/null @@ -1,15 +0,0 @@ -struct foo { - int x; -}; -const char *struct_foo = "hello world"; - -// translate-c -// c_frontend=clang -// -// pub const struct_foo_1 = extern struct { -// x: c_int = @import("std").mem.zeroes(c_int), -// }; -// -// pub const foo = struct_foo_1; -// -// pub export var struct_foo: [*c]const u8 = "hello world"; diff --git a/test/cases/translate_c/large_packed_struct.c b/test/cases/translate_c/large_packed_struct.c deleted file mode 100644 index b18ccb3cde..0000000000 --- a/test/cases/translate_c/large_packed_struct.c +++ /dev/null @@ -1,20 +0,0 @@ -struct __attribute__((packed)) bar { - short a; - float b; - double c; - short x; - float y; - double z; -}; - -// translate-c -// c_frontend=aro,clang -// -// pub const struct_bar = extern struct { -// a: c_short align(1) = @import("std").mem.zeroes(c_short), -// b: f32 align(1) = @import("std").mem.zeroes(f32), -// c: f64 align(1) = @import("std").mem.zeroes(f64), -// x: c_short align(1) = @import("std").mem.zeroes(c_short), -// y: f32 align(1) = @import("std").mem.zeroes(f32), -// z: f64 align(1) = @import("std").mem.zeroes(f64), -// }; diff --git a/test/cases/translate_c/macro_calling_convention.c b/test/cases/translate_c/macro_calling_convention.c deleted file mode 100644 index 01331e572c..0000000000 --- a/test/cases/translate_c/macro_calling_convention.c +++ /dev/null @@ -1,9 +0,0 @@ -#define SYSV_ABI __attribute__((sysv_abi)) -void SYSV_ABI foo(void); - - -// translate-c -// c_frontend=clang -// target=x86_64-windows -// -// pub extern fn foo() callconv(.{ .x86_64_sysv = .{} }) void; diff --git a/test/cases/translate_c/macro_function_string_concat.c b/test/cases/translate_c/macro_function_string_concat.c deleted file mode 100644 index cf9c236593..0000000000 --- a/test/cases/translate_c/macro_function_string_concat.c +++ /dev/null @@ -1,11 +0,0 @@ -#define bar() "" -#define FOO bar() "," bar() - -// translate-c -// target=x86_64-linux -// c_frontend=clang -// -// pub inline fn bar() @TypeOf("") { -// return ""; -// } -// pub const FOO = bar() ++ "," ++ bar(); diff --git a/test/cases/translate_c/macro_referencing_var.c b/test/cases/translate_c/macro_referencing_var.c deleted file mode 100644 index 5675d06eda..0000000000 --- a/test/cases/translate_c/macro_referencing_var.c +++ /dev/null @@ -1,21 +0,0 @@ -extern float foo; -#define FOO_TWICE foo * 2.0f -#define FOO_NEGATIVE -foo - -#define BAR 10.0f -#define BAR_TWICE BAR * 2.0f - -// translate-c -// c_frontend=clang -// -// pub extern var foo: f32; -// -// pub inline fn FOO_TWICE() @TypeOf(foo * @as(f32, 2.0)) { -// return foo * @as(f32, 2.0); -// } -// -// pub inline fn FOO_NEGATIVE() @TypeOf(-foo) { -// return -foo; -// } -// pub const BAR = @as(f32, 10.0); -// pub const BAR_TWICE = BAR * @as(f32, 2.0); diff --git a/test/cases/translate_c/noreturn attribute.c b/test/cases/translate_c/noreturn attribute.c deleted file mode 100644 index 9564fd0092..0000000000 --- a/test/cases/translate_c/noreturn attribute.c +++ /dev/null @@ -1,6 +0,0 @@ -void foo(void) __attribute__((noreturn)); - -// translate-c -// c_frontend=aro,clang -// -// pub extern fn foo() noreturn; diff --git a/test/cases/translate_c/packed_union_nested_unpacked.c b/test/cases/translate_c/packed_union_nested_unpacked.c deleted file mode 100644 index a2e2c2f5ce..0000000000 --- a/test/cases/translate_c/packed_union_nested_unpacked.c +++ /dev/null @@ -1,25 +0,0 @@ -// NOTE: The nested struct is *not* packed/aligned, -// even though the parent struct is -// this is consistent with GCC docs -union Foo{ - short x; - double y; - struct { - int b; - } z; -} __attribute__((packed)); - -// translate-c -// c_frontend=aro,clang -// -// const struct_unnamed_1 = extern struct { -// b: c_int = @import("std").mem.zeroes(c_int), -// }; -// -// pub const union_Foo = extern union { -// x: c_short align(1), -// y: f64 align(1), -// z: struct_unnamed_1 align(1), -// }; -// -// pub const Foo = union_Foo; diff --git a/test/cases/translate_c/packed_union_simple.c b/test/cases/translate_c/packed_union_simple.c deleted file mode 100644 index f69e3cb865..0000000000 --- a/test/cases/translate_c/packed_union_simple.c +++ /dev/null @@ -1,14 +0,0 @@ -union Foo { - short x; - double y; -} __attribute__((packed)); - -// translate-c -// c_frontend=aro,clang -// -// pub const union_Foo = extern union { -// x: c_short align(1), -// y: f64 align(1), -// }; -// -// pub const Foo = union_Foo; diff --git a/test/cases/translate_c/pointer_to_struct_demoted_opaque_due_to_bit_fields.c b/test/cases/translate_c/pointer_to_struct_demoted_opaque_due_to_bit_fields.c deleted file mode 100644 index 3203687497..0000000000 --- a/test/cases/translate_c/pointer_to_struct_demoted_opaque_due_to_bit_fields.c +++ /dev/null @@ -1,15 +0,0 @@ -struct Foo { - unsigned int: 1; -}; -struct Bar { - struct Foo *foo; -}; - -// translate-c -// c_frontend=clang -// -// pub const struct_Foo = opaque {}; -// -// pub const struct_Bar = extern struct { -// foo: ?*struct_Foo = @import("std").mem.zeroes(?*struct_Foo), -// }; diff --git a/test/cases/translate_c/qualified_struct_and_enum.c b/test/cases/translate_c/qualified_struct_and_enum.c deleted file mode 100644 index 19c4214c14..0000000000 --- a/test/cases/translate_c/qualified_struct_and_enum.c +++ /dev/null @@ -1,25 +0,0 @@ -struct Foo { - int x; - int y; -}; -enum Bar { - BarA, - BarB, -}; -void func(struct Foo *a, enum Bar **b); - -// translate-c -// c_frontend=clang -// target=x86_64-linux,x86_64-macos -// -// pub const struct_Foo = extern struct { -// x: c_int = @import("std").mem.zeroes(c_int), -// y: c_int = @import("std").mem.zeroes(c_int), -// }; -// pub const BarA: c_int = 0; -// pub const BarB: c_int = 1; -// pub const enum_Bar = c_uint; -// pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void; -// -// pub const Foo = struct_Foo; -// pub const Bar = enum_Bar; diff --git a/test/cases/translate_c/qualified_struct_and_enum_msvc.c b/test/cases/translate_c/qualified_struct_and_enum_msvc.c deleted file mode 100644 index b2bff8def7..0000000000 --- a/test/cases/translate_c/qualified_struct_and_enum_msvc.c +++ /dev/null @@ -1,25 +0,0 @@ -struct Foo { - int x; - int y; -}; -enum Bar { - BarA, - BarB, -}; -void func(struct Foo *a, enum Bar **b); - -// translate-c -// c_frontend=clang -// target=x86_64-windows-msvc -// -// pub const struct_Foo = extern struct { -// x: c_int = @import("std").mem.zeroes(c_int), -// y: c_int = @import("std").mem.zeroes(c_int), -// }; -// pub const BarA: c_int = 0; -// pub const BarB: c_int = 1; -// pub const enum_Bar = c_int; -// pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void; -// -// pub const Foo = struct_Foo; -// pub const Bar = enum_Bar; diff --git a/test/cases/translate_c/scoped_record.c b/test/cases/translate_c/scoped_record.c deleted file mode 100644 index fe24000b34..0000000000 --- a/test/cases/translate_c/scoped_record.c +++ /dev/null @@ -1,49 +0,0 @@ -void foo() { - struct Foo { - int A; - int B; - int C; - }; - struct Foo a = {0}; - { - struct Foo { - int A; - int B; - int C; - }; - struct Foo a = {0}; - } -} - -// translate-c -// c_frontend=clang -// -// pub export fn foo() void { -// const struct_Foo = extern struct { -// A: c_int = @import("std").mem.zeroes(c_int), -// B: c_int = @import("std").mem.zeroes(c_int), -// C: c_int = @import("std").mem.zeroes(c_int), -// }; -// _ = &struct_Foo; -// var a: struct_Foo = struct_Foo{ -// .A = @as(c_int, 0), -// .B = 0, -// .C = 0, -// }; -// _ = &a; -// { -// const struct_Foo_1 = extern struct { -// A: c_int = @import("std").mem.zeroes(c_int), -// B: c_int = @import("std").mem.zeroes(c_int), -// C: c_int = @import("std").mem.zeroes(c_int), -// }; -// _ = &struct_Foo_1; -// var a_2: struct_Foo_1 = struct_Foo_1{ -// .A = @as(c_int, 0), -// .B = 0, -// .C = 0, -// }; -// _ = &a_2; -// } -// } - diff --git a/test/cases/translate_c/simple function prototypes.c b/test/cases/translate_c/simple function prototypes.c deleted file mode 100644 index ee1e2bad32..0000000000 --- a/test/cases/translate_c/simple function prototypes.c +++ /dev/null @@ -1,8 +0,0 @@ -void __attribute__((noreturn)) foo(void); -int bar(void); - -// translate-c -// c_frontend=clang,aro -// -// pub extern fn foo() noreturn; -// pub extern fn bar() c_int; diff --git a/test/cases/translate_c/simple_struct.c b/test/cases/translate_c/simple_struct.c deleted file mode 100644 index d3e2745ee3..0000000000 --- a/test/cases/translate_c/simple_struct.c +++ /dev/null @@ -1,12 +0,0 @@ -struct Foo { - int x; -}; - -// translate-c -// c_frontend=aro,clang -// -// const struct_Foo = extern struct { -// x: c_int = @import("std").mem.zeroes(c_int), -// }; -// -// pub const Foo = struct_Foo; diff --git a/test/cases/translate_c/simple_union.c b/test/cases/translate_c/simple_union.c deleted file mode 100644 index 29940a2ab2..0000000000 --- a/test/cases/translate_c/simple_union.c +++ /dev/null @@ -1,12 +0,0 @@ -union Foo { - int x; -}; - -// translate-c -// c_frontend=aro,clang -// -// pub const union_Foo = extern union { -// x: c_int, -// }; -// -// pub const Foo = union_Foo; diff --git a/test/cases/translate_c/static empty struct.c b/test/cases/translate_c/static empty struct.c deleted file mode 100644 index 222fa48707..0000000000 --- a/test/cases/translate_c/static empty struct.c +++ /dev/null @@ -1,17 +0,0 @@ -struct empty_struct {}; - -static inline void foo() { - static struct empty_struct bar = {}; -} - -// translate-c -// target=x86_64-linux -// c_frontend=clang -// -// pub const struct_empty_struct = extern struct {}; -// pub fn foo() callconv(.c) void { -// const bar = struct { -// var static: struct_empty_struct = @import("std").mem.zeroes(struct_empty_struct); -// }; -// _ = &bar; -// } diff --git a/test/cases/translate_c/strlit_as_bool.c b/test/cases/translate_c/strlit_as_bool.c deleted file mode 100644 index 4ba0cfe2a4..0000000000 --- a/test/cases/translate_c/strlit_as_bool.c +++ /dev/null @@ -1,8 +0,0 @@ -void foo() { if(0 && "error message") {} } - -// translate-c -// c_frontend=clang -// -// pub export fn foo() void { -// if (false and (@intFromPtr("error message") != 0)) {} -// } diff --git a/test/cases/translate_c/struct prototype used in func.c b/test/cases/translate_c/struct prototype used in func.c deleted file mode 100644 index b688e6e742..0000000000 --- a/test/cases/translate_c/struct prototype used in func.c +++ /dev/null @@ -1,10 +0,0 @@ -struct Foo; -struct Foo *some_func(struct Foo *foo, int x); - -// translate-c -// c_frontend=clang,aro -// -// pub const struct_Foo = opaque {}; -// pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo; -// -// pub const Foo = struct_Foo; diff --git a/test/cases/translate_c/struct_in_struct_init_to_zero.c b/test/cases/translate_c/struct_in_struct_init_to_zero.c deleted file mode 100644 index 688a2448d1..0000000000 --- a/test/cases/translate_c/struct_in_struct_init_to_zero.c +++ /dev/null @@ -1,24 +0,0 @@ -struct Foo { - int a; - struct Bar { - int a; - } b; -} a = {}; -#define PTR void * - -// translate-c -// c_frontend=clang -// -// pub const struct_Bar_1 = extern struct { -// a: c_int = @import("std").mem.zeroes(c_int), -// }; -// pub const struct_Foo = extern struct { -// a: c_int = @import("std").mem.zeroes(c_int), -// b: struct_Bar_1 = @import("std").mem.zeroes(struct_Bar_1), -// }; -// pub export var a: struct_Foo = struct_Foo{ -// .a = 0, -// .b = @import("std").mem.zeroes(struct_Bar_1), -// }; -// -// pub const PTR = ?*anyopaque; diff --git a/test/cases/translate_c/struct_with_aligned_fields.c b/test/cases/translate_c/struct_with_aligned_fields.c deleted file mode 100644 index 37a25ff49a..0000000000 --- a/test/cases/translate_c/struct_with_aligned_fields.c +++ /dev/null @@ -1,10 +0,0 @@ -struct foo { - __attribute__((aligned(4))) short bar; -}; - -// translate-c -// c_frontend=aro,clang -// -// pub const struct_foo = extern struct { -// bar: c_short align(4) = @import("std").mem.zeroes(c_short), -// }; diff --git a/test/cases/translate_c/struct_with_invalid_field_alignment.c b/test/cases/translate_c/struct_with_invalid_field_alignment.c deleted file mode 100644 index 6b3fc55b6d..0000000000 --- a/test/cases/translate_c/struct_with_invalid_field_alignment.c +++ /dev/null @@ -1,35 +0,0 @@ -// The aligned attribute cannot decrease the alignment of a field. The packed attribute is required -// for decreasing the alignment. gcc and clang will compile these structs without error -// (and possibly without warning), but checking the alignment will reveal a different value than -// what was requested. This is consistent with the gcc documentation on type attributes. -// -// This test is currently broken for the clang frontend. See issue #19307. - -struct foo { - __attribute__((aligned(1)))int x; -}; - -struct bar { - __attribute__((aligned(2)))float y; -}; - -struct baz { - __attribute__((aligned(4)))double z; -}; - -// translate-c -// c_frontend=aro -// target=x86_64-linux -// -// pub const struct_foo = extern struct { -// x: c_int = @import("std").mem.zeroes(c_int), -// }; -// -// pub const struct_bar = extern struct { -// y: f32 = @import("std").mem.zeroes(f32), -// }; -// -// pub const struct_baz = extern struct { -// z: f64 = @import("std").mem.zeroes(f64), -// }; -// diff --git a/test/cases/translate_c/type_referenced_struct.c b/test/cases/translate_c/type_referenced_struct.c deleted file mode 100644 index 597d37329e..0000000000 --- a/test/cases/translate_c/type_referenced_struct.c +++ /dev/null @@ -1,19 +0,0 @@ -// When clang uses the -windows-none, triple it behaves as MSVC and -// interprets the inner `struct Bar` as an anonymous structure -struct Foo { - struct Bar{ - int b; - }; - struct Bar c; -}; - -// translate-c -// c_frontend=aro,clang -// target=x86_64-linux-gnu -// -// pub const struct_Bar_1 = extern struct { -// b: c_int = @import("std").mem.zeroes(c_int), -// }; -// pub const struct_Foo = extern struct { -// c: struct_Bar_1 = @import("std").mem.zeroes(struct_Bar_1), -// }; diff --git a/test/cases/translate_c/union_initializer.c b/test/cases/translate_c/union_initializer.c deleted file mode 100644 index 010e493252..0000000000 --- a/test/cases/translate_c/union_initializer.c +++ /dev/null @@ -1,22 +0,0 @@ -union { int x; char c[4]; } - ua = {1}, - ub = {.c={'a','b','b','a'}}; - -// translate-c -// c_frontend=clang -// -// const union_unnamed_1 = extern union { -// x: c_int, -// c: [4]u8, -// }; -// pub export var ua: union_unnamed_1 = union_unnamed_1{ -// .x = @as(c_int, 1), -// }; -// pub export var ub: union_unnamed_1 = union_unnamed_1{ -// .c = [4]u8{ -// 'a', -// 'b', -// 'b', -// 'a', -// }, -// }; diff --git a/test/cases/translate_c/union_struct_forward_decl.c b/test/cases/translate_c/union_struct_forward_decl.c deleted file mode 100644 index d2c721804a..0000000000 --- a/test/cases/translate_c/union_struct_forward_decl.c +++ /dev/null @@ -1,37 +0,0 @@ -struct A; -union B; -enum C; - -struct A { - short x; - double y; -}; - -union B { - short x; - double y; -}; - -struct Foo { - struct A a; - union B b; -}; - - -// translate-c -// c_frontend=aro,clang -// -// pub const struct_A = extern struct { -// x: c_short = @import("std").mem.zeroes(c_short), -// y: f64 = @import("std").mem.zeroes(f64), -// }; -// -// pub const union_B = extern union { -// x: c_short, -// y: f64, -// }; -// -// pub const struct_Foo = extern struct { -// a: struct_A = @import("std").mem.zeroes(struct_A), -// b: union_B = @import("std").mem.zeroes(union_B), -// }; diff --git a/test/cases/translate_c/unnamed_fields_have_predictable_names.c b/test/cases/translate_c/unnamed_fields_have_predictable_names.c deleted file mode 100644 index 1517bf1327..0000000000 --- a/test/cases/translate_c/unnamed_fields_have_predictable_names.c +++ /dev/null @@ -1,22 +0,0 @@ -struct a { - struct { int x; }; -}; -struct b { - struct { int y; }; -}; - -// translate-c -// c_frontend=aro,clang -// -// const struct_unnamed_1 = extern struct { -// x: c_int = @import("std").mem.zeroes(c_int), -// }; -// pub const struct_a = extern struct { -// unnamed_0: struct_unnamed_1 = @import("std").mem.zeroes(struct_unnamed_1), -// }; -// const struct_unnamed_2 = extern struct { -// y: c_int = @import("std").mem.zeroes(c_int), -// }; -// pub const struct_b = extern struct { -// unnamed_0: struct_unnamed_2 = @import("std").mem.zeroes(struct_unnamed_2), -// }; diff --git a/test/cases/translate_c/void_pointer_subtraction.c b/test/cases/translate_c/void_pointer_subtraction.c deleted file mode 100644 index 69ce5a9d4d..0000000000 --- a/test/cases/translate_c/void_pointer_subtraction.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -ptrdiff_t sub_ptr(void *a, void *b) { - return a - b; -} - -// translate-c -// c_frontend=clang -// target=x86_64-linux -// -// pub export fn sub_ptr(arg_a: ?*anyopaque, arg_b: ?*anyopaque) ptrdiff_t { -// var a = arg_a; -// _ = &a; -// var b = arg_b; -// _ = &b; -// return @as(c_long, @bitCast(@intFromPtr(a) -% @intFromPtr(b))); -// } diff --git a/test/cases/translate_c/zero_width_field_alignment.c b/test/cases/translate_c/zero_width_field_alignment.c deleted file mode 100644 index c50bb668fd..0000000000 --- a/test/cases/translate_c/zero_width_field_alignment.c +++ /dev/null @@ -1,18 +0,0 @@ -struct __attribute__((packed)) foo { - int x; - struct {}; - float y; - union {}; -}; - -// translate-c -// c_frontend=aro -// -// const struct_unnamed_1 = extern struct {}; -// const union_unnamed_2 = extern union {}; -// pub const struct_foo = extern struct { -// x: c_int align(1) = @import("std").mem.zeroes(c_int), -// unnamed_0: struct_unnamed_1 align(1) = @import("std").mem.zeroes(struct_unnamed_1), -// y: f32 align(1) = @import("std").mem.zeroes(f32), -// unnamed_1: union_unnamed_2 align(1) = @import("std").mem.zeroes(union_unnamed_2), -// }; diff --git a/test/cases/translate_c/zig_keywords_in_c_code.c b/test/cases/translate_c/zig_keywords_in_c_code.c deleted file mode 100644 index 5ec80ec26e..0000000000 --- a/test/cases/translate_c/zig_keywords_in_c_code.c +++ /dev/null @@ -1,12 +0,0 @@ -struct comptime { - int defer; -}; - -// translate-c -// c_frontend=aro,clang -// -// pub const struct_comptime = extern struct { -// @"defer": c_int = @import("std").mem.zeroes(c_int), -// }; -// -// pub const @"comptime" = struct_comptime; diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig deleted file mode 100644 index 84d8b2da1c..0000000000 --- a/test/run_translated_c.zig +++ /dev/null @@ -1,1825 +0,0 @@ -const std = @import("std"); -const tests = @import("tests.zig"); -const nl = if (@import("builtin").os.tag == .windows) "\r\n" else "\n"; - -// ********************************************************* -// * * -// * DO NOT ADD NEW CASES HERE * -// * instead add a file to test/cases/run_translated_c * -// * * -// ********************************************************* - -pub fn addCases(cases: *tests.RunTranslatedCContext) void { - cases.add("division of floating literals", - \\#define _NO_CRT_STDIO_INLINE 1 - \\#include - \\#define PI 3.14159265358979323846f - \\#define DEG2RAD (PI/180.0f) - \\int main(void) { - \\ printf("DEG2RAD is: %f\n", DEG2RAD); - \\ return 0; - \\} - , "DEG2RAD is: 0.017453" ++ nl); - - cases.add("use global scope for record/enum/typedef type translation if needed", - \\void bar(void); - \\void baz(void); - \\struct foo { int x; }; - \\void bar() { - \\ struct foo tmp; - \\} - \\ - \\void baz() { - \\ struct foo tmp; - \\} - \\ - \\int main(void) { - \\ bar(); - \\ baz(); - \\ return 0; - \\} - , ""); - - cases.add("failed macros are only declared once", - \\#define FOO = - \\#define FOO = - \\#define PtrToPtr64(p) ((void *POINTER_64) p) - \\#define STRUC_ALIGNED_STACK_COPY(t,s) ((CONST t *)(s)) - \\#define bar = 0x - \\#define baz = 0b - \\int main(void) {} - , ""); - - cases.add("parenthesized string literal", - \\void foo(const char *s) {} - \\int main(void) { - \\ foo(("bar")); - \\} - , ""); - - cases.add("variable shadowing type type", - \\#include - \\int main() { - \\ int type = 1; - \\ if (type != 1) abort(); - \\} - , ""); - - cases.add("assignment as expression", - \\#include - \\int main() { - \\ int a, b, c, d = 5; - \\ int e = a = b = c = d; - \\ if (e != 5) abort(); - \\} - , ""); - - cases.add("static variable in block scope", - \\#include - \\int foo() { - \\ static int bar; - \\ bar += 1; - \\ return bar; - \\} - \\int main() { - \\ foo(); - \\ foo(); - \\ if (foo() != 3) abort(); - \\} - , ""); - - cases.add("array initializer", - \\#include - \\int main(int argc, char **argv) { - \\ int a0[4] = {1}; - \\ int a1[4] = {1,2,3,4}; - \\ int s0 = 0, s1 = 0; - \\ for (int i = 0; i < 4; i++) { - \\ s0 += a0[i]; - \\ s1 += a1[i]; - \\ } - \\ if (s0 != 1) abort(); - \\ if (s1 != 10) abort(); - \\} - , ""); - - cases.add("forward declarations", - \\#include - \\int foo(int); - \\int foo(int x) { return x + 1; } - \\int main(int argc, char **argv) { - \\ if (foo(2) != 3) abort(); - \\ return 0; - \\} - , ""); - - cases.add("typedef and function pointer", - \\#include - \\typedef struct _Foo Foo; - \\typedef int Ret; - \\typedef int Param; - \\struct _Foo { Ret (*func)(Param p); }; - \\static Ret add1(Param p) { - \\ return p + 1; - \\} - \\int main(int argc, char **argv) { - \\ Foo strct = { .func = add1 }; - \\ if (strct.func(16) != 17) abort(); - \\ return 0; - \\} - , ""); - - cases.add("ternary operator", - \\#include - \\static int cnt = 0; - \\int foo() { cnt++; return 42; } - \\int main(int argc, char **argv) { - \\ short q = 3; - \\ signed char z0 = q?:1; - \\ if (z0 != 3) abort(); - \\ int z1 = 3?:1; - \\ if (z1 != 3) abort(); - \\ int z2 = foo()?:-1; - \\ if (z2 != 42) abort(); - \\ if (cnt != 1) abort(); - \\ return 0; - \\} - , ""); - - cases.add("switch case", - \\#include - \\int lottery(unsigned int x) { - \\ switch (x) { - \\ case 3: return 0; - \\ case -1: return 3; - \\ case 8 ... 10: return x; - \\ default: return -1; - \\ } - \\} - \\int main(int argc, char **argv) { - \\ if (lottery(2) != -1) abort(); - \\ if (lottery(3) != 0) abort(); - \\ if (lottery(-1) != 3) abort(); - \\ if (lottery(9) != 9) abort(); - \\ return 0; - \\} - , ""); - - cases.add("boolean values and expressions", - \\#include - \\static const _Bool false_val = 0; - \\static const _Bool true_val = 1; - \\void foo(int x, int y) { - \\ _Bool r = x < y; - \\ if (!r) abort(); - \\ _Bool self = foo; - \\ if (self == false_val) abort(); - \\ if (((r) ? 'a' : 'b') != 'a') abort(); - \\} - \\int main(int argc, char **argv) { - \\ foo(2, 5); - \\ if (false_val == true_val) abort(); - \\ return 0; - \\} - , ""); - - cases.add("hello world", - \\#define _NO_CRT_STDIO_INLINE 1 - \\#include - \\int main(int argc, char **argv) { - \\ printf("hello, world!\n"); - \\ return 0; - \\} - , "hello, world!" ++ nl); - - cases.add("anon struct init", - \\#include - \\struct {int a; int b;} x = {1, 2}; - \\int main(int argc, char **argv) { - \\ x.a += 2; - \\ x.b += 1; - \\ if (x.a != 3) abort(); - \\ if (x.b != 3) abort(); - \\ return 0; - \\} - , ""); - - cases.add("casting away const and volatile", - \\void foo(int *a) {} - \\void bar(const int *a) { - \\ foo((int *)a); - \\} - \\void baz(volatile int *a) { - \\ foo((int *)a); - \\} - \\int main(int argc, char **argv) { - \\ int a = 0; - \\ bar((const int *)&a); - \\ baz((volatile int *)&a); - \\ return 0; - \\} - , ""); - - cases.add("anonymous struct & unions", - \\#include - \\#include - \\static struct { struct { uint16_t x, y; }; } x = { 1 }; - \\static struct { union { uint32_t x; uint8_t y; }; } y = { 0x55AA55AA }; - \\int main(int argc, char **argv) { - \\ if (x.x != 1) abort(); - \\ if (x.y != 0) abort(); - \\ if (y.x != 0x55AA55AA) abort(); - \\ if (y.y != 0xAA) abort(); - \\ return 0; - \\} - , ""); - - cases.add("array to pointer decay", - \\#include - \\int main(int argc, char **argv) { - \\ char data[3] = {'a','b','c'}; - \\ if (2[data] != data[2]) abort(); - \\ if ("abc"[1] != data[1]) abort(); - \\ char *as_ptr = data; - \\ if (2[as_ptr] != as_ptr[2]) abort(); - \\ if ("abc"[1] != as_ptr[1]) abort(); - \\ return 0; - \\} - , ""); - - cases.add("struct initializer - packed", - \\#define _NO_CRT_STDIO_INLINE 1 - \\#include - \\#include - \\struct s {uint8_t x,y; - \\ uint32_t z;} __attribute__((packed)) s0 = {1, 2}; - \\int main() { - \\ /* sizeof nor offsetof currently supported */ - \\ if (((intptr_t)&s0.z - (intptr_t)&s0.x) != 2) abort(); - \\ return 0; - \\} - , ""); - - cases.add("cast signed array index to unsigned", - \\#include - \\int main(int argc, char **argv) { - \\ int a[10], i = 0; - \\ a[i] = 0; - \\ if (a[i] != 0) abort(); - \\ return 0; - \\} - , ""); - - cases.add("cast long long array index to unsigned", - \\#include - \\int main(int argc, char **argv) { - \\ long long a[10], i = 0; - \\ a[i] = 0; - \\ if (a[i] != 0) abort(); - \\ return 0; - \\} - , ""); - - cases.add("case boolean expression converted to int", - \\#include - \\int main(int argc, char **argv) { - \\ int value = 1 + 2 * 3 + 4 * 5 + 6 << 7 | 8 == 9; - \\ if (value != 4224) abort(); - \\ return 0; - \\} - , ""); - - cases.add("case boolean expression on left converted to int", - \\#include - \\int main(int argc, char **argv) { - \\ int value = 8 == 9 | 1 + 2 * 3 + 4 * 5 + 6 << 7; - \\ if (value != 4224) abort(); - \\ return 0; - \\} - , ""); - - cases.add("case boolean and operator+ converts bool to int", - \\#include - \\int main(int argc, char **argv) { - \\ int value = (8 == 9) + 3; - \\ int value2 = 3 + (8 == 9); - \\ if (value != value2) abort(); - \\ return 0; - \\} - , ""); - - cases.add("case boolean and operator<", - \\#include - \\int main(int argc, char **argv) { - \\ int value = (8 == 9) < 3; - \\ if (value == 0) abort(); - \\ return 0; - \\} - , ""); - - cases.add("case boolean and operator*", - \\#include - \\int main(int argc, char **argv) { - \\ int value = (8 == 9) * 3; - \\ int value2 = 3 * (9 == 9); - \\ if (value != 0) abort(); - \\ if (value2 == 0) abort(); - \\ return 0; - \\} - , ""); - - cases.add("scoped typedef", - \\int main(int argc, char **argv) { - \\ typedef int Foo; - \\ typedef Foo Bar; - \\ typedef void (*func)(int); - \\ typedef int uint32_t; - \\ uint32_t a; - \\ Foo i; - \\ Bar j; - \\ return 0; - \\} - , ""); - - cases.add("scoped for loops with shadowing", - \\#include - \\int main() { - \\ int count = 0; - \\ for (int x = 0; x < 2; x++) - \\ for (int x = 0; x < 2; x++) - \\ count++; - \\ - \\ if (count != 4) abort(); - \\ return 0; - \\} - , ""); - - cases.add("array value type casts properly", - \\#include - \\unsigned int choose[53][10]; - \\static int hash_binary(int k) - \\{ - \\ choose[0][k] = 3; - \\ int sum = 0; - \\ sum += choose[0][k]; - \\ return sum; - \\} - \\ - \\int main() { - \\ int s = hash_binary(4); - \\ if (s != 3) abort(); - \\ return 0; - \\} - , ""); - - cases.add("array value type casts properly use +=", - \\#include - \\static int hash_binary(int k) - \\{ - \\ unsigned int choose[1][1] = {{3}}; - \\ int sum = -1; - \\ int prev = 0; - \\ prev = sum += choose[0][0]; - \\ if (sum != 2) abort(); - \\ return sum + prev; - \\} - \\ - \\int main() { - \\ int x = hash_binary(4); - \\ if (x != 4) abort(); - \\ return 0; - \\} - , ""); - - cases.add("ensure array casts outside +=", - \\#include - \\static int hash_binary(int k) - \\{ - \\ unsigned int choose[3] = {1, 2, 3}; - \\ int sum = -2; - \\ int prev = sum + choose[k]; - \\ if (prev != 0) abort(); - \\ return sum + prev; - \\} - \\ - \\int main() { - \\ int x = hash_binary(1); - \\ if (x != -2) abort(); - \\ return 0; - \\} - , ""); - - cases.add("array cast int to uint", - \\#include - \\static unsigned int hash_binary(int k) - \\{ - \\ int choose[3] = {-1, -2, 3}; - \\ unsigned int sum = 2; - \\ sum += choose[k]; - \\ return sum; - \\} - \\ - \\int main() { - \\ unsigned int x = hash_binary(1); - \\ if (x != 0) abort(); - \\ return 0; - \\} - , ""); - - cases.add("assign enum to uint, no explicit cast", - \\#include - \\typedef enum { - \\ ENUM_0 = 0, - \\ ENUM_1 = 1, - \\} my_enum_t; - \\ - \\int main() { - \\ my_enum_t val = ENUM_1; - \\ unsigned int x = val; - \\ if (x != 1) abort(); - \\ return 0; - \\} - , ""); - - cases.add("assign enum to int", - \\#include - \\typedef enum { - \\ ENUM_0 = 0, - \\ ENUM_1 = 1, - \\} my_enum_t; - \\ - \\int main() { - \\ my_enum_t val = ENUM_1; - \\ int x = val; - \\ if (x != 1) abort(); - \\ return 0; - \\} - , ""); - - cases.add("cast enum to smaller uint", - \\#include - \\#include - \\typedef enum { - \\ ENUM_0 = 0, - \\ ENUM_257 = 257, - \\} my_enum_t; - \\ - \\int main() { - \\ my_enum_t val = ENUM_257; - \\ uint8_t x = (uint8_t)val; - \\ if (x != (uint8_t)257) abort(); - \\ return 0; - \\} - , ""); - - cases.add("cast enum to smaller signed int", - \\#include - \\#include - \\typedef enum { - \\ ENUM_0 = 0, - \\ ENUM_384 = 384, - \\} my_enum_t; - \\ - \\int main() { - \\ my_enum_t val = ENUM_384; - \\ int8_t x = (int8_t)val; - \\ if (x != (int8_t)384) abort(); - \\ return 0; - \\} - , ""); - - cases.add("cast negative enum to smaller signed int", - \\#include - \\#include - \\typedef enum { - \\ ENUM_MINUS_1 = -1, - \\ ENUM_384 = 384, - \\} my_enum_t; - \\ - \\int main() { - \\ my_enum_t val = ENUM_MINUS_1; - \\ int8_t x = (int8_t)val; - \\ if (x != -1) abort(); - \\ return 0; - \\} - , ""); - - cases.add("cast negative enum to smaller unsigned int", - \\#include - \\#include - \\typedef enum { - \\ ENUM_MINUS_1 = -1, - \\ ENUM_384 = 384, - \\} my_enum_t; - \\ - \\int main() { - \\ my_enum_t val = ENUM_MINUS_1; - \\ uint8_t x = (uint8_t)val; - \\ if (x != (uint8_t)-1) abort(); - \\ return 0; - \\} - , ""); - - cases.add("implicit enum cast in boolean expression", - \\#include - \\enum Foo { - \\ FooA, - \\ FooB, - \\ FooC, - \\}; - \\int main() { - \\ int a = 0; - \\ float b = 0; - \\ void *c = 0; - \\ enum Foo d = FooA; - \\ if (a || d) abort(); - \\ if (d && b) abort(); - \\ if (c || d) abort(); - \\ return 0; - \\} - , ""); - - cases.add("issue #6707 cast builtin call result to opaque struct pointer", - \\#include - \\struct foo* make_foo(void) - \\{ - \\ return (struct foo*)__builtin_strlen("0123456789ABCDEF"); - \\} - \\int main(void) { - \\ struct foo *foo_pointer = make_foo(); - \\ if (foo_pointer != (struct foo*)16) abort(); - \\ return 0; - \\} - , ""); - - cases.add("C built-ins", - \\#include - \\#include - \\#include - \\#define M_E 2.71828182845904523536 - \\#define M_PI_2 1.57079632679489661923 - \\bool check_clz(unsigned int pos) { - \\ return (__builtin_clz(1 << pos) == (8 * sizeof(unsigned int) - pos - 1)); - \\} - \\int main(void) { - \\ if (__builtin_bswap16(0x0102) != 0x0201) abort(); - \\ if (__builtin_bswap32(0x01020304) != 0x04030201) abort(); - \\ if (__builtin_bswap64(0x0102030405060708) != 0x0807060504030201) abort(); - \\ - \\ if (__builtin_signbit(0.0) != 0) abort(); - \\ if (__builtin_signbitf(0.0f) != 0) abort(); - \\ if (__builtin_signbit(1.0) != 0) abort(); - \\ if (__builtin_signbitf(1.0f) != 0) abort(); - \\ if (__builtin_signbit(-1.0) != 1) abort(); - \\ if (__builtin_signbitf(-1.0f) != 1) abort(); - \\ - \\ if (__builtin_popcount(0) != 0) abort(); - \\ if (__builtin_popcount(0b1) != 1) abort(); - \\ if (__builtin_popcount(0b11) != 2) abort(); - \\ if (__builtin_popcount(0b1111) != 4) abort(); - \\ if (__builtin_popcount(0b11111111) != 8) abort(); - \\ - \\ if (__builtin_ctz(0b1) != 0) abort(); - \\ if (__builtin_ctz(0b10) != 1) abort(); - \\ if (__builtin_ctz(0b100) != 2) abort(); - \\ if (__builtin_ctz(0b10000) != 4) abort(); - \\ if (__builtin_ctz(0b100000000) != 8) abort(); - \\ - \\ if (!check_clz(0)) abort(); - \\ if (!check_clz(1)) abort(); - \\ if (!check_clz(2)) abort(); - \\ if (!check_clz(4)) abort(); - \\ if (!check_clz(8)) abort(); - \\ - \\ if (__builtin_sqrt(__builtin_sqrt(__builtin_sqrt(256))) != 2.0) abort(); - \\ if (__builtin_sqrt(__builtin_sqrt(__builtin_sqrt(256.0))) != 2.0) abort(); - \\ if (__builtin_sqrt(__builtin_sqrt(__builtin_sqrt(256.0f))) != 2.0) abort(); - \\ if (__builtin_sqrtf(__builtin_sqrtf(__builtin_sqrtf(256.0f))) != 2.0f) abort(); - \\ - \\ if (__builtin_sin(1.0) != -__builtin_sin(-1.0)) abort(); - \\ if (__builtin_sinf(1.0f) != -__builtin_sinf(-1.0f)) abort(); - \\ if (__builtin_sin(M_PI_2) != 1.0) abort(); - \\ if (__builtin_sinf(M_PI_2) != 1.0f) abort(); - \\ - \\ if (__builtin_cos(1.0) != __builtin_cos(-1.0)) abort(); - \\ if (__builtin_cosf(1.0f) != __builtin_cosf(-1.0f)) abort(); - \\ if (__builtin_cos(0.0) != 1.0) abort(); - \\ if (__builtin_cosf(0.0f) != 1.0f) abort(); - \\ - \\ if (__builtin_exp(0) != 1.0) abort(); - \\ if (__builtin_fabs(__builtin_exp(1.0) - M_E) > 0.00000001) abort(); - \\ if (__builtin_exp(0.0f) != 1.0f) abort(); - \\ - \\ if (__builtin_exp2(0) != 1.0) abort(); - \\ if (__builtin_exp2(4.0) != 16.0) abort(); - \\ if (__builtin_exp2f(0.0f) != 1.0f) abort(); - \\ if (__builtin_exp2f(4.0f) != 16.0f) abort(); - \\ - \\ if (__builtin_log(M_E) != 1.0) abort(); - \\ if (__builtin_log(1.0) != 0.0) abort(); - \\ if (__builtin_logf(1.0f) != 0.0f) abort(); - \\ - \\ if (__builtin_log2(8.0) != 3.0) abort(); - \\ if (__builtin_log2(1.0) != 0.0) abort(); - \\ if (__builtin_log2f(8.0f) != 3.0f) abort(); - \\ if (__builtin_log2f(1.0f) != 0.0f) abort(); - \\ - \\ if (__builtin_log10(1000.0) != 3.0) abort(); - \\ if (__builtin_log10(1.0) != 0.0) abort(); - \\ if (__builtin_log10f(1000.0f) != 3.0f) abort(); - \\ if (__builtin_log10f(1.0f) != 0.0f) abort(); - \\ - \\ if (__builtin_fabs(-42.0f) != 42.0) abort(); - \\ if (__builtin_fabs(-42.0) != 42.0) abort(); - \\ if (__builtin_fabs(-42) != 42.0) abort(); - \\ if (__builtin_fabsf(-42.0f) != 42.0f) abort(); - \\ - \\ if (__builtin_fabs(-42.0f) != 42.0) abort(); - \\ if (__builtin_fabs(-42.0) != 42.0) abort(); - \\ if (__builtin_fabs(-42) != 42.0) abort(); - \\ if (__builtin_fabsf(-42.0f) != 42.0f) abort(); - \\ - \\ if (__builtin_abs(42) != 42) abort(); - \\ if (__builtin_abs(-42) != 42) abort(); - \\ if (__builtin_abs(INT_MIN) != INT_MIN) abort(); - \\ - \\ if (__builtin_floor(42.9) != 42.0) abort(); - \\ if (__builtin_floor(-42.9) != -43.0) abort(); - \\ if (__builtin_floorf(42.9f) != 42.0f) abort(); - \\ if (__builtin_floorf(-42.9f) != -43.0f) abort(); - \\ - \\ if (__builtin_ceil(42.9) != 43.0) abort(); - \\ if (__builtin_ceil(-42.9) != -42) abort(); - \\ if (__builtin_ceilf(42.9f) != 43.0f) abort(); - \\ if (__builtin_ceilf(-42.9f) != -42.0f) abort(); - \\ - \\ if (__builtin_trunc(42.9) != 42.0) abort(); - \\ if (__builtin_truncf(42.9f) != 42.0f) abort(); - \\ if (__builtin_trunc(-42.9) != -42.0) abort(); - \\ if (__builtin_truncf(-42.9f) != -42.0f) abort(); - \\ - \\ if (__builtin_round(0.5) != 1.0) abort(); - \\ if (__builtin_round(-0.5) != -1.0) abort(); - \\ if (__builtin_roundf(0.5f) != 1.0f) abort(); - \\ if (__builtin_roundf(-0.5f) != -1.0f) abort(); - \\ - \\ if (__builtin_strcmp("abc", "abc") != 0) abort(); - \\ if (__builtin_strcmp("abc", "def") >= 0 ) abort(); - \\ if (__builtin_strcmp("def", "abc") <= 0) abort(); - \\ - \\ if (__builtin_strlen("this is a string") != 16) abort(); - \\ - \\ char *s = malloc(6); - \\ __builtin_memcpy(s, "hello", 5); - \\ s[5] = '\0'; - \\ if (__builtin_strlen(s) != 5) abort(); - \\ - \\ __builtin_memset(s, 42, __builtin_strlen(s)); - \\ if (s[0] != 42 || s[1] != 42 || s[2] != 42 || s[3] != 42 || s[4] != 42) abort(); - \\ - \\ free(s); - \\ - \\ return 0; - \\} - , ""); - - cases.add("function macro that uses builtin", - \\#include - \\#define FOO(x, y) (__builtin_popcount((x)) + __builtin_strlen((y))) - \\int main() { - \\ if (FOO(7, "hello!") != 9) abort(); - \\ return 0; - \\} - , ""); - - cases.add("assign bool result to int or char", - \\#include - \\#include - \\bool foo() { return true; } - \\int main() { - \\ int x = foo(); - \\ if (x != 1) abort(); - \\ signed char c = foo(); - \\ if (c != 1) abort(); - \\ return 0; - \\} - , ""); - - cases.add("static K&R-style no prototype function declaration (empty parameter list)", - \\#include - \\static int foo() { - \\ return 42; - \\} - \\int main() { - \\ if (foo() != 42) abort(); - \\ return 0; - \\} - , ""); - - cases.add("K&R-style static function prototype for unused function", - \\static int foo(); - \\int main() { - \\ return 0; - \\} - , ""); - - cases.add("K&R-style static function prototype + separate definition", - \\#include - \\static int foo(); - \\static int foo(int a, int b) { - \\ return a + b; - \\} - \\int main() { - \\ if (foo(40, 2) != 42) abort(); - \\ return 0; - \\} - , ""); - - cases.add("dollar sign in identifiers", - \\#include - \\#define $FOO 2 - \\#define $foo bar$ - \\#define $baz($x) ($x + $FOO) - \\int $$$(int $x$) { return $x$ + $FOO; } - \\int main() { - \\ int bar$ = 42; - \\ if ($foo != 42) abort(); - \\ if (bar$ != 42) abort(); - \\ if ($baz(bar$) != 44) abort(); - \\ if ($$$(bar$) != 44) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Cast boolean expression result to int", - \\#include - \\char foo(char c) { return c; } - \\int bar(int i) { return i; } - \\long baz(long l) { return l; } - \\int main() { - \\ if (foo(1 == 2)) abort(); - \\ if (!foo(1 == 1)) abort(); - \\ if (bar(1 == 2)) abort(); - \\ if (!bar(1 == 1)) abort(); - \\ if (baz(1 == 2)) abort(); - \\ if (!baz(1 == 1)) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Wide, UTF-16, and UTF-32 character literals", - \\#include - \\#include - \\int main() { - \\ wchar_t wc = L'™'; - \\ int utf16_char = u'™'; - \\ int utf32_char = U'💯'; - \\ if (wc != 8482) abort(); - \\ if (utf16_char != 8482) abort(); - \\ if (utf32_char != 128175) abort(); - \\ unsigned char c = wc; - \\ if (c != 0x22) abort(); - \\ c = utf32_char; - \\ if (c != 0xaf) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Variadic function call", - \\#define _NO_CRT_STDIO_INLINE 1 - \\#include - \\int main(void) { - \\ printf("%d %d\n", 1, 2); - \\ return 0; - \\} - , "1 2" ++ nl); - - cases.add("multi-character character constant", - \\#include - \\int main(void) { - \\ int foo = 'abcd'; - \\ switch (foo) { - \\ case 'abcd': break; - \\ default: abort(); - \\ } - \\ return 0; - \\} - , ""); - - cases.add("Array initializers (string literals, incomplete arrays)", - \\#include - \\#include - \\extern int foo[]; - \\int global_arr[] = {1, 2, 3}; - \\char global_string[] = "hello"; - \\int main(int argc, char *argv[]) { - \\ if (global_arr[2] != 3) abort(); - \\ if (strlen(global_string) != 5) abort(); - \\ const char *const_str = "hello"; - \\ if (strcmp(const_str, "hello") != 0) abort(); - \\ char empty_str[] = ""; - \\ if (strlen(empty_str) != 0) abort(); - \\ char hello[] = "hello"; - \\ if (strlen(hello) != 5 || sizeof(hello) != 6) abort(); - \\ int empty[] = {}; - \\ if (sizeof(empty) != 0) abort(); - \\ int bar[] = {42}; - \\ if (bar[0] != 42) abort(); - \\ bar[0] = 43; - \\ if (bar[0] != 43) abort(); - \\ int baz[] = {1, [42] = 123, 456}; - \\ if (baz[42] != 123 || baz[43] != 456) abort(); - \\ if (sizeof(baz) != sizeof(int) * 44) abort(); - \\ const char *const names[] = {"first", "second", "third"}; - \\ if (strcmp(names[2], "third") != 0) abort(); - \\ char catted_str[] = "abc" "def"; - \\ if (strlen(catted_str) != 6 || sizeof(catted_str) != 7) abort(); - \\ char catted_trunc_str[2] = "abc" "def"; - \\ if (sizeof(catted_trunc_str) != 2 || catted_trunc_str[0] != 'a' || catted_trunc_str[1] != 'b') abort(); - \\ char big_array_utf8lit[10] = "💯"; - \\ if (strcmp(big_array_utf8lit, "💯") != 0 || big_array_utf8lit[9] != 0) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Wide, UTF-16, and UTF-32 string literals", - \\#include - \\#include - \\#include - \\int main(void) { - \\ const wchar_t *wide_str = L"wide"; - \\ const wchar_t wide_hello[] = L"hello"; - \\ if (wcslen(wide_str) != 4) abort(); - \\ if (wcslen(L"literal") != 7) abort(); - \\ if (wcscmp(wide_hello, L"hello") != 0) abort(); - \\ - \\ const uint16_t *u16_str = u"wide"; - \\ const uint16_t u16_hello[] = u"hello"; - \\ if (u16_str[3] != u'e' || u16_str[4] != 0) abort(); - \\ if (u16_hello[4] != u'o' || u16_hello[5] != 0) abort(); - \\ - \\ const uint32_t *u32_str = U"wide"; - \\ const uint32_t u32_hello[] = U"hello"; - \\ if (u32_str[3] != U'e' || u32_str[4] != 0) abort(); - \\ if (u32_hello[4] != U'o' || u32_hello[5] != 0) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Address of function is no-op", - \\#include - \\#include - \\typedef int (*myfunc)(int); - \\int a(int arg) { return arg + 1;} - \\int b(int arg) { return arg + 2;} - \\int caller(myfunc fn, int arg) { - \\ return fn(arg); - \\} - \\int main() { - \\ myfunc arr[3] = {&a, &b, a}; - \\ myfunc foo = a; - \\ myfunc bar = &(a); - \\ if (foo != bar) abort(); - \\ if (arr[0] == arr[1]) abort(); - \\ if (arr[0] != arr[2]) abort(); - \\ if (caller(b, 40) != 42) abort(); - \\ if (caller(&b, 40) != 42) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Obscure ways of calling functions; issue #4124", - \\#include - \\static int add(int a, int b) { - \\ return a + b; - \\} - \\typedef int (*adder)(int, int); - \\typedef void (*funcptr)(void); - \\int main() { - \\ if ((add)(1, 2) != 3) abort(); - \\ if ((&add)(1, 2) != 3) abort(); - \\ if (add(3, 1) != 4) abort(); - \\ if ((*add)(2, 3) != 5) abort(); - \\ if ((**add)(7, -1) != 6) abort(); - \\ if ((***add)(-2, 9) != 7) abort(); - \\ - \\ int (*ptr)(int a, int b); - \\ ptr = add; - \\ - \\ if (ptr(1, 2) != 3) abort(); - \\ if ((*ptr)(3, 1) != 4) abort(); - \\ if ((**ptr)(2, 3) != 5) abort(); - \\ if ((***ptr)(7, -1) != 6) abort(); - \\ if ((****ptr)(-2, 9) != 7) abort(); - \\ - \\ funcptr addr1 = (funcptr)(add); - \\ funcptr addr2 = (funcptr)(&add); - \\ - \\ if (addr1 != addr2) abort(); - \\ if (((int(*)(int, int))addr1)(1, 2) != 3) abort(); - \\ if (((adder)addr2)(1, 2) != 3) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Return boolean expression as int; issue #6215", - \\#include - \\#include - \\bool actual_bool(void) { return 4 - 1 < 4;} - \\char char_bool_ret(void) { return 0 || 1; } - \\short short_bool_ret(void) { return 0 < 1; } - \\int int_bool_ret(void) { return 1 && 1; } - \\long long_bool_ret(void) { return !(0 > 1); } - \\static int GLOBAL = 1; - \\int nested_scopes(int a, int b) { - \\ if (a == 1) { - \\ int target = 1; - \\ return b == target; - \\ } else { - \\ int target = 2; - \\ if (b == target) { - \\ return GLOBAL == 1; - \\ } - \\ return target == 2; - \\ } - \\} - \\int main(void) { - \\ if (!actual_bool()) abort(); - \\ if (!char_bool_ret()) abort(); - \\ if (!short_bool_ret()) abort(); - \\ if (!int_bool_ret()) abort(); - \\ if (!long_bool_ret()) abort(); - \\ if (!nested_scopes(1, 1)) abort(); - \\ if (nested_scopes(1, 2)) abort(); - \\ if (!nested_scopes(0, 2)) abort(); - \\ if (!nested_scopes(0, 3)) abort(); - \\ return 1 != 1; - \\} - , ""); - - cases.add("Comma operator should create new scope; issue #7989", - \\#include - \\#include - \\int main(void) { - \\ if (1 || (abort(), 1)) {} - \\ if (0 && (1, printf("do not print\n"))) {} - \\ int x = 0; - \\ x = (x = 3, 4, x + 1); - \\ if (x != 4) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Use correct break label for statement expression in nested scope", - \\#include - \\int main(void) { - \\ int x = ({1, ({2; 3;});}); - \\ if (x != 3) abort(); - \\ return 0; - \\} - , ""); - - cases.add("pointer difference: scalar array w/ size truncation or negative result. Issue #7216", - \\#include - \\#include - \\#define SIZE 10 - \\int main() { - \\ int foo[SIZE]; - \\ int *start = &foo[0]; - \\ int *one_past_end = start + SIZE; - \\ ptrdiff_t diff = one_past_end - start; - \\ char diff_char = one_past_end - start; - \\ if (diff != SIZE || diff_char != SIZE) abort(); - \\ diff = start - one_past_end; - \\ if (diff != -SIZE) abort(); - \\ if (one_past_end - foo != SIZE) abort(); - \\ if ((one_past_end - 1) - foo != SIZE - 1) abort(); - \\ if ((start + 1) - foo != 1) abort(); - \\ return 0; - \\} - , ""); - - // C standard: if the expression P points either to an element of an array object or one - // past the last element of an array object, and the expression Q points to the last - // element of the same array object, the expression ((Q)+1)-(P) has the same value as - // ((Q)-(P))+1 and as -((P)-((Q)+1)), and has the value zero if the expression P points - // one past the last element of the array object, even though the expression (Q)+1 - // does not point to an element of the array object - cases.add("pointer difference: C standard edge case", - \\#include - \\#include - \\#define SIZE 10 - \\int main() { - \\ int foo[SIZE]; - \\ int *start = &foo[0]; - \\ int *P = start + SIZE; - \\ int *Q = &foo[SIZE - 1]; - \\ if ((Q + 1) - P != 0) abort(); - \\ if ((Q + 1) - P != (Q - P) + 1) abort(); - \\ if ((Q + 1) - P != -(P - (Q + 1))) abort(); - \\ return 0; - \\} - , ""); - - cases.add("pointer difference: unary operators", - \\#include - \\int main() { - \\ int foo[10]; - \\ int *x = &foo[1]; - \\ const int *y = &foo[5]; - \\ if (y - x++ != 4) abort(); - \\ if (y - x != 3) abort(); - \\ if (y - ++x != 2) abort(); - \\ if (y - x-- != 2) abort(); - \\ if (y - x != 3) abort(); - \\ if (y - --x != 4) abort(); - \\ if (y - &foo[0] != 5) abort(); - \\ return 0; - \\} - , ""); - - cases.add("pointer difference: struct array with padding", - \\#include - \\#include - \\#define SIZE 10 - \\typedef struct my_struct { - \\ int x; - \\ char c; - \\ int y; - \\} my_struct_t; - \\int main() { - \\ my_struct_t foo[SIZE]; - \\ my_struct_t *start = &foo[0]; - \\ my_struct_t *one_past_end = start + SIZE; - \\ ptrdiff_t diff = one_past_end - start; - \\ int diff_int = one_past_end - start; - \\ if (diff != SIZE || diff_int != SIZE) abort(); - \\ diff = start - one_past_end; - \\ if (diff != -SIZE) abort(); - \\ return 0; - \\} - , ""); - - cases.add("pointer difference: array of function pointers", - \\#include - \\int a(void) { return 1;} - \\int b(void) { return 2;} - \\int c(void) { return 3;} - \\typedef int (*myfunc)(void); - \\int main() { - \\ myfunc arr[] = {a, b, c, a, b, c}; - \\ myfunc *f1 = &arr[1]; - \\ myfunc *f4 = &arr[4]; - \\ if (f4 - f1 != 3) abort(); - \\ return 0; - \\} - , ""); - - cases.add("typeof operator", - \\#include - \\static int FOO = 42; - \\typedef typeof(FOO) foo_type; - \\typeof(foo_type) myfunc(typeof(FOO) x) { return (typeof(FOO)) x; } - \\int main(void) { - \\ int x = FOO; - \\ typeof(x) y = x; - \\ foo_type z = y; - \\ if (x != y) abort(); - \\ if (myfunc(z) != x) abort(); - \\ - \\ const char *my_string = "bar"; - \\ typeof (typeof (my_string)[4]) string_arr = {"a","b","c","d"}; - \\ if (string_arr[0][0] != 'a' || string_arr[3][0] != 'd') abort(); - \\ return 0; - \\} - , ""); - - cases.add("offsetof", - \\#include - \\#include - \\#define container_of(ptr, type, member) ({ \ - \\ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - \\ (type *)( (char *)__mptr - offsetof(type,member) );}) - \\typedef struct { - \\ int i; - \\ struct { int x; char y; int z; } s; - \\ float f; - \\} container; - \\int main(void) { - \\ if (offsetof(container, i) != 0) abort(); - \\ if (offsetof(container, s) <= offsetof(container, i)) abort(); - \\ if (offsetof(container, f) <= offsetof(container, s)) abort(); - \\ - \\ container my_container; - \\ typeof(my_container.s) *inner_member_pointer = &my_container.s; - \\ float *float_member_pointer = &my_container.f; - \\ int *anon_member_pointer = &my_container.s.z; - \\ container *my_container_p; - \\ - \\ my_container_p = container_of(inner_member_pointer, container, s); - \\ if (my_container_p != &my_container) abort(); - \\ - \\ my_container_p = container_of(float_member_pointer, container, f); - \\ if (my_container_p != &my_container) abort(); - \\ - \\ if (container_of(anon_member_pointer, typeof(my_container.s), z) != inner_member_pointer) abort(); - \\ return 0; - \\} - , ""); - - cases.add("handle assert.h", - \\#include - \\int main() { - \\ int x = 1; - \\ int *xp = &x; - \\ assert(1); - \\ assert(x != 0); - \\ assert(xp); - \\ assert(*xp); - \\ return 0; - \\} - , ""); - - cases.add("NDEBUG disables assert", - \\#define NDEBUG - \\#include - \\int main() { - \\ assert(0); - \\ assert(NULL); - \\ return 0; - \\} - , ""); - - cases.add("pointer arithmetic with signed operand", - \\#include - \\int main() { - \\ int array[10]; - \\ int *x = &array[5]; - \\ int *y; - \\ int idx = 0; - \\ y = x + ++idx; - \\ if (y != x + 1 || y != &array[6]) abort(); - \\ y = idx + x; - \\ if (y != x + 1 || y != &array[6]) abort(); - \\ y = x - idx; - \\ if (y != x - 1 || y != &array[4]) abort(); - \\ - \\ idx = 0; - \\ y = --idx + x; - \\ if (y != x - 1 || y != &array[4]) abort(); - \\ y = idx + x; - \\ if (y != x - 1 || y != &array[4]) abort(); - \\ y = x - idx; - \\ if (y != x + 1 || y != &array[6]) abort(); - \\ - \\ idx = 1; - \\ x += idx; - \\ if (x != &array[6]) abort(); - \\ x -= idx; - \\ if (x != &array[5]) abort(); - \\ y = (x += idx); - \\ if (y != x || y != &array[6]) abort(); - \\ y = (x -= idx); - \\ if (y != x || y != &array[5]) abort(); - \\ - \\ if (array + idx != &array[1] || array + 1 != &array[1]) abort(); - \\ idx = -1; - \\ if (array - idx != &array[1]) abort(); - \\ - \\ return 0; - \\} - , ""); - - cases.add("Compound literals", - \\#include - \\struct Foo { - \\ int a; - \\ char b[2]; - \\ float c; - \\}; - \\int main() { - \\ struct Foo foo; - \\ int x = 1, y = 2; - \\ foo = (struct Foo) {x + y, {'a', 'b'}, 42.0f}; - \\ if (foo.a != x + y || foo.b[0] != 'a' || foo.b[1] != 'b' || foo.c != 42.0f) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Generic selections", - \\#include - \\#include - \\#include - \\#define my_generic_fn(X) _Generic((X), \ - \\ int: abs, \ - \\ char *: strlen, \ - \\ size_t: malloc, \ - \\ default: free \ - \\)(X) - \\#define my_generic_val(X) _Generic((X), \ - \\ int: 1, \ - \\ const char *: "bar" \ - \\) - \\int main(void) { - \\ if (my_generic_val(100) != 1) abort(); - \\ - \\ const char *foo = "foo"; - \\ const char *bar = my_generic_val(foo); - \\ if (strcmp(bar, "bar") != 0) abort(); - \\ - \\ if (my_generic_fn(-42) != 42) abort(); - \\ if (my_generic_fn("hello") != 5) abort(); - \\ - \\ size_t size = 8192; - \\ uint8_t *mem = my_generic_fn(size); - \\ memset(mem, 42, size); - \\ if (mem[size - 1] != 42) abort(); - \\ my_generic_fn(mem); - \\ - \\ return 0; - \\} - , ""); - - // See __builtin_alloca_with_align comment in std.zig.c_builtins - cases.add("use of unimplemented builtin in unused function does not prevent compilation", - \\#include - \\void unused() { - \\ __builtin_alloca_with_align(1, 8); - \\} - \\int main(void) { - \\ if (__builtin_sqrt(1.0) != 1.0) abort(); - \\ return 0; - \\} - , ""); - - cases.add("convert single-statement bodies into blocks for if/else/for/while. issue #8159", - \\#include - \\int foo() { return 1; } - \\int main(void) { - \\ int i = 0; - \\ if (i == 0) if (i == 0) if (i != 0) i = 1; - \\ if (i != 0) i = 1; else if (i == 0) if (i == 0) i += 1; - \\ for (; i < 10;) for (; i < 10;) i++; - \\ while (i == 100) while (i == 100) foo(); - \\ if (0) do do "string"; while(1); while(1); - \\ return 0; - \\} - , ""); - - cases.add("cast RHS of compound assignment if necessary, unused result", - \\#include - \\int main(void) { - \\ signed short val = -1; - \\ val += 1; if (val != 0) abort(); - \\ val -= 1; if (val != -1) abort(); - \\ val *= 2; if (val != -2) abort(); - \\ val /= 2; if (val != -1) abort(); - \\ val %= 2; if (val != -1) abort(); - \\ val <<= 1; if (val != -2) abort(); - \\ val >>= 1; if (val != -1) abort(); - \\ val += 100000000; // compile error if @truncate() not inserted - \\ unsigned short uval = 1; - \\ uval += 1; if (uval != 2) abort(); - \\ uval -= 1; if (uval != 1) abort(); - \\ uval *= 2; if (uval != 2) abort(); - \\ uval /= 2; if (uval != 1) abort(); - \\ uval %= 2; if (uval != 1) abort(); - \\ uval <<= 1; if (uval != 2) abort(); - \\ uval >>= 1; if (uval != 1) abort(); - \\ uval += 100000000; // compile error if @truncate() not inserted - \\} - , ""); - - cases.add("cast RHS of compound assignment if necessary, used result", - \\#include - \\int main(void) { - \\ signed short foo; - \\ signed short val = -1; - \\ foo = (val += 1); if (foo != 0) abort(); - \\ foo = (val -= 1); if (foo != -1) abort(); - \\ foo = (val *= 2); if (foo != -2) abort(); - \\ foo = (val /= 2); if (foo != -1) abort(); - \\ foo = (val %= 2); if (foo != -1) abort(); - \\ foo = (val <<= 1); if (foo != -2) abort(); - \\ foo = (val >>= 1); if (foo != -1) abort(); - \\ foo = (val += 100000000); // compile error if @truncate() not inserted - \\ unsigned short ufoo; - \\ unsigned short uval = 1; - \\ ufoo = (uval += 1); if (ufoo != 2) abort(); - \\ ufoo = (uval -= 1); if (ufoo != 1) abort(); - \\ ufoo = (uval *= 2); if (ufoo != 2) abort(); - \\ ufoo = (uval /= 2); if (ufoo != 1) abort(); - \\ ufoo = (uval %= 2); if (ufoo != 1) abort(); - \\ ufoo = (uval <<= 1); if (ufoo != 2) abort(); - \\ ufoo = (uval >>= 1); if (ufoo != 1) abort(); - \\ ufoo = (uval += 100000000); // compile error if @truncate() not inserted - \\} - , ""); - - cases.add("break from switch statement. Issue #8387", - \\#include - \\int switcher(int x) { - \\ switch (x) { - \\ case 0: // no braces - \\ x += 1; - \\ break; - \\ case 1: // conditional break - \\ if (x == 1) { - \\ x += 1; - \\ break; - \\ } - \\ x += 100; - \\ case 2: { // braces with fallthrough - \\ x += 1; - \\ } - \\ case 3: // fallthrough to return statement - \\ x += 1; - \\ case 42: { // random out of order case - \\ x += 1; - \\ return x; - \\ } - \\ case 4: { // break within braces - \\ x += 1; - \\ break; - \\ } - \\ case 5: - \\ x += 1; // fallthrough to default - \\ default: - \\ x += 1; - \\ } - \\ return x; - \\} - \\int main(void) { - \\ int expected[] = {1, 2, 5, 5, 5, 7, 7}; - \\ for (int i = 0; i < sizeof(expected) / sizeof(int); i++) { - \\ int res = switcher(i); - \\ if (res != expected[i]) abort(); - \\ } - \\ if (switcher(42) != 43) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Cast to enum from larger integral type. Issue #6011", - \\#include - \\#include - \\enum Foo { A, B, C }; - \\static inline enum Foo do_stuff(void) { - \\ int64_t i = 1; - \\ return (enum Foo)i; - \\} - \\int main(void) { - \\ if (do_stuff() != B) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Render array LHS as grouped node if necessary", - \\#include - \\int main(void) { - \\ int arr[] = {40, 41, 42, 43}; - \\ if ((arr + 1)[1] != 42) abort(); - \\ return 0; - \\} - , ""); - - cases.add("typedef with multiple names", - \\#include - \\typedef struct { - \\ char field; - \\} a_t, b_t; - \\ - \\int main(void) { - \\ a_t a = { .field = 42 }; - \\ b_t b = a; - \\ if (b.field != 42) abort(); - \\ return 0; - \\} - , ""); - - cases.add("__cleanup__ attribute", - \\#include - \\static int cleanup_count = 0; - \\void clean_up(int *final_value) { - \\ if (*final_value != cleanup_count++) abort(); - \\} - \\void doit(void) { - \\ int a __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 2; - \\ int b __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 1; - \\ int c __attribute__ ((__cleanup__(clean_up))) __attribute__ ((unused)) = 0; - \\} - \\int main(void) { - \\ doit(); - \\ if (cleanup_count != 3) abort(); - \\ return 0; - \\} - , ""); - - cases.add("enum used as boolean expression", - \\#include - \\enum FOO {BAR, BAZ}; - \\int main(void) { - \\ enum FOO x = BAR; - \\ if (x) abort(); - \\ if (!BAZ) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Flexible arrays", - \\#include - \\#include - \\typedef struct { char foo; int bar; } ITEM; - \\typedef struct { size_t count; ITEM items[]; } ITEM_LIST; - \\typedef struct { unsigned char count; int items[]; } INT_LIST; - \\#define SIZE 10 - \\int main(void) { - \\ ITEM_LIST *list = malloc(sizeof(ITEM_LIST) + SIZE * sizeof(ITEM)); - \\ for (int i = 0; i < SIZE; i++) list->items[i] = (ITEM) {.foo = i, .bar = i + 1}; - \\ const ITEM_LIST *const c_list = list; - \\ for (int i = 0; i < SIZE; i++) if (c_list->items[i].foo != i || c_list->items[i].bar != i + 1) abort(); - \\ INT_LIST *int_list = malloc(sizeof(INT_LIST) + SIZE * sizeof(int)); - \\ for (int i = 0; i < SIZE; i++) int_list->items[i] = i; - \\ const INT_LIST *const c_int_list = int_list; - \\ const int *const ints = int_list->items; - \\ for (int i = 0; i < SIZE; i++) if (ints[i] != i) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Flexible array with typedefed flexible item, issue #16838", - \\#include - \\#include - \\typedef int MARKER[0]; - \\typedef struct { int x; MARKER y; } Flexible; - \\#define SIZE 10 - \\int main(void) { - \\ Flexible *flex = malloc(sizeof(Flexible) + SIZE * sizeof(int)); - \\ for (int i = 0; i < SIZE; i++) { - \\ flex->y[i] = i; - \\ } - \\ for (int i = 0; i < SIZE; i++) { - \\ assert(flex->y[i] == i); - \\ } - \\ return 0; - \\} - , ""); - - cases.add("enum with value that fits in c_uint but not c_int, issue #8003", - \\#include - \\enum my_enum { - \\ FORCE_UINT = 0xffffffff - \\}; - \\int main(void) { - \\ if(FORCE_UINT != 0xffffffff) abort(); - \\} - , ""); - - cases.add("block-scope static variable shadows function parameter. Issue #8208", - \\#include - \\int func1(int foo) { return foo + 1; } - \\int func2(void) { - \\ static int foo = 5; - \\ return foo++; - \\} - \\int main(void) { - \\ if (func1(42) != 43) abort(); - \\ if (func2() != 5) abort(); - \\ if (func2() != 6) abort(); - \\ return 0; - \\} - , ""); - - cases.add("nested same-name static locals", - \\#include - \\int func(int val) { - \\ static int foo; - \\ if (foo != val) abort(); - \\ { - \\ foo += 1; - \\ static int foo = 2; - \\ if (foo != val + 2) abort(); - \\ foo += 1; - \\ } - \\ return foo; - \\} - \\int main(void) { - \\ int foo = 1; - \\ if (func(0) != 1) abort(); - \\ if (func(1) != 2) abort(); - \\ if (func(2) != 3) abort(); - \\ if (foo != 1) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Enum constants are assigned correct type. Issue #9153", - \\enum A { A0, A1=0xFFFFFFFF }; - \\enum B { B0=-1, B1=0xFFFFFFFF }; - \\enum C { C0=-1, C1=0 }; - \\enum D { D0, D1=0xFFFFFFFFFFL }; - \\enum E { E0=-1, E1=0xFFFFFFFFFFL }; - \\int main(void) { - \\ signed char a0 = A0, a1 = A1; - \\ signed char b0 = B0, b1 = B1; - \\ signed char c0 = C0, c1 = C1; - \\ signed char d0 = D0, d1 = D1; - \\ signed char e0 = E0, e1 = E1; - \\ return 0; - \\} - , ""); - - cases.add("Enum constant matches enum name; multiple enumerations with same value", - \\#include - \\enum FOO { - \\ FOO = 1, - \\ BAR = 2, - \\ BAZ = 1, - \\}; - \\int main(void) { - \\ enum FOO x = BAZ; - \\ if (x != 1) abort(); - \\ if (x != BAZ) abort(); - \\ if (x != FOO) abort(); - \\} - , ""); - - cases.add("Scoped enums", - \\#include - \\int main(void) { - \\ enum Foo { A, B, C }; - \\ enum Foo a = B; - \\ if (a != B) abort(); - \\ if (a != 1) abort(); - \\ { - \\ enum Foo { A = 5, B = 6, C = 7 }; - \\ enum Foo a = B; - \\ if (a != B) abort(); - \\ if (a != 6) abort(); - \\ } - \\ if (a != B) abort(); - \\ if (a != 1) abort(); - \\} - , ""); - - cases.add("Underscore identifiers", - \\#include - \\int _ = 10; - \\typedef struct { int _; } S; - \\int main(void) { - \\ if (_ != 10) abort(); - \\ S foo = { ._ = _ }; - \\ if (foo._ != _) abort(); - \\ return 0; - \\} - , ""); - - cases.add("__builtin_choose_expr (unchosen expression is not evaluated)", - \\#include - \\int main(void) { - \\ int x = 0.0; - \\ int y = 0.0; - \\ int res; - \\ res = __builtin_choose_expr(1, 1, x / y); - \\ if (res != 1) abort(); - \\ res = __builtin_choose_expr(0, x / y, 2); - \\ if (res != 2) abort(); - \\ return 0; - \\} - , ""); - - // TODO: add isnan check for long double once bitfield support is added - // (needed for x86_64-windows-gnu) - // TODO: add isinf check for long double once std.math.isInf supports c_longdouble - cases.add("NAN and INFINITY", - \\#include - \\#include - \\#include - \\union uf { uint32_t u; float f; }; - \\#define CHECK_NAN(STR, VAL) { \ - \\ union uf unpack = {.f = __builtin_nanf(STR)}; \ - \\ if (!isnan(unpack.f)) abort(); \ - \\ if (unpack.u != VAL) abort(); \ - \\} - \\int main(void) { - \\ float f_nan = NAN; - \\ if (!isnan(f_nan)) abort(); - \\ double d_nan = NAN; - \\ if (!isnan(d_nan)) abort(); - \\ CHECK_NAN("0", 0x7FC00000); - \\ CHECK_NAN("", 0x7FC00000); - \\ CHECK_NAN("1", 0x7FC00001); - \\ CHECK_NAN("0x7FC00000", 0x7FC00000); - \\ CHECK_NAN("0x7FC0000F", 0x7FC0000F); - \\ CHECK_NAN("0x7FC000F0", 0x7FC000F0); - \\ CHECK_NAN("0x7FC00F00", 0x7FC00F00); - \\ CHECK_NAN("0x7FC0F000", 0x7FC0F000); - \\ CHECK_NAN("0x7FCF0000", 0x7FCF0000); - \\ CHECK_NAN("0xFFFFFFFF", 0x7FFFFFFF); - \\ float f_inf = INFINITY; - \\ if (!isinf(f_inf)) abort(); - \\ double d_inf = INFINITY; - \\ if (!isinf(d_inf)) abort(); - \\ return 0; - \\} - , ""); - - cases.add("signed array subscript. Issue #8556", - \\#include - \\#include - \\#define TEST_NEGATIVE(type) { type x = -1; if (ptr[x] != 42) abort(); } - \\#define TEST_UNSIGNED(type) { type x = 2; if (arr[x] != 42) abort(); } - \\int main(void) { - \\ int arr[] = {40, 41, 42, 43}; - \\ int *ptr = arr + 3; - \\ if (ptr[-1] != 42) abort(); - \\ TEST_NEGATIVE(int); - \\ TEST_NEGATIVE(long); - \\ TEST_NEGATIVE(long long); - \\ TEST_NEGATIVE(int64_t); - \\ TEST_NEGATIVE(__int128); - \\ TEST_UNSIGNED(unsigned); - \\ TEST_UNSIGNED(unsigned long); - \\ TEST_UNSIGNED(unsigned long long); - \\ TEST_UNSIGNED(uint64_t); - \\ TEST_UNSIGNED(size_t); - \\ TEST_UNSIGNED(unsigned __int128); - \\ return 0; - \\} - , ""); - - cases.add("Ensure side-effects only evaluated once for signed array indices", - \\#include - \\int main(void) { - \\ int foo[] = {1, 2, 3, 4}; - \\ int *p = foo; - \\ int idx = 1; - \\ if ((++p)[--idx] != 2) abort(); - \\ if (p != foo + 1) abort(); - \\ if (idx != 0) abort(); - \\ if ((p++)[idx++] != 2) abort(); - \\ if (p != foo + 2) abort(); - \\ if (idx != 1) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Allow non-const char* string literals. Issue #9126", - \\#include - \\int func(char *x) { return x[0]; } - \\struct S { char *member; }; - \\struct S global_struct = { .member = "global" }; - \\char *g = "global"; - \\int main(void) { - \\ if (g[0] != 'g') abort(); - \\ if (global_struct.member[0] != 'g') abort(); - \\ char *string = "hello"; - \\ if (string[0] != 'h') abort(); - \\ struct S s = {.member = "hello"}; - \\ if (s.member[0] != 'h') abort(); - \\ if (func("foo") != 'f') abort(); - \\ return 0; - \\} - , ""); - - cases.add("Ensure while loop under an if doesn't steal the else. Issue #9953", - \\#include - \\void doWork(int id) { } - \\int reallyDelete(int id) { printf("deleted %d\n", id); return 1; } - \\int process(int id, int n, int delete) { - \\ if(!delete) - \\ while(n-- > 0) doWork(id); - \\ else - \\ return reallyDelete(id); - \\ return 0; - \\} - \\int main(void) { - \\ process(99, 3, 0); - \\ return 0; - \\} - , ""); - - cases.add("Remainder operator with negative integers. Issue #10176", - \\#include - \\int main(void) { - \\ int denominator = -2; - \\ int numerator = 5; - \\ if (numerator % denominator != 1) abort(); - \\ numerator = -5; denominator = 2; - \\ if (numerator % denominator != -1) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Boolean expression coerced to int. Issue #10175", - \\#include - \\int sign(int v) { - \\ return -(v < 0); - \\} - \\int main(void) { - \\ if (sign(-5) != -1) abort(); - \\ if (sign(5) != 0) abort(); - \\ if (sign(0) != 0) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Typedef'ed void used as return type. Issue #10356", - \\typedef void V; - \\V foo(V *f) {} - \\int main(void) { - \\ int x = 0; - \\ foo(&x); - \\ return 0; - \\} - , ""); - - cases.add("Zero-initialization of global union. Issue #10797", - \\#include - \\union U { int x; double y; }; - \\union U u; - \\int main(void) { - \\ if (u.x != 0) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Cast-to-union. Issue #10955", - \\#include - \\struct S { int x; }; - \\union U { - \\ long l; - \\ double d; - \\ struct S s; - \\}; - \\union U bar(union U u) { return u; } - \\int main(void) { - \\ union U u = (union U) 42L; - \\ if (u.l != 42L) abort(); - \\ u = (union U) 2.0; - \\ if (u.d != 2.0) abort(); - \\ u = bar((union U)4.0); - \\ if (u.d != 4.0) abort(); - \\ u = (union U)(struct S){ .x = 5 }; - \\ if (u.s.x != 5) abort(); - \\ return 0; - \\} - , ""); - - cases.add("Nested comma operator in macro. Issue #11040", - \\#include - \\#define FOO (1, (2, 3)) - \\int main(void) { - \\ int x = FOO; - \\ if (x != 3) abort(); - \\ return 0; - \\} - , ""); - - // The C standard does not require function pointers to be convertible to any integer type. - // However, POSIX requires that function pointers have the same representation as `void *` - // so that dlsym() can work - cases.add("Function to integral", - \\#include - \\int main(void) { - \\#if defined(__UINTPTR_MAX__) && __has_include() - \\ uintptr_t x = (uintptr_t)main; - \\#endif - \\ return 0; - \\} - , ""); - - cases.add("Closure over local in typeof", - \\#include - \\int main(void) { - \\ int x = 123; - \\ union { typeof(x) val; } u = { x }; - \\ if (u.val != 123) abort(); - \\ return 0; - \\} - , ""); - - cases.add("struct without global declaration does not conflict with local variable name", - \\#include - \\static void foo(struct foobar *unused) {} - \\int main(void) { - \\ int struct_foobar = 123; - \\ if (struct_foobar != 123) abort(); - \\ int foobar = 456; - \\ if (foobar != 456) abort(); - \\ return 0; - \\} - , ""); - - cases.add("struct without global declaration does not conflict with global variable name", - \\#include - \\static void foo(struct foobar *unused) {} - \\static int struct_foobar = 123; - \\static int foobar = 456; - \\int main(void) { - \\ if (struct_foobar != 123) abort(); - \\ if (foobar != 456) abort(); - \\ return 0; - \\} - , ""); -} diff --git a/test/src/Cases.zig b/test/src/Cases.zig index d278808327..7edb66aede 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -9,7 +9,6 @@ const ArrayList = std.ArrayList; gpa: Allocator, arena: Allocator, cases: std.array_list.Managed(Case), -translate: std.array_list.Managed(Translate), pub const IncrementalCase = struct { base_path: []const u8, @@ -127,25 +126,6 @@ pub const Case = struct { } }; -pub const Translate = struct { - /// The name of the test case. This is shown if a test fails, and - /// otherwise ignored. - name: []const u8, - - input: [:0]const u8, - target: std.Build.ResolvedTarget, - link_libc: bool, - c_frontend: CFrontend, - kind: union(enum) { - /// Translate the input, run it and check that it - /// outputs the expected text. - run: []const u8, - /// Translate the input and check that it contains - /// the expected lines of code. - translate: []const []const u8, - }, -}; - pub fn addExe( ctx: *Cases, name: []const u8, @@ -374,7 +354,6 @@ fn addFromDirInner( const backends = try manifest.getConfigForKeyAlloc(ctx.arena, "backend", Backend); const targets = try manifest.getConfigForKeyAlloc(ctx.arena, "target", std.Target.Query); - const c_frontends = try manifest.getConfigForKeyAlloc(ctx.arena, "c_frontend", CFrontend); const is_test = try manifest.getConfigForKeyAssertSingle("is_test", bool); const link_libc = try manifest.getConfigForKeyAssertSingle("link_libc", bool); const output_mode = try manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode); @@ -384,39 +363,6 @@ fn addFromDirInner( const emit_bin = try manifest.getConfigForKeyAssertSingle("emit_bin", bool); const imports = try manifest.getConfigForKeyAlloc(ctx.arena, "imports", []const u8); - if (manifest.type == .translate_c) { - for (c_frontends) |c_frontend| { - for (targets) |target_query| { - const output = try manifest.trailingLinesSplit(ctx.arena); - try ctx.translate.append(.{ - .name = try caseNameFromPath(ctx.arena, filename), - .c_frontend = c_frontend, - .target = b.resolveTargetQuery(target_query), - .link_libc = link_libc, - .input = src, - .kind = .{ .translate = output }, - }); - } - } - continue; - } - if (manifest.type == .run_translated_c) { - for (c_frontends) |c_frontend| { - for (targets) |target_query| { - const output = try manifest.trailingSplit(ctx.arena); - try ctx.translate.append(.{ - .name = try caseNameFromPath(ctx.arena, filename), - .c_frontend = c_frontend, - .target = b.resolveTargetQuery(target_query), - .link_libc = link_libc, - .input = src, - .kind = .{ .run = output }, - }); - } - } - continue; - } - var cases = std.array_list.Managed(usize).init(ctx.arena); // Cross-product to get all possible test combinations @@ -484,101 +430,11 @@ fn addFromDirInner( pub fn init(gpa: Allocator, arena: Allocator) Cases { return .{ .gpa = gpa, - .cases = std.array_list.Managed(Case).init(gpa), - .translate = std.array_list.Managed(Translate).init(gpa), + .cases = .init(gpa), .arena = arena, }; } -pub const TranslateCOptions = struct { - skip_translate_c: bool = false, - skip_run_translated_c: bool = false, -}; -pub fn lowerToTranslateCSteps( - self: *Cases, - b: *std.Build, - parent_step: *std.Build.Step, - test_filters: []const []const u8, - test_target_filters: []const []const u8, - target: std.Build.ResolvedTarget, - translate_c_options: TranslateCOptions, -) void { - const tests = @import("../tests.zig"); - const test_translate_c_step = b.step("test-translate-c", "Run the C translation tests"); - if (!translate_c_options.skip_translate_c) { - tests.addTranslateCTests(b, test_translate_c_step, test_filters, test_target_filters); - parent_step.dependOn(test_translate_c_step); - } - - const test_run_translated_c_step = b.step("test-run-translated-c", "Run the Run-Translated-C tests"); - if (!translate_c_options.skip_run_translated_c) { - tests.addRunTranslatedCTests(b, test_run_translated_c_step, test_filters, target); - parent_step.dependOn(test_run_translated_c_step); - } - - for (self.translate.items) |case| switch (case.kind) { - .run => |output| { - if (translate_c_options.skip_run_translated_c) continue; - const annotated_case_name = b.fmt("run-translated-c {s}", .{case.name}); - for (test_filters) |test_filter| { - if (std.mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; - } else if (test_filters.len > 0) continue; - if (!std.process.can_spawn) { - std.debug.print("Unable to spawn child processes on {s}, skipping test.\n", .{@tagName(builtin.os.tag)}); - continue; // Pass test. - } - - const write_src = b.addWriteFiles(); - const file_source = write_src.add("tmp.c", case.input); - - const translate_c = b.addTranslateC(.{ - .root_source_file = file_source, - .optimize = .Debug, - .target = case.target, - .link_libc = case.link_libc, - .use_clang = case.c_frontend == .clang, - }); - translate_c.step.name = b.fmt("{s} translate-c", .{annotated_case_name}); - - const run_exe = b.addExecutable(.{ - .name = "translated_c", - .root_module = translate_c.createModule(), - }); - run_exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name}); - run_exe.root_module.link_libc = true; - const run = b.addRunArtifact(run_exe); - run.step.name = b.fmt("{s} run", .{annotated_case_name}); - run.expectStdOutEqual(output); - run.skip_foreign_checks = true; - - test_run_translated_c_step.dependOn(&run.step); - }, - .translate => |output| { - if (translate_c_options.skip_translate_c) continue; - const annotated_case_name = b.fmt("zig translate-c {s}", .{case.name}); - for (test_filters) |test_filter| { - if (std.mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; - } else if (test_filters.len > 0) continue; - - const write_src = b.addWriteFiles(); - const file_source = write_src.add("tmp.c", case.input); - - const translate_c = b.addTranslateC(.{ - .root_source_file = file_source, - .optimize = .Debug, - .target = case.target, - .link_libc = case.link_libc, - .use_clang = case.c_frontend == .clang, - }); - translate_c.step.name = b.fmt("{s} translate-c", .{annotated_case_name}); - - const check_file = translate_c.addCheckFile(output); - check_file.step.name = b.fmt("{s} CheckFile", .{annotated_case_name}); - test_translate_c_step.dependOn(&check_file.step); - }, - }; -} - pub const CaseTestOptions = struct { test_filters: []const []const u8, test_target_filters: []const []const u8, diff --git a/test/tests.zig b/test/tests.zig index b060ad64e5..bb035747c9 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -7,14 +7,10 @@ const Step = std.Build.Step; // Cases const stack_traces = @import("stack_traces.zig"); -const translate_c = @import("translate_c.zig"); -const run_translated_c = @import("run_translated_c.zig"); const llvm_ir = @import("llvm_ir.zig"); const libc = @import("libc.zig"); // Implementations -pub const TranslateCContext = @import("src/TranslateC.zig"); -pub const RunTranslatedCContext = @import("src/RunTranslatedC.zig"); pub const StackTracesContext = @import("src/StackTrace.zig"); pub const DebuggerContext = @import("src/Debugger.zig"); pub const LlvmIrContext = @import("src/LlvmIr.zig"); @@ -1901,7 +1897,6 @@ pub fn addStandaloneTests( enable_macos_sdk: bool, enable_ios_sdk: bool, enable_symlinks_windows: bool, - skip_translate_c: bool, ) *Step { const step = b.step("test-standalone", "Run the standalone tests"); if (compilerHasPackageManager(b)) { @@ -1914,7 +1909,6 @@ pub fn addStandaloneTests( .simple_skip_release_safe = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseSafe) == null, .simple_skip_release_fast = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseFast) == null, .simple_skip_release_small = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseSmall) == null, - .skip_translate_c = skip_translate_c, }); const test_cases_dep_step = test_cases_dep.builder.default_step; test_cases_dep_step.name = b.dupe(test_cases_dep_name); @@ -2155,42 +2149,6 @@ pub fn addCliTests(b: *std.Build) *Step { return step; } -pub fn addTranslateCTests( - b: *std.Build, - parent_step: *std.Build.Step, - test_filters: []const []const u8, - test_target_filters: []const []const u8, -) void { - const cases = b.allocator.create(TranslateCContext) catch @panic("OOM"); - cases.* = TranslateCContext{ - .b = b, - .step = parent_step, - .test_index = 0, - .test_filters = test_filters, - .test_target_filters = test_target_filters, - }; - - translate_c.addCases(cases); -} - -pub fn addRunTranslatedCTests( - b: *std.Build, - parent_step: *std.Build.Step, - test_filters: []const []const u8, - target: std.Build.ResolvedTarget, -) void { - const cases = b.allocator.create(RunTranslatedCContext) catch @panic("OOM"); - cases.* = .{ - .b = b, - .step = parent_step, - .test_index = 0, - .test_filters = test_filters, - .target = target, - }; - - run_translated_c.addCases(cases); -} - const ModuleTestOptions = struct { test_filters: []const []const u8, test_target_filters: []const []const u8, @@ -2558,9 +2516,7 @@ pub fn addCAbiTests(b: *std.Build, options: CAbiTestOptions) *Step { pub fn addCases( b: *std.Build, parent_step: *Step, - target: std.Build.ResolvedTarget, case_test_options: @import("src/Cases.zig").CaseTestOptions, - translate_c_options: @import("src/Cases.zig").TranslateCOptions, build_options: @import("cases.zig").BuildOptions, ) !void { const arena = b.allocator; @@ -2574,15 +2530,6 @@ pub fn addCases( cases.addFromDir(dir, b); try @import("cases.zig").addCases(&cases, build_options, b); - cases.lowerToTranslateCSteps( - b, - parent_step, - case_test_options.test_filters, - case_test_options.test_target_filters, - target, - translate_c_options, - ); - cases.lowerToBuildSteps( b, parent_step, diff --git a/test/translate_c.zig b/test/translate_c.zig deleted file mode 100644 index 6d1a8916f2..0000000000 --- a/test/translate_c.zig +++ /dev/null @@ -1,3923 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const tests = @import("tests.zig"); - -// ******************************************************** -// * * -// * DO NOT ADD NEW CASES HERE * -// * instead add a file to test/cases/translate_c * -// * * -// ******************************************************** - -pub fn addCases(cases: *tests.TranslateCContext) void { - const default_enum_type = if (builtin.abi == .msvc) "c_int" else "c_uint"; - - cases.add("do while with breaks", - \\void foo(int a) { - \\ do { - \\ if (a) break; - \\ } while (4); - \\ do { - \\ if (a) break; - \\ } while (0); - \\ do { - \\ if (a) break; - \\ } while (a); - \\ do { - \\ break; - \\ } while (3); - \\ do { - \\ break; - \\ } while (0); - \\ do { - \\ break; - \\ } while (a); - \\} - , &[_][]const u8{ - \\pub export fn foo(arg_a: c_int) void { - \\ var a = arg_a; - \\ _ = &a; - \\ while (true) { - \\ if (a != 0) break; - \\ } - \\ while (true) { - \\ if (a != 0) break; - \\ if (!false) break; - \\ } - \\ while (true) { - \\ if (a != 0) break; - \\ if (!(a != 0)) break; - \\ } - \\ while (true) { - \\ break; - \\ } - \\ while (true) { - \\ break; - \\ } - \\ while (true) { - \\ break; - \\ } - \\} - }); - - cases.add("variables check for opaque demotion", - \\struct A { - \\ _Atomic int a; - \\} a; - \\int main(void) { - \\ struct A a; - \\} - , &[_][]const u8{ - \\pub const struct_A = opaque {}; - \\pub const a = @compileError("non-extern variable has opaque type"); - , - \\pub extern fn main() c_int; - }); - - cases.add("unnamed child types of typedef receive typedef's name", - \\typedef enum { - \\ FooA, - \\ FooB, - \\} Foo; - \\typedef struct { - \\ int a, b; - \\} Bar; - , &[_][]const u8{ - \\pub const FooA: c_int = 0; - \\pub const FooB: c_int = 1; - \\pub const Foo = - ++ " " ++ default_enum_type ++ - \\; - \\pub const Bar = extern struct { - \\ a: c_int = @import("std").mem.zeroes(c_int), - \\ b: c_int = @import("std").mem.zeroes(c_int), - \\}; - }); - - cases.add("if as while stmt has semicolon", - \\void foo() { - \\ while (1) if (1) { - \\ int a = 1; - \\ } else { - \\ int b = 2; - \\ } - \\ if (1) if (1) {} - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ while (true) if (true) { - \\ var a: c_int = 1; - \\ _ = &a; - \\ } else { - \\ var b: c_int = 2; - \\ _ = &b; - \\ }; - \\ if (true) if (true) {}; - \\} - }); - - cases.add("conditional operator cast to void", - \\int bar(); - \\void foo() { - \\ int a; - \\ a ? a = 2 : bar(); - \\} - , &[_][]const u8{ - \\pub extern fn bar(...) c_int; - \\pub export fn foo() void { - \\ var a: c_int = undefined; - \\ _ = &a; - \\ if (a != 0) a = 2 else _ = bar(); - \\} - }); - - cases.add("scoped typedef", - \\void foo() { - \\ typedef union { - \\ int A; - \\ int B; - \\ int C; - \\ } Foo; - \\ Foo a = {0}; - \\ { - \\ typedef union { - \\ int A; - \\ int B; - \\ int C; - \\ } Foo; - \\ Foo a = {0}; - \\ } - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ const union_unnamed_1 = extern union { - \\ A: c_int, - \\ B: c_int, - \\ C: c_int, - \\ }; - \\ _ = &union_unnamed_1; - \\ const Foo = union_unnamed_1; - \\ _ = &Foo; - \\ var a: Foo = Foo{ - \\ .A = @as(c_int, 0), - \\ }; - \\ _ = &a; - \\ { - \\ const union_unnamed_2 = extern union { - \\ A: c_int, - \\ B: c_int, - \\ C: c_int, - \\ }; - \\ _ = &union_unnamed_2; - \\ const Foo_1 = union_unnamed_2; - \\ _ = &Foo_1; - \\ var a_2: Foo_1 = Foo_1{ - \\ .A = @as(c_int, 0), - \\ }; - \\ _ = &a_2; - \\ } - \\} - }); - - cases.add("use cast param as macro fn return type", - \\#include - \\#define SYS_BASE_CACHED 0 - \\#define MEM_PHYSICAL_TO_K0(x) (void*)((uint32_t)(x) + SYS_BASE_CACHED) - , &[_][]const u8{ - \\pub inline fn MEM_PHYSICAL_TO_K0(x: anytype) ?*anyopaque { - \\ _ = &x; - \\ return @import("std").zig.c_translation.cast(?*anyopaque, @import("std").zig.c_translation.cast(u32, x) + SYS_BASE_CACHED); - \\} - }); - - cases.add("variadic function demoted to extern", - \\int foo(int bar, ...) { - \\ return 1; - \\} - , &[_][]const u8{ - \\warning: TODO unable to translate variadic function, demoted to extern - \\pub extern fn foo(bar: c_int, ...) c_int; - }); - - cases.add("pointer to opaque demoted struct", - \\typedef struct { - \\ _Atomic int foo; - \\} Foo; - \\ - \\typedef struct { - \\ Foo *bar; - \\} Bar; - , &[_][]const u8{ - \\source.h:1:9: warning: struct demoted to opaque type - unable to translate type of field foo - \\pub const Foo = opaque {}; - \\pub const Bar = extern struct { - \\ bar: ?*Foo = @import("std").mem.zeroes(?*Foo), - \\}; - }); - - cases.add("macro expressions respect C operator precedence", - \\int *foo = 0; - \\#define FOO *((foo) + 2) - \\#define VALUE (1 + 2 * 3 + 4 * 5 + 6 << 7 | 8 == 9) - \\#define _AL_READ3BYTES(p) ((*(unsigned char *)(p)) \ - \\ | (*((unsigned char *)(p) + 1) << 8) \ - \\ | (*((unsigned char *)(p) + 2) << 16)) - , &[_][]const u8{ - \\pub inline fn FOO() @TypeOf((foo + @as(c_int, 2)).*) { - \\ return (foo + @as(c_int, 2)).*; - \\} - , - \\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)); - , - \\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))) { - \\ _ = &p; - \\ 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)); - \\} - }); - - cases.add("static variable in block scope", - \\float bar; - \\int foo() { - \\ _Thread_local static int bar = 2; - \\} - , &[_][]const u8{ - \\pub export var bar: f32 = @import("std").mem.zeroes(f32); - \\pub export fn foo() c_int { - \\ const bar_1 = struct { - \\ threadlocal var static: c_int = 2; - \\ }; - \\ _ = &bar_1; - \\ return 0; - \\} - }); - - cases.add("missing return stmt", - \\int foo() {} - \\int bar() { - \\ int a = 2; - \\} - \\int baz() { - \\ return 0; - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ return 0; - \\} - \\pub export fn bar() c_int { - \\ var a: c_int = 2; - \\ _ = &a; - \\ return 0; - \\} - \\pub export fn baz() c_int { - \\ return 0; - \\} - }); - - cases.add("alignof", - \\void main() { - \\ int a = _Alignof(int); - \\} - , &[_][]const u8{ - \\pub export fn main() void { - \\ var a: c_int = @as(c_int, @bitCast(@as(c_uint, @truncate(@alignOf(c_int))))); - \\ _ = &a; - \\} - }); - - cases.add("initializer list macro", - \\typedef struct Color { - \\ unsigned char r; - \\ unsigned char g; - \\ unsigned char b; - \\ unsigned char a; - \\} Color; - \\#define CLITERAL(type) (type) - \\#define LIGHTGRAY CLITERAL(Color){ 200, 200, 200, 255 } // Light Gray - \\typedef struct boom_t - \\{ - \\ int i1; - \\} boom_t; - \\#define FOO ((boom_t){1}) - \\typedef struct { float x; } MyCStruct; - \\#define A(_x) (MyCStruct) { .x = (_x) } - \\#define B A(0.f) - , &[_][]const u8{ - \\pub const struct_Color = extern struct { - \\ r: u8 = @import("std").mem.zeroes(u8), - \\ g: u8 = @import("std").mem.zeroes(u8), - \\ b: u8 = @import("std").mem.zeroes(u8), - \\ a: u8 = @import("std").mem.zeroes(u8), - \\}; - \\pub const Color = struct_Color; - , - \\pub inline fn CLITERAL(@"type": anytype) @TypeOf(@"type") { - \\ _ = &@"type"; - \\ return @"type"; - \\} - , - \\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) }); - , - \\pub const struct_boom_t = extern struct { - \\ i1: c_int = @import("std").mem.zeroes(c_int), - \\}; - \\pub const boom_t = struct_boom_t; - , - \\pub const FOO = @import("std").mem.zeroInit(boom_t, .{@as(c_int, 1)}); - , - \\pub const MyCStruct = extern struct { - \\ x: f32 = @import("std").mem.zeroes(f32), - \\}; - , - \\pub inline fn A(_x: anytype) MyCStruct { - \\ _ = &_x; - \\ return @import("std").mem.zeroInit(MyCStruct, .{ - \\ .x = _x, - \\ }); - \\} - , - \\pub const B = A(@as(f32, 0)); - }); - - cases.add("complex switch", - \\int main() { - \\ int i = 2; - \\ switch (i) { - \\ case 0: { - \\ case 2:{ - \\ i += 2;} - \\ i += 1; - \\ } - \\ } - \\} - , &[_][]const u8{ // TODO properly translate this - \\source.h:5:13: warning: TODO complex switch - , - \\source.h:1:5: warning: unable to translate function, demoted to extern - \\pub extern fn main() c_int; - }); - - cases.add("correct semicolon after infixop", - \\#define _IO_ERR_SEEN 0 - \\#define __ferror_unlocked_body(_fp) (((_fp)->_flags & _IO_ERR_SEEN) != 0) - , &[_][]const u8{ - \\pub inline fn __ferror_unlocked_body(_fp: anytype) @TypeOf((_fp.*._flags & _IO_ERR_SEEN) != @as(c_int, 0)) { - \\ _ = &_fp; - \\ return (_fp.*._flags & _IO_ERR_SEEN) != @as(c_int, 0); - \\} - }); - - cases.add("c booleans are just ints", - \\#define FOO(x) ((x >= 0) + (x >= 0)) - \\#define BAR 1 && 2 > 4 - , &[_][]const u8{ - \\pub inline fn FOO(x: anytype) @TypeOf(@intFromBool(x >= @as(c_int, 0)) + @intFromBool(x >= @as(c_int, 0))) { - \\ _ = &x; - \\ return @intFromBool(x >= @as(c_int, 0)) + @intFromBool(x >= @as(c_int, 0)); - \\} - , - \\pub const BAR = (@as(c_int, 1) != 0) and (@as(c_int, 2) > @as(c_int, 4)); - }); - - cases.add("struct with flexible array", - \\struct foo { int x; int y[]; }; - \\struct bar { int x; int y[0]; }; - , &[_][]const u8{ - \\pub const struct_foo = extern struct { - \\ x: c_int align(4) = @import("std").mem.zeroes(c_int), - \\ pub fn y(self: anytype) @import("std").zig.c_translation.FlexibleArrayType(@TypeOf(self), c_int) { - \\ const Intermediate = @import("std").zig.c_translation.FlexibleArrayType(@TypeOf(self), u8); - \\ const ReturnType = @import("std").zig.c_translation.FlexibleArrayType(@TypeOf(self), c_int); - \\ return @as(ReturnType, @ptrCast(@alignCast(@as(Intermediate, @ptrCast(self)) + 4))); - \\ } - \\}; - \\pub const struct_bar = extern struct { - \\ x: c_int align(4) = @import("std").mem.zeroes(c_int), - \\ pub fn y(self: anytype) @import("std").zig.c_translation.FlexibleArrayType(@TypeOf(self), c_int) { - \\ const Intermediate = @import("std").zig.c_translation.FlexibleArrayType(@TypeOf(self), u8); - \\ const ReturnType = @import("std").zig.c_translation.FlexibleArrayType(@TypeOf(self), c_int); - \\ return @as(ReturnType, @ptrCast(@alignCast(@as(Intermediate, @ptrCast(self)) + 4))); - \\ } - \\}; - }); - - cases.add("nested loops without blocks", - \\void foo() { - \\ while (0) while (0) {} - \\ for (;;) while (0); - \\ for (;;) do {} while (0); - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ while (false) while (false) {}; - \\ while (true) while (false) {}; - \\ while (true) while (true) { - \\ if (!false) break; - \\ }; - \\} - }); - - cases.add("macro comma operator", - \\#define foo (foo, bar) - \\int baz(int x, int y) { return 0; } - \\#define bar(x) (&x, +3, 4 == 4, 5 * 6, baz(1, 2), 2 % 2, baz(1,2)) - , &[_][]const u8{ - \\pub const foo = blk_1: { - \\ _ = &foo; - \\ break :blk_1 bar; - \\}; - , - \\pub inline fn bar(x: anytype) @TypeOf(baz(@as(c_int, 1), @as(c_int, 2))) { - \\ _ = &x; - \\ return blk_1: { - \\ _ = &x; - \\ _ = @as(c_int, 3); - \\ _ = @as(c_int, 4) == @as(c_int, 4); - \\ _ = @as(c_int, 5) * @as(c_int, 6); - \\ _ = baz(@as(c_int, 1), @as(c_int, 2)); - \\ _ = @import("std").zig.c_translation.MacroArithmetic.rem(@as(c_int, 2), @as(c_int, 2)); - \\ break :blk_1 baz(@as(c_int, 1), @as(c_int, 2)); - \\ }; - \\} - }); - - cases.add("macro keyword define", - \\#define foo 1 - \\#define inline 2 - , &[_][]const u8{ - \\pub const foo = @as(c_int, 1); - , - \\pub const @"inline" = @as(c_int, 2); - }); - - cases.add("macro line continuation", - \\int BAR = 0; - \\#define FOO -\ - \\BAR - , &[_][]const u8{ - \\pub inline fn FOO() @TypeOf(-BAR) { - \\ return -BAR; - \\} - }); - - cases.add("struct with atomic field", - \\struct arcan_shmif_cont { - \\ struct arcan_shmif_page* addr; - \\}; - \\struct arcan_shmif_page { - \\ volatile _Atomic int abufused[12]; - \\}; - , &[_][]const u8{ - \\source.h:4:8: warning: struct demoted to opaque type - unable to translate type of field abufused - \\pub const struct_arcan_shmif_page = opaque {}; - \\pub const struct_arcan_shmif_cont = extern struct { - \\ addr: ?*struct_arcan_shmif_page = @import("std").mem.zeroes(?*struct_arcan_shmif_page), - \\}; - }); - - cases.add("function prototype translated as optional", - \\typedef void (*fnptr_ty)(void); - \\typedef __attribute__((cdecl)) void (*fnptr_attr_ty)(void); - \\struct foo { - \\ __attribute__((cdecl)) void (*foo)(void); - \\ void (*bar)(void); - \\ fnptr_ty baz; - \\ fnptr_attr_ty qux; - \\}; - , &[_][]const u8{ - \\pub const fnptr_ty = ?*const fn () callconv(.c) void; - \\pub const fnptr_attr_ty = ?*const fn () callconv(.c) void; - \\pub const struct_foo = extern struct { - \\ foo: ?*const fn () callconv(.c) void = @import("std").mem.zeroes(?*const fn () callconv(.c) void), - \\ bar: ?*const fn () callconv(.c) void = @import("std").mem.zeroes(?*const fn () callconv(.c) void), - \\ baz: fnptr_ty = @import("std").mem.zeroes(fnptr_ty), - \\ qux: fnptr_attr_ty = @import("std").mem.zeroes(fnptr_attr_ty), - \\}; - }); - - cases.add("array initializer w/ typedef", - \\typedef unsigned char uuid_t[16]; - \\static const uuid_t UUID_NULL __attribute__ ((unused)) = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - , &[_][]const u8{ - \\pub const uuid_t = [16]u8; - \\pub const UUID_NULL: uuid_t = [16]u8{ - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\ 0, - \\}; - }); - - cases.add("#define hex literal with capital X", - \\#define VAL 0XF00D - , &[_][]const u8{ - \\pub const VAL = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xF00D, .hex); - }); - - cases.add("anonymous struct & unions", - \\typedef struct { - \\ union { - \\ char x; - \\ struct { int y; }; - \\ }; - \\} outer; - \\void foo(outer *x) { x->y = x->x; } - , &[_][]const u8{ - \\const struct_unnamed_2 = extern struct { - \\ y: c_int = @import("std").mem.zeroes(c_int), - \\}; - \\const union_unnamed_1 = extern union { - \\ x: u8, - \\ unnamed_0: struct_unnamed_2, - \\}; - \\pub const outer = extern struct { - \\ unnamed_0: union_unnamed_1 = @import("std").mem.zeroes(union_unnamed_1), - \\}; - \\pub export fn foo(arg_x: [*c]outer) void { - \\ var x = arg_x; - \\ _ = &x; - \\ x.*.unnamed_0.unnamed_0.y = @as(c_int, @bitCast(@as(c_uint, x.*.unnamed_0.x))); - \\} - }); - - cases.add("struct initializer - simple", - \\typedef struct { int x; } foo; - \\struct {double x,y,z;} s0 = {1.2, 1.3}; - \\struct {int sec,min,hour,day,mon,year;} s1 = {.day=31,12,2014,.sec=30,15,17}; - \\struct {int x,y;} s2 = {.y = 2, .x=1}; - \\foo s3 = { 123 }; - , &[_][]const u8{ - \\pub const foo = extern struct { - \\ x: c_int = @import("std").mem.zeroes(c_int), - \\}; - \\const struct_unnamed_1 = extern struct { - \\ x: f64 = @import("std").mem.zeroes(f64), - \\ y: f64 = @import("std").mem.zeroes(f64), - \\ z: f64 = @import("std").mem.zeroes(f64), - \\}; - \\pub export var s0: struct_unnamed_1 = struct_unnamed_1{ - \\ .x = 1.2, - \\ .y = 1.3, - \\ .z = 0, - \\}; - \\const struct_unnamed_2 = extern struct { - \\ sec: c_int = @import("std").mem.zeroes(c_int), - \\ min: c_int = @import("std").mem.zeroes(c_int), - \\ hour: c_int = @import("std").mem.zeroes(c_int), - \\ day: c_int = @import("std").mem.zeroes(c_int), - \\ mon: c_int = @import("std").mem.zeroes(c_int), - \\ year: c_int = @import("std").mem.zeroes(c_int), - \\}; - \\pub export var s1: struct_unnamed_2 = struct_unnamed_2{ - \\ .sec = @as(c_int, 30), - \\ .min = @as(c_int, 15), - \\ .hour = @as(c_int, 17), - \\ .day = @as(c_int, 31), - \\ .mon = @as(c_int, 12), - \\ .year = @as(c_int, 2014), - \\}; - \\const struct_unnamed_3 = extern struct { - \\ x: c_int = @import("std").mem.zeroes(c_int), - \\ y: c_int = @import("std").mem.zeroes(c_int), - \\}; - \\pub export var s2: struct_unnamed_3 = struct_unnamed_3{ - \\ .x = @as(c_int, 1), - \\ .y = @as(c_int, 2), - \\}; - \\pub export var s3: foo = foo{ - \\ .x = @as(c_int, 123), - \\}; - }); - - cases.add("simple ptrCast for casts between opaque types", - \\struct opaque; - \\struct opaque_2; - \\void function(struct opaque *opaque) { - \\ struct opaque_2 *cast = (struct opaque_2 *)opaque; - \\} - , &[_][]const u8{ - \\pub const struct_opaque = opaque {}; - \\pub const struct_opaque_2 = opaque {}; - \\pub export fn function(arg_opaque_1: ?*struct_opaque) void { - \\ var opaque_1 = arg_opaque_1; - \\ _ = &opaque_1; - \\ var cast: ?*struct_opaque_2 = @as(?*struct_opaque_2, @ptrCast(opaque_1)); - \\ _ = &cast; - \\} - }); - - cases.add("struct initializer - packed", - \\struct {int x,y,z;} __attribute__((packed)) s0 = {1, 2}; - , &[_][]const u8{ - \\const struct_unnamed_1 = extern struct { - \\ x: c_int align(1) = @import("std").mem.zeroes(c_int), - \\ y: c_int align(1) = @import("std").mem.zeroes(c_int), - \\ z: c_int align(1) = @import("std").mem.zeroes(c_int), - \\}; - \\pub export var s0: struct_unnamed_1 = struct_unnamed_1{ - \\ .x = @as(c_int, 1), - \\ .y = @as(c_int, 2), - \\ .z = 0, - \\}; - }); - - cases.add("linksection() attribute", - \\// Use the "segment,section" format to make this test pass when - \\// targeting the mach-o binary format - \\__attribute__ ((__section__("NEAR,.data"))) - \\extern char my_array[16]; - \\__attribute__ ((__section__("NEAR,.data"))) - \\void my_fn(void) { } - , &[_][]const u8{ - \\pub extern var my_array: [16]u8 linksection("NEAR,.data"); - \\pub export fn my_fn() linksection("NEAR,.data") void {} - }); - - cases.add("simple var decls", - \\void foo(void) { - \\ int a; - \\ char b = 123; - \\ const int c; - \\ const unsigned d = 440; - \\ int e = 10; - \\ unsigned int f = 10u; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: c_int = undefined; - \\ _ = &a; - \\ var b: u8 = 123; - \\ _ = &b; - \\ const c: c_int = undefined; - \\ _ = &c; - \\ const d: c_uint = @as(c_uint, @bitCast(@as(c_int, 440))); - \\ _ = &d; - \\ var e: c_int = 10; - \\ _ = &e; - \\ var f: c_uint = 10; - \\ _ = &f; - \\} - }); - - cases.add("ignore result, explicit function arguments", - \\void foo(void) { - \\ int a; - \\ 1; - \\ "hey"; - \\ 1 + 1; - \\ 1 - 1; - \\ a = 1; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: c_int = undefined; - \\ _ = &a; - \\ _ = @as(c_int, 1); - \\ _ = "hey"; - \\ _ = @as(c_int, 1) + @as(c_int, 1); - \\ _ = @as(c_int, 1) - @as(c_int, 1); - \\ a = 1; - \\} - }); - - cases.add("function with no prototype", - \\int foo() { - \\ return 5; - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ return 5; - \\} - }); - - cases.add("variables", - \\extern int extern_var; - \\static const int int_var = 13; - \\int foo; - , &[_][]const u8{ - \\pub extern var extern_var: c_int; - \\pub const int_var: c_int = 13; - \\pub export var foo: c_int = @import("std").mem.zeroes(c_int); - }); - - cases.add("const ptr initializer", - \\static const char *v0 = "0.0.0"; - , &[_][]const u8{ - \\pub var v0: [*c]const u8 = "0.0.0"; - }); - - cases.add("static incomplete array inside function", - \\void foo(void) { - \\ static const char v2[] = "2.2.2"; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ const v2 = struct { - \\ const static: [5:0]u8 = "2.2.2".*; - \\ }; - \\ _ = &v2; - \\} - }); - - cases.add("simple function definition", - \\void foo(void) {} - \\static void bar(void) {} - , &[_][]const u8{ - \\pub export fn foo() void {} - \\pub fn bar() callconv(.c) void {} - }); - - cases.add("typedef void", - \\typedef void Foo; - \\Foo fun(Foo *a); - , &[_][]const u8{ - \\pub const Foo = anyopaque; - , - \\pub extern fn fun(a: ?*Foo) void; - }); - - cases.add("duplicate typedef", - \\typedef long foo; - \\typedef int bar; - \\typedef long foo; - \\typedef int baz; - , &[_][]const u8{ - \\pub const foo = c_long; - \\pub const bar = c_int; - \\pub const baz = c_int; - }); - - cases.add("casting pointers to ints and ints to pointers", - \\void foo(void); - \\void bar(void) { - \\ void *func_ptr = foo; - \\ void (*typed_func_ptr)(void) = (void (*)(void)) (unsigned long) func_ptr; - \\} - , &[_][]const u8{ - \\pub extern fn foo() void; - \\pub export fn bar() void { - \\ var func_ptr: ?*anyopaque = @as(?*anyopaque, @ptrCast(&foo)); - \\ _ = &func_ptr; - \\ var typed_func_ptr: ?*const fn () callconv(.c) void = @as(?*const fn () callconv(.c) void, @ptrFromInt(@as(c_ulong, @intCast(@intFromPtr(func_ptr))))); - \\ _ = &typed_func_ptr; - \\} - }); - - cases.add("always_inline attribute", - \\__attribute__((always_inline)) int foo() { - \\ return 5; - \\} - , &[_][]const u8{ - \\pub inline fn foo() c_int { - \\ return 5; - \\} - }); - - cases.add("add, sub, mul, div, rem", - \\int s() { - \\ int a, b, c; - \\ c = a + b; - \\ c = a - b; - \\ c = a * b; - \\ c = a / b; - \\ c = a % b; - \\} - \\unsigned u() { - \\ unsigned a, b, c; - \\ c = a + b; - \\ c = a - b; - \\ c = a * b; - \\ c = a / b; - \\ c = a % b; - \\} - , &[_][]const u8{ - \\pub export fn s() c_int { - \\ var a: c_int = undefined; - \\ _ = &a; - \\ var b: c_int = undefined; - \\ _ = &b; - \\ var c: c_int = undefined; - \\ _ = &c; - \\ c = a + b; - \\ c = a - b; - \\ c = a * b; - \\ c = @divTrunc(a, b); - \\ c = @import("std").zig.c_translation.signedRemainder(a, b); - \\ return 0; - \\} - \\pub export fn u() c_uint { - \\ var a: c_uint = undefined; - \\ _ = &a; - \\ var b: c_uint = undefined; - \\ _ = &b; - \\ var c: c_uint = undefined; - \\ _ = &c; - \\ c = a +% b; - \\ c = a -% b; - \\ c = a *% b; - \\ c = a / b; - \\ c = a % b; - \\ return 0; - \\} - }); - - cases.add("typedef of function in struct field", - \\typedef void lws_callback_function(void); - \\struct Foo { - \\ void (*func)(void); - \\ lws_callback_function *callback_http; - \\}; - , &[_][]const u8{ - \\pub const lws_callback_function = fn () callconv(.c) void; - \\pub const struct_Foo = extern struct { - \\ func: ?*const fn () callconv(.c) void = @import("std").mem.zeroes(?*const fn () callconv(.c) void), - \\ callback_http: ?*const lws_callback_function = @import("std").mem.zeroes(?*const lws_callback_function), - \\}; - }); - - cases.add("macro with left shift", - \\#define REDISMODULE_READ (1<<0) - , &[_][]const u8{ - \\pub const REDISMODULE_READ = @as(c_int, 1) << @as(c_int, 0); - }); - - cases.add("macro with right shift", - \\#define FLASH_SIZE 0x200000UL /* 2 MB */ - \\#define FLASH_BANK_SIZE (FLASH_SIZE >> 1) /* 1 MB */ - , &[_][]const u8{ - \\pub const FLASH_SIZE = @as(c_ulong, 0x200000); - , - \\pub const FLASH_BANK_SIZE = FLASH_SIZE >> @as(c_int, 1); - }); - - cases.add("self referential struct with function pointer", - \\struct Foo { - \\ void (*derp)(struct Foo *foo); - \\}; - , &[_][]const u8{ - \\pub const struct_Foo = extern struct { - \\ derp: ?*const fn ([*c]struct_Foo) callconv(.c) void = @import("std").mem.zeroes(?*const fn ([*c]struct_Foo) callconv(.c) void), - \\}; - , - \\pub const Foo = struct_Foo; - }); - - cases.add("#define an unsigned integer literal", - \\#define CHANNEL_COUNT 24 - , &[_][]const u8{ - \\pub const CHANNEL_COUNT = @as(c_int, 24); - }); - - cases.add("#define referencing another #define", - \\#define THING2 THING1 - \\#define THING1 1234 - , &[_][]const u8{ - \\pub const THING1 = @as(c_int, 1234); - , - \\pub const THING2 = THING1; - }); - - cases.add("#define string", - \\#define foo "a string" - , &[_][]const u8{ - \\pub const foo = "a string"; - }); - - cases.add("macro with parens around negative number", - \\#define LUA_GLOBALSINDEX (-10002) - , &[_][]const u8{ - \\pub const LUA_GLOBALSINDEX = -@as(c_int, 10002); - }); - - cases.add( - "u integer suffix after 0 (zero) in macro definition", - "#define ZERO 0U", - &[_][]const u8{ - "pub const ZERO = @as(c_uint, 0);", - }, - ); - - cases.add( - "l integer suffix after 0 (zero) in macro definition", - "#define ZERO 0L", - &[_][]const u8{ - "pub const ZERO = @as(c_long, 0);", - }, - ); - - cases.add( - "ul integer suffix after 0 (zero) in macro definition", - "#define ZERO 0UL", - &[_][]const u8{ - "pub const ZERO = @as(c_ulong, 0);", - }, - ); - - cases.add( - "lu integer suffix after 0 (zero) in macro definition", - "#define ZERO 0LU", - &[_][]const u8{ - "pub const ZERO = @as(c_ulong, 0);", - }, - ); - - cases.add( - "ll integer suffix after 0 (zero) in macro definition", - "#define ZERO 0LL", - &[_][]const u8{ - "pub const ZERO = @as(c_longlong, 0);", - }, - ); - - cases.add( - "ull integer suffix after 0 (zero) in macro definition", - "#define ZERO 0ULL", - &[_][]const u8{ - "pub const ZERO = @as(c_ulonglong, 0);", - }, - ); - - cases.add( - "llu integer suffix after 0 (zero) in macro definition", - "#define ZERO 0LLU", - &[_][]const u8{ - "pub const ZERO = @as(c_ulonglong, 0);", - }, - ); - - cases.add( - "bitwise not on u-suffixed 0 (zero) in macro definition", - "#define NOT_ZERO (~0U)", - &[_][]const u8{ - "pub const NOT_ZERO = ~@as(c_uint, 0);", - }, - ); - - cases.add("float suffixes", - \\#define foo 3.14f - \\#define bar 16.e-2l - \\#define FOO 0.12345 - \\#define BAR .12345 - \\#define baz 1e1 - \\#define BAZ 42e-3f - \\#define foobar -73.L - \\extern const float my_float = 1.0f; - \\extern const double my_double = 1.0; - \\extern const long double my_longdouble = 1.0l; - \\extern const long double my_extended_precision_longdouble = 1.0000000000000003l; - , &([_][]const u8{ - "pub const foo = @as(f32, 3.14);", - "pub const bar = @as(c_longdouble, 16.e-2);", - "pub const FOO = @as(f64, 0.12345);", - "pub const BAR = @as(f64, 0.12345);", - "pub const baz = @as(f64, 1e1);", - "pub const BAZ = @as(f32, 42e-3);", - "pub const foobar = -@as(c_longdouble, 73);", - "pub export const my_float: f32 = 1.0;", - "pub export const my_double: f64 = 1.0;", - "pub export const my_longdouble: c_longdouble = 1.0;", - switch (@bitSizeOf(c_longdouble)) { - // TODO implement decimal format for f128 - // (so that f80/f128 values not exactly representable as f64 can be emitted in decimal form) - 80 => "pub export const my_extended_precision_longdouble: c_longdouble = 0x1.000000000000159ep0;", - 128 => "pub export const my_extended_precision_longdouble: c_longdouble = 0x1.000000000000159e05f1e2674d21p0;", - else => "pub export const my_extended_precision_longdouble: c_longdouble = 1.0000000000000002;", - }, - })); - - cases.add("macro defines hexadecimal float", - \\#define FOO 0xf7p38 - \\#define BAR -0X8F.BP5F - \\#define FOOBAR 0X0P+0 - \\#define BAZ -0x.0a5dp+12 - \\#define FOOBAZ 0xfE.P-1l - , &[_][]const u8{ - "pub const FOO = @as(f64, 0xf7p38);", - "pub const BAR = -@as(f32, 0x8F.BP5);", - "pub const FOOBAR = @as(f64, 0x0P+0);", - "pub const BAZ = -@as(f64, 0x0.0a5dp+12);", - "pub const FOOBAZ = @as(c_longdouble, 0xfE.P-1);", - }); - - cases.add("comments", - \\#define foo 1 //foo - \\#define bar /* bar */ 2 - , &[_][]const u8{ - "pub const foo = @as(c_int, 1);", - "pub const bar = @as(c_int, 2);", - }); - - cases.add("string prefix", - \\#define foo L"hello" - , &[_][]const u8{ - "pub const foo = \"hello\";", - }); - - cases.add("null statements", - \\void foo(void) { - \\ ;;;;; - \\} - , &[_][]const u8{ - \\pub export fn foo() void {} - }); - - if (builtin.os.tag != .windows) { - // Windows treats this as an enum with type c_int - cases.add("big negative enum init values when C ABI supports long long enums", - \\enum EnumWithInits { - \\ VAL01 = 0, - \\ VAL02 = 1, - \\ VAL03 = 2, - \\ VAL04 = 3, - \\ VAL05 = -1, - \\ VAL06 = -2, - \\ VAL07 = -3, - \\ VAL08 = -4, - \\ VAL09 = VAL02 + VAL08, - \\ VAL10 = -1000012000, - \\ VAL11 = -1000161000, - \\ VAL12 = -1000174001, - \\ VAL13 = VAL09, - \\ VAL14 = VAL10, - \\ VAL15 = VAL11, - \\ VAL16 = VAL13, - \\ VAL17 = (VAL16 - VAL10 + 1), - \\ VAL18 = 0x1000000000000000L, - \\ VAL19 = VAL18 + VAL18 + VAL18 - 1, - \\ VAL20 = VAL19 + VAL19, - \\ VAL21 = VAL20 + 0xFFFFFFFFFFFFFFFF, - \\ VAL22 = 0xFFFFFFFFFFFFFFFF + 1, - \\ VAL23 = 0xFFFFFFFFFFFFFFFF, - \\}; - , &[_][]const u8{ - \\pub const VAL01: c_longlong = 0; - \\pub const VAL02: c_longlong = 1; - \\pub const VAL03: c_longlong = 2; - \\pub const VAL04: c_longlong = 3; - \\pub const VAL05: c_longlong = -1; - \\pub const VAL06: c_longlong = -2; - \\pub const VAL07: c_longlong = -3; - \\pub const VAL08: c_longlong = -4; - \\pub const VAL09: c_longlong = -3; - \\pub const VAL10: c_longlong = -1000012000; - \\pub const VAL11: c_longlong = -1000161000; - \\pub const VAL12: c_longlong = -1000174001; - \\pub const VAL13: c_longlong = -3; - \\pub const VAL14: c_longlong = -1000012000; - \\pub const VAL15: c_longlong = -1000161000; - \\pub const VAL16: c_longlong = -3; - \\pub const VAL17: c_longlong = 1000011998; - \\pub const VAL18: c_longlong = 1152921504606846976; - \\pub const VAL19: c_longlong = 3458764513820540927; - \\pub const VAL20: c_longlong = 6917529027641081854; - \\pub const VAL21: c_longlong = 6917529027641081853; - \\pub const VAL22: c_longlong = 0; - \\pub const VAL23: c_longlong = -1; - \\pub const enum_EnumWithInits = c_longlong; - }); - } - - cases.add("predefined expressions", - \\void foo(void) { - \\ __func__; - \\ __FUNCTION__; - \\ __PRETTY_FUNCTION__; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ _ = "foo"; - \\ _ = "foo"; - \\ _ = "void foo(void)"; - \\} - }); - - cases.add("constant size array", - \\void func(int array[20]); - , &[_][]const u8{ - \\pub extern fn func(array: [*c]c_int) void; - }); - - cases.add("__cdecl doesn't mess up function pointers", - \\void foo(void (__cdecl *fn_ptr)(void)); - , &[_][]const u8{ - \\pub extern fn foo(fn_ptr: ?*const fn () callconv(.c) void) void; - }); - - cases.add("void cast", - \\void foo() { - \\ int a; - \\ (void) a; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: c_int = undefined; - \\ _ = &a; - \\ _ = &a; - \\} - }); - - cases.add("implicit cast to void *", - \\void *foo() { - \\ unsigned short *x; - \\ return x; - \\} - , &[_][]const u8{ - \\pub export fn foo() ?*anyopaque { - \\ var x: [*c]c_ushort = undefined; - \\ _ = &x; - \\ return @as(?*anyopaque, @ptrCast(x)); - \\} - }); - - cases.add("null pointer implicit cast", - \\int* foo(void) { - \\ return 0; - \\} - , &[_][]const u8{ - \\pub export fn foo() [*c]c_int { - \\ return null; - \\} - }); - - cases.add("string literal", - \\const char *foo(void) { - \\ return "bar"; - \\} - , &[_][]const u8{ - \\pub export fn foo() [*c]const u8 { - \\ return "bar"; - \\} - }); - - cases.add("return void", - \\void foo(void) { - \\ return; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ return; - \\} - }); - - cases.add("for loop", - \\void foo(void) { - \\ for (int i = 0; i; i++) { } - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ { - \\ var i: c_int = 0; - \\ _ = &i; - \\ while (i != 0) : (i += 1) {} - \\ } - \\} - }); - - cases.add("empty for loop", - \\void foo(void) { - \\ for (;;) { } - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ while (true) {} - \\} - }); - - cases.add("for loop with simple init expression", - \\void foo(void) { - \\ int i; - \\ for (i = 3; i; i--) { } - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var i: c_int = undefined; - \\ _ = &i; - \\ { - \\ i = 3; - \\ while (i != 0) : (i -= 1) {} - \\ } - \\} - }); - - cases.add("break statement", - \\void foo(void) { - \\ for (;;) { - \\ break; - \\ } - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ while (true) { - \\ break; - \\ } - \\} - }); - - cases.add("continue statement", - \\void foo(void) { - \\ for (;;) { - \\ continue; - \\ } - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ while (true) { - \\ continue; - \\ } - \\} - }); - - cases.add("pointer casting", - \\float *ptrcast() { - \\ int *a; - \\ return (float *)a; - \\} - , &[_][]const u8{ - \\pub export fn ptrcast() [*c]f32 { - \\ var a: [*c]c_int = undefined; - \\ _ = &a; - \\ return @as([*c]f32, @ptrCast(@alignCast(a))); - \\} - }); - - cases.add("casting pointer to pointer", - \\float **ptrptrcast() { - \\ int **a; - \\ return (float **)a; - \\} - , &[_][]const u8{ - \\pub export fn ptrptrcast() [*c][*c]f32 { - \\ var a: [*c][*c]c_int = undefined; - \\ _ = &a; - \\ return @as([*c][*c]f32, @ptrCast(@alignCast(a))); - \\} - }); - - cases.add("pointer conversion with different alignment", - \\void test_ptr_cast() { - \\ void *p; - \\ { - \\ char *to_char = (char *)p; - \\ short *to_short = (short *)p; - \\ int *to_int = (int *)p; - \\ long long *to_longlong = (long long *)p; - \\ } - \\ { - \\ char *to_char = p; - \\ short *to_short = p; - \\ int *to_int = p; - \\ long long *to_longlong = p; - \\ } - \\} - , &[_][]const u8{ - \\pub export fn test_ptr_cast() void { - \\ var p: ?*anyopaque = undefined; - \\ _ = &p; - \\ { - \\ var to_char: [*c]u8 = @as([*c]u8, @ptrCast(@alignCast(p))); - \\ _ = &to_char; - \\ var to_short: [*c]c_short = @as([*c]c_short, @ptrCast(@alignCast(p))); - \\ _ = &to_short; - \\ var to_int: [*c]c_int = @as([*c]c_int, @ptrCast(@alignCast(p))); - \\ _ = &to_int; - \\ var to_longlong: [*c]c_longlong = @as([*c]c_longlong, @ptrCast(@alignCast(p))); - \\ _ = &to_longlong; - \\ } - \\ { - \\ var to_char: [*c]u8 = @as([*c]u8, @ptrCast(@alignCast(p))); - \\ _ = &to_char; - \\ var to_short: [*c]c_short = @as([*c]c_short, @ptrCast(@alignCast(p))); - \\ _ = &to_short; - \\ var to_int: [*c]c_int = @as([*c]c_int, @ptrCast(@alignCast(p))); - \\ _ = &to_int; - \\ var to_longlong: [*c]c_longlong = @as([*c]c_longlong, @ptrCast(@alignCast(p))); - \\ _ = &to_longlong; - \\ } - \\} - }); - - cases.add("while on non-bool", - \\int while_none_bool() { - \\ int a; - \\ float b; - \\ void *c; - \\ while (a) return 0; - \\ while (b) return 1; - \\ while (c) return 2; - \\ return 3; - \\} - , &[_][]const u8{ - \\pub export fn while_none_bool() c_int { - \\ var a: c_int = undefined; - \\ _ = &a; - \\ var b: f32 = undefined; - \\ _ = &b; - \\ var c: ?*anyopaque = undefined; - \\ _ = &c; - \\ while (a != 0) return 0; - \\ while (b != 0) return 1; - \\ while (c != null) return 2; - \\ return 3; - \\} - }); - - cases.add("for on non-bool", - \\int for_none_bool() { - \\ int a; - \\ float b; - \\ void *c; - \\ for (;a;) return 0; - \\ for (;b;) return 1; - \\ for (;c;) return 2; - \\ return 3; - \\} - , &[_][]const u8{ - \\pub export fn for_none_bool() c_int { - \\ var a: c_int = undefined; - \\ _ = &a; - \\ var b: f32 = undefined; - \\ _ = &b; - \\ var c: ?*anyopaque = undefined; - \\ _ = &c; - \\ while (a != 0) return 0; - \\ while (b != 0) return 1; - \\ while (c != null) return 2; - \\ return 3; - \\} - }); - - cases.add("bitshift", - \\int foo(void) { - \\ return (1 << 2) >> 1; - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ return (@as(c_int, 1) << @intCast(2)) >> @intCast(1); - \\} - }); - - cases.add("sizeof", - \\#include - \\size_t size_of(void) { - \\ return sizeof(int); - \\} - , &[_][]const u8{ - \\pub export fn size_of() usize { - \\ return @sizeOf(c_int); - \\} - }); - - cases.add("normal deref", - \\void foo() { - \\ int *x; - \\ *x = 1; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var x: [*c]c_int = undefined; - \\ _ = &x; - \\ x.* = 1; - \\} - }); - - cases.add("address of operator", - \\int foo(void) { - \\ int x = 1234; - \\ int *ptr = &x; - \\ return *ptr; - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ var x: c_int = 1234; - \\ _ = &x; - \\ var ptr: [*c]c_int = &x; - \\ _ = &ptr; - \\ return ptr.*; - \\} - }); - - cases.add("bin not", - \\int foo() { - \\ int x; - \\ return ~x; - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ var x: c_int = undefined; - \\ _ = &x; - \\ return ~x; - \\} - }); - - cases.add("bool not", - \\int foo() { - \\ int a; - \\ float b; - \\ void *c; - \\ return !(a == 0); - \\ return !a; - \\ return !b; - \\ return !c; - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ var a: c_int = undefined; - \\ _ = &a; - \\ var b: f32 = undefined; - \\ _ = &b; - \\ var c: ?*anyopaque = undefined; - \\ _ = &c; - \\ return @intFromBool(!(a == @as(c_int, 0))); - \\ return @intFromBool(!(a != 0)); - \\ return @intFromBool(!(b != 0)); - \\ return @intFromBool(!(c != null)); - \\} - }); - - cases.add("__extension__ cast", - \\int foo(void) { - \\ return __extension__ 1; - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ return 1; - \\} - }); - - if (builtin.os.tag != .windows) { - // sysv_abi not currently supported on windows - cases.add("Macro qualified functions", - \\void __attribute__((sysv_abi)) foo(void); - , &[_][]const u8{ - \\pub extern fn foo() void; - }); - } - - cases.add("Forward-declared enum", - \\extern enum enum_ty my_enum; - \\enum enum_ty { FOO }; - , &[_][]const u8{ - \\pub const FOO: c_int = 0; - \\pub const enum_enum_ty = c_int; - \\pub extern var my_enum: enum_enum_ty; - }); - - cases.add("Parameterless function pointers", - \\typedef void (*fn0)(); - \\typedef void (*fn1)(char); - , &[_][]const u8{ - \\pub const fn0 = ?*const fn (...) callconv(.c) void; - \\pub const fn1 = ?*const fn (u8) callconv(.c) void; - }); - - cases.addWithTarget("Calling convention", .{ - .cpu_arch = .x86, - .os_tag = .linux, - .abi = .none, - }, - \\void __attribute__((fastcall)) foo1(float *a); - \\void __attribute__((stdcall)) foo2(float *a); - \\void __attribute__((vectorcall)) foo3(float *a); - \\void __attribute__((cdecl)) foo4(float *a); - \\void __attribute__((thiscall)) foo5(float *a); - , &[_][]const u8{ - \\pub extern fn foo1(a: [*c]f32) callconv(.{ .x86_fastcall = .{} }) void; - \\pub extern fn foo2(a: [*c]f32) callconv(.{ .x86_stdcall = .{} }) void; - \\pub extern fn foo3(a: [*c]f32) callconv(.{ .x86_vectorcall = .{} }) void; - \\pub extern fn foo4(a: [*c]f32) void; - \\pub extern fn foo5(a: [*c]f32) callconv(.{ .x86_thiscall = .{} }) void; - }); - - cases.addWithTarget("Calling convention", std.Target.Query.parse(.{ - .arch_os_abi = "arm-linux-none", - .cpu_features = "generic+v8_5a", - }) catch unreachable, - \\void __attribute__((pcs("aapcs"))) foo1(float *a); - \\void __attribute__((pcs("aapcs-vfp"))) foo2(float *a); - , &[_][]const u8{ - \\pub extern fn foo1(a: [*c]f32) callconv(.{ .arm_aapcs = .{} }) void; - \\pub extern fn foo2(a: [*c]f32) callconv(.{ .arm_aapcs_vfp = .{} }) void; - }); - - cases.addWithTarget("Calling convention", std.Target.Query.parse(.{ - .arch_os_abi = "aarch64-linux-none", - .cpu_features = "generic+v8_5a", - }) catch unreachable, - \\void __attribute__((aarch64_vector_pcs)) foo1(float *a); - , &[_][]const u8{ - \\pub extern fn foo1(a: [*c]f32) callconv(.{ .aarch64_vfabi = .{} }) void; - }); - - cases.add("Parameterless function prototypes", - \\void a() {} - \\void b(void) {} - \\void c(); - \\void d(void); - \\static void e() {} - \\static void f(void) {} - \\static void g(); - \\static void h(void); - , &[_][]const u8{ - \\pub export fn a() void {} - \\pub export fn b() void {} - \\pub extern fn c(...) void; - \\pub extern fn d() void; - \\pub fn e() callconv(.c) void {} - \\pub fn f() callconv(.c) void {} - \\pub extern fn g() void; - \\pub extern fn h() void; - }); - - cases.add("variable declarations", - \\extern char arr0[] = "hello"; - \\static char arr1[] = "hello"; - \\char arr2[] = "hello"; - , &[_][]const u8{ - \\pub export var arr0: [5:0]u8 = "hello".*; - \\pub var arr1: [5:0]u8 = "hello".*; - \\pub export var arr2: [5:0]u8 = "hello".*; - }); - - cases.add("array initializer expr", - \\static void foo(void){ - \\ char arr[10] ={1}; - \\ char *arr1[10] ={0}; - \\} - , &[_][]const u8{ - \\pub fn foo() callconv(.c) void { - \\ var arr: [10]u8 = [1]u8{ - \\ 1, - \\ } ++ [1]u8{0} ** 9; - \\ _ = &arr; - \\ var arr1: [10][*c]u8 = [1][*c]u8{ - \\ null, - \\ } ++ [1][*c]u8{null} ** 9; - \\ _ = &arr1; - \\} - }); - - cases.add("enums", - \\typedef enum { - \\ a, - \\ b, - \\ c, - \\} d; - \\enum { - \\ e, - \\ f = 4, - \\ g, - \\} h = e; - \\struct Baz { - \\ enum { - \\ i, - \\ j, - \\ k, - \\ } l; - \\ d m; - \\}; - \\enum i { - \\ n, - \\ o, - \\ p, - \\}; - , &[_][]const u8{ - \\pub const a: c_int = 0; - \\pub const b: c_int = 1; - \\pub const c: c_int = 2; - \\pub const d = - ++ " " ++ default_enum_type ++ - \\; - \\pub const e: c_int = 0; - \\pub const f: c_int = 4; - \\pub const g: c_int = 5; - \\const enum_unnamed_1 = - ++ " " ++ default_enum_type ++ - \\; - \\pub export var h: enum_unnamed_1 = @as(c_uint, @bitCast(e)); - \\pub const i: c_int = 0; - \\pub const j: c_int = 1; - \\pub const k: c_int = 2; - \\const enum_unnamed_2 = - ++ " " ++ default_enum_type ++ - \\; - \\pub const struct_Baz = extern struct { - \\ l: enum_unnamed_2 = @import("std").mem.zeroes(enum_unnamed_2), - \\ m: d = @import("std").mem.zeroes(d), - \\}; - \\pub const n: c_int = 0; - \\pub const o: c_int = 1; - \\pub const p: c_int = 2; - \\pub const enum_i = - ++ " " ++ default_enum_type ++ - \\; - , - "pub const Baz = struct_Baz;", - }); - - cases.add("#define a char literal", - \\#define A_CHAR 'a' - , &[_][]const u8{ - \\pub const A_CHAR = 'a'; - }); - - cases.add("comment after integer literal", - \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_int, 0x00000020); - }); - - cases.add("u integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_uint, 0x00000020); - }); - - cases.add("l integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_long, 0x00000020); - }); - - cases.add("ul integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020); - }); - - cases.add("lu integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020); - }); - - cases.add("ll integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_longlong, 0x00000020); - }); - - cases.add("ull integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); - }); - - cases.add("llu integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); - }); - - cases.add("generate inline func for #define global extern fn", - \\extern void (*fn_ptr)(void); - \\#define foo fn_ptr - \\ - \\extern char (*fn_ptr2)(int, float); - \\#define bar fn_ptr2 - , &[_][]const u8{ - \\pub extern var fn_ptr: ?*const fn () callconv(.c) void; - , - \\pub inline fn foo() void { - \\ return fn_ptr.?(); - \\} - , - \\pub extern var fn_ptr2: ?*const fn (c_int, f32) callconv(.c) u8; - , - \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 { - \\ return fn_ptr2.?(arg_1, arg_2); - \\} - }); - - cases.add("macros with field targets", - \\typedef unsigned int GLbitfield; - \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); - \\typedef void(*OpenGLProc)(void); - \\union OpenGLProcs { - \\ OpenGLProc ptr[1]; - \\ struct { - \\ PFNGLCLEARPROC Clear; - \\ } gl; - \\}; - \\extern union OpenGLProcs glProcs; - \\#define glClearUnion glProcs.gl.Clear - \\#define glClearPFN PFNGLCLEARPROC - , &[_][]const u8{ - \\pub const GLbitfield = c_uint; - \\pub const PFNGLCLEARPROC = ?*const fn (GLbitfield) callconv(.c) void; - \\pub const OpenGLProc = ?*const fn () callconv(.c) void; - \\const struct_unnamed_1 = extern struct { - \\ Clear: PFNGLCLEARPROC = @import("std").mem.zeroes(PFNGLCLEARPROC), - \\}; - \\pub const union_OpenGLProcs = extern union { - \\ ptr: [1]OpenGLProc, - \\ gl: struct_unnamed_1, - \\}; - \\pub extern var glProcs: union_OpenGLProcs; - , - \\pub const glClearPFN = PFNGLCLEARPROC; - , - \\pub inline fn glClearUnion(arg_2: GLbitfield) void { - \\ return glProcs.gl.Clear.?(arg_2); - \\} - , - \\pub const OpenGLProcs = union_OpenGLProcs; - }); - - cases.add("macro pointer cast", - \\#define NRF_GPIO_BASE 0 - \\typedef struct { int dummy; } NRF_GPIO_Type; - \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) - , &[_][]const u8{ - \\pub const NRF_GPIO = @import("std").zig.c_translation.cast([*c]NRF_GPIO_Type, NRF_GPIO_BASE); - }); - - cases.add("basic macro function", - \\extern int c; - \\#define BASIC(c) (c*2) - \\#define FOO(L,b) (L + b) - \\#define BAR() (c*c) - , &[_][]const u8{ - \\pub extern var c: c_int; - , - \\pub inline fn BASIC(c_1: anytype) @TypeOf(c_1 * @as(c_int, 2)) { - \\ _ = &c_1; - \\ return c_1 * @as(c_int, 2); - \\} - , - \\pub inline fn FOO(L: anytype, b: anytype) @TypeOf(L + b) { - \\ _ = &L; - \\ _ = &b; - \\ return L + b; - \\} - , - \\pub inline fn BAR() @TypeOf(c * c) { - \\ return c * c; - \\} - }); - - cases.add("macro defines string literal with hex", - \\#define FOO "aoeu\xab derp" - \\#define FOO2 "aoeu\x0007a derp" - \\#define FOO_CHAR '\xfF' - , &[_][]const u8{ - \\pub const FOO = "aoeu\xab derp"; - , - \\pub const FOO2 = "aoeu\x7a derp"; - , - \\pub const FOO_CHAR = '\xff'; - }); - - cases.add("macro add", - \\#define D3_AHB1PERIPH_BASE 0 - \\#define PERIPH_BASE (0x40000000UL) /*!< Base address of : AHB/APB Peripherals */ - \\#define D3_APB1PERIPH_BASE (PERIPH_BASE + 0x18000000UL) - \\#define RCC_BASE (D3_AHB1PERIPH_BASE + 0x4400UL) - , &[_][]const u8{ - \\pub const PERIPH_BASE = @as(c_ulong, 0x40000000); - , - \\pub const D3_APB1PERIPH_BASE = PERIPH_BASE + @as(c_ulong, 0x18000000); - , - \\pub const RCC_BASE = D3_AHB1PERIPH_BASE + @as(c_ulong, 0x4400); - }); - - cases.add("variable aliasing", - \\static long a = 2; - \\static long b = 2; - \\static int c = 4; - \\void foo(char c) { - \\ int a; - \\ char b = 123; - \\ b = (char) a; - \\ { - \\ int d = 5; - \\ } - \\ unsigned d = 440; - \\} - , &[_][]const u8{ - \\pub var a: c_long = 2; - \\pub var b: c_long = 2; - \\pub var c: c_int = 4; - \\pub export fn foo(arg_c_1: u8) void { - \\ var c_1 = arg_c_1; - \\ _ = &c_1; - \\ var a_2: c_int = undefined; - \\ _ = &a_2; - \\ var b_3: u8 = 123; - \\ _ = &b_3; - \\ b_3 = @as(u8, @bitCast(@as(i8, @truncate(a_2)))); - \\ { - \\ var d: c_int = 5; - \\ _ = &d; - \\ } - \\ var d: c_uint = @as(c_uint, @bitCast(@as(c_int, 440))); - \\ _ = &d; - \\} - }); - - cases.add("comma operator", - \\int foo() { - \\ 2, 4; - \\ return 2, 4, 6; - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ _ = blk: { - \\ _ = @as(c_int, 2); - \\ break :blk @as(c_int, 4); - \\ }; - \\ return blk: { - \\ _ = blk_1: { - \\ _ = @as(c_int, 2); - \\ break :blk_1 @as(c_int, 4); - \\ }; - \\ break :blk @as(c_int, 6); - \\ }; - \\} - }); - - cases.add("worst-case assign", - \\void foo() { - \\ int a; - \\ int b; - \\ a = b = 2; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: c_int = undefined; - \\ _ = &a; - \\ var b: c_int = undefined; - \\ _ = &b; - \\ a = blk: { - \\ const tmp = @as(c_int, 2); - \\ b = tmp; - \\ break :blk tmp; - \\ }; - \\} - }); - - cases.add("while loops", - \\int foo() { - \\ int a = 5; - \\ while (2) - \\ a = 2; - \\ while (4) { - \\ int a = 4; - \\ a = 9; - \\ return 6, a; - \\ } - \\ do { - \\ int a = 2; - \\ a = 12; - \\ } while (4); - \\ do - \\ a = 7; - \\ while (4); - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ var a: c_int = 5; - \\ _ = &a; - \\ while (true) { - \\ a = 2; - \\ } - \\ while (true) { - \\ var a_1: c_int = 4; - \\ _ = &a_1; - \\ a_1 = 9; - \\ return blk: { - \\ _ = @as(c_int, 6); - \\ break :blk a_1; - \\ }; - \\ } - \\ while (true) { - \\ var a_1: c_int = 2; - \\ _ = &a_1; - \\ a_1 = 12; - \\ } - \\ while (true) { - \\ a = 7; - \\ } - \\ return 0; - \\} - }); - - cases.add("for loops", - \\void foo() { - \\ for (int i = 2, b = 4; i + 2; i = 2) { - \\ int a = 2; - \\ a = 6, 5, 7; - \\ } - \\ char i = 2; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ { - \\ var i: c_int = 2; - \\ _ = &i; - \\ var b: c_int = 4; - \\ _ = &b; - \\ while ((i + @as(c_int, 2)) != 0) : (i = 2) { - \\ var a: c_int = 2; - \\ _ = &a; - \\ _ = blk: { - \\ _ = blk_1: { - \\ a = 6; - \\ break :blk_1 @as(c_int, 5); - \\ }; - \\ break :blk @as(c_int, 7); - \\ }; - \\ } - \\ } - \\ var i: u8 = 2; - \\ _ = &i; - \\} - }); - - cases.add("shadowing primitive types", - \\unsigned anyerror = 2; - \\#define noreturn _Noreturn - \\typedef enum { - \\ f32, - \\ u32, - \\} BadEnum; - , &[_][]const u8{ - \\pub export var @"anyerror": c_uint = 2; - , - \\pub const @"noreturn" = @compileError("unable to translate C expr: unexpected token '_Noreturn'"); - , - \\pub const @"f32": c_int = 0; - \\pub const @"u32": c_int = 1; - \\pub const BadEnum = c_uint; - }); - - cases.add("floats", - \\float a = 3.1415; - \\double b = 3.1415; - \\int c = 3.1415; - \\double d = 3; - , &[_][]const u8{ - \\pub export var a: f32 = @as(f32, @floatCast(3.1415)); - \\pub export var b: f64 = 3.1415; - \\pub export var c: c_int = @as(c_int, @intFromFloat(3.1415)); - \\pub export var d: f64 = 3; - }); - - cases.add("conditional operator", - \\int bar(void) { - \\ if (2 ? 5 : 5 ? 4 : 6) 2; - \\ return 2 ? 5 : 5 ? 4 : 6; - \\} - , &[_][]const u8{ - \\pub export fn bar() c_int { - \\ if ((if (true) @as(c_int, 5) else if (true) @as(c_int, 4) else @as(c_int, 6)) != 0) { - \\ _ = @as(c_int, 2); - \\ } - \\ return if (true) @as(c_int, 5) else if (true) @as(c_int, 4) else @as(c_int, 6); - \\} - }); - - cases.add("switch on int", - \\void switch_fn(int i) { - \\ int res = 0; - \\ switch (i) { - \\ case 0: - \\ res = 1; - \\ case 1 ... 3: - \\ res = 2; - \\ default: - \\ res = 3 * i; - \\ break; - \\ break; - \\ case 7: { - \\ res = 7; - \\ break; - \\ } - \\ case 4: - \\ case 5: - \\ res = 69; - \\ { - \\ res = 5; - \\ return; - \\ } - \\ case 6: - \\ switch (res) { - \\ case 9: break; - \\ } - \\ res = 1; - \\ return; - \\ } - \\} - , &[_][]const u8{ - \\pub export fn switch_fn(arg_i: c_int) void { - \\ var i = arg_i; - \\ _ = &i; - \\ var res: c_int = 0; - \\ _ = &res; - \\ while (true) { - \\ switch (i) { - \\ @as(c_int, 0) => { - \\ res = 1; - \\ res = 2; - \\ res = @as(c_int, 3) * i; - \\ break; - \\ }, - \\ @as(c_int, 1)...@as(c_int, 3) => { - \\ res = 2; - \\ res = @as(c_int, 3) * i; - \\ break; - \\ }, - \\ else => { - \\ res = @as(c_int, 3) * i; - \\ break; - \\ }, - \\ @as(c_int, 7) => { - \\ { - \\ res = 7; - \\ break; - \\ } - \\ }, - \\ @as(c_int, 4), @as(c_int, 5) => { - \\ res = 69; - \\ { - \\ res = 5; - \\ return; - \\ } - \\ }, - \\ @as(c_int, 6) => { - \\ while (true) { - \\ switch (res) { - \\ @as(c_int, 9) => break, - \\ else => {}, - \\ } - \\ break; - \\ } - \\ res = 1; - \\ return; - \\ }, - \\ } - \\ break; - \\ } - \\} - }); - cases.add("undefined array global", - \\int array[100] = {}; - , &[_][]const u8{ - \\pub export var array: [100]c_int = [1]c_int{0} ** 100; - }); - - cases.add("restrict -> noalias", - \\void foo(void *restrict bar, void *restrict); - , &[_][]const u8{ - \\pub extern fn foo(noalias bar: ?*anyopaque, noalias ?*anyopaque) void; - }); - - cases.add("assign", - \\void max(int a) { - \\ int tmp; - \\ tmp = a; - \\ a = tmp; - \\} - , &[_][]const u8{ - \\pub export fn max(arg_a: c_int) void { - \\ var a = arg_a; - \\ _ = &a; - \\ var tmp: c_int = undefined; - \\ _ = &tmp; - \\ tmp = a; - \\ a = tmp; - \\} - }); - - cases.add("chaining assign", - \\void max(int a) { - \\ int b, c; - \\ c = b = a; - \\} - , &[_][]const u8{ - \\pub export fn max(arg_a: c_int) void { - \\ var a = arg_a; - \\ _ = &a; - \\ var b: c_int = undefined; - \\ _ = &b; - \\ var c: c_int = undefined; - \\ _ = &c; - \\ c = blk: { - \\ const tmp = a; - \\ b = tmp; - \\ break :blk tmp; - \\ }; - \\} - }); - - cases.add("anonymous enum", - \\enum { - \\ One, - \\ Two, - \\}; - , &[_][]const u8{ - \\pub const One: c_int = 0; - \\pub const Two: c_int = 1; - \\const enum_unnamed_1 = - ++ " " ++ default_enum_type ++ - \\; - }); - - cases.add("c style cast", - \\int int_from_float(float a) { - \\ return (int)a; - \\} - , &[_][]const u8{ - \\pub export fn int_from_float(arg_a: f32) c_int { - \\ var a = arg_a; - \\ _ = &a; - \\ return @as(c_int, @intFromFloat(a)); - \\} - }); - - cases.add("escape sequences", - \\const char *escapes() { - \\char a = '\'', - \\ b = '\\', - \\ c = '\a', - \\ d = '\b', - \\ e = '\f', - \\ f = '\n', - \\ g = '\r', - \\ h = '\t', - \\ i = '\v', - \\ j = '\0', - \\ k = '\"'; - \\ return "\'\\\a\b\f\n\r\t\v\0\""; - \\} - \\ - , &[_][]const u8{ - \\pub export fn escapes() [*c]const u8 { - \\ var a: u8 = '\''; - \\ _ = &a; - \\ var b: u8 = '\\'; - \\ _ = &b; - \\ var c: u8 = '\x07'; - \\ _ = &c; - \\ var d: u8 = '\x08'; - \\ _ = &d; - \\ var e: u8 = '\x0c'; - \\ _ = &e; - \\ var f: u8 = '\n'; - \\ _ = &f; - \\ var g: u8 = '\r'; - \\ _ = &g; - \\ var h: u8 = '\t'; - \\ _ = &h; - \\ var i: u8 = '\x0b'; - \\ _ = &i; - \\ var j: u8 = '\x00'; - \\ _ = &j; - \\ var k: u8 = '"'; - \\ _ = &k; - \\ return "'\\\x07\x08\x0c\n\r\t\x0b\x00\""; - \\} - }); - - cases.add("do loop", - \\void foo(void) { - \\ int a = 2; - \\ do { - \\ a = a - 1; - \\ } while (a); - \\ - \\ int b = 2; - \\ do - \\ b = b -1; - \\ while (b); - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: c_int = 2; - \\ _ = &a; - \\ while (true) { - \\ a = a - @as(c_int, 1); - \\ if (!(a != 0)) break; - \\ } - \\ var b: c_int = 2; - \\ _ = &b; - \\ while (true) { - \\ b = b - @as(c_int, 1); - \\ if (!(b != 0)) break; - \\ } - \\} - }); - - cases.add("logical and, logical or, on non-bool values, extra parens", - \\enum Foo { - \\ FooA, - \\ FooB, - \\ FooC, - \\}; - \\typedef int SomeTypedef; - \\int and_or_non_bool(int a, float b, void *c) { - \\ enum Foo d = FooA; - \\ int e = (a && b); - \\ int f = (b && c); - \\ int g = (a && c); - \\ int h = (a || b); - \\ int i = (b || c); - \\ int j = (a || c); - \\ int k = (a || (int)d); - \\ int l = ((int)d && b); - \\ int m = (c || (unsigned int)d); - \\ SomeTypedef td = 44; - \\ int o = (td || b); - \\ int p = (c && td); - \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p); - \\} - , &[_][]const u8{ - \\pub const FooA: c_int = 0; - \\pub const FooB: c_int = 1; - \\pub const FooC: c_int = 2; - \\pub const enum_Foo = - ++ " " ++ default_enum_type ++ - \\; - \\pub const SomeTypedef = c_int; - \\pub export fn and_or_non_bool(arg_a: c_int, arg_b: f32, arg_c: ?*anyopaque) c_int { - \\ var a = arg_a; - \\ _ = &a; - \\ var b = arg_b; - \\ _ = &b; - \\ var c = arg_c; - \\ _ = &c; - \\ var d: enum_Foo = @as(c_uint, @bitCast(FooA)); - \\ _ = &d; - \\ var e: c_int = @intFromBool((a != 0) and (b != 0)); - \\ _ = &e; - \\ var f: c_int = @intFromBool((b != 0) and (c != null)); - \\ _ = &f; - \\ var g: c_int = @intFromBool((a != 0) and (c != null)); - \\ _ = &g; - \\ var h: c_int = @intFromBool((a != 0) or (b != 0)); - \\ _ = &h; - \\ var i: c_int = @intFromBool((b != 0) or (c != null)); - \\ _ = &i; - \\ var j: c_int = @intFromBool((a != 0) or (c != null)); - \\ _ = &j; - \\ var k: c_int = @intFromBool((a != 0) or (@as(c_int, @bitCast(d)) != 0)); - \\ _ = &k; - \\ var l: c_int = @intFromBool((@as(c_int, @bitCast(d)) != 0) and (b != 0)); - \\ _ = &l; - \\ var m: c_int = @intFromBool((c != null) or (d != 0)); - \\ _ = &m; - \\ var td: SomeTypedef = 44; - \\ _ = &td; - \\ var o: c_int = @intFromBool((td != 0) or (b != 0)); - \\ _ = &o; - \\ var p: c_int = @intFromBool((c != null) and (td != 0)); - \\ _ = &p; - \\ return (((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p; - \\} - , - \\pub const Foo = enum_Foo; - }); - - cases.add("bitwise binary operators, simpler parens", - \\int max(int a, int b) { - \\ return (a & b) ^ (a | b); - \\} - , &[_][]const u8{ - \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int { - \\ var a = arg_a; - \\ _ = &a; - \\ var b = arg_b; - \\ _ = &b; - \\ return (a & b) ^ (a | b); - \\} - }); - - cases.add("comparison operators (no if)", // TODO Come up with less contrived tests? Make sure to cover all these comparisons. - \\int test_comparisons(int a, int b) { - \\ int c = (a < b); - \\ int d = (a > b); - \\ int e = (a <= b); - \\ int f = (a >= b); - \\ int g = (c < d); - \\ int h = (e < f); - \\ int i = (g < h); - \\ return i; - \\} - , &[_][]const u8{ - \\pub export fn test_comparisons(arg_a: c_int, arg_b: c_int) c_int { - \\ var a = arg_a; - \\ _ = &a; - \\ var b = arg_b; - \\ _ = &b; - \\ var c: c_int = @intFromBool(a < b); - \\ _ = &c; - \\ var d: c_int = @intFromBool(a > b); - \\ _ = &d; - \\ var e: c_int = @intFromBool(a <= b); - \\ _ = &e; - \\ var f: c_int = @intFromBool(a >= b); - \\ _ = &f; - \\ var g: c_int = @intFromBool(c < d); - \\ _ = &g; - \\ var h: c_int = @intFromBool(e < f); - \\ _ = &h; - \\ var i: c_int = @intFromBool(g < h); - \\ _ = &i; - \\ return i; - \\} - }); - - cases.add("==, !=", - \\int max(int a, int b) { - \\ if (a == b) - \\ return a; - \\ if (a != b) - \\ return b; - \\ return a; - \\} - , &[_][]const u8{ - \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int { - \\ var a = arg_a; - \\ _ = &a; - \\ var b = arg_b; - \\ _ = &b; - \\ if (a == b) return a; - \\ if (a != b) return b; - \\ return a; - \\} - }); - - cases.add("typedeffed bool expression", - \\typedef char* yes; - \\void foo(void) { - \\ yes a; - \\ if (a) 2; - \\} - , &[_][]const u8{ - \\pub const yes = [*c]u8; - \\pub export fn foo() void { - \\ var a: yes = undefined; - \\ _ = &a; - \\ if (a != null) { - \\ _ = @as(c_int, 2); - \\ } - \\} - }); - - cases.add("statement expression", - \\int foo(void) { - \\ return ({ - \\ int a = 1; - \\ a; - \\ a; - \\ }); - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ return blk: { - \\ var a: c_int = 1; - \\ _ = &a; - \\ _ = &a; - \\ break :blk a; - \\ }; - \\} - }); - - cases.add("field access expression", - \\#define ARROW a->b - \\#define DOT a.b - \\extern struct Foo { - \\ int b; - \\}a; - \\float b = 2.0f; - \\void foo(void) { - \\ struct Foo *c; - \\ a.b; - \\ c->b; - \\} - , &[_][]const u8{ - \\pub const struct_Foo = extern struct { - \\ b: c_int = @import("std").mem.zeroes(c_int), - \\}; - \\pub extern var a: struct_Foo; - \\pub export var b: f32 = 2.0; - \\pub export fn foo() void { - \\ var c: [*c]struct_Foo = undefined; - \\ _ = &c; - \\ _ = a.b; - \\ _ = c.*.b; - \\} - , - \\pub inline fn ARROW() @TypeOf(a.*.b) { - \\ return a.*.b; - \\} - , - \\pub inline fn DOT() @TypeOf(a.b) { - \\ return a.b; - \\} - }); - - cases.add("array access", - \\#define ACCESS array[2] - \\int array[100] = {}; - \\int foo(int index) { - \\ return array[index]; - \\} - , &[_][]const u8{ - \\pub export var array: [100]c_int = [1]c_int{0} ** 100; - \\pub export fn foo(arg_index: c_int) c_int { - \\ var index = arg_index; - \\ _ = &index; - \\ return array[@as(c_uint, @intCast(index))]; - \\} - , - \\pub inline fn ACCESS() @TypeOf(array[@as(usize, @intCast(@as(c_int, 2)))]) { - \\ return array[@as(usize, @intCast(@as(c_int, 2)))]; - \\} - }); - - cases.add("cast signed array index to unsigned", - \\void foo() { - \\ int a[10], i = 0; - \\ a[i] = 0; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: [10]c_int = undefined; - \\ _ = &a; - \\ var i: c_int = 0; - \\ _ = &i; - \\ a[@as(c_uint, @intCast(i))] = 0; - \\} - }); - - cases.add("long long array index cast to usize", - \\void foo() { - \\ long long a[10], i = 0; - \\ a[i] = 0; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: [10]c_longlong = undefined; - \\ _ = &a; - \\ var i: c_longlong = 0; - \\ _ = &i; - \\ a[@as(usize, @intCast(i))] = 0; - \\} - }); - - cases.add("unsigned array index skips cast", - \\void foo() { - \\ unsigned int a[10], i = 0; - \\ a[i] = 0; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: [10]c_uint = undefined; - \\ _ = &a; - \\ var i: c_uint = 0; - \\ _ = &i; - \\ a[i] = 0; - \\} - }); - - cases.add("macro call", - \\#define CALL(arg) bar(arg) - \\int bar(int x) { return x; } - , &[_][]const u8{ - \\pub inline fn CALL(arg: anytype) @TypeOf(bar(arg)) { - \\ _ = &arg; - \\ return bar(arg); - \\} - }); - - cases.add("macro call with no args", - \\#define CALL(arg) bar() - \\int bar(void) { return 0; } - , &[_][]const u8{ - \\pub inline fn CALL(arg: anytype) @TypeOf(bar()) { - \\ _ = &arg; - \\ return bar(); - \\} - }); - - cases.add("logical and, logical or", - \\int max(int a, int b) { - \\ if (a < b || a == b) - \\ return b; - \\ if (a >= b && a == b) - \\ return a; - \\ return a; - \\} - , &[_][]const u8{ - \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int { - \\ var a = arg_a; - \\ _ = &a; - \\ var b = arg_b; - \\ _ = &b; - \\ if ((a < b) or (a == b)) return b; - \\ if ((a >= b) and (a == b)) return a; - \\ return a; - \\} - }); - - cases.add("simple if statement", - \\int max(int a, int b) { - \\ if (a < b) - \\ return b; - \\ - \\ if (a < b) - \\ return b; - \\ else - \\ return a; - \\ - \\ if (a < b) ; else ; - \\} - , &[_][]const u8{ - \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int { - \\ var a = arg_a; - \\ _ = &a; - \\ var b = arg_b; - \\ _ = &b; - \\ if (a < b) return b; - \\ if (a < b) return b else return a; - \\ if (a < b) {} else {} - \\ return 0; - \\} - }); - - cases.add("if statements", - \\void foo() { - \\ if (2) { - \\ int a = 2; - \\ } - \\ if (2, 5) { - \\ int a = 2; - \\ } - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ if (true) { - \\ var a: c_int = 2; - \\ _ = &a; - \\ } - \\ if ((blk: { - \\ _ = @as(c_int, 2); - \\ break :blk @as(c_int, 5); - \\ }) != 0) { - \\ var a: c_int = 2; - \\ _ = &a; - \\ } - \\} - }); - - cases.add("if on non-bool", - \\enum SomeEnum { A, B, C }; - \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) { - \\ if (a) return 0; - \\ if (b) return 1; - \\ if (c) return 2; - \\ if (d) return 3; - \\ return 4; - \\} - , &[_][]const u8{ - \\pub const A: c_int = 0; - \\pub const B: c_int = 1; - \\pub const C: c_int = 2; - \\pub const enum_SomeEnum = - ++ " " ++ default_enum_type ++ - \\; - \\pub export fn if_none_bool(arg_a: c_int, arg_b: f32, arg_c: ?*anyopaque, arg_d: enum_SomeEnum) c_int { - \\ var a = arg_a; - \\ _ = &a; - \\ var b = arg_b; - \\ _ = &b; - \\ var c = arg_c; - \\ _ = &c; - \\ var d = arg_d; - \\ _ = &d; - \\ if (a != 0) return 0; - \\ if (b != 0) return 1; - \\ if (c != null) return 2; - \\ if (d != 0) return 3; - \\ return 4; - \\} - }); - - cases.add("simple data types", - \\#include - \\int foo(char a, unsigned char b, signed char c); - \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype - \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d); - \\void baz(int8_t a, int16_t b, int32_t c, int64_t d); - , &[_][]const u8{ - \\pub extern fn foo(a: u8, b: u8, c: i8) c_int; - \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void; - \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void; - }); - - cases.add("simple function", - \\int abs(int a) { - \\ return a < 0 ? -a : a; - \\} - , &[_][]const u8{ - \\pub export fn abs(arg_a: c_int) c_int { - \\ var a = arg_a; - \\ _ = &a; - \\ return if (a < @as(c_int, 0)) -a else a; - \\} - }); - - cases.add("post increment", - \\unsigned foo1(unsigned a) { - \\ a++; - \\ return a; - \\} - \\int foo2(int a) { - \\ a++; - \\ return a; - \\} - \\int *foo3(int *a) { - \\ a++; - \\ return a; - \\} - , &[_][]const u8{ - \\pub export fn foo1(arg_a: c_uint) c_uint { - \\ var a = arg_a; - \\ _ = &a; - \\ a +%= 1; - \\ return a; - \\} - \\pub export fn foo2(arg_a: c_int) c_int { - \\ var a = arg_a; - \\ _ = &a; - \\ a += 1; - \\ return a; - \\} - \\pub export fn foo3(arg_a: [*c]c_int) [*c]c_int { - \\ var a = arg_a; - \\ _ = &a; - \\ a += 1; - \\ return a; - \\} - }); - - cases.add("deref function pointer", - \\void foo(void) {} - \\int baz(void) { return 0; } - \\void bar(void) { - \\ void(*f)(void) = foo; - \\ int(*b)(void) = baz; - \\ f(); - \\ (*(f))(); - \\ foo(); - \\ b(); - \\ (*(b))(); - \\ baz(); - \\} - , &[_][]const u8{ - \\pub export fn foo() void {} - \\pub export fn baz() c_int { - \\ return 0; - \\} - \\pub export fn bar() void { - \\ var f: ?*const fn () callconv(.c) void = &foo; - \\ _ = &f; - \\ var b: ?*const fn () callconv(.c) c_int = &baz; - \\ _ = &b; - \\ f.?(); - \\ f.?(); - \\ foo(); - \\ _ = b.?(); - \\ _ = b.?(); - \\ _ = baz(); - \\} - }); - - cases.add("pre increment/decrement", - \\void foo(void) { - \\ int i = 0; - \\ unsigned u = 0; - \\ ++i; - \\ --i; - \\ ++u; - \\ --u; - \\ i = ++i; - \\ i = --i; - \\ u = ++u; - \\ u = --u; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var i: c_int = 0; - \\ _ = &i; - \\ var u: c_uint = 0; - \\ _ = &u; - \\ i += 1; - \\ i -= 1; - \\ u +%= 1; - \\ u -%= 1; - \\ i = blk: { - \\ const ref = &i; - \\ ref.* += 1; - \\ break :blk ref.*; - \\ }; - \\ i = blk: { - \\ const ref = &i; - \\ ref.* -= 1; - \\ break :blk ref.*; - \\ }; - \\ u = blk: { - \\ const ref = &u; - \\ ref.* +%= 1; - \\ break :blk ref.*; - \\ }; - \\ u = blk: { - \\ const ref = &u; - \\ ref.* -%= 1; - \\ break :blk ref.*; - \\ }; - \\} - }); - - cases.add("shift right assign", - \\int log2(unsigned a) { - \\ int i = 0; - \\ while (a > 0) { - \\ a >>= 1; - \\ } - \\ return i; - \\} - , &[_][]const u8{ - \\pub export fn log2(arg_a: c_uint) c_int { - \\ var a = arg_a; - \\ _ = &a; - \\ var i: c_int = 0; - \\ _ = &i; - \\ while (a > @as(c_uint, @bitCast(@as(c_int, 0)))) { - \\ a >>= @intCast(@as(c_int, 1)); - \\ } - \\ return i; - \\} - }); - - cases.add("shift right assign with a fixed size type", - \\#include - \\int log2(uint32_t a) { - \\ int i = 0; - \\ while (a > 0) { - \\ a >>= 1; - \\ } - \\ return i; - \\} - , &[_][]const u8{ - \\pub export fn log2(arg_a: u32) c_int { - \\ var a = arg_a; - \\ _ = &a; - \\ var i: c_int = 0; - \\ _ = &i; - \\ while (a > @as(u32, @bitCast(@as(c_int, 0)))) { - \\ a >>= @intCast(@as(c_int, 1)); - \\ } - \\ return i; - \\} - }); - - cases.add("compound assignment operators", - \\void foo(void) { - \\ int a = 0; - \\ unsigned b = 0; - \\ a += (a += 1); - \\ a -= (a -= 1); - \\ a *= (a *= 1); - \\ a &= (a &= 1); - \\ a |= (a |= 1); - \\ a ^= (a ^= 1); - \\ a >>= (a >>= 1); - \\ a <<= (a <<= 1); - \\ a /= (a /= 1); - \\ a %= (a %= 1); - \\ b /= (b /= 1); - \\ b %= (b %= 1); - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: c_int = 0; - \\ _ = &a; - \\ var b: c_uint = 0; - \\ _ = &b; - \\ a += blk: { - \\ const ref = &a; - \\ ref.* += @as(c_int, 1); - \\ break :blk ref.*; - \\ }; - \\ a -= blk: { - \\ const ref = &a; - \\ ref.* -= @as(c_int, 1); - \\ break :blk ref.*; - \\ }; - \\ a *= blk: { - \\ const ref = &a; - \\ ref.* *= @as(c_int, 1); - \\ break :blk ref.*; - \\ }; - \\ a &= blk: { - \\ const ref = &a; - \\ ref.* &= @as(c_int, 1); - \\ break :blk ref.*; - \\ }; - \\ a |= blk: { - \\ const ref = &a; - \\ ref.* |= @as(c_int, 1); - \\ break :blk ref.*; - \\ }; - \\ a ^= blk: { - \\ const ref = &a; - \\ ref.* ^= @as(c_int, 1); - \\ break :blk ref.*; - \\ }; - \\ a >>= @intCast(blk: { - \\ const ref = &a; - \\ ref.* >>= @intCast(@as(c_int, 1)); - \\ break :blk ref.*; - \\ }); - \\ a <<= @intCast(blk: { - \\ const ref = &a; - \\ ref.* <<= @intCast(@as(c_int, 1)); - \\ break :blk ref.*; - \\ }); - \\ a = @divTrunc(a, blk: { - \\ const ref = &a; - \\ ref.* = @divTrunc(ref.*, @as(c_int, 1)); - \\ break :blk ref.*; - \\ }); - \\ a = @import("std").zig.c_translation.signedRemainder(a, blk: { - \\ const ref = &a; - \\ ref.* = @import("std").zig.c_translation.signedRemainder(ref.*, @as(c_int, 1)); - \\ break :blk ref.*; - \\ }); - \\ b /= blk: { - \\ const ref = &b; - \\ ref.* /= @as(c_uint, @bitCast(@as(c_int, 1))); - \\ break :blk ref.*; - \\ }; - \\ b %= blk: { - \\ const ref = &b; - \\ ref.* %= @as(c_uint, @bitCast(@as(c_int, 1))); - \\ break :blk ref.*; - \\ }; - \\} - }); - - cases.add("compound assignment operators unsigned", - \\void foo(void) { - \\ unsigned a = 0; - \\ a += (a += 1); - \\ a -= (a -= 1); - \\ a *= (a *= 1); - \\ a &= (a &= 1); - \\ a |= (a |= 1); - \\ a ^= (a ^= 1); - \\ a >>= (a >>= 1); - \\ a <<= (a <<= 1); - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: c_uint = 0; - \\ _ = &a; - \\ a +%= blk: { - \\ const ref = &a; - \\ ref.* +%= @as(c_uint, @bitCast(@as(c_int, 1))); - \\ break :blk ref.*; - \\ }; - \\ a -%= blk: { - \\ const ref = &a; - \\ ref.* -%= @as(c_uint, @bitCast(@as(c_int, 1))); - \\ break :blk ref.*; - \\ }; - \\ a *%= blk: { - \\ const ref = &a; - \\ ref.* *%= @as(c_uint, @bitCast(@as(c_int, 1))); - \\ break :blk ref.*; - \\ }; - \\ a &= blk: { - \\ const ref = &a; - \\ ref.* &= @as(c_uint, @bitCast(@as(c_int, 1))); - \\ break :blk ref.*; - \\ }; - \\ a |= blk: { - \\ const ref = &a; - \\ ref.* |= @as(c_uint, @bitCast(@as(c_int, 1))); - \\ break :blk ref.*; - \\ }; - \\ a ^= blk: { - \\ const ref = &a; - \\ ref.* ^= @as(c_uint, @bitCast(@as(c_int, 1))); - \\ break :blk ref.*; - \\ }; - \\ a >>= @intCast(blk: { - \\ const ref = &a; - \\ ref.* >>= @intCast(@as(c_int, 1)); - \\ break :blk ref.*; - \\ }); - \\ a <<= @intCast(blk: { - \\ const ref = &a; - \\ ref.* <<= @intCast(@as(c_int, 1)); - \\ break :blk ref.*; - \\ }); - \\} - }); - - cases.add("post increment/decrement", - \\void foo(void) { - \\ int i = 0; - \\ unsigned u = 0; - \\ i++; - \\ i--; - \\ u++; - \\ u--; - \\ i = i++; - \\ i = i--; - \\ u = u++; - \\ u = u--; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var i: c_int = 0; - \\ _ = &i; - \\ var u: c_uint = 0; - \\ _ = &u; - \\ i += 1; - \\ i -= 1; - \\ u +%= 1; - \\ u -%= 1; - \\ i = blk: { - \\ const ref = &i; - \\ const tmp = ref.*; - \\ ref.* += 1; - \\ break :blk tmp; - \\ }; - \\ i = blk: { - \\ const ref = &i; - \\ const tmp = ref.*; - \\ ref.* -= 1; - \\ break :blk tmp; - \\ }; - \\ u = blk: { - \\ const ref = &u; - \\ const tmp = ref.*; - \\ ref.* +%= 1; - \\ break :blk tmp; - \\ }; - \\ u = blk: { - \\ const ref = &u; - \\ const tmp = ref.*; - \\ ref.* -%= 1; - \\ break :blk tmp; - \\ }; - \\} - }); - - cases.add("implicit casts", - \\#include - \\ - \\void fn_int(int x); - \\void fn_f32(float x); - \\void fn_f64(double x); - \\void fn_char(char x); - \\void fn_bool(bool x); - \\void fn_ptr(void *x); - \\ - \\void call() { - \\ fn_int(3.0f); - \\ fn_int(3.0); - \\ fn_int('ABCD'); - \\ fn_f32(3); - \\ fn_f64(3); - \\ fn_char('3'); - \\ fn_char('\x1'); - \\ fn_char(0); - \\ fn_f32(3.0f); - \\ fn_f64(3.0); - \\ fn_bool(123); - \\ fn_bool(0); - \\ fn_bool(&fn_int); - \\ fn_int((int)&fn_int); - \\ fn_ptr((void *)42); - \\} - , &[_][]const u8{ - \\pub extern fn fn_int(x: c_int) void; - \\pub extern fn fn_f32(x: f32) void; - \\pub extern fn fn_f64(x: f64) void; - \\pub extern fn fn_char(x: u8) void; - \\pub extern fn fn_bool(x: bool) void; - \\pub extern fn fn_ptr(x: ?*anyopaque) void; - \\pub export fn call() void { - \\ fn_int(@as(c_int, @intFromFloat(3.0))); - \\ fn_int(@as(c_int, @intFromFloat(3.0))); - \\ fn_int(@as(c_int, 1094861636)); - \\ fn_f32(@as(f32, @floatFromInt(@as(c_int, 3)))); - \\ fn_f64(@as(f64, @floatFromInt(@as(c_int, 3)))); - \\ fn_char(@as(u8, @bitCast(@as(i8, @truncate(@as(c_int, '3')))))); - \\ fn_char(@as(u8, @bitCast(@as(i8, @truncate(@as(c_int, '\x01')))))); - \\ fn_char(@as(u8, @bitCast(@as(i8, @truncate(@as(c_int, 0)))))); - \\ fn_f32(3.0); - \\ fn_f64(3.0); - \\ fn_bool(@as(c_int, 123) != 0); - \\ fn_bool(@as(c_int, 0) != 0); - \\ fn_bool(@intFromPtr(&fn_int) != 0); - \\ fn_int(@as(c_int, @intCast(@intFromPtr(&fn_int)))); - \\ fn_ptr(@as(?*anyopaque, @ptrFromInt(@as(c_int, 42)))); - \\} - }); - - cases.add("function call", - \\static void bar(void) { } - \\void foo(int *(baz)(void)) { - \\ bar(); - \\ baz(); - \\} - , &[_][]const u8{ - \\pub fn bar() callconv(.c) void {} - \\pub export fn foo(arg_baz: ?*const fn () callconv(.c) [*c]c_int) void { - \\ var baz = arg_baz; - \\ _ = &baz; - \\ bar(); - \\ _ = baz.?(); - \\} - }); - - cases.add("macro defines string literal with octal", - \\#define FOO "aoeu\023 derp" - \\#define FOO2 "aoeu\0234 derp" - \\#define FOO_CHAR '\077' - , &[_][]const u8{ - \\pub const FOO = "aoeu\x13 derp"; - , - \\pub const FOO2 = "aoeu\x134 derp"; - , - \\pub const FOO_CHAR = '\x3f'; - }); - - cases.add("macro cast", - \\#include - \\int baz(void *arg) { return 0; } - \\#define FOO(bar) baz((void *)(baz)) - \\#define BAR (void*) a - \\#define BAZ (uint32_t)(2) - \\#define a 2 - , &[_][]const u8{ - \\pub inline fn FOO(bar: anytype) @TypeOf(baz(@import("std").zig.c_translation.cast(?*anyopaque, baz))) { - \\ _ = &bar; - \\ return baz(@import("std").zig.c_translation.cast(?*anyopaque, baz)); - \\} - , - \\pub const BAR = @import("std").zig.c_translation.cast(?*anyopaque, a); - , - \\pub const BAZ = @import("std").zig.c_translation.cast(u32, @as(c_int, 2)); - }); - - cases.add("macro with cast to unsigned short, long, and long long", - \\#define CURLAUTH_BASIC_BUT_USHORT ((unsigned short) 1) - \\#define CURLAUTH_BASIC ((unsigned long) 1) - \\#define CURLAUTH_BASIC_BUT_ULONGLONG ((unsigned long long) 1) - , &[_][]const u8{ - \\pub const CURLAUTH_BASIC_BUT_USHORT = @import("std").zig.c_translation.cast(c_ushort, @as(c_int, 1)); - \\pub const CURLAUTH_BASIC = @import("std").zig.c_translation.cast(c_ulong, @as(c_int, 1)); - \\pub const CURLAUTH_BASIC_BUT_ULONGLONG = @import("std").zig.c_translation.cast(c_ulonglong, @as(c_int, 1)); - }); - - cases.add("macro conditional operator", - \\ int a, b, c; - \\#define FOO a ? b : c - , &[_][]const u8{ - \\pub inline fn FOO() @TypeOf(if (a) b else c) { - \\ return if (a) b else c; - \\} - }); - - cases.add("do while as expr", - \\static void foo(void) { - \\ if (1) - \\ do {} while (0); - \\} - , &[_][]const u8{ - \\pub fn foo() callconv(.c) void { - \\ if (true) while (true) { - \\ if (!false) break; - \\ }; - \\} - }); - - cases.add("macro comparisons", - \\#define MIN(a, b) ((b) < (a) ? (b) : (a)) - \\#define MAX(a, b) ((b) > (a) ? (b) : (a)) - , &[_][]const u8{ - \\pub inline fn MIN(a: anytype, b: anytype) @TypeOf(if (b < a) b else a) { - \\ _ = &a; - \\ _ = &b; - \\ return if (b < a) b else a; - \\} - , - \\pub inline fn MAX(a: anytype, b: anytype) @TypeOf(if (b > a) b else a) { - \\ _ = &a; - \\ _ = &b; - \\ return if (b > a) b else a; - \\} - }); - - cases.add("nested assignment", - \\int foo(int *p, int x) { - \\ return *p++ = x; - \\} - , &[_][]const u8{ - \\pub export fn foo(arg_p: [*c]c_int, arg_x: c_int) c_int { - \\ var p = arg_p; - \\ _ = &p; - \\ var x = arg_x; - \\ _ = &x; - \\ return blk: { - \\ const tmp = x; - \\ (blk_1: { - \\ const ref = &p; - \\ const tmp_2 = ref.*; - \\ ref.* += 1; - \\ break :blk_1 tmp_2; - \\ }).* = tmp; - \\ break :blk tmp; - \\ }; - \\} - }); - - cases.add("widening and truncating integer casting to different signedness", - \\unsigned long foo(void) { - \\ return -1; - \\} - \\unsigned short bar(long x) { - \\ return x; - \\} - , &[_][]const u8{ - \\pub export fn foo() c_ulong { - \\ return @as(c_ulong, @bitCast(@as(c_long, -@as(c_int, 1)))); - \\} - \\pub export fn bar(arg_x: c_long) c_ushort { - \\ var x = arg_x; - \\ _ = &x; - \\ return @as(c_ushort, @bitCast(@as(c_short, @truncate(x)))); - \\} - }); - - cases.add("arg name aliasing decl which comes after", - \\void foo(int bar) { - \\ bar = 2; - \\} - \\int bar = 4; - , &[_][]const u8{ - \\pub export fn foo(arg_bar_1: c_int) void { - \\ var bar_1 = arg_bar_1; - \\ _ = &bar_1; - \\ bar_1 = 2; - \\} - \\pub export var bar: c_int = 4; - }); - - cases.add("arg name aliasing macro which comes after", - \\void foo(int bar) { - \\ bar = 2; - \\} - \\#define bar 4 - , &[_][]const u8{ - \\pub export fn foo(arg_bar_1: c_int) void { - \\ var bar_1 = arg_bar_1; - \\ _ = &bar_1; - \\ bar_1 = 2; - \\} - , - \\pub const bar = @as(c_int, 4); - }); - - cases.add("don't export inline functions", - \\inline void a(void) {} - \\static void b(void) {} - \\void c(void) {} - \\static void foo() {} - , &[_][]const u8{ - \\pub fn a() callconv(.c) void {} - \\pub fn b() callconv(.c) void {} - \\pub export fn c() void {} - \\pub fn foo() callconv(.c) void {} - }); - - cases.add("casting away const and volatile", - \\void foo(int *a) {} - \\void bar(const int *a) { - \\ foo((int *)a); - \\} - \\void baz(volatile int *a) { - \\ foo((int *)a); - \\} - , &[_][]const u8{ - \\pub export fn foo(arg_a: [*c]c_int) void { - \\ var a = arg_a; - \\ _ = &a; - \\} - \\pub export fn bar(arg_a: [*c]const c_int) void { - \\ var a = arg_a; - \\ _ = &a; - \\ foo(@as([*c]c_int, @ptrCast(@constCast(@volatileCast(a))))); - \\} - \\pub export fn baz(arg_a: [*c]volatile c_int) void { - \\ var a = arg_a; - \\ _ = &a; - \\ foo(@as([*c]c_int, @ptrCast(@constCast(@volatileCast(a))))); - \\} - }); - - cases.add("handling of _Bool type", - \\_Bool foo(_Bool x) { - \\ _Bool a = x != 1; - \\ _Bool b = a != 0; - \\ _Bool c = foo; - \\ return foo(c != b); - \\} - , &[_][]const u8{ - \\pub export fn foo(arg_x: bool) bool { - \\ var x = arg_x; - \\ _ = &x; - \\ var a: bool = @as(c_int, @intFromBool(x)) != @as(c_int, 1); - \\ _ = &a; - \\ var b: bool = @as(c_int, @intFromBool(a)) != @as(c_int, 0); - \\ _ = &b; - \\ var c: bool = @intFromPtr(&foo) != 0; - \\ _ = &c; - \\ return foo(@as(c_int, @intFromBool(c)) != @as(c_int, @intFromBool(b))); - \\} - }); - - cases.add("Don't make const parameters mutable", - \\int max(const int x, int y) { - \\ return (x > y) ? x : y; - \\} - , &[_][]const u8{ - \\pub export fn max(x: c_int, arg_y: c_int) c_int { - \\ _ = &x; - \\ var y = arg_y; - \\ _ = &y; - \\ return if (x > y) x else y; - \\} - }); - - cases.add("string concatenation in macros", - \\#define FOO "hello" - \\#define BAR FOO " world" - \\#define BAZ "oh, " FOO - , &[_][]const u8{ - \\pub const FOO = "hello"; - , - \\pub const BAR = FOO ++ " world"; - , - \\pub const BAZ = "oh, " ++ FOO; - }); - - cases.add("string concatenation in macros: two defines", - \\#define FOO "hello" - \\#define BAZ " world" - \\#define BAR FOO BAZ - , &[_][]const u8{ - \\pub const FOO = "hello"; - , - \\pub const BAZ = " world"; - , - \\pub const BAR = FOO ++ BAZ; - }); - - cases.add("string concatenation in macros: two strings", - \\#define FOO "a" "b" - \\#define BAR FOO "c" - , &[_][]const u8{ - \\pub const FOO = "a" ++ "b"; - , - \\pub const BAR = FOO ++ "c"; - }); - - cases.add("string concatenation in macros: three strings", - \\#define FOO "a" "b" "c" - , &[_][]const u8{ - \\pub const FOO = "a" ++ "b" ++ "c"; - }); - - cases.add("multibyte character literals", - \\#define FOO 'abcd' - , &[_][]const u8{ - \\pub const FOO = 0x61626364; - }); - - cases.add("Make sure casts are grouped", - \\typedef struct - \\{ - \\ int i; - \\} - \\*_XPrivDisplay; - \\typedef struct _XDisplay Display; - \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen) - \\ - , &[_][]const u8{ - \\pub inline fn DefaultScreen(dpy: anytype) @TypeOf(@import("std").zig.c_translation.cast(_XPrivDisplay, dpy).*.default_screen) { - \\ _ = &dpy; - \\ return @import("std").zig.c_translation.cast(_XPrivDisplay, dpy).*.default_screen; - \\} - }); - - cases.add("macro integer literal casts", - \\#define NULL ((void*)0) - \\#define FOO ((int)0x8000) - , &[_][]const u8{ - \\pub const NULL = @import("std").zig.c_translation.cast(?*anyopaque, @as(c_int, 0)); - , - \\pub const FOO = @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hex)); - }); - - if (builtin.abi == .msvc) { - cases.add("nameless struct fields", - \\typedef struct NAMED - \\{ - \\ long name; - \\} NAMED; - \\ - \\typedef struct ONENAMEWITHSTRUCT - \\{ - \\ NAMED; - \\ long b; - \\} ONENAMEWITHSTRUCT; - , &[_][]const u8{ - \\pub const struct_NAMED = extern struct { - \\ name: c_long = @import("std").mem.zeroes(c_long), - \\}; - \\pub const NAMED = struct_NAMED; - \\pub const struct_ONENAMEWITHSTRUCT = extern struct { - \\ unnamed_0: struct_NAMED = = @import("std").mem.zeroes(struct_NAMED), - \\ b: c_long = @import("std").mem.zeroes(c_long), - \\}; - }); - } else { - cases.add("nameless struct fields", - \\typedef struct NAMED - \\{ - \\ long name; - \\} NAMED; - \\ - \\typedef struct ONENAMEWITHSTRUCT - \\{ - \\ NAMED; - \\ long b; - \\} ONENAMEWITHSTRUCT; - , &[_][]const u8{ - \\pub const struct_NAMED = extern struct { - \\ name: c_long = @import("std").mem.zeroes(c_long), - \\}; - \\pub const NAMED = struct_NAMED; - \\pub const struct_ONENAMEWITHSTRUCT = extern struct { - \\ b: c_long = @import("std").mem.zeroes(c_long), - \\}; - }); - } - - cases.add("integer literal promotion", - \\#define GUARANTEED_TO_FIT_1 1024 - \\#define GUARANTEED_TO_FIT_2 10241024L - \\#define GUARANTEED_TO_FIT_3 20482048LU - \\#define MAY_NEED_PROMOTION_1 10241024 - \\#define MAY_NEED_PROMOTION_2 307230723072L - \\#define MAY_NEED_PROMOTION_3 819281928192LU - \\#define MAY_NEED_PROMOTION_HEX 0x80000000 - \\#define MAY_NEED_PROMOTION_OCT 020000000000 - , &[_][]const u8{ - \\pub const GUARANTEED_TO_FIT_1 = @as(c_int, 1024); - \\pub const GUARANTEED_TO_FIT_2 = @as(c_long, 10241024); - \\pub const GUARANTEED_TO_FIT_3 = @as(c_ulong, 20482048); - \\pub const MAY_NEED_PROMOTION_1 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 10241024, .decimal); - \\pub const MAY_NEED_PROMOTION_2 = @import("std").zig.c_translation.promoteIntLiteral(c_long, 307230723072, .decimal); - \\pub const MAY_NEED_PROMOTION_3 = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 819281928192, .decimal); - \\pub const MAY_NEED_PROMOTION_HEX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x80000000, .hex); - \\pub const MAY_NEED_PROMOTION_OCT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0o20000000000, .octal); - }); - - cases.add("demote un-implemented builtins", - \\#define FOO(X) __builtin_alloca_with_align((X), 8) - , &[_][]const u8{ - \\pub const FOO = @compileError("unable to translate macro: undefined identifier `__builtin_alloca_with_align`"); - }); - - cases.add("null sentinel arrays when initialized from string literal. Issue #8256", - \\#include - \\char zero[0] = "abc"; - \\uint32_t zero_w[0] = U"💯💯💯"; - \\char empty_incomplete[] = ""; - \\uint32_t empty_incomplete_w[] = U""; - \\char empty_constant[100] = ""; - \\uint32_t empty_constant_w[100] = U""; - \\char incomplete[] = "abc"; - \\uint32_t incomplete_w[] = U"💯💯💯"; - \\char truncated[1] = "abc"; - \\uint32_t truncated_w[1] = U"💯💯💯"; - \\char extend[5] = "a"; - \\uint32_t extend_w[5] = U"💯"; - \\char no_null[3] = "abc"; - \\uint32_t no_null_w[3] = U"💯💯💯"; - , &[_][]const u8{ - \\pub export var zero: [0]u8 = [0]u8{}; - \\pub export var zero_w: [0]u32 = [0]u32{}; - \\pub export var empty_incomplete: [1]u8 = [1]u8{0} ** 1; - \\pub export var empty_incomplete_w: [1]u32 = [1]u32{0} ** 1; - \\pub export var empty_constant: [100]u8 = [1]u8{0} ** 100; - \\pub export var empty_constant_w: [100]u32 = [1]u32{0} ** 100; - \\pub export var incomplete: [3:0]u8 = "abc".*; - \\pub export var incomplete_w: [3:0]u32 = [3:0]u32{ - \\ '\u{1f4af}', - \\ '\u{1f4af}', - \\ '\u{1f4af}', - \\}; - \\pub export var truncated: [1]u8 = "abc"[0..1].*; - \\pub export var truncated_w: [1]u32 = [1]u32{ - \\ '\u{1f4af}', - \\}; - \\pub export var extend: [5]u8 = "a"[0..1].* ++ [1]u8{0} ** 4; - \\pub export var extend_w: [5]u32 = [1]u32{ - \\ '\u{1f4af}', - \\} ++ [1]u32{0} ** 4; - \\pub export var no_null: [3]u8 = "abc".*; - \\pub export var no_null_w: [3]u32 = [3]u32{ - \\ '\u{1f4af}', - \\ '\u{1f4af}', - \\ '\u{1f4af}', - \\}; - }); - - cases.add("global assembly", - \\__asm__(".globl func\n\t" - \\ ".type func, @function\n\t" - \\ "func:\n\t" - \\ ".cfi_startproc\n\t" - \\ "movl $42, %eax\n\t" - \\ "ret\n\t" - \\ ".cfi_endproc"); - , &[_][]const u8{ - \\comptime { - \\ asm (".globl func\n\t.type func, @function\n\tfunc:\n\t.cfi_startproc\n\tmovl $42, %eax\n\tret\n\t.cfi_endproc"); - \\} - }); - - cases.add("Demote function that initializes opaque struct", - \\struct my_struct { - \\ unsigned a: 15; - \\ unsigned: 2; - \\ unsigned b: 15; - \\}; - \\void initialize(void) { - \\ struct my_struct S = {.a = 1, .b = 2}; - \\} - , &[_][]const u8{ - \\warning: local variable has opaque type - , - \\warning: unable to translate function, demoted to extern - \\pub extern fn initialize() void; - }); - - cases.add("Demote function that dereferences opaque type", - \\struct my_struct { - \\ unsigned a: 1; - \\}; - \\void deref(struct my_struct *s) { - \\ *s; - \\} - , &[_][]const u8{ - \\warning: cannot dereference opaque type - , - \\warning: unable to translate function, demoted to extern - \\pub extern fn deref(arg_s: ?*struct_my_struct) void; - }); - - cases.add("Demote function that dereference types that contain opaque type", - \\struct inner { - \\ _Atomic int a; - \\}; - \\struct outer { - \\ int thing; - \\ struct inner sub_struct; - \\}; - \\void deref(struct outer *s) { - \\ *s; - \\} - , &[_][]const u8{ - \\pub const struct_inner = opaque {}; - , - \\pub const struct_outer = extern struct { - \\ thing: c_int = @import("std").mem.zeroes(c_int), - \\ sub_struct: struct_inner = @import("std").mem.zeroes(struct_inner), - \\}; - , - \\warning: unable to translate function, demoted to extern - , - \\pub extern fn deref(arg_s: ?*struct_outer) void; - }); - - cases.add("Function prototype declared within function", - \\int foo(void) { - \\ extern int bar(int, int); - \\ return bar(1, 2); - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ const ExternLocal_bar = struct { - \\ pub extern fn bar(c_int, c_int) c_int; - \\ }; - \\ _ = &ExternLocal_bar; - \\ return ExternLocal_bar.bar(@as(c_int, 1), @as(c_int, 2)); - \\} - }); - - cases.add("static local variable zero-initialized if no initializer", - \\struct FOO {int x; int y;}; - \\int bar(void) { - \\ static struct FOO foo; - \\ return foo.x; - \\} - , &[_][]const u8{ - \\pub const struct_FOO = extern struct { - \\ x: c_int = @import("std").mem.zeroes(c_int), - \\ y: c_int = @import("std").mem.zeroes(c_int), - \\}; - \\pub export fn bar() c_int { - \\ const foo = struct { - \\ var static: struct_FOO = @import("std").mem.zeroes(struct_FOO); - \\ }; - \\ _ = &foo; - \\ return foo.static.x; - \\} - }); - - cases.add("macro with nontrivial cast", - \\#define MAP_FAILED ((void *) -1) - \\typedef long long LONG_PTR; - \\#define INVALID_HANDLE_VALUE ((void *)(LONG_PTR)-1) - , &[_][]const u8{ - \\pub const MAP_FAILED = @import("std").zig.c_translation.cast(?*anyopaque, -@as(c_int, 1)); - \\pub const INVALID_HANDLE_VALUE = @import("std").zig.c_translation.cast(?*anyopaque, @import("std").zig.c_translation.cast(LONG_PTR, -@as(c_int, 1))); - }); - - cases.add("discard unused local variables and function parameters", - \\#define FOO(A, B) (A) - \\int bar(int x, int y) { - \\ return x; - \\} - , &[_][]const u8{ - \\pub export fn bar(arg_x: c_int, arg_y: c_int) c_int { - \\ var x = arg_x; - \\ _ = &x; - \\ var y = arg_y; - \\ _ = &y; - \\ return x; - \\} - , - \\pub inline fn FOO(A: anytype, B: anytype) @TypeOf(A) { - \\ _ = &A; - \\ _ = &B; - \\ return A; - \\} - }); - - cases.add("Use @ syntax for bare underscore identifier in macro or public symbol", - \\#define FOO _ - \\int _ = 42; - , &[_][]const u8{ - \\pub inline fn FOO() @TypeOf(@"_") { - \\ return @"_"; - \\} - , - \\pub export var @"_": c_int = 42; - }); - - cases.add("Macro matching", - \\#define FOO(X) (X ## U) - , &[_][]const u8{ - \\pub const FOO = @import("std").zig.c_translation.Macros.U_SUFFIX; - }); - - cases.add("Simple array access of pointer with non-negative integer constant", - \\void foo(int *p) { - \\ p[0]; - \\ p[1]; - \\} - , &[_][]const u8{ - \\_ = p[@as(c_uint, @intCast(@as(c_int, 0)))]; - , - \\_ = p[@as(c_uint, @intCast(@as(c_int, 1)))]; - }); - - cases.add("Undefined macro identifier", - \\#define FOO BAR - , &[_][]const u8{ - \\pub const FOO = @compileError("unable to translate macro: undefined identifier `BAR`"); - }); - - cases.add("Macro redefines builtin", - \\#define FOO __builtin_popcount - , &[_][]const u8{ - \\pub const FOO = __builtin_popcount; - }); - - cases.add("Only consider public decls in `isBuiltinDefined`", - \\#define FOO std - , &[_][]const u8{ - \\pub const FOO = @compileError("unable to translate macro: undefined identifier `std`"); - }); - - cases.add("Macro without a value", - \\#define FOO - , &[_][]const u8{ - \\pub const FOO = ""; - }); - - cases.add("leading zeroes", - \\#define O_RDONLY 00 - \\#define HELLO 000 - \\#define ZERO 0 - \\#define WORLD 00000123 - , &[_][]const u8{ - \\pub const O_RDONLY = @as(c_int, 0o0); - \\pub const HELLO = @as(c_int, 0o00); - \\pub const ZERO = @as(c_int, 0); - \\pub const WORLD = @as(c_int, 0o0000123); - }); - - cases.add("Assign expression from bool to int", - \\void foo(void) { - \\ int a; - \\ if (a = 1 > 0) {} - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: c_int = undefined; - \\ _ = &a; - \\ if ((blk: { - \\ const tmp = @intFromBool(@as(c_int, 1) > @as(c_int, 0)); - \\ a = tmp; - \\ break :blk tmp; - \\ }) != 0) {} - \\} - }); - - if (builtin.os.tag == .windows) { - cases.add("Pointer subtraction with typedef", - \\typedef char* S; - \\void foo() { - \\ S a, b; - \\ long long c = a - b; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: S = undefined; - \\ _ = &a; - \\ var b: S = undefined; - \\ _ = &b; - \\ var c: c_longlong = @divExact(@as(c_longlong, @bitCast(@intFromPtr(a) -% @intFromPtr(b))), @sizeOf(u8)); - \\ _ = &c; - \\} - }); - } else { - cases.add("Pointer subtraction with typedef", - \\typedef char* S; - \\void foo() { - \\ S a, b; - \\ long c = a - b; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: S = undefined; - \\ _ = &a; - \\ var b: S = undefined; - \\ _ = &b; - \\ var c: c_long = @divExact(@as(c_long, @bitCast(@intFromPtr(a) -% @intFromPtr(b))), @sizeOf(u8)); - \\ _ = &c; - \\} - }); - } - - cases.add("extern array of unknown length", - \\extern int foo[]; - , &[_][]const u8{ - \\const foo: [*c]c_int = @extern([*c]c_int, .{ - \\ .name = "foo", - \\}); - }); - - cases.add("string array initializer", - \\static const char foo[] = {"bar"}; - , &[_][]const u8{ - \\pub const foo: [3:0]u8 = "bar"; - }); - - cases.add("worst-case assign from mangle prefix", - \\void foo() { - \\ int n, tmp = 1; - \\ if (n = tmp) {} - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var n: c_int = undefined; - \\ _ = &n; - \\ var tmp: c_int = 1; - \\ _ = &tmp; - \\ if ((blk: { - \\ const tmp_1 = tmp; - \\ n = tmp_1; - \\ break :blk tmp_1; - \\ }) != 0) {} - \\} - }); - - cases.add("worst-case assign to mangle prefix", - \\void foo() { - \\ int tmp, n = 1; - \\ if (tmp = n) {} - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var tmp: c_int = undefined; - \\ _ = &tmp; - \\ var n: c_int = 1; - \\ _ = &n; - \\ if ((blk: { - \\ const tmp_1 = n; - \\ tmp = tmp_1; - \\ break :blk tmp_1; - \\ }) != 0) {} - \\} - }); - - cases.add("worst-case precrement mangle prefix", - \\void foo() { - \\ int n, ref = 1; - \\ if (n = ++ref) {} - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var n: c_int = undefined; - \\ _ = &n; - \\ var ref: c_int = 1; - \\ _ = &ref; - \\ if ((blk: { - \\ const tmp = blk_1: { - \\ const ref_2 = &ref; - \\ ref_2.* += 1; - \\ break :blk_1 ref_2.*; - \\ }; - \\ n = tmp; - \\ break :blk tmp; - \\ }) != 0) {} - \\} - }); - - cases.add("worst-case postcrement mangle prefix", - \\void foo() { - \\ int n, ref = 1; - \\ if (n = ref++) {} - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var n: c_int = undefined; - \\ _ = &n; - \\ var ref: c_int = 1; - \\ _ = &ref; - \\ if ((blk: { - \\ const tmp = blk_1: { - \\ const ref_2 = &ref; - \\ const tmp_3 = ref_2.*; - \\ ref_2.* += 1; - \\ break :blk_1 tmp_3; - \\ }; - \\ n = tmp; - \\ break :blk tmp; - \\ }) != 0) {} - \\} - }); - - cases.add("worst-case compound assign from mangle prefix", - \\void foo() { - \\ int n, ref = 1; - \\ if (n += ref) {} - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var n: c_int = undefined; - \\ _ = &n; - \\ var ref: c_int = 1; - \\ _ = &ref; - \\ if ((blk: { - \\ const ref_1 = &n; - \\ ref_1.* += ref; - \\ break :blk ref_1.*; - \\ }) != 0) {} - \\} - }); - - cases.add("worst-case compound assign to mangle prefix", - \\void foo() { - \\ int ref, n = 1; - \\ if (ref += n) {} - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var ref: c_int = undefined; - \\ _ = &ref; - \\ var n: c_int = 1; - \\ _ = &n; - \\ if ((blk: { - \\ const ref_1 = &ref; - \\ ref_1.* += n; - \\ break :blk ref_1.*; - \\ }) != 0) {} - \\} - }); - - cases.add("binary conditional operator where condition is the mangle prefix", - \\void foo() { - \\ int f = 1; - \\ int n, cond_temp = 1; - \\ if (n = (cond_temp)?:(f)) {} - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var f: c_int = 1; - \\ _ = &f; - \\ var n: c_int = undefined; - \\ _ = &n; - \\ var cond_temp: c_int = 1; - \\ _ = &cond_temp; - \\ if ((blk: { - \\ const tmp = blk_1: { - \\ const cond_temp_2 = cond_temp; - \\ break :blk_1 if (cond_temp_2 != 0) cond_temp_2 else f; - \\ }; - \\ n = tmp; - \\ break :blk tmp; - \\ }) != 0) {} - \\} - }); - - cases.add("binary conditional operator where false_expr is the mangle prefix", - \\void foo() { - \\ int cond_temp = 1; - \\ int n, f = 1; - \\ if (n = (f)?:(cond_temp)) {} - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var cond_temp: c_int = 1; - \\ _ = &cond_temp; - \\ var n: c_int = undefined; - \\ _ = &n; - \\ var f: c_int = 1; - \\ _ = &f; - \\ if ((blk: { - \\ const tmp = blk_1: { - \\ const cond_temp_2 = f; - \\ break :blk_1 if (cond_temp_2 != 0) cond_temp_2 else cond_temp; - \\ }; - \\ n = tmp; - \\ break :blk tmp; - \\ }) != 0) {} - \\} - }); - - cases.add("macro using argument as struct name is not translated", - \\#define FOO(x) struct x - , &[_][]const u8{ - \\pub const FOO = @compileError("unable to translate macro: untranslatable usage of arg `x`"); - }); - - cases.add("unsupport declare statement at the last of a compound statement which belongs to a statement expr", - \\void somefunc(void) { - \\ int y; - \\ (void)({y=1; _Static_assert(1);}); - \\} - , &[_][]const u8{ - \\pub export fn somefunc() void { - \\ var y: c_int = undefined; - \\ _ = &y; - \\ _ = blk: { - \\ y = 1; - \\ }; - \\} - }); -}