From 9e4bbcd40a2bd92a310237f0b14798ff8002449c Mon Sep 17 00:00:00 2001 From: David Rubin Date: Sat, 3 Feb 2024 01:29:55 -0800 Subject: [PATCH 1/4] fix --- src/Sema.zig | 13 +++++++++++ .../int_from_enum_undefined.zig | 22 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 test/cases/compile_errors/int_from_enum_undefined.zig diff --git a/src/Sema.zig b/src/Sema.zig index f852710b9561..470532ec32f6 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8577,6 +8577,12 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const operand = try sema.resolveInst(inst_data.operand); const operand_ty = sema.typeOf(operand); + if (try sema.resolveValue(operand)) |resolved_op| { + if (resolved_op.isUndef(mod)) { + return sema.failWithUseOfUndef(block, operand_src); + } + } + const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(mod)) { .Enum => operand, .Union => blk: { @@ -8589,6 +8595,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError .{src}, ); }; + break :blk try sema.unionToTag(block, tag_ty, operand, operand_src); }, else => { @@ -8599,6 +8606,12 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError }; const enum_tag_ty = sema.typeOf(enum_tag); + if (enum_tag_ty.enumFieldCount(mod) == 0) { + return sema.fail(block, operand_src, "cannot use @intFromEnum on empty enum '{}'", .{ + enum_tag_ty.fmt(mod), + }); + } + const int_tag_ty = enum_tag_ty.intTagType(mod); if (try sema.typeHasOnePossibleValue(enum_tag_ty)) |opv| { diff --git a/test/cases/compile_errors/int_from_enum_undefined.zig b/test/cases/compile_errors/int_from_enum_undefined.zig new file mode 100644 index 000000000000..cf1b04c3dc36 --- /dev/null +++ b/test/cases/compile_errors/int_from_enum_undefined.zig @@ -0,0 +1,22 @@ +export fn a() void { + const E = enum {}; + var e: E = undefined; + _ = &e; + _ = @intFromEnum(e); +} + +comptime { + const E = union(enum(u16)) { + a: u32, + b: u32, + }; + const e: E = undefined; + _ = @intFromEnum(e); +} + +// error +// backend=stage2 +// target=native +// +// :14:22: error: use of undefined value here causes undefined behavior +// :5:22: error: cannot use @intFromEnum on empty enum 'tmp.a.E' From 29d38a5cdef028ed7befebb4f6af7b81e90f7e22 Mon Sep 17 00:00:00 2001 From: David Rubin Date: Sat, 3 Feb 2024 01:51:21 -0800 Subject: [PATCH 2/4] edge case non-exhaustive enum --- src/Sema.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Sema.zig b/src/Sema.zig index 470532ec32f6..adf97a28fb72 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8606,7 +8606,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError }; const enum_tag_ty = sema.typeOf(enum_tag); - if (enum_tag_ty.enumFieldCount(mod) == 0) { + if (enum_tag_ty.enumFieldCount(mod) == 0 and !enum_tag_ty.isNonexhaustiveEnum(mod)) { return sema.fail(block, operand_src, "cannot use @intFromEnum on empty enum '{}'", .{ enum_tag_ty.fmt(mod), }); From b868ea09cba3548f73dfdffb86b0f231d33d9781 Mon Sep 17 00:00:00 2001 From: David Rubin Date: Sun, 4 Feb 2024 01:17:25 -0800 Subject: [PATCH 3/4] fix --- src/Sema.zig | 15 +++++++++------ .../compile_errors/int_from_enum_undefined.zig | 10 ---------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index adf97a28fb72..618b6b1c2f63 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8577,12 +8577,6 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const operand = try sema.resolveInst(inst_data.operand); const operand_ty = sema.typeOf(operand); - if (try sema.resolveValue(operand)) |resolved_op| { - if (resolved_op.isUndef(mod)) { - return sema.failWithUseOfUndef(block, operand_src); - } - } - const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(mod)) { .Enum => operand, .Union => blk: { @@ -8606,6 +8600,8 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError }; const enum_tag_ty = sema.typeOf(enum_tag); + // TODO: use correct solution + // https://github.com/ziglang/zig/issues/15909 if (enum_tag_ty.enumFieldCount(mod) == 0 and !enum_tag_ty.isNonexhaustiveEnum(mod)) { return sema.fail(block, operand_src, "cannot use @intFromEnum on empty enum '{}'", .{ enum_tag_ty.fmt(mod), @@ -8614,6 +8610,12 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const int_tag_ty = enum_tag_ty.intTagType(mod); + if (try sema.resolveValue(operand)) |resolved_op| { + if (resolved_op.isUndef(mod)) { + return mod.undefRef(int_tag_ty); + } + } + if (try sema.typeHasOnePossibleValue(enum_tag_ty)) |opv| { return Air.internedToRef((try mod.getCoerced(opv, int_tag_ty)).toIntern()); } @@ -20861,6 +20863,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air if (enum_ty.enumFieldCount(mod) == 0) { // TODO I don't think this is the correct way to handle this but // it prevents a crash. + // https://github.com/ziglang/zig/issues/15909 return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{}'", .{ enum_ty.fmt(mod), }); diff --git a/test/cases/compile_errors/int_from_enum_undefined.zig b/test/cases/compile_errors/int_from_enum_undefined.zig index cf1b04c3dc36..cae99e620f93 100644 --- a/test/cases/compile_errors/int_from_enum_undefined.zig +++ b/test/cases/compile_errors/int_from_enum_undefined.zig @@ -5,18 +5,8 @@ export fn a() void { _ = @intFromEnum(e); } -comptime { - const E = union(enum(u16)) { - a: u32, - b: u32, - }; - const e: E = undefined; - _ = @intFromEnum(e); -} - // error // backend=stage2 // target=native // -// :14:22: error: use of undefined value here causes undefined behavior // :5:22: error: cannot use @intFromEnum on empty enum 'tmp.a.E' From 1d76a497b4262569617c528fd1f3be2c49d22506 Mon Sep 17 00:00:00 2001 From: David Rubin Date: Sun, 4 Feb 2024 02:30:44 -0800 Subject: [PATCH 4/4] fix 2 eletric boogaloo --- src/Sema.zig | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 618b6b1c2f63..8cd501963d52 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8599,6 +8599,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError }, }; const enum_tag_ty = sema.typeOf(enum_tag); + const int_tag_ty = enum_tag_ty.intTagType(mod); // TODO: use correct solution // https://github.com/ziglang/zig/issues/15909 @@ -8608,19 +8609,15 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError }); } - const int_tag_ty = enum_tag_ty.intTagType(mod); - - if (try sema.resolveValue(operand)) |resolved_op| { - if (resolved_op.isUndef(mod)) { - return mod.undefRef(int_tag_ty); - } - } - if (try sema.typeHasOnePossibleValue(enum_tag_ty)) |opv| { return Air.internedToRef((try mod.getCoerced(opv, int_tag_ty)).toIntern()); } if (try sema.resolveValue(enum_tag)) |enum_tag_val| { + if (enum_tag_val.isUndef(mod)) { + return mod.undefRef(int_tag_ty); + } + const val = try enum_tag_val.intFromEnum(enum_tag_ty, mod); return Air.internedToRef(val.toIntern()); }