Select correct field in union of struct types

Hello all.

I’m running into a strange error message.
I have (something similar to) the following construction in some code:

const std = @import("std");


const SmallStruct = struct {
    data: [10]f32 = undefined,

    pub fn init(self: *SmallStruct, data: [10]f32) void {
        self.data = data;
    }
};

const LargerStruct = struct {
    data: [10]f32 = undefined,
    name: []const u8 = undefined,
};

const StructUnion = union(enum) {
    small: SmallStruct,
    large: LargerStruct,
};


test "struct union" {
    const allocator = std.testing.allocator;
    var new_struct = try allocator.create(StructUnion);
    const data = [_]f32{1} ** 10;
    new_struct.small.init(data);
    allocator.destroy(new_struct);
}

When running this test, I get the following error message:

thread 425089 panic: access of union field 'small' while field 'small' is active
/home/user/union.zig:27:15: 0x103cd1c in test.struct union (test)
    new_struct.small.init(data);
              ^
/nix/store/zwx8hvsrzwk87v84q60a0pxv256jmpjz-zig-0.13.0/lib/zig/compiler/test_runner.zig:157:25: 0x104c8f9 in mainTerminal (test)
        if (test_fn.func()) |_| {
                        ^
/nix/store/zwx8hvsrzwk87v84q60a0pxv256jmpjz-zig-0.13.0/lib/zig/compiler/test_runner.zig:37:28: 0x1042adb in main (test)
        return mainTerminal();
                           ^
/nix/store/zwx8hvsrzwk87v84q60a0pxv256jmpjz-zig-0.13.0/lib/zig/std/start.zig:514:22: 0x103f1a9 in posixCallMainAndExit (test)
            root.main();
                     ^
/nix/store/zwx8hvsrzwk87v84q60a0pxv256jmpjz-zig-0.13.0/lib/zig/std/start.zig:266:5: 0x103ed11 in _start (test)
    asm volatile (switch (native_arch) {
    ^
???:?:?: 0x0 in ??? (???)
error: the following test command crashed:
/home/user/.cache/zig/o/ca9d7035406045db94d3ca7e2424da48/test

I don’t really get what this is trying to say.

I did notice that, if I switch the order of the tagged union, it instead complains access of union field 'small' while field 'large' is active, so I assume I’m not properly ``telling the allocated union what kind of field should be active’', so it defaults to the first specified (?).

Any insight is appreciated.
Thanks.

When using an allocator to create a new instance of something, this instance is undefined thus possibly in an invalid state. I suspect its tag is simply neither small nor large but an illegal value.

When you access the small variant with new_struct.small.init(data) your program panic in debug and safe mode. You should set the variant before:

new_struct.* = .{ .small = undefined };
new_struct.small.init(data);
5 Likes