1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const expect = std.testing.expect;
5const expectEqual = std.testing.expectEqual;
6
7test "flags in packed union" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
13
14 try testFlagsInPackedUnion();
15 try comptime testFlagsInPackedUnion();
16}
17
18fn testFlagsInPackedUnion() !void {
19 const FlagBits = packed struct(u8) {
20 enable_1: bool = false,
21 enable_2: bool = false,
22 enable_3: bool = false,
23 enable_4: bool = false,
24 other_flags: packed union {
25 flags: packed struct(u4) {
26 enable_1: bool = true,
27 enable_2: bool = false,
28 enable_3: bool = false,
29 enable_4: bool = false,
30 },
31 bits: u4,
32 } = .{ .flags = .{} },
33 };
34 var test_bits: FlagBits = .{};
35
36 try expectEqual(false, test_bits.enable_1);
37 try expectEqual(true, test_bits.other_flags.flags.enable_1);
38
39 test_bits.enable_1 = true;
40
41 try expectEqual(true, test_bits.enable_1);
42 try expectEqual(true, test_bits.other_flags.flags.enable_1);
43
44 test_bits.other_flags.flags.enable_1 = false;
45
46 try expectEqual(true, test_bits.enable_1);
47 try expectEqual(false, test_bits.other_flags.flags.enable_1);
48}
49
50test "flags in packed union at offset" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
52 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
53 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
54 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
55 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
56
57 try testFlagsInPackedUnionAtOffset();
58 try comptime testFlagsInPackedUnionAtOffset();
59}
60
61fn testFlagsInPackedUnionAtOffset() !void {
62 const FlagBits = packed union {
63 base_flags: packed struct(u12) {
64 a: packed union {
65 flags: packed struct(u4) {
66 enable_1: bool = true,
67 enable_2: bool = false,
68 enable_3: bool = false,
69 enable_4: bool = false,
70 },
71 bits: u4,
72 },
73 pad: u8 = 0,
74 },
75 adv_flags: packed struct(u12) {
76 pad: u8 = 0,
77 adv: packed union {
78 flags: packed struct(u4) {
79 enable_1: bool = true,
80 enable_2: bool = false,
81 enable_3: bool = false,
82 enable_4: bool = false,
83 },
84 bits: u4,
85 },
86 },
87 };
88 var test_bits: FlagBits = .{ .adv_flags = .{ .adv = .{ .flags = .{} } } };
89
90 try expectEqual(@as(u8, 0), test_bits.adv_flags.pad);
91 try expectEqual(true, test_bits.adv_flags.adv.flags.enable_1);
92 try expectEqual(false, test_bits.adv_flags.adv.flags.enable_2);
93
94 test_bits.adv_flags.adv.flags.enable_1 = false;
95 test_bits.adv_flags.adv.flags.enable_2 = true;
96 try expectEqual(@as(u8, 0), test_bits.adv_flags.pad);
97 try expectEqual(false, test_bits.adv_flags.adv.flags.enable_1);
98 try expectEqual(true, test_bits.adv_flags.adv.flags.enable_2);
99
100 test_bits.adv_flags.adv.bits = 12;
101 try expectEqual(@as(u8, 0), test_bits.adv_flags.pad);
102 try expectEqual(false, test_bits.adv_flags.adv.flags.enable_1);
103 try expectEqual(false, test_bits.adv_flags.adv.flags.enable_2);
104}
105
106// Originally reported at https://github.com/ziglang/zig/issues/16581
107test "packed union in packed struct" {
108 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
110 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
111
112 try testPackedUnionInPackedStruct();
113 try comptime testPackedUnionInPackedStruct();
114}
115
116fn testPackedUnionInPackedStruct() !void {
117 const ReadRequest = packed struct { key: i32 };
118 const RequestType = enum(u1) {
119 read,
120 insert,
121 };
122 const RequestUnion = packed union {
123 read: ReadRequest,
124 };
125
126 const Request = packed struct {
127 active_type: RequestType,
128 request: RequestUnion,
129 const Self = @This();
130
131 fn init(read: ReadRequest) Self {
132 return .{
133 .active_type = .read,
134 .request = RequestUnion{ .read = read },
135 };
136 }
137 };
138
139 try std.testing.expectEqual(RequestType.read, Request.init(.{ .key = 3 }).active_type);
140}
141
142test "packed union initialized with a runtime value" {
143 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
144 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
147 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
148
149 const Fields = packed struct {
150 timestamp: u50,
151 random_bits: u13,
152 };
153 const ID = packed union {
154 value: u63,
155 fields: Fields,
156
157 fn getValue() i64 {
158 return 1341;
159 }
160 };
161
162 const timestamp: i64 = ID.getValue();
163 const id = ID{ .fields = Fields{
164 .timestamp = @as(u50, @intCast(timestamp)),
165 .random_bits = 420,
166 } };
167 try std.testing.expect((ID{ .value = id.value }).fields.timestamp == timestamp);
168}
169
170test "assigning to non-active field at comptime" {
171 comptime {
172 const FlagBits = packed union {
173 flags: packed struct {},
174 bits: packed struct {},
175 };
176
177 var test_bits: FlagBits = .{ .flags = .{} };
178 test_bits.bits = .{};
179 }
180}
181
182test "packed union with explicit backing integer" {
183 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
184 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
185 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
186
187 const U = packed union(i32) {
188 raw: i32,
189 unsigned_halves: packed struct { low: u16, high: u16 },
190
191 fn check(val: @This()) !void {
192 try expect(@as(i32, @bitCast(val)) == -2);
193 try expect(@as(u32, @bitCast(val)) == 0xFFFFFFFE);
194 try expect(val.raw == -2);
195 try expect(val.unsigned_halves.low == 0xFFFE);
196 try expect(val.unsigned_halves.high == 0xFFFF);
197 }
198 };
199 try U.check(.{ .raw = -2 });
200 try comptime U.check(.{ .raw = -2 });
201}
202
203test "packed union equality" {
204 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
205
206 const Foo = packed union {
207 a: u4,
208 b: i4,
209 };
210
211 const S = struct {
212 fn doTest(x: Foo, y: Foo) !void {
213 try expect(x == y);
214 try expect(!(x != y));
215 }
216 };
217
218 const x: Foo = .{ .a = 3 };
219 const y: Foo = .{ .b = 3 };
220
221 try S.doTest(x, y);
222 comptime try S.doTest(x, y);
223}
224
225test "initialize packed union field to undefined at comptime" {
226 const U = packed union(u8) { x: u8 };
227 const val: U = .{ .x = undefined };
228 _ = val;
229}
230
231test "convert from/to backing int" {
232 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
233
234 const U = packed union(u10) {
235 a: i10,
236 b: enum(u10) { x, y, z },
237 fn doTheTest(u: @This()) !void {
238 const backing_int = @backingInt(u);
239 const reconstructed: @This() = @fromBackingInt(backing_int);
240 try expect(reconstructed == u);
241 }
242 };
243 try U.doTheTest(.{ .a = 123 });
244 try comptime U.doTheTest(.{ .a = 123 });
245}
246
247test "equality with wide backing integer" {
248 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35982
249 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
250
251 const U = packed union(i200) {
252 x: u200,
253 fn doTheTest(s: @This(), int: i200) !void {
254 try expect(s == @as(@This(), @bitCast(int)));
255 }
256 };
257 try U.doTheTest(.{ .x = (1 << 200) - 1 }, -1);
258 try comptime U.doTheTest(.{ .x = (1 << 200) - 1 }, -1);
259}