aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2017-12-05 18:09:22 -0500
committerAndrew Kelley <superjoe30@gmail.com>2017-12-05 18:09:22 -0500
commit63a2f9a8b2251ffdc37d5f28dfbd3f6be1bd7908 (patch)
tree799f7a95b9cda222a9242aaa5d866c38ace5effc
parent74cea89fce2af41d2af7379ff526d7046c4d8d77 (diff)
downloadzig-63a2f9a8b2251ffdc37d5f28dfbd3f6be1bd7908.tar.gz
zig-63a2f9a8b2251ffdc37d5f28dfbd3f6be1bd7908.zip
fix casting integer literal to enum
-rw-r--r--src/ir.cpp26
-rw-r--r--test/cases/enum.zig5
-rw-r--r--test/compile_errors.zig12
3 files changed, 36 insertions, 7 deletions
diff --git a/src/ir.cpp b/src/ir.cpp
index facd7087f0..7c933ae950 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -8436,14 +8436,16 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
- BigInt enum_member_count;
- bigint_init_unsigned(&enum_member_count, wanted_type->data.enumeration.src_field_count);
- if (bigint_cmp(&val->data.x_bigint, &enum_member_count) != CmpLT) {
+
+ TypeEnumField *field = find_enum_field_by_tag(wanted_type, &val->data.x_bigint);
+ if (field == nullptr) {
Buf *val_buf = buf_alloc();
bigint_append_buf(val_buf, &val->data.x_bigint, 10);
- ir_add_error(ira, source_instr,
- buf_sprintf("integer value %s too big for enum '%s' which has %" PRIu32 " fields",
- buf_ptr(val_buf), buf_ptr(&wanted_type->name), wanted_type->data.enumeration.src_field_count));
+ ErrorMsg *msg = ir_add_error(ira, source_instr,
+ buf_sprintf("enum '%s' has no tag matching integer value %s",
+ buf_ptr(&wanted_type->name), buf_ptr(val_buf)));
+ add_error_note(ira->codegen, msg, wanted_type->data.enumeration.decl_node,
+ buf_sprintf("'%s' declared here", buf_ptr(&wanted_type->name)));
return ira->codegen->invalid_instruction;
}
@@ -8827,7 +8829,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
if (actual_type->id == TypeTableEntryIdNumLitFloat ||
actual_type->id == TypeTableEntryIdNumLitInt)
{
- if (wanted_type->id == TypeTableEntryIdPointer &&
+ if (wanted_type->id == TypeTableEntryIdEnum) {
+ IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.enumeration.tag_int_type, value);
+ if (type_is_invalid(cast1->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
+ if (type_is_invalid(cast2->value.type))
+ return ira->codegen->invalid_instruction;
+
+ return cast2;
+ } else if (wanted_type->id == TypeTableEntryIdPointer &&
wanted_type->data.pointer.is_const)
{
IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
diff --git a/test/cases/enum.zig b/test/cases/enum.zig
index ec900511eb..d15614f9fd 100644
--- a/test/cases/enum.zig
+++ b/test/cases/enum.zig
@@ -344,3 +344,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) {
MultipleChoice2.Unspecified5 => 9,
});
}
+
+test "cast integer literal to enum" {
+ assert(MultipleChoice2(0) == MultipleChoice2.Unspecified1);
+ assert(MultipleChoice2(40) == MultipleChoice2.B);
+}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 5d13ed8d48..162109f4d8 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2684,4 +2684,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
,
".tmp_source.zig:11:13: error: switch on union which has no attached enum",
".tmp_source.zig:1:17: note: consider 'union(enum)' here");
+
+ cases.add("enum in field count range but not matching tag",
+ \\const Foo = enum(u32) {
+ \\ A = 10,
+ \\ B = 11,
+ \\};
+ \\export fn entry() {
+ \\ var x = Foo(0);
+ \\}
+ ,
+ ".tmp_source.zig:6:16: error: enum 'Foo' has no tag matching integer value 0",
+ ".tmp_source.zig:1:13: note: 'Foo' declared here");
}