authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-18 19:25:23-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-01-18 19:25:23-05:00
log7bb4c855ad3776d7f7d21f2bf1c5c93366205ff2
tree1695efe0e849848743d3c152f4349b054a7bf96e
parent405b8e9eeefda07b16044690471cfd57fc654c75
parentb0f753e21d6fcaafd0b35dc02fdfe23b14e310d6
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4222 from LemonBoy/eutwouwth

Prevent crash with empty non-exhaustive enum

4 files changed, 40 insertions(+), 2 deletions(-)

src/analyze.cpp+1-1
...@@ -8312,7 +8312,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatu...@@ -8312,7 +8312,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatu
83128312
8313 uint32_t field_count = enum_type->data.enumeration.src_field_count;8313 uint32_t field_count = enum_type->data.enumeration.src_field_count;
83148314
8315 assert(enum_type->data.enumeration.fields);8315 assert(field_count == 0 || enum_type->data.enumeration.fields != nullptr);
8316 ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);8316 ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
83178317
8318 for (uint32_t i = 0; i < field_count; i += 1) {8318 for (uint32_t i = 0; i < field_count; i += 1) {
src/ir.cpp+10-1
...@@ -21614,7 +21614,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,...@@ -21614,7 +21614,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
21614 case ZigTypeIdEnum: {21614 case ZigTypeIdEnum: {
21615 if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown)))21615 if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown)))
21616 return ira->codegen->invalid_instruction;21616 return ira->codegen->invalid_instruction;
21617 if (target_type->data.enumeration.src_field_count < 2) {21617 if (target_type->data.enumeration.src_field_count == 1) {
21618 TypeEnumField *only_field = &target_type->data.enumeration.fields[0];21618 TypeEnumField *only_field = &target_type->data.enumeration.fields[0];
21619 IrInstruction *result = ir_const(ira, &switch_target_instruction->base, target_type);21619 IrInstruction *result = ir_const(ira, &switch_target_instruction->base, target_type);
21620 bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value);21620 bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value);
...@@ -22351,6 +22351,15 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns...@@ -22351,6 +22351,15 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
2235122351
22352 assert(target->value->type->id == ZigTypeIdEnum);22352 assert(target->value->type->id == ZigTypeIdEnum);
2235322353
22354 if (target->value->type->data.enumeration.src_field_count == 1 &&
22355 !target->value->type->data.enumeration.non_exhaustive) {
22356 TypeEnumField *only_field = &target->value->type->data.enumeration.fields[0];
22357 ZigValue *array_val = create_const_str_lit(ira->codegen, only_field->name)->data.x_ptr.data.ref.pointee;
22358 IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
22359 init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(only_field->name), true);
22360 return result;
22361 }
22362
22354 if (instr_is_comptime(target)) {22363 if (instr_is_comptime(target)) {
22355 if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))22364 if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))
22356 return ira->codegen->invalid_instruction;22365 return ira->codegen->invalid_instruction;
test/stage1/behavior/enum.zig+20
...@@ -65,6 +65,26 @@ test "non-exhaustive enum" {...@@ -65,6 +65,26 @@ test "non-exhaustive enum" {
65 comptime S.doTheTest(52);65 comptime S.doTheTest(52);
66}66}
6767
68test "empty non-exhaustive enum" {
69 const S = struct {
70 const E = enum(u8) {
71 _,
72 };
73 fn doTheTest(y: u8) void {
74 var e = @intToEnum(E, y);
75 expect(switch (e) {
76 _ => true,
77 });
78 expect(@enumToInt(e) == y);
79
80 expect(@typeInfo(E).Enum.fields.len == 0);
81 expect(@typeInfo(E).Enum.is_exhaustive == false);
82 }
83 };
84 S.doTheTest(42);
85 comptime S.doTheTest(42);
86}
87
68test "enum type" {88test "enum type" {
69 const foo1 = Foo{ .One = 13 };89 const foo1 = Foo{ .One = 13 };
70 const foo2 = Foo{90 const foo2 = Foo{
test/stage1/behavior/union.zig+9
...@@ -629,3 +629,12 @@ test "union initializer generates padding only if needed" {...@@ -629,3 +629,12 @@ test "union initializer generates padding only if needed" {
629 var v = U{ .A = 532 };629 var v = U{ .A = 532 };
630 expect(v.A == 532);630 expect(v.A == 532);
631}631}
632
633test "runtime tag name with single field" {
634 const U = union(enum) {
635 A: i32,
636 };
637
638 var v = U{ .A = 42 };
639 expect(std.mem.eql(u8, @tagName(v), "A"));
640}