diff --git a/src/all_types.hpp b/src/all_types.hpp index 6061f63da6..086ad7db49 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1266,7 +1266,7 @@ enum BuiltinFnId { BuiltinFnIdIntToPtr, BuiltinFnIdPtrToInt, BuiltinFnIdTagName, - BuiltinFnIdEnumTagType, + BuiltinFnIdTagType, BuiltinFnIdFieldParentPtr, BuiltinFnIdOffsetOf, BuiltinFnIdInlineCall, @@ -1889,8 +1889,8 @@ enum IrInstructionId { IrInstructionIdSetGlobalLinkage, IrInstructionIdDeclRef, IrInstructionIdPanic, - IrInstructionIdEnumTagName, - IrInstructionIdEnumTagType, + IrInstructionIdTagName, + IrInstructionIdTagType, IrInstructionIdFieldParentPtr, IrInstructionIdOffsetOf, IrInstructionIdTypeId, @@ -2652,13 +2652,13 @@ struct IrInstructionPanic { IrInstruction *msg; }; -struct IrInstructionEnumTagName { +struct IrInstructionTagName { IrInstruction base; IrInstruction *target; }; -struct IrInstructionEnumTagType { +struct IrInstructionTagType { IrInstruction base; IrInstruction *target; diff --git a/src/codegen.cpp b/src/codegen.cpp index dbf4f8522b..bd84310ff1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2717,7 +2717,7 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI } static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable, - IrInstructionEnumTagName *instruction) + IrInstructionTagName *instruction) { TypeTableEntry *enum_type = instruction->target->value.type; assert(enum_type->id == TypeTableEntryIdEnum); @@ -3484,7 +3484,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdOpaqueType: case IrInstructionIdSetAlignStack: case IrInstructionIdArgType: - case IrInstructionIdEnumTagType: + case IrInstructionIdTagType: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); @@ -3594,8 +3594,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction); case IrInstructionIdPanic: return ir_render_panic(g, executable, (IrInstructionPanic *)instruction); - case IrInstructionIdEnumTagName: - return ir_render_enum_tag_name(g, executable, (IrInstructionEnumTagName *)instruction); + case IrInstructionIdTagName: + return ir_render_enum_tag_name(g, executable, (IrInstructionTagName *)instruction); case IrInstructionIdFieldParentPtr: return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction); case IrInstructionIdAlignCast: @@ -4963,7 +4963,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2); create_builtin_fn(g, BuiltinFnIdPtrToInt, "ptrToInt", 1); create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1); - create_builtin_fn(g, BuiltinFnIdEnumTagType, "EnumTagType", 1); + create_builtin_fn(g, BuiltinFnIdTagType, "TagType", 1); create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3); create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2); create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2); diff --git a/src/ir.cpp b/src/ir.cpp index 5da59fedb7..e70340b300 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -539,12 +539,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPanic *) { return IrInstructionIdPanic; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTagName *) { - return IrInstructionIdEnumTagName; +static constexpr IrInstructionId ir_instruction_id(IrInstructionTagName *) { + return IrInstructionIdTagName; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTagType *) { - return IrInstructionIdEnumTagType; +static constexpr IrInstructionId ir_instruction_id(IrInstructionTagType *) { + return IrInstructionIdTagType; } static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr *) { @@ -2205,10 +2205,10 @@ static IrInstruction *ir_build_panic(IrBuilder *irb, Scope *scope, AstNode *sour return &instruction->base; } -static IrInstruction *ir_build_enum_tag_name(IrBuilder *irb, Scope *scope, AstNode *source_node, +static IrInstruction *ir_build_tag_name(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target) { - IrInstructionEnumTagName *instruction = ir_build_instruction(irb, scope, source_node); + IrInstructionTagName *instruction = ir_build_instruction(irb, scope, source_node); instruction->target = target; ir_ref_instruction(target, irb->current_basic_block); @@ -2216,10 +2216,10 @@ static IrInstruction *ir_build_enum_tag_name(IrBuilder *irb, Scope *scope, AstNo return &instruction->base; } -static IrInstruction *ir_build_enum_tag_type(IrBuilder *irb, Scope *scope, AstNode *source_node, +static IrInstruction *ir_build_tag_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target) { - IrInstructionEnumTagType *instruction = ir_build_instruction(irb, scope, source_node); + IrInstructionTagType *instruction = ir_build_instruction(irb, scope, source_node); instruction->target = target; ir_ref_instruction(target, irb->current_basic_block); @@ -3002,14 +3002,14 @@ static IrInstruction *ir_instruction_panic_get_dep(IrInstructionPanic *instructi } } -static IrInstruction *ir_instruction_enumtagname_get_dep(IrInstructionEnumTagName *instruction, size_t index) { +static IrInstruction *ir_instruction_enumtagname_get_dep(IrInstructionTagName *instruction, size_t index) { switch (index) { case 0: return instruction->target; default: return nullptr; } } -static IrInstruction *ir_instruction_enumtagtype_get_dep(IrInstructionEnumTagType *instruction, size_t index) { +static IrInstruction *ir_instruction_enumtagtype_get_dep(IrInstructionTagType *instruction, size_t index) { switch (index) { case 0: return instruction->target; default: return nullptr; @@ -3270,10 +3270,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_declref_get_dep((IrInstructionDeclRef *) instruction, index); case IrInstructionIdPanic: return ir_instruction_panic_get_dep((IrInstructionPanic *) instruction, index); - case IrInstructionIdEnumTagName: - return ir_instruction_enumtagname_get_dep((IrInstructionEnumTagName *) instruction, index); - case IrInstructionIdEnumTagType: - return ir_instruction_enumtagtype_get_dep((IrInstructionEnumTagType *) instruction, index); + case IrInstructionIdTagName: + return ir_instruction_enumtagname_get_dep((IrInstructionTagName *) instruction, index); + case IrInstructionIdTagType: + return ir_instruction_enumtagtype_get_dep((IrInstructionTagType *) instruction, index); case IrInstructionIdFieldParentPtr: return ir_instruction_fieldparentptr_get_dep((IrInstructionFieldParentPtr *) instruction, index); case IrInstructionIdOffsetOf: @@ -4627,16 +4627,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value); - return ir_build_enum_tag_name(irb, scope, node, actual_tag); + return ir_build_tag_name(irb, scope, node, actual_tag); } - case BuiltinFnIdEnumTagType: + case BuiltinFnIdTagType: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; - return ir_build_enum_tag_type(irb, scope, node, arg0_value); + return ir_build_tag_type(irb, scope, node, arg0_value); } case BuiltinFnIdFieldParentPtr: { @@ -13638,7 +13638,7 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc return str_type; } -static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructionEnumTagName *instruction) { +static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructionTagName *instruction) { IrInstruction *target = instruction->target->other; if (type_is_invalid(target->value.type)) return ira->codegen->builtin_types.entry_invalid; @@ -13658,7 +13658,7 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn ira->codegen->name_table_enums.append(target->value.type); } - IrInstruction *result = ir_build_enum_tag_name(&ira->new_irb, instruction->base.scope, + IrInstruction *result = ir_build_tag_name(&ira->new_irb, instruction->base.scope, instruction->base.source_node, target); ir_link_new_instruction(result, &instruction->base); TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true); @@ -15838,22 +15838,43 @@ static TypeTableEntry *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruc return ira->codegen->builtin_types.entry_type; } -static TypeTableEntry *ir_analyze_instruction_enum_tag_type(IrAnalyze *ira, IrInstructionEnumTagType *instruction) { +static TypeTableEntry *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstructionTagType *instruction) { IrInstruction *target_inst = instruction->target->other; TypeTableEntry *enum_type = ir_resolve_type(ira, target_inst); if (type_is_invalid(enum_type)) return ira->codegen->builtin_types.entry_invalid; - if (enum_type->id != TypeTableEntryIdEnum) { - ir_add_error(ira, target_inst, buf_sprintf("expected enum, found '%s'", buf_ptr(&enum_type->name))); + + if (enum_type->id == TypeTableEntryIdEnum) { + ensure_complete_type(ira->codegen, enum_type); + if (type_is_invalid(enum_type)) + return ira->codegen->builtin_types.entry_invalid; + + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); + out_val->data.x_type = enum_type->data.enumeration.tag_int_type; + return ira->codegen->builtin_types.entry_type; + } else if (enum_type->id == TypeTableEntryIdUnion) { + ensure_complete_type(ira->codegen, enum_type); + if (type_is_invalid(enum_type)) + return ira->codegen->builtin_types.entry_invalid; + + AstNode *decl_node = enum_type->data.unionation.decl_node; + if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) { + assert(enum_type->data.unionation.tag_type != nullptr); + + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); + out_val->data.x_type = enum_type->data.unionation.tag_type; + return ira->codegen->builtin_types.entry_type; + } else { + ErrorMsg *msg = ir_add_error(ira, target_inst, buf_sprintf("union '%s' has no tag", + buf_ptr(&enum_type->name))); + add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here")); + return ira->codegen->builtin_types.entry_invalid; + } + } else { + ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'", + buf_ptr(&enum_type->name))); return ira->codegen->builtin_types.entry_invalid; } - ensure_complete_type(ira->codegen, enum_type); - if (type_is_invalid(enum_type)) - return ira->codegen->builtin_types.entry_invalid; - - ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); - out_val->data.x_type = enum_type->data.enumeration.tag_int_type; - return ira->codegen->builtin_types.entry_type; } static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { @@ -16032,8 +16053,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction); case IrInstructionIdPtrToInt: return ir_analyze_instruction_ptr_to_int(ira, (IrInstructionPtrToInt *)instruction); - case IrInstructionIdEnumTagName: - return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionEnumTagName *)instruction); + case IrInstructionIdTagName: + return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionTagName *)instruction); case IrInstructionIdFieldParentPtr: return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction); case IrInstructionIdOffsetOf: @@ -16052,8 +16073,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_set_align_stack(ira, (IrInstructionSetAlignStack *)instruction); case IrInstructionIdArgType: return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction); - case IrInstructionIdEnumTagType: - return ir_analyze_instruction_enum_tag_type(ira, (IrInstructionEnumTagType *)instruction); + case IrInstructionIdTagType: + return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction); } zig_unreachable(); } @@ -16230,14 +16251,14 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdDeclRef: case IrInstructionIdErrName: case IrInstructionIdTypeName: - case IrInstructionIdEnumTagName: + case IrInstructionIdTagName: case IrInstructionIdFieldParentPtr: case IrInstructionIdOffsetOf: case IrInstructionIdTypeId: case IrInstructionIdAlignCast: case IrInstructionIdOpaqueType: case IrInstructionIdArgType: - case IrInstructionIdEnumTagType: + case IrInstructionIdTagType: return false; case IrInstructionIdAsm: { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 99617056de..223a012456 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -872,8 +872,8 @@ static void ir_print_type_name(IrPrint *irp, IrInstructionTypeName *instruction) ir_print_other_instruction(irp, instruction->type_value); } -static void ir_print_enum_tag_name(IrPrint *irp, IrInstructionEnumTagName *instruction) { - fprintf(irp->f, "enumtagname "); +static void ir_print_tag_name(IrPrint *irp, IrInstructionTagName *instruction) { + fprintf(irp->f, "tagname "); ir_print_other_instruction(irp, instruction->target); } @@ -981,8 +981,8 @@ static void ir_print_arg_type(IrPrint *irp, IrInstructionArgType *instruction) { fprintf(irp->f, ")"); } -static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionEnumTagType *instruction) { - fprintf(irp->f, "@EnumTagType("); +static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionTagType *instruction) { + fprintf(irp->f, "@TagType("); ir_print_other_instruction(irp, instruction->target); fprintf(irp->f, ")"); } @@ -1254,8 +1254,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdTypeName: ir_print_type_name(irp, (IrInstructionTypeName *)instruction); break; - case IrInstructionIdEnumTagName: - ir_print_enum_tag_name(irp, (IrInstructionEnumTagName *)instruction); + case IrInstructionIdTagName: + ir_print_tag_name(irp, (IrInstructionTagName *)instruction); break; case IrInstructionIdCanImplicitCast: ir_print_can_implicit_cast(irp, (IrInstructionCanImplicitCast *)instruction); @@ -1299,8 +1299,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdArgType: ir_print_arg_type(irp, (IrInstructionArgType *)instruction); break; - case IrInstructionIdEnumTagType: - ir_print_enum_tag_type(irp, (IrInstructionEnumTagType *)instruction); + case IrInstructionIdTagType: + ir_print_enum_tag_type(irp, (IrInstructionTagType *)instruction); break; } fprintf(irp->f, "\n"); diff --git a/test/cases/enum.zig b/test/cases/enum.zig index f3240045df..ec900511eb 100644 --- a/test/cases/enum.zig +++ b/test/cases/enum.zig @@ -204,12 +204,12 @@ test "set enum tag type" { { var x = Small.One; x = Small.Two; - comptime assert(@EnumTagType(Small) == u2); + comptime assert(@TagType(Small) == u2); } { var x = Small2.One; x = Small2.Two; - comptime assert(@EnumTagType(Small2) == u2); + comptime assert(@TagType(Small2) == u2); } } diff --git a/test/cases/union.zig b/test/cases/union.zig index ec050a20d5..c4767fd649 100644 --- a/test/cases/union.zig +++ b/test/cases/union.zig @@ -104,3 +104,36 @@ fn bar(value: &const Payload) -> i32 { Payload.C => |x| if (x) i32(30) else 31, }; } + +const MultipleChoice2 = union(enum(u32)) { + Unspecified1: i32, + A: f32 = 20, + Unspecified2: void, + B: bool = 40, + Unspecified3: i32, + C: i8 = 60, + Unspecified4: void, + D: void = 1000, + Unspecified5: i32, +}; + +test "union(enum(u32)) with specified and unspecified tag values" { + comptime assert(@TagType(@TagType(MultipleChoice2)) == u32); + testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 {.C = 123}); + comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 { .C = 123} ); +} + +fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) { + assert(u32(@TagType(MultipleChoice2)(*x)) == 60); + assert(1123 == switch (*x) { + MultipleChoice2.A => 1, + MultipleChoice2.B => 2, + MultipleChoice2.C => |v| i32(1000) + v, + MultipleChoice2.D => 4, + MultipleChoice2.Unspecified1 => 5, + MultipleChoice2.Unspecified2 => 6, + MultipleChoice2.Unspecified3 => 7, + MultipleChoice2.Unspecified4 => 8, + MultipleChoice2.Unspecified5 => 9, + }); +}