master
  1const std = @import("std");
  2const builtin = @import("builtin");
  3const assert = std.debug.assert;
  4const expectEqual = std.testing.expectEqual;
  5
  6test "flags in packed union" {
  7    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
  8    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
  9    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
 10    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 11    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
 12
 13    try testFlagsInPackedUnion();
 14    try comptime testFlagsInPackedUnion();
 15}
 16
 17fn testFlagsInPackedUnion() !void {
 18    const FlagBits = packed struct(u8) {
 19        enable_1: bool = false,
 20        enable_2: bool = false,
 21        enable_3: bool = false,
 22        enable_4: bool = false,
 23        other_flags: packed union {
 24            flags: packed struct(u4) {
 25                enable_1: bool = true,
 26                enable_2: bool = false,
 27                enable_3: bool = false,
 28                enable_4: bool = false,
 29            },
 30            bits: u4,
 31        } = .{ .flags = .{} },
 32    };
 33    var test_bits: FlagBits = .{};
 34
 35    try expectEqual(false, test_bits.enable_1);
 36    try expectEqual(true, test_bits.other_flags.flags.enable_1);
 37
 38    test_bits.enable_1 = true;
 39
 40    try expectEqual(true, test_bits.enable_1);
 41    try expectEqual(true, test_bits.other_flags.flags.enable_1);
 42
 43    test_bits.other_flags.flags.enable_1 = false;
 44
 45    try expectEqual(true, test_bits.enable_1);
 46    try expectEqual(false, test_bits.other_flags.flags.enable_1);
 47}
 48
 49test "flags in packed union at offset" {
 50    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 51    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 52    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
 53    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 54    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
 55
 56    try testFlagsInPackedUnionAtOffset();
 57    try comptime testFlagsInPackedUnionAtOffset();
 58}
 59
 60fn testFlagsInPackedUnionAtOffset() !void {
 61    const FlagBits = packed union {
 62        base_flags: packed struct(u12) {
 63            a: packed union {
 64                flags: packed struct(u4) {
 65                    enable_1: bool = true,
 66                    enable_2: bool = false,
 67                    enable_3: bool = false,
 68                    enable_4: bool = false,
 69                },
 70                bits: u4,
 71            },
 72            pad: u8 = 0,
 73        },
 74        adv_flags: packed struct(u12) {
 75            pad: u8 = 0,
 76            adv: packed union {
 77                flags: packed struct(u4) {
 78                    enable_1: bool = true,
 79                    enable_2: bool = false,
 80                    enable_3: bool = false,
 81                    enable_4: bool = false,
 82                },
 83                bits: u4,
 84            },
 85        },
 86    };
 87    var test_bits: FlagBits = .{ .adv_flags = .{ .adv = .{ .flags = .{} } } };
 88
 89    try expectEqual(@as(u8, 0), test_bits.adv_flags.pad);
 90    try expectEqual(true, test_bits.adv_flags.adv.flags.enable_1);
 91    try expectEqual(false, test_bits.adv_flags.adv.flags.enable_2);
 92
 93    test_bits.adv_flags.adv.flags.enable_1 = false;
 94    test_bits.adv_flags.adv.flags.enable_2 = true;
 95    try expectEqual(@as(u8, 0), test_bits.adv_flags.pad);
 96    try expectEqual(false, test_bits.adv_flags.adv.flags.enable_1);
 97    try expectEqual(true, test_bits.adv_flags.adv.flags.enable_2);
 98
 99    test_bits.adv_flags.adv.bits = 12;
100    try expectEqual(@as(u8, 0), test_bits.adv_flags.pad);
101    try expectEqual(false, test_bits.adv_flags.adv.flags.enable_1);
102    try expectEqual(false, test_bits.adv_flags.adv.flags.enable_2);
103}
104
105// Originally reported at https://github.com/ziglang/zig/issues/16581
106test "packed union in packed struct" {
107    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
108    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
109    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
110
111    try testPackedUnionInPackedStruct();
112    try comptime testPackedUnionInPackedStruct();
113}
114
115fn testPackedUnionInPackedStruct() !void {
116    const ReadRequest = packed struct { key: i32 };
117    const RequestType = enum(u1) {
118        read,
119        insert,
120    };
121    const RequestUnion = packed union {
122        read: ReadRequest,
123    };
124
125    const Request = packed struct {
126        active_type: RequestType,
127        request: RequestUnion,
128        const Self = @This();
129
130        fn init(read: ReadRequest) Self {
131            return .{
132                .active_type = .read,
133                .request = RequestUnion{ .read = read },
134            };
135        }
136    };
137
138    try std.testing.expectEqual(RequestType.read, Request.init(.{ .key = 3 }).active_type);
139}
140
141test "packed union initialized with a runtime value" {
142    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
143    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
144    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
145    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
146    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
147
148    const Fields = packed struct {
149        timestamp: u50,
150        random_bits: u13,
151    };
152    const ID = packed union {
153        value: u63,
154        fields: Fields,
155
156        fn getValue() i64 {
157            return 1341;
158        }
159    };
160
161    const timestamp: i64 = ID.getValue();
162    const id = ID{ .fields = Fields{
163        .timestamp = @as(u50, @intCast(timestamp)),
164        .random_bits = 420,
165    } };
166    try std.testing.expect((ID{ .value = id.value }).fields.timestamp == timestamp);
167}
168
169test "assigning to non-active field at comptime" {
170    comptime {
171        const FlagBits = packed union {
172            flags: packed struct {},
173            bits: packed struct {},
174        };
175
176        var test_bits: FlagBits = .{ .flags = .{} };
177        test_bits.bits = .{};
178    }
179}
180
181test "comptime packed union of pointers" {
182    const U = packed union {
183        a: *const u32,
184        b: *const [1]u32,
185    };
186
187    const x: u32 = 123;
188    const u: U = .{ .a = &x };
189
190    comptime assert(u.b[0] == 123);
191}