From 2948f2d262926725b4b8cb5beeb4fdba00b48336 Mon Sep 17 00:00:00 2001 From: Vexu Date: Mon, 27 Jul 2020 18:42:13 +0300 Subject: [PATCH] fix cast from invalid non-exhaustive enum to union --- src/ir.cpp | 16 +++++++++++++++- test/compile_errors.zig | 23 +++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/ir.cpp b/src/ir.cpp index 347cae7e79..209dd6d7d0 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14177,7 +14177,14 @@ static IrInstGen *ir_analyze_enum_to_union(IrAnalyze *ira, IrInst* source_instr, if (!val) return ira->codegen->invalid_inst_gen; TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag); - assert(union_field != nullptr); + if (union_field == nullptr) { + Buf *int_buf = buf_alloc(); + bigint_append_buf(int_buf, &target->value->data.x_enum_tag, 10); + + ir_add_error(ira, &target->base, + buf_sprintf("no tag by value %s", buf_ptr(int_buf))); + return ira->codegen->invalid_inst_gen; + } ZigType *field_type = resolve_union_field_type(ira->codegen, union_field); if (field_type == nullptr) return ira->codegen->invalid_inst_gen; @@ -14213,6 +14220,13 @@ static IrInstGen *ir_analyze_enum_to_union(IrAnalyze *ira, IrInst* source_instr, return result; } + if (target->value->type->data.enumeration.non_exhaustive) { + ir_add_error(ira, source_instr, + buf_sprintf("runtime cast to union '%s' from non-exhustive enum", + buf_ptr(&wanted_type->name))); + return ira->codegen->invalid_inst_gen; + } + // if the union has all fields 0 bits, we can do it // and in fact it's a noop cast because the union value is just the enum value if (wanted_type->data.unionation.gen_field_count == 0) { diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 6c123925da..0b9c754329 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -51,6 +51,29 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:17:23: error: cannot adjust alignment of zero sized type 'fn(u32) anytype'", }); + cases.addTest("invalid non-exhaustive enum to union", + \\const E = enum(u8) { + \\ a, + \\ b, + \\ _, + \\}; + \\const U = union(E) { + \\ a, + \\ b, + \\}; + \\export fn foo() void { + \\ var e = @intToEnum(E, 15); + \\ var u: U = e; + \\} + \\export fn bar() void { + \\ const e = @intToEnum(E, 15); + \\ var u: U = e; + \\} + , &[_][]const u8{ + "tmp.zig:12:16: error: runtime cast to union 'U' from non-exhustive enum", + "tmp.zig:16:16: error: no tag by value 15", + }); + cases.addTest("switching with exhaustive enum has '_' prong ", \\const E = enum{ \\ a,