aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-02-26 11:21:30 -0500
committerAndrew Kelley <andrew@ziglang.org>2020-02-26 11:21:30 -0500
commit6291e8e4926c2e7dbd5cfa651f862c7dbd2e5bda (patch)
treec30178b457a4afcca39e355da12502f2c6216a7f /src
parentc4a2734aa08a9e810680d7be2c976fe3ae67cc5b (diff)
parent62de32a18c1eecedc29055e4199fa364f9e9b7c6 (diff)
downloadzig-6291e8e4926c2e7dbd5cfa651f862c7dbd2e5bda.tar.gz
zig-6291e8e4926c2e7dbd5cfa651f862c7dbd2e5bda.zip
Merge branch 'Vexu-tagname'
closes #4559 closes #3991
Diffstat (limited to 'src')
-rw-r--r--src/codegen.cpp33
-rw-r--r--src/ir.cpp11
2 files changed, 33 insertions, 11 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index f9d2566da7..ee3e05a801 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3329,11 +3329,24 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutableGen *executabl
LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");
size_t field_count = wanted_type->data.enumeration.src_field_count;
LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);
+
+ HashMap<BigInt, Buf *, bigint_hash, bigint_eql> occupied_tag_values = {};
+ occupied_tag_values.init(field_count);
+
for (size_t field_i = 0; field_i < field_count; field_i += 1) {
+ TypeEnumField *type_enum_field = &wanted_type->data.enumeration.fields[field_i];
+
+ Buf *name = type_enum_field->name;
+ auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
+ if (entry != nullptr) {
+ continue;
+ }
+
LLVMValueRef this_tag_int_value = bigint_to_llvm_const(get_llvm_type(g, tag_int_type),
- &wanted_type->data.enumeration.fields[field_i].value);
+ &type_enum_field->value);
LLVMAddCase(switch_instr, this_tag_int_value, ok_value_block);
}
+ occupied_tag_values.deinit();
LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
gen_safety_crash(g, PanicMsgIdBadEnumValue);
@@ -5031,8 +5044,18 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
LLVMConstNull(usize->llvm_type),
};
+ HashMap<BigInt, Buf *, bigint_hash, bigint_eql> occupied_tag_values = {};
+ occupied_tag_values.init(field_count);
+
for (size_t field_i = 0; field_i < field_count; field_i += 1) {
- Buf *name = enum_type->data.enumeration.fields[field_i].name;
+ TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];
+
+ Buf *name = type_enum_field->name;
+ auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
+ if (entry != nullptr) {
+ continue;
+ }
+
LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
LLVMSetInitializer(str_global, str_init);
@@ -5062,6 +5085,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
LLVMPositionBuilderAtEnd(g->builder, return_block);
LLVMBuildRet(g->builder, slice_global);
}
+ occupied_tag_values.deinit();
LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) {
@@ -5086,11 +5110,6 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutableGen *executa
{
ZigType *enum_type = instruction->target->value->type;
assert(enum_type->id == ZigTypeIdEnum);
- if (enum_type->data.enumeration.non_exhaustive) {
- add_node_error(g, instruction->base.base.source_node,
- buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));
- codegen_report_errors_and_exit(g);
- }
LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);
diff --git a/src/ir.cpp b/src/ir.cpp
index 8a7976995c..4d24ec7dfb 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -23190,12 +23190,15 @@ static IrInstGen *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstSrc
if (instr_is_comptime(target)) {
if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_inst_gen;
- if (target->value->type->data.enumeration.non_exhaustive) {
- ir_add_error(ira, &instruction->base.base,
- buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));
+ TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
+ if (field == nullptr) {
+ Buf *int_buf = buf_alloc();
+ bigint_append_buf(int_buf, &target->value->data.x_bigint, 10);
+
+ ir_add_error(ira, &target->base,
+ buf_sprintf("no tag by value %s", buf_ptr(int_buf)));
return ira->codegen->invalid_inst_gen;
}
- TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
ZigValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee;
IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr);
init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(field->name), true);