commit
6291e8e492
|
@ -414,10 +414,9 @@ pub fn formatType(
|
|||
if (max_depth == 0) {
|
||||
return output(context, "{ ... }");
|
||||
}
|
||||
comptime var field_i = 0;
|
||||
try output(context, "{");
|
||||
inline for (StructT.fields) |f| {
|
||||
if (field_i == 0) {
|
||||
inline for (StructT.fields) |f, i| {
|
||||
if (i == 0) {
|
||||
try output(context, " .");
|
||||
} else {
|
||||
try output(context, ", .");
|
||||
|
@ -425,7 +424,6 @@ pub fn formatType(
|
|||
try output(context, f.name);
|
||||
try output(context, " = ");
|
||||
try formatType(@field(value, f.name), fmt, options, context, Errors, output, max_depth - 1);
|
||||
field_i += 1;
|
||||
}
|
||||
try output(context, " }");
|
||||
},
|
||||
|
|
|
@ -1803,7 +1803,7 @@ pub const Builder = struct {
|
|||
|
||||
// Look at the params and ref() other instructions
|
||||
inline for (@typeInfo(I.Params).Struct.fields) |f| {
|
||||
switch (f.fiedl_type) {
|
||||
switch (f.field_type) {
|
||||
*Inst => @field(inst.params, f.name).ref(self),
|
||||
*BasicBlock => @field(inst.params, f.name).ref(self),
|
||||
?*Inst => if (@field(inst.params, f.name)) |other| other.ref(self),
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
11
src/ir.cpp
11
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);
|
||||
|
|
|
@ -3,6 +3,15 @@ const builtin = @import("builtin");
|
|||
const Target = @import("std").Target;
|
||||
|
||||
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
cases.addTest("@tagName on invalid value of non-exhaustive enum",
|
||||
\\test "enum" {
|
||||
\\ const E = enum(u8) {A, B, _};
|
||||
\\ _ = @tagName(@intToEnum(E, 5));
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:3:18: error: no tag by value 5",
|
||||
});
|
||||
|
||||
cases.addTest("@ptrToInt with pointer to zero-sized type",
|
||||
\\export fn entry() void {
|
||||
\\ var pointer: ?*u0 = null;
|
||||
|
|
|
@ -491,6 +491,17 @@ test "@intToEnum passed a comptime_int to an enum with one item" {
|
|||
expect(x == E.A);
|
||||
}
|
||||
|
||||
test "@intToEnum runtime to an extern enum with duplicate values" {
|
||||
const E = extern enum(u8) {
|
||||
A = 1,
|
||||
B = 1,
|
||||
};
|
||||
var a: u8 = 1;
|
||||
var x = @intToEnum(E, a);
|
||||
expect(x == E.A);
|
||||
expect(x == E.B);
|
||||
}
|
||||
|
||||
test "@intCast to u0 and use the result" {
|
||||
const S = struct {
|
||||
fn doTheTest(zero: u1, one: u1, bigzero: i32) void {
|
||||
|
|
|
@ -198,7 +198,17 @@ test "@tagName" {
|
|||
comptime expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
|
||||
}
|
||||
|
||||
fn testEnumTagNameBare(n: BareNumber) []const u8 {
|
||||
test "@tagName extern enum with duplicates" {
|
||||
expect(mem.eql(u8, testEnumTagNameBare(ExternDuplicates.B), "A"));
|
||||
comptime expect(mem.eql(u8, testEnumTagNameBare(ExternDuplicates.B), "A"));
|
||||
}
|
||||
|
||||
test "@tagName non-exhaustive enum" {
|
||||
expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
|
||||
comptime expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
|
||||
}
|
||||
|
||||
fn testEnumTagNameBare(n: var) []const u8 {
|
||||
return @tagName(n);
|
||||
}
|
||||
|
||||
|
@ -208,6 +218,17 @@ const BareNumber = enum {
|
|||
Three,
|
||||
};
|
||||
|
||||
const ExternDuplicates = extern enum(u8) {
|
||||
A = 1,
|
||||
B = 1,
|
||||
};
|
||||
|
||||
const NonExhaustive = enum(u8) {
|
||||
A,
|
||||
B,
|
||||
_,
|
||||
};
|
||||
|
||||
test "enum alignment" {
|
||||
comptime {
|
||||
expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
|
||||
|
|
Loading…
Reference in New Issue