Is @intFromEnum on out of bounds values illegal behavior?

Would the following be illegal behavior?

const std = @import("std");

const MyEnum = enum(u8) { x = 0, y = 1 };

fn questionable(bytes: []const u8) bool {
    const e: *const MyEnum = std.mem.bytesAsValue(MyEnum, bytes[0..1]);
    return @intFromEnum(e.*) == 92;

pub fn main() void {
    std.debug.print("{}\n", .{questionable(&.{92})});

My understanding is that this program is guaranteed to print true — in general, Zig allows invalid values, and only makes branching on illegal values illegal. Is this correct?

  • As documented currently in master:
    std.mem.bytesAsValue is implemented as @ptrCast and this case is not one of the “cannot be used for” or an “undefined behavior”.
  • As implemeted currently in master:
    No special handling code is generated, except from the bytes[0..1] for handling out of bounds.

My understanding is the same as yours.

1 Like

UB. All the switch logic is going to assume only the two values in the enums and optimize around them so you will probably get some very weird results.

There are these things called inexhaustible enums by adding a default value (_) that allow you use any value in the backing int range. They basically like making a new int type and close to the same thing as struct {v: u8, pub const x: u8 = 0; pub const y: u8 = 1;}

1 Like

Note that just having an undefined/illegal value is not illegal behavior in Zig as far as I understand:

switching on enum falls under “Branching on an undefined value is Illegal Behavior”, but there’s no switch in the above litmus test program.

1 Like

If the compiler allows it, it is either a bug or legal – by definition. no? That why I just called it UB since releasefast is probably more than happy to generate code for that (it would be weird for the langauge to havve different “legalities” depending on optimizations wouldnt itt?

spec-less languages this is more of a philosophical construct since there no standard to hold them too. When I think illegal I think will not compile.

edit: Also not understanding why would be called an underfined value. It has entirely different semantics from undefined. It is just outside the range of the enum (like assigning a 64 bit value to a 32 but one – yes that isn’t legal and the compiler won’t let you but it isn’t undefined – here the compiler lets you so doesn’t seem very similar at all).