authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-26 11:21:30-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-26 11:21:30-05:00
log6291e8e4926c2e7dbd5cfa651f862c7dbd2e5bda
treec30178b457a4afcca39e355da12502f2c6216a7f
parentc4a2734aa08a9e810680d7be2c976fe3ae67cc5b
parent62de32a18c1eecedc29055e4199fa364f9e9b7c6
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'Vexu-tagname'

closes #4559 closes #3991

7 files changed, 78 insertions(+), 17 deletions(-)

lib/std/fmt.zig+2-4
...@@ -414,10 +414,9 @@ pub fn formatType(...@@ -414,10 +414,9 @@ pub fn formatType(
414 if (max_depth == 0) {414 if (max_depth == 0) {
415 return output(context, "{ ... }");415 return output(context, "{ ... }");
416 }416 }
417 comptime var field_i = 0;
418 try output(context, "{");417 try output(context, "{");
419 inline for (StructT.fields) |f| {418 inline for (StructT.fields) |f, i| {
420 if (field_i == 0) {419 if (i == 0) {
421 try output(context, " .");420 try output(context, " .");
422 } else {421 } else {
423 try output(context, ", .");422 try output(context, ", .");
...@@ -425,7 +424,6 @@ pub fn formatType(...@@ -425,7 +424,6 @@ pub fn formatType(
425 try output(context, f.name);424 try output(context, f.name);
426 try output(context, " = ");425 try output(context, " = ");
427 try formatType(@field(value, f.name), fmt, options, context, Errors, output, max_depth - 1);426 try formatType(@field(value, f.name), fmt, options, context, Errors, output, max_depth - 1);
428 field_i += 1;
429 }427 }
430 try output(context, " }");428 try output(context, " }");
431 },429 },
src-self-hosted/ir.zig+1-1
...@@ -1803,7 +1803,7 @@ pub const Builder = struct {...@@ -1803,7 +1803,7 @@ pub const Builder = struct {
18031803
1804 // Look at the params and ref() other instructions1804 // Look at the params and ref() other instructions
1805 inline for (@typeInfo(I.Params).Struct.fields) |f| {1805 inline for (@typeInfo(I.Params).Struct.fields) |f| {
1806 switch (f.fiedl_type) {1806 switch (f.field_type) {
1807 *Inst => @field(inst.params, f.name).ref(self),1807 *Inst => @field(inst.params, f.name).ref(self),
1808 *BasicBlock => @field(inst.params, f.name).ref(self),1808 *BasicBlock => @field(inst.params, f.name).ref(self),
1809 ?*Inst => if (@field(inst.params, f.name)) |other| other.ref(self),1809 ?*Inst => if (@field(inst.params, f.name)) |other| other.ref(self),
src/codegen.cpp+26-7
...@@ -3329,11 +3329,24 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutableGen *executabl...@@ -3329,11 +3329,24 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutableGen *executabl
3329 LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");3329 LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");
3330 size_t field_count = wanted_type->data.enumeration.src_field_count;3330 size_t field_count = wanted_type->data.enumeration.src_field_count;
3331 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);3331 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);
3332
3333 HashMap<BigInt, Buf *, bigint_hash, bigint_eql> occupied_tag_values = {};
3334 occupied_tag_values.init(field_count);
3335
3332 for (size_t field_i = 0; field_i < field_count; field_i += 1) {3336 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
3337 TypeEnumField *type_enum_field = &wanted_type->data.enumeration.fields[field_i];
3338
3339 Buf *name = type_enum_field->name;
3340 auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
3341 if (entry != nullptr) {
3342 continue;
3343 }
3344
3333 LLVMValueRef this_tag_int_value = bigint_to_llvm_const(get_llvm_type(g, tag_int_type),3345 LLVMValueRef this_tag_int_value = bigint_to_llvm_const(get_llvm_type(g, tag_int_type),
3334 &wanted_type->data.enumeration.fields[field_i].value);3346 &type_enum_field->value);
3335 LLVMAddCase(switch_instr, this_tag_int_value, ok_value_block);3347 LLVMAddCase(switch_instr, this_tag_int_value, ok_value_block);
3336 }3348 }
3349 occupied_tag_values.deinit();
3337 LLVMPositionBuilderAtEnd(g->builder, bad_value_block);3350 LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
3338 gen_safety_crash(g, PanicMsgIdBadEnumValue);3351 gen_safety_crash(g, PanicMsgIdBadEnumValue);
33393352
...@@ -5031,8 +5044,18 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {...@@ -5031,8 +5044,18 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
5031 LLVMConstNull(usize->llvm_type),5044 LLVMConstNull(usize->llvm_type),
5032 };5045 };
50335046
5047 HashMap<BigInt, Buf *, bigint_hash, bigint_eql> occupied_tag_values = {};
5048 occupied_tag_values.init(field_count);
5049
5034 for (size_t field_i = 0; field_i < field_count; field_i += 1) {5050 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
5035 Buf *name = enum_type->data.enumeration.fields[field_i].name;5051 TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];
5052
5053 Buf *name = type_enum_field->name;
5054 auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
5055 if (entry != nullptr) {
5056 continue;
5057 }
5058
5036 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);5059 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
5037 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");5060 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
5038 LLVMSetInitializer(str_global, str_init);5061 LLVMSetInitializer(str_global, str_init);
...@@ -5062,6 +5085,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {...@@ -5062,6 +5085,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
5062 LLVMPositionBuilderAtEnd(g->builder, return_block);5085 LLVMPositionBuilderAtEnd(g->builder, return_block);
5063 LLVMBuildRet(g->builder, slice_global);5086 LLVMBuildRet(g->builder, slice_global);
5064 }5087 }
5088 occupied_tag_values.deinit();
50655089
5066 LLVMPositionBuilderAtEnd(g->builder, bad_value_block);5090 LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
5067 if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) {5091 if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) {
...@@ -5086,11 +5110,6 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutableGen *executa...@@ -5086,11 +5110,6 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutableGen *executa
5086{5110{
5087 ZigType *enum_type = instruction->target->value->type;5111 ZigType *enum_type = instruction->target->value->type;
5088 assert(enum_type->id == ZigTypeIdEnum);5112 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 }
50945113
5095 LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);5114 LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);
50965115
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/cast.zig+11
...@@ -491,6 +491,17 @@ test "@intToEnum passed a comptime_int to an enum with one item" {...@@ -491,6 +491,17 @@ test "@intToEnum passed a comptime_int to an enum with one item" {
491 expect(x == E.A);491 expect(x == E.A);
492}492}
493493
494test "@intToEnum runtime to an extern enum with duplicate values" {
495 const E = extern enum(u8) {
496 A = 1,
497 B = 1,
498 };
499 var a: u8 = 1;
500 var x = @intToEnum(E, a);
501 expect(x == E.A);
502 expect(x == E.B);
503}
504
494test "@intCast to u0 and use the result" {505test "@intCast to u0 and use the result" {
495 const S = struct {506 const S = struct {
496 fn doTheTest(zero: u1, one: u1, bigzero: i32) void {507 fn doTheTest(zero: u1, one: u1, bigzero: i32) void {
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));