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
signaturelock-open 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) {...@@ -5031,8 +5031,18 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
5031 LLVMConstNull(usize->llvm_type),5031 LLVMConstNull(usize->llvm_type),
5032 };5032 };
50335033
5034 HashMap<BigInt, Buf *, bigint_hash, bigint_eql> occupied_tag_values = {};
5035 occupied_tag_values.init(field_count);
5036
5034 for (size_t field_i = 0; field_i < field_count; field_i += 1) {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 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);5046 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
5037 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");5047 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
5038 LLVMSetInitializer(str_global, str_init);5048 LLVMSetInitializer(str_global, str_init);
...@@ -5086,11 +5096,6 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutableGen *executa...@@ -5086,11 +5096,6 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutableGen *executa
5086{5096{
5087 ZigType *enum_type = instruction->target->value->type;5097 ZigType *enum_type = instruction->target->value->type;
5088 assert(enum_type->id == ZigTypeIdEnum);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 }
50945099
5095 LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);5100 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...@@ -23190,12 +23190,15 @@ static IrInstGen *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstSrc
23190 if (instr_is_comptime(target)) {23190 if (instr_is_comptime(target)) {
23191 if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))23191 if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))
23192 return ira->codegen->invalid_inst_gen;23192 return ira->codegen->invalid_inst_gen;
23193 if (target->value->type->data.enumeration.non_exhaustive) {23193 TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
23194 ir_add_error(ira, &instruction->base.base,23194 if (field == nullptr) {
23195 buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));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 return ira->codegen->invalid_inst_gen;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 ZigValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee;23202 ZigValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee;
23200 IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr);23203 IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr);
23201 init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(field->name), true);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,6 +3,15 @@ const builtin = @import("builtin");
3const Target = @import("std").Target;3const Target = @import("std").Target;
44
5pub fn addCases(cases: *tests.CompileErrorContext) void {5pub 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 cases.addTest("@ptrToInt with pointer to zero-sized type",15 cases.addTest("@ptrToInt with pointer to zero-sized type",
7 \\export fn entry() void {16 \\export fn entry() void {
8 \\ var pointer: ?*u0 = null;17 \\ var pointer: ?*u0 = null;
test/stage1/behavior/enum.zig+22-1
...@@ -198,7 +198,17 @@ test "@tagName" {...@@ -198,7 +198,17 @@ test "@tagName" {
198 comptime expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));198 comptime expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
199}199}
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 {
202 return @tagName(n);212 return @tagName(n);
203}213}
204214
...@@ -208,6 +218,17 @@ const BareNumber = enum {...@@ -208,6 +218,17 @@ const BareNumber = enum {
208 Three,218 Three,
209};219};
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
211test "enum alignment" {232test "enum alignment" {
212 comptime {233 comptime {
213 expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8));234 expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8));