authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-02-26 01:03:58+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-26 11:19:39-05:00
logd505ea6cafe8bf6549eb2c56396b0a94d8109859
treee3aabeb7b0aaa1d1c334a020e653fd815a9d2821
parentc4a2734aa08a9e810680d7be2c976fe3ae67cc5b
signature Commit is signed but in an unrecognized format.

fix `@tagName` on extern and non-exhaustive enums


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) {
50315031 LLVMConstNull(usize->llvm_type),
50325032 };
50335033
5034 HashMap<BigInt, Buf *, bigint_hash, bigint_eql> occupied_tag_values = {};
5035 occupied_tag_values.init(field_count);
5036
50345037 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
50365046 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
50375047 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
50385048 LLVMSetInitializer(str_global, str_init);
......@@ -5086,11 +5096,6 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutableGen *executa
50865096{
50875097 ZigType *enum_type = instruction->target->value->type;
50885098 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 }
50945099
50955100 LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);
50965101
src/ir.cpp+7-4
......@@ -23190,12 +23190,15 @@ static IrInstGen *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstSrc
2319023190 if (instr_is_comptime(target)) {
2319123191 if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))
2319223192 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)));
2319623200 return ira->codegen->invalid_inst_gen;
2319723201 }
23198 TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
2319923202 ZigValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee;
2320023203 IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr);
2320123204 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");
33const Target = @import("std").Target;
44
55pub 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
615 cases.addTest("@ptrToInt with pointer to zero-sized type",
716 \\export fn entry() void {
817 \\ var pointer: ?*u0 = null;
test/stage1/behavior/enum.zig+22-1
......@@ -198,7 +198,17 @@ test "@tagName" {
198198 comptime expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
199199}
200200
201fn testEnumTagNameBare(n: BareNumber) []const u8 {
201test "@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
206test "@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
211fn testEnumTagNameBare(n: var) []const u8 {
202212 return @tagName(n);
203213}
204214
......@@ -208,6 +218,17 @@ const BareNumber = enum {
208218 Three,
209219};
210220
221const ExternDuplicates = extern enum(u8) {
222 A = 1,
223 B = 1,
224};
225
226const NonExhaustive = enum(u8) {
227 A,
228 B,
229 _,
230};
231
211232test "enum alignment" {
212233 comptime {
213234 expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8));