From c53d94e5127a8dcfefd906c5be0e6b81eaf3d22c Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 18 Jan 2020 15:13:21 +0100 Subject: [PATCH 1/2] Prevent crash with empty non-exhaustive enum --- src/analyze.cpp | 2 +- src/ir.cpp | 2 +- test/stage1/behavior/enum.zig | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index e064677a09..0bbec66a9b 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -8312,7 +8312,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatu uint32_t field_count = enum_type->data.enumeration.src_field_count; - assert(enum_type->data.enumeration.fields); + assert(field_count == 0 || enum_type->data.enumeration.fields != nullptr); ZigLLVMDIEnumerator **di_enumerators = allocate(field_count); for (uint32_t i = 0; i < field_count; i += 1) { diff --git a/src/ir.cpp b/src/ir.cpp index 88b4c1a832..ae02ac9cae 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -21631,7 +21631,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, case ZigTypeIdEnum: { if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; - if (target_type->data.enumeration.src_field_count < 2) { + if (target_type->data.enumeration.src_field_count == 1) { TypeEnumField *only_field = &target_type->data.enumeration.fields[0]; IrInstruction *result = ir_const(ira, &switch_target_instruction->base, target_type); bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value); diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index 83ad76b72c..a478729003 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -65,6 +65,26 @@ test "non-exhaustive enum" { comptime S.doTheTest(52); } +test "empty non-exhaustive enum" { + const S = struct { + const E = enum(u8) { + _, + }; + fn doTheTest(y: u8) void { + var e = @intToEnum(E, y); + expect(switch (e) { + _ => true, + }); + expect(@enumToInt(e) == y); + + expect(@typeInfo(E).Enum.fields.len == 0); + expect(@typeInfo(E).Enum.is_exhaustive == false); + } + }; + S.doTheTest(42); + comptime S.doTheTest(42); +} + test "enum type" { const foo1 = Foo{ .One = 13 }; const foo2 = Foo{ From b0f753e21d6fcaafd0b35dc02fdfe23b14e310d6 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 18 Jan 2020 19:58:05 +0100 Subject: [PATCH 2/2] Fix edge case in tagName handling of unions Closes #4226 --- src/ir.cpp | 9 +++++++++ test/stage1/behavior/union.zig | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/ir.cpp b/src/ir.cpp index ae02ac9cae..ff4b552a9b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -22354,6 +22354,15 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns assert(target->value->type->id == ZigTypeIdEnum); + if (target->value->type->data.enumeration.src_field_count == 1 && + !target->value->type->data.enumeration.non_exhaustive) { + TypeEnumField *only_field = &target->value->type->data.enumeration.fields[0]; + ZigValue *array_val = create_const_str_lit(ira->codegen, only_field->name)->data.x_ptr.data.ref.pointee; + IrInstruction *result = ir_const(ira, &instruction->base, nullptr); + init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(only_field->name), true); + return result; + } + if (instr_is_comptime(target)) { if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index a24bee03e6..4625b7573a 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -629,3 +629,12 @@ test "union initializer generates padding only if needed" { var v = U{ .A = 532 }; expect(v.A == 532); } + +test "runtime tag name with single field" { + const U = union(enum) { + A: i32, + }; + + var v = U{ .A = 42 }; + expect(std.mem.eql(u8, @tagName(v), "A")); +}