From cacba6f4357fdec8db0ea792889c60022c39fbd3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 22 Jan 2018 17:23:23 -0500 Subject: [PATCH] fix crash on union-enums with only 1 field closes #713 --- src/analyze.cpp | 9 +++++---- src/ir.cpp | 21 ++++++++++++++++----- test/cases/union.zig | 27 +++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 1bdd8bede4..ade9b4b1fe 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1867,7 +1867,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits; TypeTableEntry *tag_type = union_type->data.unionation.tag_type; - if (tag_type == nullptr) { + if (tag_type == nullptr || tag_type->zero_bits) { assert(most_aligned_union_member != nullptr); if (padding_in_bits > 0) { @@ -2509,8 +2509,10 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { if (create_enum_type) { ImportTableEntry *import = get_scope_import(scope); - uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref); - uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref); + uint64_t tag_debug_size_in_bits = tag_type->zero_bits ? 0 : + 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref); + uint64_t tag_debug_align_in_bits = tag_type->zero_bits ? 0 : + 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref); // TODO get a more accurate debug scope ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, ZigLLVMFileToScope(import->di_file), buf_ptr(&tag_type->name), @@ -3451,7 +3453,6 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) { TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) { assert(type_entry->id == TypeTableEntryIdUnion); assert(type_entry->data.unionation.zero_bits_known); - assert(type_entry->data.unionation.gen_tag_index != SIZE_MAX); for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { TypeUnionField *field = &type_entry->data.unionation.fields[i]; if (bigint_cmp(&field->enum_field->value, tag) == CmpEQ) { diff --git a/src/ir.cpp b/src/ir.cpp index 161e3397cc..3729f50755 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4769,7 +4769,8 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * } static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node, - IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *target_value_ptr, IrInstruction *prong_value, + IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *var_is_comptime, + IrInstruction *target_value_ptr, IrInstruction *prong_value, ZigList *incoming_blocks, ZigList *incoming_values) { assert(switch_node->type == NodeTypeSwitchExpr); @@ -4786,7 +4787,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit bool is_shadowable = false; bool is_const = true; VariableTableEntry *var = ir_create_var(irb, var_symbol_node, scope, - var_name, is_const, is_const, is_shadowable, is_comptime); + var_name, is_const, is_const, is_shadowable, var_is_comptime); child_scope = var->child_scope; IrInstruction *var_value; if (prong_value) { @@ -4827,10 +4828,13 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * ZigList cases = {0}; IrInstruction *is_comptime; + IrInstruction *var_is_comptime; if (ir_should_inline(irb->exec, scope)) { is_comptime = ir_build_const_bool(irb, scope, node, true); + var_is_comptime = is_comptime; } else { is_comptime = ir_build_test_comptime(irb, scope, node, target_value); + var_is_comptime = ir_build_test_comptime(irb, scope, node, target_value_ptr); } ZigList incoming_values = {0}; @@ -4856,7 +4860,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * IrBasicBlock *prev_block = irb->current_basic_block; ir_set_cursor_at_end_and_append_block(irb, else_block); if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block, - is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values)) + is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values)) { return irb->codegen->invalid_instruction; } @@ -4923,7 +4927,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * ir_set_cursor_at_end_and_append_block(irb, range_block_yes); if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block, - is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values)) + is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values)) { return irb->codegen->invalid_instruction; } @@ -4967,7 +4971,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * IrBasicBlock *prev_block = irb->current_basic_block; ir_set_cursor_at_end_and_append_block(irb, prong_block); if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block, - is_comptime, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values)) + is_comptime, var_is_comptime, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values)) { return irb->codegen->invalid_instruction; } @@ -12254,11 +12258,18 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, } TypeTableEntry *tag_type = target_type->data.unionation.tag_type; assert(tag_type != nullptr); + assert(tag_type->id == TypeTableEntryIdEnum); if (pointee_val) { ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base); bigint_init_bigint(&out_val->data.x_enum_tag, &pointee_val->data.x_union.tag); return tag_type; } + if (tag_type->data.enumeration.src_field_count == 1) { + ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base); + TypeEnumField *only_field = &tag_type->data.enumeration.fields[0]; + bigint_init_bigint(&out_val->data.x_enum_tag, &only_field->value); + return tag_type; + } IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, switch_target_instruction->base.source_node, target_value_ptr); diff --git a/test/cases/union.zig b/test/cases/union.zig index adab8b7e96..74c840b883 100644 --- a/test/cases/union.zig +++ b/test/cases/union.zig @@ -235,3 +235,30 @@ test "constant packed union" { fn testConstPackedUnion(expected_tokens: []const PackThis) { assert(expected_tokens[0].StringLiteral == 1); } + +test "switch on union with only 1 field" { + var r: PartialInst = undefined; + r = PartialInst.Compiled; + switch (r) { + PartialInst.Compiled => { + var z: PartialInstWithPayload = undefined; + z = PartialInstWithPayload { .Compiled = 1234 }; + switch (z) { + PartialInstWithPayload.Compiled => |x| { + assert(x == 1234); + return; + }, + } + }, + } + unreachable; +} + +const PartialInst = union(enum) { + Compiled, +}; + +const PartialInstWithPayload = union(enum) { + Compiled: i32, +}; +