| author | |
| committer | |
| log | d505ea6cafe8bf6549eb2c56396b0a94d8109859 |
| tree | e3aabeb7b0aaa1d1c334a020e653fd815a9d2821 |
| parent | c4a2734aa08a9e810680d7be2c976fe3ae67cc5b |
| signature | Commit is signed but in an unrecognized format. |
4 files changed, 49 insertions(+), 11 deletions(-)
src/codegen.cpp+11-6| ... | ... | @@ -5031,8 +5031,18 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) { |
| 5031 | 5031 | LLVMConstNull(usize->llvm_type), |
| 5032 | 5032 | }; |
| 5033 | 5033 | |
| 5034 | HashMap<BigInt, Buf *, bigint_hash, bigint_eql> occupied_tag_values = {}; | |
| 5035 | occupied_tag_values.init(field_count); | |
| 5036 | ||
| 5034 | 5037 | for (size_t field_i = 0; field_i < field_count; field_i += 1) { |
| 5035 | Buf *name = enum_type->data.enumeration.fields[field_i].name; | |
| 5038 | TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i]; | |
| 5039 | ||
| 5040 | Buf *name = type_enum_field->name; | |
| 5041 | auto entry = occupied_tag_values.put_unique(type_enum_field->value, name); | |
| 5042 | if (entry != nullptr) { | |
| 5043 | continue; | |
| 5044 | } | |
| 5045 | ||
| 5036 | 5046 | LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true); |
| 5037 | 5047 | LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), ""); |
| 5038 | 5048 | LLVMSetInitializer(str_global, str_init); |
| ... | ... | @@ -5086,11 +5096,6 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutableGen *executa |
| 5086 | 5096 | { |
| 5087 | 5097 | ZigType *enum_type = instruction->target->value->type; |
| 5088 | 5098 | assert(enum_type->id == ZigTypeIdEnum); |
| 5089 | if (enum_type->data.enumeration.non_exhaustive) { | |
| 5090 | add_node_error(g, instruction->base.base.source_node, | |
| 5091 | buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991")); | |
| 5092 | codegen_report_errors_and_exit(g); | |
| 5093 | } | |
| 5094 | 5099 | |
| 5095 | 5100 | LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type); |
| 5096 | 5101 |
src/ir.cpp+7-4| ... | ... | @@ -23190,12 +23190,15 @@ static IrInstGen *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstSrc |
| 23190 | 23190 | if (instr_is_comptime(target)) { |
| 23191 | 23191 | if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown))) |
| 23192 | 23192 | return ira->codegen->invalid_inst_gen; |
| 23193 | if (target->value->type->data.enumeration.non_exhaustive) { | |
| 23194 | ir_add_error(ira, &instruction->base.base, | |
| 23195 | buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991")); | |
| 23193 | TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint); | |
| 23194 | if (field == nullptr) { | |
| 23195 | Buf *int_buf = buf_alloc(); | |
| 23196 | bigint_append_buf(int_buf, &target->value->data.x_bigint, 10); | |
| 23197 | ||
| 23198 | ir_add_error(ira, &target->base, | |
| 23199 | buf_sprintf("no tag by value %s", buf_ptr(int_buf))); | |
| 23196 | 23200 | return ira->codegen->invalid_inst_gen; |
| 23197 | 23201 | } |
| 23198 | TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint); | |
| 23199 | 23202 | ZigValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee; |
| 23200 | 23203 | IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr); |
| 23201 | 23204 | init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(field->name), true); |
test/compile_errors.zig+9| ... | ... | @@ -3,6 +3,15 @@ const builtin = @import("builtin"); |
| 3 | 3 | const Target = @import("std").Target; |
| 4 | 4 | |
| 5 | 5 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 6 | cases.addTest("@tagName on invalid value of non-exhaustive enum", | |
| 7 | \\test "enum" { | |
| 8 | \\ const E = enum(u8) {A, B, _}; | |
| 9 | \\ _ = @tagName(@intToEnum(E, 5)); | |
| 10 | \\} | |
| 11 | , &[_][]const u8{ | |
| 12 | "tmp.zig:3:18: error: no tag by value 5", | |
| 13 | }); | |
| 14 | ||
| 6 | 15 | cases.addTest("@ptrToInt with pointer to zero-sized type", |
| 7 | 16 | \\export fn entry() void { |
| 8 | 17 | \\ var pointer: ?*u0 = null; |
test/stage1/behavior/enum.zig+22-1| ... | ... | @@ -198,7 +198,17 @@ test "@tagName" { |
| 198 | 198 | comptime expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); |
| 199 | 199 | } |
| 200 | 200 | |
| 201 | fn testEnumTagNameBare(n: BareNumber) []const u8 { | |
| 201 | test "@tagName extern enum with duplicates" { | |
| 202 | expect(mem.eql(u8, testEnumTagNameBare(ExternDuplicates.B), "A")); | |
| 203 | comptime expect(mem.eql(u8, testEnumTagNameBare(ExternDuplicates.B), "A")); | |
| 204 | } | |
| 205 | ||
| 206 | test "@tagName non-exhaustive enum" { | |
| 207 | expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B")); | |
| 208 | comptime expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B")); | |
| 209 | } | |
| 210 | ||
| 211 | fn testEnumTagNameBare(n: var) []const u8 { | |
| 202 | 212 | return @tagName(n); |
| 203 | 213 | } |
| 204 | 214 | |
| ... | ... | @@ -208,6 +218,17 @@ const BareNumber = enum { |
| 208 | 218 | Three, |
| 209 | 219 | }; |
| 210 | 220 | |
| 221 | const ExternDuplicates = extern enum(u8) { | |
| 222 | A = 1, | |
| 223 | B = 1, | |
| 224 | }; | |
| 225 | ||
| 226 | const NonExhaustive = enum(u8) { | |
| 227 | A, | |
| 228 | B, | |
| 229 | _, | |
| 230 | }; | |
| 231 | ||
| 211 | 232 | test "enum alignment" { |
| 212 | 233 | comptime { |
| 213 | 234 | expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); |