aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorhryx <codroid@gmail.com>2019-05-12 02:00:49 -0700
committerhryx <codroid@gmail.com>2019-05-12 02:00:49 -0700
commit3787f3428625e830fd852a8f5a40c7d8a2d429f6 (patch)
tree23fb493b9d2f07c7abe57955874682959936319a /test
parent16aee1f58a80295f7599a8290d764a5c7040c373 (diff)
parentedcc7c72d1a684a8a16ca23ad26689f2cce4e803 (diff)
downloadzig-3787f3428625e830fd852a8f5a40c7d8a2d429f6.tar.gz
zig-3787f3428625e830fd852a8f5a40c7d8a2d429f6.zip
Merge branch 'master' into rebased
Diffstat (limited to 'test')
-rw-r--r--test/compile_errors.zig113
-rw-r--r--test/runtime_safety.zig20
-rw-r--r--test/stage1/behavior.zig3
-rw-r--r--test/stage1/behavior/bit_shifting.zig10
-rw-r--r--test/stage1/behavior/bugs/1607.zig15
-rw-r--r--test/stage1/behavior/bugs/2114.zig19
-rw-r--r--test/stage1/behavior/bugs/2346.zig6
-rw-r--r--test/stage1/behavior/enum.zig39
-rw-r--r--test/stage1/behavior/math.zig7
-rw-r--r--test/stage1/behavior/pointers.zig50
-rw-r--r--test/stage1/behavior/sizeof_and_typeof.zig7
-rw-r--r--test/stage1/behavior/struct.zig22
-rw-r--r--test/stage1/behavior/syntax.zig8
-rw-r--r--test/stage1/behavior/union.zig37
-rw-r--r--test/tests.zig36
-rw-r--r--test/translate_c.zig215
16 files changed, 522 insertions, 85 deletions
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index a31605b02a..297673235d 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -3,6 +3,64 @@ const builtin = @import("builtin");
pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.add(
+ "peer cast then implicit cast const pointer to mutable C pointer",
+ \\export fn func() void {
+ \\ var strValue: [*c]u8 = undefined;
+ \\ strValue = strValue orelse c"";
+ \\}
+ ,
+ "tmp.zig:3:32: error: cast discards const qualifier",
+ );
+
+ cases.add(
+ "overflow in enum value allocation",
+ \\const Moo = enum(u8) {
+ \\ Last = 255,
+ \\ Over,
+ \\};
+ \\pub fn main() void {
+ \\ var y = Moo.Last;
+ \\}
+ ,
+ "tmp.zig:3:5: error: enumeration value 256 too large for type 'u8'",
+ );
+
+ cases.add(
+ "attempt to cast enum literal to error",
+ \\export fn entry() void {
+ \\ switch (error.Hi) {
+ \\ .Hi => {},
+ \\ }
+ \\}
+ ,
+ "tmp.zig:3:9: error: expected type 'error{Hi}', found '(enum literal)'",
+ );
+
+ cases.add(
+ "@sizeOf bad type",
+ \\export fn entry() void {
+ \\ _ = @sizeOf(@typeOf(null));
+ \\}
+ ,
+ "tmp.zig:2:17: error: no size available for type '(null)'",
+ );
+
+ cases.add(
+ "Generic function where return type is self-referenced",
+ \\fn Foo(comptime T: type) Foo(T) {
+ \\ return struct{ x: T };
+ \\}
+ \\export fn entry() void {
+ \\ const t = Foo(u32) {
+ \\ .x = 1
+ \\ };
+ \\}
+ ,
+ "tmp.zig:1:29: error: evaluation exceeded 1000 backwards branches",
+ "tmp.zig:1:29: note: called from here",
+ );
+
+ cases.add(
"@ptrToInt 0 to non optional pointer",
\\export fn entry() void {
\\ var b = @intToPtr(*i32, 0);
@@ -553,15 +611,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
);
cases.add(
- "threadlocal qualifier on local variable",
- \\export fn entry() void {
- \\ threadlocal var x: i32 = 1234;
- \\}
- ,
- "tmp.zig:2:5: error: function-local variable 'x' cannot be threadlocal",
- );
-
- cases.add(
"@bitCast same size but bit count mismatch",
\\export fn entry(byte: u8) void {
\\ var oops = @bitCast(u7, byte);
@@ -839,7 +888,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = &x == null;
\\}
,
- "tmp.zig:3:12: error: only optionals (not '*i32') can compare to null",
+ "tmp.zig:3:12: error: comparison of '*i32' with null",
);
cases.add(
@@ -5347,8 +5396,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:12:20: note: referenced here",
);
- cases.add(
- "specify enum tag type that is too small",
+ cases.add("specify enum tag type that is too small",
\\const Small = enum (u2) {
\\ One,
\\ Two,
@@ -5360,9 +5408,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry() void {
\\ var x = Small.One;
\\}
- ,
- "tmp.zig:1:21: error: 'u2' too small to hold all bits; must be at least 'u3'",
- );
+ , "tmp.zig:6:5: error: enumeration value 4 too large for type 'u2'");
cases.add(
"specify non-integer enum tag type",
@@ -5413,22 +5459,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
);
cases.add(
- "non unsigned integer enum tag type",
- \\const Small = enum(i2) {
- \\ One,
- \\ Two,
- \\ Three,
- \\ Four,
- \\};
- \\
- \\export fn entry() void {
- \\ var y = Small.Two;
- \\}
- ,
- "tmp.zig:1:20: error: expected unsigned integer, found 'i2'",
- );
-
- cases.add(
"struct fields with value assignments",
\\const MultipleChoice = struct {
\\ A: i32 = 20,
@@ -5486,8 +5516,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x = MultipleChoice.C;
\\}
,
- "tmp.zig:6:9: error: enum tag value 60 already taken",
- "tmp.zig:4:9: note: other occurrence here",
+ "tmp.zig:6:5: error: enum tag value 60 already taken",
+ "tmp.zig:4:5: note: other occurrence here",
);
cases.add(
@@ -5892,4 +5922,21 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
,
"tmp.zig:3:23: error: expected type '[]u32', found '*const u32'",
);
+
+ cases.add(
+ "for loop body expression ignored",
+ \\fn returns() usize {
+ \\ return 2;
+ \\}
+ \\export fn f1() void {
+ \\ for ("hello") |_| returns();
+ \\}
+ \\export fn f2() void {
+ \\ var x: anyerror!i32 = error.Bad;
+ \\ for ("hello") |_| returns() else unreachable;
+ \\}
+ ,
+ "tmp.zig:5:30: error: expression value is ignored",
+ "tmp.zig:9:30: error: expression value is ignored",
+ );
}
diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig
index 78b45ac05f..b10accd213 100644
--- a/test/runtime_safety.zig
+++ b/test/runtime_safety.zig
@@ -1,6 +1,26 @@
const tests = @import("tests.zig");
pub fn addCases(cases: *tests.CompareOutputContext) void {
+ cases.addRuntimeSafety(".? operator on null pointer",
+ \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
+ \\ @import("std").os.exit(126);
+ \\}
+ \\pub fn main() void {
+ \\ var ptr: ?*i32 = null;
+ \\ var b = ptr.?;
+ \\}
+ );
+
+ cases.addRuntimeSafety(".? operator on C pointer",
+ \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
+ \\ @import("std").os.exit(126);
+ \\}
+ \\pub fn main() void {
+ \\ var ptr: [*c]i32 = null;
+ \\ var b = ptr.?;
+ \\}
+ );
+
cases.addRuntimeSafety("@ptrToInt address zero to non-optional pointer",
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
\\ @import("std").os.exit(126);
diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig
index da90660bf1..bc3be172ab 100644
--- a/test/stage1/behavior.zig
+++ b/test/stage1/behavior.zig
@@ -20,9 +20,12 @@ comptime {
_ = @import("behavior/bugs/1442.zig");
_ = @import("behavior/bugs/1486.zig");
_ = @import("behavior/bugs/1500.zig");
+ _ = @import("behavior/bugs/1607.zig");
_ = @import("behavior/bugs/1851.zig");
_ = @import("behavior/bugs/1914.zig");
_ = @import("behavior/bugs/2006.zig");
+ _ = @import("behavior/bugs/2114.zig");
+ _ = @import("behavior/bugs/2346.zig");
_ = @import("behavior/bugs/394.zig");
_ = @import("behavior/bugs/421.zig");
_ = @import("behavior/bugs/529.zig");
diff --git a/test/stage1/behavior/bit_shifting.zig b/test/stage1/behavior/bit_shifting.zig
index 610acc06c2..1877c8cdcb 100644
--- a/test/stage1/behavior/bit_shifting.zig
+++ b/test/stage1/behavior/bit_shifting.zig
@@ -86,3 +86,13 @@ fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, c
expect(table.get(@intCast(Key, i)) == node);
}
}
+
+// #2225
+test "comptime shr of BigInt" {
+ comptime {
+ var n0 = 0xdeadbeef0000000000000000;
+ std.debug.assert(n0 >> 64 == 0xdeadbeef);
+ var n1 = 17908056155735594659;
+ std.debug.assert(n1 >> 64 == 0);
+ }
+}
diff --git a/test/stage1/behavior/bugs/1607.zig b/test/stage1/behavior/bugs/1607.zig
new file mode 100644
index 0000000000..f32eeb03d6
--- /dev/null
+++ b/test/stage1/behavior/bugs/1607.zig
@@ -0,0 +1,15 @@
+const std = @import("std");
+const testing = std.testing;
+
+const a = []u8{ 1, 2, 3 };
+
+fn checkAddress(s: []const u8) void {
+ for (s) |*i, j| {
+ testing.expect(i == &a[j]);
+ }
+}
+
+test "slices pointing at the same address as global array." {
+ checkAddress(a);
+ comptime checkAddress(a);
+}
diff --git a/test/stage1/behavior/bugs/2114.zig b/test/stage1/behavior/bugs/2114.zig
new file mode 100644
index 0000000000..61ea2675b9
--- /dev/null
+++ b/test/stage1/behavior/bugs/2114.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const math = std.math;
+
+fn ctz(x: var) usize {
+ return @ctz(x);
+}
+
+test "fixed" {
+ testClz();
+ comptime testClz();
+}
+
+fn testClz() void {
+ expect(ctz(u128(0x40000000000000000000000000000000)) == 126);
+ expect(math.rotl(u128, u128(0x40000000000000000000000000000000), u8(1)) == u128(0x80000000000000000000000000000000));
+ expect(ctz(u128(0x80000000000000000000000000000000)) == 127);
+ expect(ctz(math.rotl(u128, u128(0x40000000000000000000000000000000), u8(1))) == 127);
+}
diff --git a/test/stage1/behavior/bugs/2346.zig b/test/stage1/behavior/bugs/2346.zig
new file mode 100644
index 0000000000..c8cea34813
--- /dev/null
+++ b/test/stage1/behavior/bugs/2346.zig
@@ -0,0 +1,6 @@
+test "fixed" {
+ const a: *void = undefined;
+ const b: *[1]void = a;
+ const c: *[0]u8 = undefined;
+ const d: []u8 = c;
+}
diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig
index f584fc265a..8a5edaa3dd 100644
--- a/test/stage1/behavior/enum.zig
+++ b/test/stage1/behavior/enum.zig
@@ -923,3 +923,42 @@ test "peer type resolution with enum literal" {
expect(Items.two == .two);
expect(.two == Items.two);
}
+
+test "enum literal in array literal" {
+ const Items = enum {
+ one,
+ two,
+ };
+
+ const array = []Items {
+ .one,
+ .two,
+ };
+
+ expect(array[0] == .one);
+ expect(array[1] == .two);
+}
+
+test "signed integer as enum tag" {
+ const SignedEnum = enum(i2) {
+ A0 = -1,
+ A1 = 0,
+ A2 = 1,
+ };
+
+ expect(@enumToInt(SignedEnum.A0) == -1);
+ expect(@enumToInt(SignedEnum.A1) == 0);
+ expect(@enumToInt(SignedEnum.A2) == 1);
+}
+
+test "enum value allocation" {
+ const LargeEnum = enum(u32) {
+ A0 = 0x80000000,
+ A1,
+ A2,
+ };
+
+ expect(@enumToInt(LargeEnum.A0) == 0x80000000);
+ expect(@enumToInt(LargeEnum.A1) == 0x80000001);
+ expect(@enumToInt(LargeEnum.A2) == 0x80000002);
+}
diff --git a/test/stage1/behavior/math.zig b/test/stage1/behavior/math.zig
index 23dc6d1feb..acbd9209df 100644
--- a/test/stage1/behavior/math.zig
+++ b/test/stage1/behavior/math.zig
@@ -632,3 +632,10 @@ fn testNanEqNan(comptime F: type) void {
expect(!(nan1 < nan2));
expect(!(nan1 <= nan2));
}
+
+test "128-bit multiplication" {
+ var a: i128 = 3;
+ var b: i128 = 2;
+ var c = a * b;
+ expect(c == 6);
+}
diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig
index be47718358..50b36fe583 100644
--- a/test/stage1/behavior/pointers.zig
+++ b/test/stage1/behavior/pointers.zig
@@ -150,3 +150,53 @@ test "allowzero pointer and slice" {
expect(@typeInfo(@typeOf(ptr)).Pointer.is_allowzero);
expect(@typeInfo(@typeOf(slice)).Pointer.is_allowzero);
}
+
+test "assign null directly to C pointer and test null equality" {
+ var x: [*c]i32 = null;
+ expect(x == null);
+ expect(null == x);
+ expect(!(x != null));
+ expect(!(null != x));
+ if (x) |same_x| {
+ @panic("fail");
+ }
+ var otherx: i32 = undefined;
+ expect((x orelse &otherx) == &otherx);
+
+ const y: [*c]i32 = null;
+ comptime expect(y == null);
+ comptime expect(null == y);
+ comptime expect(!(y != null));
+ comptime expect(!(null != y));
+ if (y) |same_y| @panic("fail");
+ const othery: i32 = undefined;
+ comptime expect((y orelse &othery) == &othery);
+
+ var n: i32 = 1234;
+ var x1: [*c]i32 = &n;
+ expect(!(x1 == null));
+ expect(!(null == x1));
+ expect(x1 != null);
+ expect(null != x1);
+ expect(x1.?.* == 1234);
+ if (x1) |same_x1| {
+ expect(same_x1.* == 1234);
+ } else {
+ @panic("fail");
+ }
+ expect((x1 orelse &otherx) == x1);
+
+ const nc: i32 = 1234;
+ const y1: [*c]const i32 = &nc;
+ comptime expect(!(y1 == null));
+ comptime expect(!(null == y1));
+ comptime expect(y1 != null);
+ comptime expect(null != y1);
+ comptime expect(y1.?.* == 1234);
+ if (y1) |same_y1| {
+ expect(same_y1.* == 1234);
+ } else {
+ @compileError("fail");
+ }
+ comptime expect((y1 orelse &othery) == y1);
+}
diff --git a/test/stage1/behavior/sizeof_and_typeof.zig b/test/stage1/behavior/sizeof_and_typeof.zig
index 58a6c81759..cfad311e06 100644
--- a/test/stage1/behavior/sizeof_and_typeof.zig
+++ b/test/stage1/behavior/sizeof_and_typeof.zig
@@ -67,3 +67,10 @@ test "@bitOffsetOf" {
expect(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f"));
expect(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
}
+
+test "@sizeOf on compile-time types" {
+ expect(@sizeOf(comptime_int) == 0);
+ expect(@sizeOf(comptime_float) == 0);
+ expect(@sizeOf(@typeOf(.hi)) == 0);
+ expect(@sizeOf(@typeOf(type)) == 0);
+}
diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig
index 62fb41ca28..114f06982b 100644
--- a/test/stage1/behavior/struct.zig
+++ b/test/stage1/behavior/struct.zig
@@ -2,8 +2,7 @@ const std = @import("std");
const expect = std.testing.expect;
const expectEqualSlices = std.testing.expectEqualSlices;
const builtin = @import("builtin");
-const maxInt = std.math.maxInt;
-
+const maxInt = std.math.maxInt;
const StructWithNoFields = struct {
fn add(a: i32, b: i32) i32 {
return a + b;
@@ -505,3 +504,22 @@ test "packed struct with u0 field access" {
var s = S{ .f0 = 0 };
comptime expect(s.f0 == 0);
}
+
+const S0 = struct{
+ bar: S1,
+
+ pub const S1 = struct{
+ value: u8,
+ };
+
+ fn init() @This() {
+ return S0{ .bar = S1{ .value = 123 } };
+ }
+};
+
+var g_foo: S0 = S0.init();
+
+test "access to global struct fields" {
+ g_foo.bar.value = 42;
+ expect(g_foo.bar.value == 42);
+}
diff --git a/test/stage1/behavior/syntax.zig b/test/stage1/behavior/syntax.zig
index 451e396142..12df8a4315 100644
--- a/test/stage1/behavior/syntax.zig
+++ b/test/stage1/behavior/syntax.zig
@@ -1,6 +1,14 @@
// Test trailing comma syntax
// zig fmt: off
+extern var a: c_int;
+extern "c" var b: c_int;
+export var c: c_int = 0;
+threadlocal var d: c_int;
+extern threadlocal var e: c_int;
+extern "c" threadlocal var f: c_int;
+export threadlocal var g: c_int = 0;
+
const struct_trailing_comma = struct { x: i32, y: i32, };
const struct_no_comma = struct { x: i32, y: i32 };
const struct_fn_no_comma = struct { fn m() void {} y: i32 };
diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig
index bbba867667..b8bb9a51b8 100644
--- a/test/stage1/behavior/union.zig
+++ b/test/stage1/behavior/union.zig
@@ -365,3 +365,40 @@ test "@enumToInt works on unions" {
expect(@enumToInt(b) == 1);
expect(@enumToInt(c) == 2);
}
+
+const Attribute = union(enum) {
+ A: bool,
+ B: u8,
+};
+
+fn setAttribute(attr: Attribute) void {}
+
+fn Setter(attr: Attribute) type {
+ return struct{
+ fn set() void {
+ setAttribute(attr);
+ }
+ };
+}
+
+test "comptime union field value equality" {
+ const a0 = Setter(Attribute{ .A = false });
+ const a1 = Setter(Attribute{ .A = true });
+ const a2 = Setter(Attribute{ .A = false });
+
+ const b0 = Setter(Attribute{ .B = 5 });
+ const b1 = Setter(Attribute{ .B = 9 });
+ const b2 = Setter(Attribute{ .B = 5 });
+
+ expect(a0 == a0);
+ expect(a1 == a1);
+ expect(a0 == a2);
+
+ expect(b0 == b0);
+ expect(b1 == b1);
+ expect(b0 == b2);
+
+ expect(a0 != b0);
+ expect(a0 != a1);
+ expect(b0 != b1);
+}
diff --git a/test/tests.zig b/test/tests.zig
index 61fd0426f1..4b67cf0f6c 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -903,6 +903,7 @@ pub const TranslateCContext = struct {
sources: ArrayList(SourceFile),
expected_lines: ArrayList([]const u8),
allow_warnings: bool,
+ stage2: bool,
const SourceFile = struct {
filename: []const u8,
@@ -955,7 +956,8 @@ pub const TranslateCContext = struct {
var zig_args = ArrayList([]const u8).init(b.allocator);
zig_args.append(b.zig_exe) catch unreachable;
- zig_args.append("translate-c") catch unreachable;
+ const translate_c_cmd = if (self.case.stage2) "translate-c-2" else "translate-c";
+ zig_args.append(translate_c_cmd) catch unreachable;
zig_args.append(b.pathFromRoot(root_src)) catch unreachable;
warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
@@ -1052,6 +1054,7 @@ pub const TranslateCContext = struct {
.sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
.expected_lines = ArrayList([]const u8).init(self.b.allocator),
.allow_warnings = allow_warnings,
+ .stage2 = false,
};
tc.addSourceFile(filename, source);
@@ -1072,6 +1075,34 @@ pub const TranslateCContext = struct {
self.addCase(tc);
}
+ pub fn add_both(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
+ for ([]bool{ false, true }) |stage2| {
+ const tc = self.create(false, "source.h", name, source, expected_lines);
+ tc.stage2 = stage2;
+ self.addCase(tc);
+ }
+ }
+
+ pub fn addC_both(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
+ for ([]bool{ false, true }) |stage2| {
+ const tc = self.create(false, "source.c", name, source, expected_lines);
+ tc.stage2 = stage2;
+ self.addCase(tc);
+ }
+ }
+
+ pub fn add_2(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
+ const tc = self.create(false, "source.h", name, source, expected_lines);
+ tc.stage2 = true;
+ self.addCase(tc);
+ }
+
+ pub fn addC_2(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
+ const tc = self.create(false, "source.c", name, source, expected_lines);
+ tc.stage2 = true;
+ self.addCase(tc);
+ }
+
pub fn addAllowWarnings(self: *TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) void {
const tc = self.create(true, "source.h", name, source, expected_lines);
self.addCase(tc);
@@ -1080,7 +1111,8 @@ pub const TranslateCContext = struct {
pub fn addCase(self: *TranslateCContext, case: *const TestCase) void {
const b = self.b;
- const annotated_case_name = fmt.allocPrint(self.b.allocator, "translate-c {}", case.name) catch unreachable;
+ const translate_c_cmd = if (case.stage2) "translate-c-2" else "translate-c";
+ const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {}", translate_c_cmd, case.name) catch unreachable;
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
}
diff --git a/test/translate_c.zig b/test/translate_c.zig
index cd8e7cb6d0..930442f293 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -1,7 +1,66 @@
const tests = @import("tests.zig");
const builtin = @import("builtin");
+// add_both - test for stage1 and stage2, in #include mode
+// add - test stage1 only, in #include mode
+// add_2 - test stage2 only, in #include mode
+// addC_both - test for stage1 and stage2, in -c mode
+// addC - test stage1 only, in -c mode
+// addC_2 - test stage2 only, in -c mode
+
pub fn addCases(cases: *tests.TranslateCContext) void {
+ /////////////// Cases that pass for both stage1/stage2 ////////////////
+ cases.add_both("simple function prototypes",
+ \\void __attribute__((noreturn)) foo(void);
+ \\int bar(void);
+ ,
+ \\pub extern fn foo() noreturn;
+ \\pub extern fn bar() c_int;
+ );
+
+ /////////////// Cases that pass for only stage2 ////////////////
+ cases.add_2("Parameterless function prototypes",
+ \\void a() {}
+ \\void b(void) {}
+ \\void c();
+ \\void d(void);
+ ,
+ \\pub export fn a() void {}
+ \\pub export fn b() void {}
+ \\pub extern fn c(...) void;
+ \\pub extern fn d() void;
+ );
+
+ cases.add_2("simple function definition",
+ \\void foo(void) {}
+ \\static void bar(void) {}
+ ,
+ \\pub export fn foo() void {}
+ \\pub extern fn bar() void {}
+ );
+
+ /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
+
+ cases.add("macro with left shift",
+ \\#define REDISMODULE_READ (1<<0)
+ ,
+ \\pub const REDISMODULE_READ = 1 << 0;
+ );
+
+ 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;
+ \\}
+ ,
+ \\pub extern fn foo() void;
+ \\pub fn bar() void {
+ \\ var func_ptr: ?*c_void = @ptrCast(?*c_void, foo);
+ \\ var typed_func_ptr: ?extern fn() void = @intToPtr(?extern fn() void, c_ulong(@ptrToInt(func_ptr)));
+ \\}
+ );
+
if (builtin.os != builtin.Os.windows) {
// Windows treats this as an enum with type c_int
cases.add("big negative enum init values when C ABI supports long long enums",
@@ -72,7 +131,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ _ = c"void foo(void)";
\\}
);
-
+
cases.add("ignore result",
\\void foo() {
\\ int a;
@@ -648,11 +707,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
,
\\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
\\ if ((a != 0) and (b != 0)) return 0;
- \\ if ((b != 0) and (c != 0)) return 1;
- \\ if ((a != 0) and (c != 0)) return 2;
+ \\ if ((b != 0) and (c != null)) return 1;
+ \\ if ((a != 0) and (c != null)) return 2;
\\ if ((a != 0) or (b != 0)) return 3;
- \\ if ((b != 0) or (c != 0)) return 4;
- \\ if ((a != 0) or (c != 0)) return 5;
+ \\ if ((b != 0) or (c != null)) return 4;
+ \\ if ((a != 0) or (c != null)) return 5;
\\ return 6;
\\}
);
@@ -832,7 +891,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
,
\\pub export fn foo() [*c]c_int {
- \\ return 0;
+ \\ return null;
\\}
);
@@ -1334,7 +1393,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
,
\\fn ptrcast(a: [*c]c_int) [*c]f32 {
- \\ return @ptrCast([*c]f32, a);
+ \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a));
\\}
);
@@ -1360,7 +1419,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return !(a == 0);
\\ return !(a != 0);
\\ return !(b != 0);
- \\ return !(c != 0);
+ \\ return !(c != null);
\\}
);
@@ -1417,7 +1476,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int {
\\ if (a != 0) return 0;
\\ if (b != 0) return 1;
- \\ if (c != 0) return 2;
+ \\ if (c != null) return 2;
\\ if (d != @bitCast(enum_SomeEnum, @TagType(enum_SomeEnum)(0))) return 3;
\\ return 4;
\\}
@@ -1434,7 +1493,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
\\ while (a != 0) return 0;
\\ while (b != 0) return 1;
- \\ while (c != 0) return 2;
+ \\ while (c != null) return 2;
\\ return 3;
\\}
);
@@ -1450,7 +1509,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
\\ while (a != 0) return 0;
\\ while (b != 0) return 1;
- \\ while (c != 0) return 2;
+ \\ while (c != null) return 2;
\\ return 3;
\\}
);
@@ -1497,14 +1556,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
);
- cases.addC("Parameterless function prototypes",
- \\void foo() {}
- \\void bar(void) {}
- ,
- \\pub export fn foo() void {}
- \\pub export fn bar() void {}
- );
-
cases.addC(
"u integer suffix after 0 (zero) in macro definition",
"#define ZERO 0U",
@@ -1553,33 +1604,101 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
"pub const NOT_ZERO = ~c_uint(0);",
);
- // cases.add("empty array with initializer",
- // "int a[4] = {};"
- // ,
- // "pub var a: [4]c_int = [1]c_int{0} ** 4;"
- // );
-
- // cases.add("array with initialization",
- // "int a[4] = {1, 2, 3, 4};"
- // ,
- // "pub var a: [4]c_int = [4]c_int{1, 2, 3, 4};"
- // );
-
- // cases.add("array with incomplete initialization",
- // "int a[4] = {3, 4};"
- // ,
- // "pub var a: [4]c_int = [2]c_int{3, 4} ++ ([1]c_int{0} ** 2);"
- // );
-
- // cases.add("2D array with initialization",
- // "int a[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };"
- // ,
- // "pub var a: [3][3]c_int = [3][3]c_int{[3]c_int{1, 2, 3}, [3]c_int{4, 5, 6}, [3]c_int{7, 8, 9}};"
- // );
-
- // cases.add("2D array with incomplete initialization",
- // "int a[3][3] = { {1, 2}, {4, 5, 6} };"
- // ,
- // "pub var a: [3][3]c_int = [2][3]c_int{[2]c_int{1, 2} ++ [1]c_int{0}, [3]c_int{4, 5, 6}} ++ [1][3]c_int{[1]c_int{0} ** 3};"
- // );
+ cases.addC("implicit casts",
+ \\#include <stdbool.h>
+ \\
+ \\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(int q) {
+ \\ fn_int(3.0f);
+ \\ fn_int(3.0);
+ \\ fn_int(3.0L);
+ \\ 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(&fn_int);
+ \\ fn_ptr(42);
+ \\}
+ ,
+ \\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: ?*c_void) void;
+ \\pub export fn call(q: c_int) void {
+ \\ fn_int(@floatToInt(c_int, 3.000000));
+ \\ fn_int(@floatToInt(c_int, 3.000000));
+ \\ fn_int(@floatToInt(c_int, 3.000000));
+ \\ fn_int(1094861636);
+ \\ fn_f32(@intToFloat(f32, 3));
+ \\ fn_f64(@intToFloat(f64, 3));
+ \\ fn_char(u8('3'));
+ \\ fn_char(u8('\x01'));
+ \\ fn_char(u8(0));
+ \\ fn_f32(3.000000);
+ \\ fn_f64(3.000000);
+ \\ fn_bool(true);
+ \\ fn_bool(false);
+ \\ fn_bool(@ptrToInt(&fn_int) != 0);
+ \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int)));
+ \\ fn_ptr(@intToPtr(?*c_void, 42));
+ \\}
+ );
+
+ cases.addC("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;
+ \\ }
+ \\}
+ ,
+ \\pub export fn test_ptr_cast() void {
+ \\ var p: ?*c_void = undefined;
+ \\ {
+ \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
+ \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
+ \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
+ \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
+ \\ }
+ \\ {
+ \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
+ \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
+ \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
+ \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
+ \\ }
+ \\}
+ );
+
+ /////////////// Cases for only stage1 because stage2 behavior is better ////////////////
+ cases.addC("Parameterless function prototypes",
+ \\void foo() {}
+ \\void bar(void) {}
+ ,
+ \\pub export fn foo() void {}
+ \\pub export fn bar() void {}
+ );
}