authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-03-28 11:53:37-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-03-28 11:53:37-07:00
logc808e546a766192c4a9bd45190d4bcfae61d6f3b
tree2be2310f30c3f7cbd69456ad0d1944e9c55885b8
parent7aa42f47b79f289829a1b43a68c8c08e374aa6a2
parent9106fdffaf772283acaa2fd24f9789d431a25586
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #19461 from Vexu/tests

add tests for stage1 bugs; remove cbe.zig

10 files changed, 132 insertions(+), 1018 deletions(-)

lib/std/packed_int_array.zig+53-43
......@@ -66,32 +66,31 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
6666
6767 fn getBits(bytes: []const u8, comptime Container: type, bit_index: usize) Int {
6868 const container_bits = @bitSizeOf(Container);
69 const Shift = std.math.Log2Int(Container);
7069
7170 const start_byte = bit_index / 8;
7271 const head_keep_bits = bit_index - (start_byte * 8);
7372 const tail_keep_bits = container_bits - (int_bits + head_keep_bits);
7473
7574 //read bytes as container
76 const value_ptr = @as(*align(1) const Container, @ptrCast(&bytes[start_byte]));
75 const value_ptr: *align(1) const Container = @ptrCast(&bytes[start_byte]);
7776 var value = value_ptr.*;
7877
7978 if (endian != native_endian) value = @byteSwap(value);
8079
8180 switch (endian) {
8281 .big => {
83 value <<= @as(Shift, @intCast(head_keep_bits));
84 value >>= @as(Shift, @intCast(head_keep_bits));
85 value >>= @as(Shift, @intCast(tail_keep_bits));
82 value <<= @intCast(head_keep_bits);
83 value >>= @intCast(head_keep_bits);
84 value >>= @intCast(tail_keep_bits);
8685 },
8786 .little => {
88 value <<= @as(Shift, @intCast(tail_keep_bits));
89 value >>= @as(Shift, @intCast(tail_keep_bits));
90 value >>= @as(Shift, @intCast(head_keep_bits));
87 value <<= @intCast(tail_keep_bits);
88 value >>= @intCast(tail_keep_bits);
89 value >>= @intCast(head_keep_bits);
9190 },
9291 }
9392
94 return @as(Int, @bitCast(@as(UnInt, @truncate(value))));
93 return @bitCast(@as(UnInt, @truncate(value)));
9594 }
9695
9796 /// Sets the integer at `index` to `val` within the packed data beginning
......@@ -114,16 +113,16 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
114113 const start_byte = bit_index / 8;
115114 const head_keep_bits = bit_index - (start_byte * 8);
116115 const tail_keep_bits = container_bits - (int_bits + head_keep_bits);
117 const keep_shift = switch (endian) {
118 .big => @as(Shift, @intCast(tail_keep_bits)),
119 .little => @as(Shift, @intCast(head_keep_bits)),
116 const keep_shift: Shift = switch (endian) {
117 .big => @intCast(tail_keep_bits),
118 .little => @intCast(head_keep_bits),
120119 };
121120
122121 //position the bits where they need to be in the container
123122 const value = @as(Container, @intCast(@as(UnInt, @bitCast(int)))) << keep_shift;
124123
125124 //read existing bytes
126 const target_ptr = @as(*align(1) Container, @ptrCast(&bytes[start_byte]));
125 const target_ptr: *align(1) Container = @ptrCast(&bytes[start_byte]);
127126 var target = target_ptr.*;
128127
129128 if (endian != native_endian) target = @byteSwap(target);
......@@ -156,7 +155,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
156155 if (length == 0) return PackedIntSliceEndian(Int, endian).init(new_bytes[0..0], 0);
157156
158157 var new_slice = PackedIntSliceEndian(Int, endian).init(new_bytes, length);
159 new_slice.bit_offset = @as(u3, @intCast((bit_index - (start_byte * 8))));
158 new_slice.bit_offset = @intCast((bit_index - (start_byte * 8)));
160159 return new_slice;
161160 }
162161
......@@ -214,15 +213,14 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim
214213 /// Initialize a packed array using an unpacked array
215214 /// or, more likely, an array literal.
216215 pub fn init(ints: [int_count]Int) Self {
217 var self = @as(Self, undefined);
216 var self: Self = undefined;
218217 for (ints, 0..) |int, i| self.set(i, int);
219218 return self;
220219 }
221220
222221 /// Initialize all entries of a packed array to the same value.
223222 pub fn initAllTo(int: Int) Self {
224 // TODO: use `var self = @as(Self, undefined);` https://github.com/ziglang/zig/issues/7635
225 var self = Self{ .bytes = [_]u8{0} ** total_bytes, .len = int_count };
223 var self: Self = undefined;
226224 self.setAll(int);
227225 return self;
228226 }
......@@ -365,11 +363,11 @@ test "PackedIntArray" {
365363 const expected_bytes = ((bits * int_count) + 7) / 8;
366364 try testing.expect(@sizeOf(PackedArray) == expected_bytes);
367365
368 var data = @as(PackedArray, undefined);
366 var data: PackedArray = undefined;
369367
370368 //write values, counting up
371 var i = @as(usize, 0);
372 var count = @as(I, 0);
369 var i: usize = 0;
370 var count: I = 0;
373371 while (i < data.len) : (i += 1) {
374372 data.set(i, count);
375373 if (bits > 0) count +%= 1;
......@@ -395,17 +393,29 @@ test "PackedIntIo" {
395393}
396394
397395test "PackedIntArray init" {
398 const PackedArray = PackedIntArray(u3, 8);
399 var packed_array = PackedArray.init([_]u3{ 0, 1, 2, 3, 4, 5, 6, 7 });
400 var i = @as(usize, 0);
401 while (i < packed_array.len) : (i += 1) try testing.expectEqual(@as(u3, @intCast(i)), packed_array.get(i));
396 const S = struct {
397 fn doTheTest() !void {
398 const PackedArray = PackedIntArray(u3, 8);
399 var packed_array = PackedArray.init([_]u3{ 0, 1, 2, 3, 4, 5, 6, 7 });
400 var i: usize = 0;
401 while (i < packed_array.len) : (i += 1) try testing.expectEqual(@as(u3, @intCast(i)), packed_array.get(i));
402 }
403 };
404 try S.doTheTest();
405 try comptime S.doTheTest();
402406}
403407
404408test "PackedIntArray initAllTo" {
405 const PackedArray = PackedIntArray(u3, 8);
406 var packed_array = PackedArray.initAllTo(5);
407 var i = @as(usize, 0);
408 while (i < packed_array.len) : (i += 1) try testing.expectEqual(@as(u3, 5), packed_array.get(i));
409 const S = struct {
410 fn doTheTest() !void {
411 const PackedArray = PackedIntArray(u3, 8);
412 var packed_array = PackedArray.initAllTo(5);
413 var i: usize = 0;
414 while (i < packed_array.len) : (i += 1) try testing.expectEqual(@as(u3, 5), packed_array.get(i));
415 }
416 };
417 try S.doTheTest();
418 try comptime S.doTheTest();
409419}
410420
411421test "PackedIntSlice" {
......@@ -433,8 +443,8 @@ test "PackedIntSlice" {
433443 var data = P.init(&buffer, int_count);
434444
435445 //write values, counting up
436 var i = @as(usize, 0);
437 var count = @as(I, 0);
446 var i: usize = 0;
447 var count: I = 0;
438448 while (i < data.len) : (i += 1) {
439449 data.set(i, count);
440450 if (bits > 0) count +%= 1;
......@@ -463,13 +473,13 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {
463473 const Int = std.meta.Int(.unsigned, bits);
464474
465475 const PackedArray = PackedIntArray(Int, int_count);
466 var packed_array = @as(PackedArray, undefined);
476 var packed_array: PackedArray = undefined;
467477
468478 const limit = (1 << bits);
469479
470 var i = @as(usize, 0);
480 var i: usize = 0;
471481 while (i < packed_array.len) : (i += 1) {
472 packed_array.set(i, @as(Int, @intCast(i % limit)));
482 packed_array.set(i, @intCast(i % limit));
473483 }
474484
475485 //slice of array
......@@ -524,20 +534,20 @@ test "PackedIntSlice accumulating bit offsets" {
524534 // anything
525535 {
526536 const PackedArray = PackedIntArray(u3, 16);
527 var packed_array = @as(PackedArray, undefined);
537 var packed_array: PackedArray = undefined;
528538
529539 var packed_slice = packed_array.slice(0, packed_array.len);
530 var i = @as(usize, 0);
540 var i: usize = 0;
531541 while (i < packed_array.len - 1) : (i += 1) {
532542 packed_slice = packed_slice.slice(1, packed_slice.len);
533543 }
534544 }
535545 {
536546 const PackedArray = PackedIntArray(u11, 88);
537 var packed_array = @as(PackedArray, undefined);
547 var packed_array: PackedArray = undefined;
538548
539549 var packed_slice = packed_array.slice(0, packed_array.len);
540 var i = @as(usize, 0);
550 var i: usize = 0;
541551 while (i < packed_array.len - 1) : (i += 1) {
542552 packed_slice = packed_slice.slice(1, packed_slice.len);
543553 }
......@@ -552,7 +562,7 @@ test "PackedInt(Array/Slice) sliceCast" {
552562 var packed_slice_cast_9 = packed_array.slice(0, (packed_array.len / 9) * 9).sliceCast(u9);
553563 const packed_slice_cast_3 = packed_slice_cast_9.sliceCast(u3);
554564
555 var i = @as(usize, 0);
565 var i: usize = 0;
556566 while (i < packed_slice_cast_2.len) : (i += 1) {
557567 const val = switch (native_endian) {
558568 .big => 0b01,
......@@ -576,9 +586,9 @@ test "PackedInt(Array/Slice) sliceCast" {
576586 }
577587 i = 0;
578588 while (i < packed_slice_cast_3.len) : (i += 1) {
579 const val = switch (native_endian) {
580 .big => if (i % 2 == 0) @as(u3, 0b111) else @as(u3, 0b000),
581 .little => if (i % 2 == 0) @as(u3, 0b111) else @as(u3, 0b000),
589 const val: u3 = switch (native_endian) {
590 .big => if (i % 2 == 0) 0b111 else 0b000,
591 .little => if (i % 2 == 0) 0b111 else 0b000,
582592 };
583593 try testing.expect(packed_slice_cast_3.get(i) == val);
584594 }
......@@ -591,7 +601,7 @@ test "PackedInt(Array/Slice)Endian" {
591601 try testing.expect(packed_array_be.bytes[0] == 0b00000001);
592602 try testing.expect(packed_array_be.bytes[1] == 0b00100011);
593603
594 var i = @as(usize, 0);
604 var i: usize = 0;
595605 while (i < packed_array_be.len) : (i += 1) {
596606 try testing.expect(packed_array_be.get(i) == i);
597607 }
......@@ -620,7 +630,7 @@ test "PackedInt(Array/Slice)Endian" {
620630 try testing.expect(packed_array_be.bytes[3] == 0b00000001);
621631 try testing.expect(packed_array_be.bytes[4] == 0b00000000);
622632
623 var i = @as(usize, 0);
633 var i: usize = 0;
624634 while (i < packed_array_be.len) : (i += 1) {
625635 try testing.expect(packed_array_be.get(i) == i);
626636 }
src/Sema.zig+15
......@@ -22636,6 +22636,21 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
2263622636 if (dest_tag == .ErrorSet and operand_tag == .ErrorUnion) {
2263722637 return sema.fail(block, src, "cannot cast an error union type to error set", .{});
2263822638 }
22639 if (dest_tag == .ErrorUnion and operand_tag == .ErrorUnion and
22640 base_dest_ty.errorUnionPayload(mod).toIntern() != base_operand_ty.errorUnionPayload(mod).toIntern())
22641 {
22642 return sema.failWithOwnedErrorMsg(block, msg: {
22643 const msg = try sema.errMsg(block, src, "payload types of error unions must match", .{});
22644 errdefer msg.destroy(sema.gpa);
22645 const dest_ty = base_dest_ty.errorUnionPayload(mod);
22646 const operand_ty = base_operand_ty.errorUnionPayload(mod);
22647 try sema.errNote(block, src, msg, "destination payload is '{}'", .{dest_ty.fmt(mod)});
22648 try sema.errNote(block, src, msg, "operand payload is '{}'", .{operand_ty.fmt(mod)});
22649 try addDeclaredHereNote(sema, msg, dest_ty);
22650 try addDeclaredHereNote(sema, msg, operand_ty);
22651 break :msg msg;
22652 });
22653 }
2263922654 const dest_ty = if (dest_tag == .ErrorUnion) base_dest_ty.errorUnionSet(mod) else base_dest_ty;
2264022655 const operand_ty = if (operand_tag == .ErrorUnion) base_operand_ty.errorUnionSet(mod) else base_operand_ty;
2264122656
test/behavior/error.zig+10
......@@ -930,6 +930,16 @@ test "optional error set return type" {
930930 try expect(E.A == S.foo(false).?);
931931}
932932
933test "optional error set function parameter" {
934 const S = struct {
935 fn doTheTest(a: ?anyerror) !void {
936 try std.testing.expect(a.? == error.OutOfMemory);
937 }
938 };
939 try S.doTheTest(error.OutOfMemory);
940 try comptime S.doTheTest(error.OutOfMemory);
941}
942
933943test "returning an error union containing a type with no runtime bits" {
934944 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
935945 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
test/cases.zig-1
......@@ -11,7 +11,6 @@ pub const BuildOptions = struct {
1111
1212pub fn addCases(cases: *Cases, build_options: BuildOptions, b: *std.Build) !void {
1313 try @import("compile_errors.zig").addCases(cases, b);
14 try @import("cbe.zig").addCases(cases, b);
1514 try @import("llvm_targets.zig").addCases(cases, build_options, b);
1615 try @import("nvptx.zig").addCases(cases, b);
1716}
test/cases/compile_errors/@errorCast_with_bad_type.zig+8
......@@ -13,6 +13,11 @@ export fn entry3() void {
1313 const a: anyerror = @errorCast(e);
1414 _ = a;
1515}
16pub export fn entry4() void {
17 const a: anyerror!u32 = 123;
18 const b: anyerror!f32 = @errorCast(a);
19 _ = b;
20}
1621
1722// error
1823// backend=stage2
......@@ -21,3 +26,6 @@ export fn entry3() void {
2126// :4:25: error: expected error set or error union type, found 'ComptimeInt'
2227// :8:20: error: expected error set or error union type, found 'Int'
2328// :13:25: error: cannot cast an error union type to error set
29// :18:29: error: payload types of error unions must match
30// :18:29: note: destination payload is 'f32'
31// :18:29: note: operand payload is 'u32'
test/cases/compile_errors/error_union_field_default_init.zig created+13
......@@ -0,0 +1,13 @@
1const Input = struct {
2 value: u32 = @as(error{}!u32, 0),
3};
4export fn foo() void {
5 var x: Input = Input{};
6 _ = &x;
7}
8
9// error
10//
11//:2:18: error: expected type 'u32', found 'error{}!u32'
12//:2:18: note: cannot convert error union to payload type
13//:2:18: note: consider using 'try', 'catch', or 'if'
test/cases/compile_errors/type_error_union_field_type.zig created+16
......@@ -0,0 +1,16 @@
1fn CreateType() !type {
2 return struct {};
3}
4const MyType = CreateType();
5const TestType = struct {
6 my_type: MyType,
7};
8comptime {
9 _ = @sizeOf(TestType) + 1;
10}
11
12// error
13//
14//:6:14: error: expected type 'type', found 'error{}!type'
15//:6:14: note: cannot convert error union to payload type
16//:6:14: note: consider using 'try', 'catch', or 'if'
test/cases/translate_c/align() attribute.c created+17
......@@ -0,0 +1,17 @@
1__attribute__ ((aligned(128)))
2extern char my_array[16];
3__attribute__ ((aligned(128)))
4void my_fn(void) { }
5void other_fn(void) {
6 char ARR[16] __attribute__ ((aligned (16)));
7}
8
9// translate-c
10// c_frontend=clang
11//
12// pub extern var my_array: [16]u8 align(128);
13// pub export fn my_fn() align(128) void {}
14// pub export fn other_fn() void {
15// var ARR: [16]u8 align(16) = undefined;
16// _ = &ARR;
17// }
test/cbe.zig deleted-953
......@@ -1,953 +0,0 @@
1const std = @import("std");
2const Cases = @import("src/Cases.zig");
3const nl = if (@import("builtin").os.tag == .windows) "\r\n" else "\n";
4
5pub fn addCases(ctx: *Cases, b: *std.Build) !void {
6 // These tests should work with all platforms, but we're using linux_x64 for
7 // now for consistency. Will be expanded eventually.
8 const linux_x64: std.Target.Query = .{
9 .cpu_arch = .x86_64,
10 .os_tag = .linux,
11 };
12
13 {
14 var case = ctx.exeFromCompiledC("hello world with updates", .{}, b);
15
16 // Regular old hello world
17 case.addCompareOutput(
18 \\extern fn puts(s: [*:0]const u8) c_int;
19 \\pub export fn main() c_int {
20 \\ _ = puts("hello world!");
21 \\ return 0;
22 \\}
23 , "hello world!" ++ nl);
24
25 // Now change the message only
26 case.addCompareOutput(
27 \\extern fn puts(s: [*:0]const u8) c_int;
28 \\pub export fn main() c_int {
29 \\ _ = puts("yo");
30 \\ return 0;
31 \\}
32 , "yo" ++ nl);
33
34 // Add an unused Decl
35 case.addCompareOutput(
36 \\extern fn puts(s: [*:0]const u8) c_int;
37 \\pub export fn main() c_int {
38 \\ _ = puts("yo!");
39 \\ return 0;
40 \\}
41 \\fn unused() void {}
42 , "yo!" ++ nl);
43
44 // Comptime return type and calling convention expected.
45 case.addError(
46 \\var x: i32 = 1234;
47 \\pub export fn main() x {
48 \\ return 0;
49 \\}
50 \\export fn foo() callconv(y) c_int {
51 \\ return 0;
52 \\}
53 \\var y: @import("std").builtin.CallingConvention = .C;
54 , &.{
55 ":2:22: error: expected type 'type', found 'i32'",
56 ":5:26: error: unable to resolve comptime value",
57 ":5:26: note: calling convention must be comptime-known",
58 });
59 }
60
61 {
62 var case = ctx.exeFromCompiledC("var args", .{}, b);
63
64 case.addCompareOutput(
65 \\extern fn printf(format: [*:0]const u8, ...) c_int;
66 \\
67 \\pub export fn main() c_int {
68 \\ _ = printf("Hello, %s!\n", "world");
69 \\ return 0;
70 \\}
71 , "Hello, world!" ++ nl);
72 }
73
74 {
75 var case = ctx.exeFromCompiledC("errorFromInt", .{}, b);
76
77 case.addCompareOutput(
78 \\pub export fn main() c_int {
79 \\ // comptime checks
80 \\ const a = error.A;
81 \\ const b = error.B;
82 \\ const c = @errorFromInt(2);
83 \\ const d = @errorFromInt(1);
84 \\ if (!(c == b)) unreachable;
85 \\ if (!(a == d)) unreachable;
86 \\ // runtime checks
87 \\ var x = error.A;
88 \\ var y = error.B;
89 \\ var z = @errorFromInt(2);
90 \\ var f = @errorFromInt(1);
91 \\ if (!(y == z)) unreachable;
92 \\ if (!(x == f)) unreachable;
93 \\ return 0;
94 \\}
95 , "");
96 case.addError(
97 \\pub export fn main() c_int {
98 \\ _ = @errorFromInt(0);
99 \\ return 0;
100 \\}
101 , &.{":2:21: error: integer value '0' represents no error"});
102 case.addError(
103 \\pub export fn main() c_int {
104 \\ _ = @errorFromInt(3);
105 \\ return 0;
106 \\}
107 , &.{":2:21: error: integer value '3' represents no error"});
108 }
109
110 {
111 var case = ctx.exeFromCompiledC("x86_64-linux inline assembly", linux_x64, b);
112
113 // Exit with 0
114 case.addCompareOutput(
115 \\fn exitGood() noreturn {
116 \\ asm volatile ("syscall"
117 \\ :
118 \\ : [number] "{rax}" (231),
119 \\ [arg1] "{rdi}" (0)
120 \\ );
121 \\ unreachable;
122 \\}
123 \\
124 \\pub export fn main() c_int {
125 \\ exitGood();
126 \\}
127 , "");
128
129 // Pass a usize parameter to exit
130 case.addCompareOutput(
131 \\pub export fn main() c_int {
132 \\ exit(0);
133 \\}
134 \\
135 \\fn exit(code: usize) noreturn {
136 \\ asm volatile ("syscall"
137 \\ :
138 \\ : [number] "{rax}" (231),
139 \\ [arg1] "{rdi}" (code)
140 \\ );
141 \\ unreachable;
142 \\}
143 , "");
144
145 // Change the parameter to u8
146 case.addCompareOutput(
147 \\pub export fn main() c_int {
148 \\ exit(0);
149 \\}
150 \\
151 \\fn exit(code: u8) noreturn {
152 \\ asm volatile ("syscall"
153 \\ :
154 \\ : [number] "{rax}" (231),
155 \\ [arg1] "{rdi}" (code)
156 \\ );
157 \\ unreachable;
158 \\}
159 , "");
160
161 // Do some arithmetic at the exit callsite
162 case.addCompareOutput(
163 \\pub export fn main() c_int {
164 \\ exitMath(1);
165 \\}
166 \\
167 \\fn exitMath(a: u8) noreturn {
168 \\ exit(0 + a - a);
169 \\}
170 \\
171 \\fn exit(code: u8) noreturn {
172 \\ asm volatile ("syscall"
173 \\ :
174 \\ : [number] "{rax}" (231),
175 \\ [arg1] "{rdi}" (code)
176 \\ );
177 \\ unreachable;
178 \\}
179 \\
180 , "");
181
182 // Invert the arithmetic
183 case.addCompareOutput(
184 \\pub export fn main() c_int {
185 \\ exitMath(1);
186 \\}
187 \\
188 \\fn exitMath(a: u8) noreturn {
189 \\ exit(a + 0 - a);
190 \\}
191 \\
192 \\fn exit(code: u8) noreturn {
193 \\ asm volatile ("syscall"
194 \\ :
195 \\ : [number] "{rax}" (231),
196 \\ [arg1] "{rdi}" (code)
197 \\ );
198 \\ unreachable;
199 \\}
200 \\
201 , "");
202 }
203
204 {
205 var case = ctx.exeFromCompiledC("alloc and retptr", .{}, b);
206
207 case.addCompareOutput(
208 \\fn add(a: i32, b: i32) i32 {
209 \\ return a + b;
210 \\}
211 \\
212 \\fn addIndirect(a: i32, b: i32) i32 {
213 \\ return add(a, b);
214 \\}
215 \\
216 \\pub export fn main() c_int {
217 \\ return addIndirect(1, 2) - 3;
218 \\}
219 , "");
220 }
221
222 {
223 var case = ctx.exeFromCompiledC("inferred local const and var", .{}, b);
224
225 case.addCompareOutput(
226 \\fn add(a: i32, b: i32) i32 {
227 \\ return a + b;
228 \\}
229 \\
230 \\pub export fn main() c_int {
231 \\ const x = add(1, 2);
232 \\ var y = add(3, 0);
233 \\ y -= x;
234 \\ return y;
235 \\}
236 , "");
237 }
238 {
239 var case = ctx.exeFromCompiledC("control flow", .{}, b);
240
241 // Simple while loop
242 case.addCompareOutput(
243 \\pub export fn main() c_int {
244 \\ var a: c_int = 0;
245 \\ while (a < 5) : (a+=1) {}
246 \\ return a - 5;
247 \\}
248 , "");
249 case.addCompareOutput(
250 \\pub export fn main() c_int {
251 \\ var a = true;
252 \\ while (!a) {}
253 \\ return 0;
254 \\}
255 , "");
256
257 // If expression
258 case.addCompareOutput(
259 \\pub export fn main() c_int {
260 \\ var cond: c_int = 0;
261 \\ var a: c_int = @as(c_int, if (cond == 0)
262 \\ 2
263 \\ else
264 \\ 3) + 9;
265 \\ return a - 11;
266 \\}
267 , "");
268
269 // If expression with breakpoint that does not get hit
270 case.addCompareOutput(
271 \\pub export fn main() c_int {
272 \\ var x: i32 = 1;
273 \\ if (x != 1) @breakpoint();
274 \\ return 0;
275 \\}
276 , "");
277
278 // Switch expression
279 case.addCompareOutput(
280 \\pub export fn main() c_int {
281 \\ var cond: c_int = 0;
282 \\ var a: c_int = switch (cond) {
283 \\ 1 => 1,
284 \\ 2 => 2,
285 \\ 99...300, 12 => 3,
286 \\ 0 => 4,
287 \\ else => 5,
288 \\ };
289 \\ return a - 4;
290 \\}
291 , "");
292
293 // Switch expression missing else case.
294 case.addError(
295 \\pub export fn main() c_int {
296 \\ var cond: c_int = 0;
297 \\ const a: c_int = switch (cond) {
298 \\ 1 => 1,
299 \\ 2 => 2,
300 \\ 3 => 3,
301 \\ 4 => 4,
302 \\ };
303 \\ return a - 4;
304 \\}
305 , &.{":3:22: error: switch must handle all possibilities"});
306
307 // Switch expression, has an unreachable prong.
308 case.addCompareOutput(
309 \\pub export fn main() c_int {
310 \\ var cond: c_int = 0;
311 \\ const a: c_int = switch (cond) {
312 \\ 1 => 1,
313 \\ 2 => 2,
314 \\ 99...300, 12 => 3,
315 \\ 0 => 4,
316 \\ 13 => unreachable,
317 \\ else => 5,
318 \\ };
319 \\ return a - 4;
320 \\}
321 , "");
322
323 // Switch expression, has an unreachable prong and prongs write
324 // to result locations.
325 case.addCompareOutput(
326 \\pub export fn main() c_int {
327 \\ var cond: c_int = 0;
328 \\ var a: c_int = switch (cond) {
329 \\ 1 => 1,
330 \\ 2 => 2,
331 \\ 99...300, 12 => 3,
332 \\ 0 => 4,
333 \\ 13 => unreachable,
334 \\ else => 5,
335 \\ };
336 \\ return a - 4;
337 \\}
338 , "");
339
340 // Integer switch expression has duplicate case value.
341 case.addError(
342 \\pub export fn main() c_int {
343 \\ var cond: c_int = 0;
344 \\ const a: c_int = switch (cond) {
345 \\ 1 => 1,
346 \\ 2 => 2,
347 \\ 96, 11...13, 97 => 3,
348 \\ 0 => 4,
349 \\ 90, 12 => 100,
350 \\ else => 5,
351 \\ };
352 \\ return a - 4;
353 \\}
354 , &.{
355 ":8:13: error: duplicate switch value",
356 ":6:15: note: previous value here",
357 });
358
359 // Boolean switch expression has duplicate case value.
360 case.addError(
361 \\pub export fn main() c_int {
362 \\ var a: bool = false;
363 \\ const b: c_int = switch (a) {
364 \\ false => 1,
365 \\ true => 2,
366 \\ false => 3,
367 \\ };
368 \\ _ = b;
369 \\}
370 , &.{
371 ":6:9: error: duplicate switch value",
372 });
373
374 // Sparse (no range capable) switch expression has duplicate case value.
375 case.addError(
376 \\pub export fn main() c_int {
377 \\ const A: type = i32;
378 \\ const b: c_int = switch (A) {
379 \\ i32 => 1,
380 \\ bool => 2,
381 \\ f64, i32 => 3,
382 \\ else => 4,
383 \\ };
384 \\ _ = b;
385 \\}
386 , &.{
387 ":6:14: error: duplicate switch value",
388 ":4:9: note: previous value here",
389 });
390
391 // Ranges not allowed for some kinds of switches.
392 case.addError(
393 \\pub export fn main() c_int {
394 \\ const A: type = i32;
395 \\ const b: c_int = switch (A) {
396 \\ i32 => 1,
397 \\ bool => 2,
398 \\ f16...f64 => 3,
399 \\ else => 4,
400 \\ };
401 \\ _ = b;
402 \\}
403 , &.{
404 ":3:30: error: ranges not allowed when switching on type 'type'",
405 ":6:12: note: range here",
406 });
407
408 // Switch expression has unreachable else prong.
409 case.addError(
410 \\pub export fn main() c_int {
411 \\ var a: u2 = 0;
412 \\ const b: i32 = switch (a) {
413 \\ 0 => 10,
414 \\ 1 => 20,
415 \\ 2 => 30,
416 \\ 3 => 40,
417 \\ else => 50,
418 \\ };
419 \\ _ = b;
420 \\}
421 , &.{
422 ":8:14: error: unreachable else prong; all cases already handled",
423 });
424 }
425 //{
426 // var case = ctx.exeFromCompiledC("optionals", .{}, b);
427
428 // // Simple while loop
429 // case.addCompareOutput(
430 // \\pub export fn main() c_int {
431 // \\ var count: c_int = 0;
432 // \\ var opt_ptr: ?*c_int = &count;
433 // \\ while (opt_ptr) |_| : (count += 1) {
434 // \\ if (count == 4) opt_ptr = null;
435 // \\ }
436 // \\ return count - 5;
437 // \\}
438 // , "");
439
440 // // Same with non pointer optionals
441 // case.addCompareOutput(
442 // \\pub export fn main() c_int {
443 // \\ var count: c_int = 0;
444 // \\ var opt_ptr: ?c_int = count;
445 // \\ while (opt_ptr) |_| : (count += 1) {
446 // \\ if (count == 4) opt_ptr = null;
447 // \\ }
448 // \\ return count - 5;
449 // \\}
450 // , "");
451 //}
452
453 {
454 var case = ctx.exeFromCompiledC("errors", .{}, b);
455 case.addCompareOutput(
456 \\pub export fn main() c_int {
457 \\ var e1 = error.Foo;
458 \\ var e2 = error.Bar;
459 \\ assert(e1 != e2);
460 \\ assert(e1 == error.Foo);
461 \\ assert(e2 == error.Bar);
462 \\ return 0;
463 \\}
464 \\fn assert(b: bool) void {
465 \\ if (!b) unreachable;
466 \\}
467 , "");
468 case.addCompareOutput(
469 \\pub export fn main() c_int {
470 \\ var e: anyerror!c_int = 0;
471 \\ const i = e catch 69;
472 \\ return i;
473 \\}
474 , "");
475 case.addCompareOutput(
476 \\pub export fn main() c_int {
477 \\ var e: anyerror!c_int = error.Foo;
478 \\ const i = e catch 69;
479 \\ return 69 - i;
480 \\}
481 , "");
482 case.addCompareOutput(
483 \\const E = error{e};
484 \\const S = struct { x: u32 };
485 \\fn f() E!u32 {
486 \\ const x = (try @as(E!S, S{ .x = 1 })).x;
487 \\ return x;
488 \\}
489 \\pub export fn main() c_int {
490 \\ const x = f() catch @as(u32, 0);
491 \\ if (x != 1) unreachable;
492 \\ return 0;
493 \\}
494 , "");
495 }
496
497 {
498 var case = ctx.exeFromCompiledC("structs", .{}, b);
499 case.addError(
500 \\const Point = struct { x: i32, y: i32 };
501 \\pub export fn main() c_int {
502 \\ var p: Point = .{
503 \\ .y = 24,
504 \\ .x = 12,
505 \\ .y = 24,
506 \\ };
507 \\ return p.y - p.x - p.x;
508 \\}
509 , &.{
510 ":4:10: error: duplicate struct field name",
511 ":6:10: note: duplicate name here",
512 ":3:21: note: struct declared here",
513 });
514 case.addError(
515 \\const Point = struct { x: i32, y: i32 };
516 \\pub export fn main() c_int {
517 \\ var p: Point = .{
518 \\ .y = 24,
519 \\ };
520 \\ return p.y - p.x - p.x;
521 \\}
522 , &.{
523 ":3:21: error: missing struct field: x",
524 ":1:15: note: struct 'tmp.Point' declared here",
525 });
526 case.addError(
527 \\const Point = struct { x: i32, y: i32 };
528 \\pub export fn main() c_int {
529 \\ var p: Point = .{
530 \\ .x = 12,
531 \\ .y = 24,
532 \\ .z = 48,
533 \\ };
534 \\ return p.y - p.x - p.x;
535 \\}
536 , &.{
537 ":6:10: error: no field named 'z' in struct 'tmp.Point'",
538 ":1:15: note: struct declared here",
539 });
540 case.addCompareOutput(
541 \\const Point = struct { x: i32, y: i32 };
542 \\pub export fn main() c_int {
543 \\ var p: Point = .{
544 \\ .x = 12,
545 \\ .y = 24,
546 \\ };
547 \\ return p.y - p.x - p.x;
548 \\}
549 , "");
550 case.addCompareOutput(
551 \\const Point = struct { x: i32, y: i32, z: i32, a: i32, b: i32 };
552 \\pub export fn main() c_int {
553 \\ var p: Point = .{
554 \\ .x = 18,
555 \\ .y = 24,
556 \\ .z = 1,
557 \\ .a = 2,
558 \\ .b = 3,
559 \\ };
560 \\ return p.y - p.x - p.z - p.a - p.b;
561 \\}
562 , "");
563 }
564
565 {
566 var case = ctx.exeFromCompiledC("unions", .{}, b);
567
568 case.addError(
569 \\const U = union {
570 \\ a: u32,
571 \\ b
572 \\};
573 , &.{
574 ":3:5: error: union field missing type",
575 });
576
577 case.addError(
578 \\const E = enum { a, b };
579 \\const U = union(E) {
580 \\ a: u32 = 1,
581 \\ b: f32 = 2,
582 \\};
583 , &.{
584 ":2:11: error: explicitly valued tagged union requires inferred enum tag type",
585 ":3:14: note: tag value specified here",
586 });
587
588 case.addError(
589 \\const U = union(enum) {
590 \\ a: u32 = 1,
591 \\ b: f32 = 2,
592 \\};
593 , &.{
594 ":1:11: error: explicitly valued tagged union missing integer tag type",
595 ":2:14: note: tag value specified here",
596 });
597 }
598
599 {
600 var case = ctx.exeFromCompiledC("enums", .{}, b);
601
602 case.addError(
603 \\const E1 = packed enum { a, b, c };
604 \\const E2 = extern enum { a, b, c };
605 \\export fn foo() void {
606 \\ _ = E1.a;
607 \\}
608 \\export fn bar() void {
609 \\ _ = E2.a;
610 \\}
611 , &.{
612 ":1:12: error: enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type",
613 ":2:12: error: enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type",
614 });
615
616 // comptime and types are caught in AstGen.
617 case.addError(
618 \\const E1 = enum {
619 \\ a,
620 \\ comptime b,
621 \\ c,
622 \\};
623 \\const E2 = enum {
624 \\ a,
625 \\ b: i32,
626 \\ c,
627 \\};
628 \\export fn foo() void {
629 \\ _ = E1.a;
630 \\}
631 \\export fn bar() void {
632 \\ _ = E2.a;
633 \\}
634 , &.{
635 ":3:5: error: enum fields cannot be marked comptime",
636 ":8:8: error: enum fields do not have types",
637 ":6:12: note: consider 'union(enum)' here to make it a tagged union",
638 });
639
640 // @intFromEnum, @enumFromInt, enum literal coercion, field access syntax, comparison, switch
641 case.addCompareOutput(
642 \\const Number = enum { One, Two, Three };
643 \\
644 \\pub export fn main() c_int {
645 \\ var number1 = Number.One;
646 \\ var number2: Number = .Two;
647 \\ const number3: Number = @enumFromInt(2);
648 \\ if (number1 == number2) return 1;
649 \\ if (number2 == number3) return 1;
650 \\ if (@intFromEnum(number1) != 0) return 1;
651 \\ if (@intFromEnum(number2) != 1) return 1;
652 \\ if (@intFromEnum(number3) != 2) return 1;
653 \\ var x: Number = .Two;
654 \\ if (number2 != x) return 1;
655 \\ switch (x) {
656 \\ .One => return 1,
657 \\ .Two => return 0,
658 \\ number3 => return 2,
659 \\ }
660 \\}
661 , "");
662
663 // Specifying alignment is a parse error.
664 // This also tests going from a successful build to a parse error.
665 case.addError(
666 \\const E1 = enum {
667 \\ a,
668 \\ b align(4),
669 \\ c,
670 \\};
671 \\export fn foo() void {
672 \\ _ = E1.a;
673 \\}
674 , &.{
675 ":3:13: error: enum fields cannot be aligned",
676 });
677
678 // Redundant non-exhaustive enum mark.
679 // This also tests going from a parse error to an AstGen error.
680 case.addError(
681 \\const E1 = enum {
682 \\ a,
683 \\ _,
684 \\ b,
685 \\ c,
686 \\ _,
687 \\};
688 \\export fn foo() void {
689 \\ _ = E1.a;
690 \\}
691 , &.{
692 ":6:5: error: redundant non-exhaustive enum mark",
693 ":3:5: note: other mark here",
694 });
695
696 case.addError(
697 \\const E1 = enum {
698 \\ a,
699 \\ b,
700 \\ c,
701 \\ _ = 10,
702 \\};
703 \\export fn foo() void {
704 \\ _ = E1.a;
705 \\}
706 , &.{
707 ":5:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value",
708 });
709
710 case.addError(
711 \\const E1 = enum { a, b, _ };
712 \\export fn foo() void {
713 \\ _ = E1.a;
714 \\}
715 , &.{
716 ":1:12: error: non-exhaustive enum missing integer tag type",
717 ":1:25: note: marked non-exhaustive here",
718 });
719
720 case.addError(
721 \\const E1 = enum { a, b, c, b, d };
722 \\pub export fn main() c_int {
723 \\ _ = E1.a;
724 \\}
725 , &.{
726 ":1:22: error: duplicate enum field name",
727 ":1:28: note: duplicate field here",
728 ":1:12: note: enum declared here",
729 });
730
731 case.addError(
732 \\pub export fn main() c_int {
733 \\ const a = true;
734 \\ _ = @intFromEnum(a);
735 \\}
736 , &.{
737 ":3:20: error: expected enum or tagged union, found 'bool'",
738 });
739
740 case.addError(
741 \\pub export fn main() c_int {
742 \\ const a = 1;
743 \\ _ = @as(bool, @enumFromInt(a));
744 \\}
745 , &.{
746 ":3:19: error: expected enum, found 'bool'",
747 });
748
749 case.addError(
750 \\const E = enum { a, b, c };
751 \\pub export fn main() c_int {
752 \\ _ = @as(E, @enumFromInt(3));
753 \\}
754 , &.{
755 ":3:16: error: enum 'tmp.E' has no tag with value '3'",
756 ":1:11: note: enum declared here",
757 });
758
759 case.addError(
760 \\const E = enum { a, b, c };
761 \\pub export fn main() c_int {
762 \\ var x: E = .a;
763 \\ switch (x) {
764 \\ .a => {},
765 \\ .c => {},
766 \\ }
767 \\}
768 , &.{
769 ":4:5: error: switch must handle all possibilities",
770 ":1:21: note: unhandled enumeration value: 'b'",
771 ":1:11: note: enum 'tmp.E' declared here",
772 });
773
774 case.addError(
775 \\const E = enum { a, b, c };
776 \\pub export fn main() c_int {
777 \\ var x: E = .a;
778 \\ switch (x) {
779 \\ .a => {},
780 \\ .b => {},
781 \\ .b => {},
782 \\ .c => {},
783 \\ }
784 \\}
785 , &.{
786 ":7:10: error: duplicate switch value",
787 ":6:10: note: previous value here",
788 });
789
790 case.addError(
791 \\const E = enum { a, b, c };
792 \\pub export fn main() c_int {
793 \\ var x: E = .a;
794 \\ switch (x) {
795 \\ .a => {},
796 \\ .b => {},
797 \\ .c => {},
798 \\ else => {},
799 \\ }
800 \\}
801 , &.{
802 ":8:14: error: unreachable else prong; all cases already handled",
803 });
804
805 case.addError(
806 \\const E = enum { a, b, c };
807 \\pub export fn main() c_int {
808 \\ var x: E = .a;
809 \\ switch (x) {
810 \\ .a => {},
811 \\ .b => {},
812 \\ _ => {},
813 \\ }
814 \\}
815 , &.{
816 ":4:5: error: '_' prong only allowed when switching on non-exhaustive enums",
817 ":7:11: note: '_' prong here",
818 });
819
820 case.addError(
821 \\const E = enum { a, b, c };
822 \\pub export fn main() c_int {
823 \\ _ = E.d;
824 \\}
825 , &.{
826 ":3:11: error: enum 'tmp.E' has no member named 'd'",
827 ":1:11: note: enum declared here",
828 });
829
830 case.addError(
831 \\const E = enum { a, b, c };
832 \\pub export fn main() c_int {
833 \\ var x: E = .d;
834 \\ _ = x;
835 \\}
836 , &.{
837 ":3:17: error: no field named 'd' in enum 'tmp.E'",
838 ":1:11: note: enum declared here",
839 });
840 }
841
842 {
843 var case = ctx.exeFromCompiledC("shift right and left", .{}, b);
844 case.addCompareOutput(
845 \\pub export fn main() c_int {
846 \\ var i: u32 = 16;
847 \\ assert(i >> 1, 8);
848 \\ return 0;
849 \\}
850 \\fn assert(a: u32, b: u32) void {
851 \\ if (a != b) unreachable;
852 \\}
853 , "");
854
855 case.addCompareOutput(
856 \\pub export fn main() c_int {
857 \\ var i: u32 = 16;
858 \\ assert(i << 1, 32);
859 \\ return 0;
860 \\}
861 \\fn assert(a: u32, b: u32) void {
862 \\ if (a != b) unreachable;
863 \\}
864 , "");
865 }
866
867 {
868 var case = ctx.exeFromCompiledC("inferred error sets", .{}, b);
869
870 case.addCompareOutput(
871 \\pub export fn main() c_int {
872 \\ if (foo()) |_| {
873 \\ @panic("test fail");
874 \\ } else |err| {
875 \\ if (err != error.ItBroke) {
876 \\ @panic("test fail");
877 \\ }
878 \\ }
879 \\ return 0;
880 \\}
881 \\fn foo() !void {
882 \\ return error.ItBroke;
883 \\}
884 , "");
885 }
886
887 {
888 // TODO: add u64 tests, ran into issues with the literal generated for std.math.maxInt(u64)
889 var case = ctx.exeFromCompiledC("add and sub wrapping operations", .{}, b);
890 case.addCompareOutput(
891 \\pub export fn main() c_int {
892 \\ // Addition
893 \\ if (!add_u3(1, 1, 2)) return 1;
894 \\ if (!add_u3(7, 1, 0)) return 1;
895 \\ if (!add_i3(1, 1, 2)) return 1;
896 \\ if (!add_i3(3, 2, -3)) return 1;
897 \\ if (!add_i3(-3, -2, 3)) return 1;
898 \\ if (!add_c_int(1, 1, 2)) return 1;
899 \\ // TODO enable these when stage2 supports std.math.maxInt
900 \\ //if (!add_c_int(maxInt(c_int), 2, minInt(c_int) + 1)) return 1;
901 \\ //if (!add_c_int(maxInt(c_int) + 1, -2, maxInt(c_int))) return 1;
902 \\
903 \\ // Subtraction
904 \\ if (!sub_u3(2, 1, 1)) return 1;
905 \\ if (!sub_u3(0, 1, 7)) return 1;
906 \\ if (!sub_i3(2, 1, 1)) return 1;
907 \\ if (!sub_i3(3, -2, -3)) return 1;
908 \\ if (!sub_i3(-3, 2, 3)) return 1;
909 \\ if (!sub_c_int(2, 1, 1)) return 1;
910 \\ // TODO enable these when stage2 supports std.math.maxInt
911 \\ //if (!sub_c_int(maxInt(c_int), -2, minInt(c_int) + 1)) return 1;
912 \\ //if (!sub_c_int(minInt(c_int) + 1, 2, maxInt(c_int))) return 1;
913 \\
914 \\ return 0;
915 \\}
916 \\fn add_u3(lhs: u3, rhs: u3, expected: u3) bool {
917 \\ return expected == lhs +% rhs;
918 \\}
919 \\fn add_i3(lhs: i3, rhs: i3, expected: i3) bool {
920 \\ return expected == lhs +% rhs;
921 \\}
922 \\fn add_c_int(lhs: c_int, rhs: c_int, expected: c_int) bool {
923 \\ return expected == lhs +% rhs;
924 \\}
925 \\fn sub_u3(lhs: u3, rhs: u3, expected: u3) bool {
926 \\ return expected == lhs -% rhs;
927 \\}
928 \\fn sub_i3(lhs: i3, rhs: i3, expected: i3) bool {
929 \\ return expected == lhs -% rhs;
930 \\}
931 \\fn sub_c_int(lhs: c_int, rhs: c_int, expected: c_int) bool {
932 \\ return expected == lhs -% rhs;
933 \\}
934 , "");
935 }
936
937 {
938 var case = ctx.exeFromCompiledC("rem", linux_x64, b);
939 case.addCompareOutput(
940 \\fn assert(ok: bool) void {
941 \\ if (!ok) unreachable;
942 \\}
943 \\fn rem(lhs: i32, rhs: i32, expected: i32) bool {
944 \\ return @rem(lhs, rhs) == expected;
945 \\}
946 \\pub export fn main() c_int {
947 \\ assert(rem(-5, 3, -2));
948 \\ assert(rem(5, 3, 2));
949 \\ return 0;
950 \\}
951 , "");
952 }
953}
test/translate_c.zig-21
......@@ -764,27 +764,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
764764 \\};
765765 });
766766
767 // Test case temporarily disabled:
768 // https://github.com/ziglang/zig/issues/12055
769 if (false) {
770 cases.add("align() attribute",
771 \\__attribute__ ((aligned(128)))
772 \\extern char my_array[16];
773 \\__attribute__ ((aligned(128)))
774 \\void my_fn(void) { }
775 \\void other_fn(void) {
776 \\ char ARR[16] __attribute__ ((aligned (16)));
777 \\}
778 , &[_][]const u8{
779 \\pub extern var my_array: [16]u8 align(128);
780 \\pub export fn my_fn() align(128) void {}
781 \\pub export fn other_fn() void {
782 \\ var ARR: [16]u8 align(16) = undefined;
783 \\ _ = &ARR;
784 \\}
785 });
786 }
787
788767 cases.add("linksection() attribute",
789768 \\// Use the "segment,section" format to make this test pass when
790769 \\// targeting the mach-o binary format