aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-01-18 19:25:23 -0500
committerGitHub <noreply@github.com>2020-01-18 19:25:23 -0500
commit7bb4c855ad3776d7f7d21f2bf1c5c93366205ff2 (patch)
tree1695efe0e849848743d3c152f4349b054a7bf96e
parent405b8e9eeefda07b16044690471cfd57fc654c75 (diff)
parentb0f753e21d6fcaafd0b35dc02fdfe23b14e310d6 (diff)
downloadzig-7bb4c855ad3776d7f7d21f2bf1c5c93366205ff2.tar.gz
zig-7bb4c855ad3776d7f7d21f2bf1c5c93366205ff2.zip
Merge pull request #4222 from LemonBoy/eutwouwth
Prevent crash with empty non-exhaustive enum
-rw-r--r--src/analyze.cpp2
-rw-r--r--src/ir.cpp11
-rw-r--r--test/stage1/behavior/enum.zig20
-rw-r--r--test/stage1/behavior/union.zig9
4 files changed, 40 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<ZigLLVMDIEnumerator*>(field_count);
for (uint32_t i = 0; i < field_count; i += 1) {
diff --git a/src/ir.cpp b/src/ir.cpp
index 42a5043279..db1faac37c 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -21614,7 +21614,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);
@@ -22351,6 +22351,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/enum.zig b/test/stage1/behavior/enum.zig
index 5532a3ddf5..6187cee431 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{
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"));
+}