authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-22 17:23:23-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-22 17:23:23-05:00
logcacba6f4357fdec8db0ea792889c60022c39fbd3
tree498cd96fc5f8e21f8ea4eb972251090c5f6f7bde
parentb52bffcf8d37d60509514d32663bd4eb2c36c4e4

fix crash on union-enums with only 1 field

closes #713

3 files changed, 48 insertions(+), 9 deletions(-)

src/analyze.cpp+5-4
...@@ -1867,7 +1867,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {...@@ -1867,7 +1867,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
1867 uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;1867 uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
18681868
1869 TypeTableEntry *tag_type = union_type->data.unionation.tag_type;1869 TypeTableEntry *tag_type = union_type->data.unionation.tag_type;
1870 if (tag_type == nullptr) {1870 if (tag_type == nullptr || tag_type->zero_bits) {
1871 assert(most_aligned_union_member != nullptr);1871 assert(most_aligned_union_member != nullptr);
18721872
1873 if (padding_in_bits > 0) {1873 if (padding_in_bits > 0) {
...@@ -2509,8 +2509,10 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {...@@ -2509,8 +2509,10 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
25092509
2510 if (create_enum_type) {2510 if (create_enum_type) {
2511 ImportTableEntry *import = get_scope_import(scope);2511 ImportTableEntry *import = get_scope_import(scope);
2512 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);2512 uint64_t tag_debug_size_in_bits = tag_type->zero_bits ? 0 :
2513 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);2513 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
2514 uint64_t tag_debug_align_in_bits = tag_type->zero_bits ? 0 :
2515 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
2514 // TODO get a more accurate debug scope2516 // TODO get a more accurate debug scope
2515 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,2517 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
2516 ZigLLVMFileToScope(import->di_file), buf_ptr(&tag_type->name),2518 ZigLLVMFileToScope(import->di_file), buf_ptr(&tag_type->name),
...@@ -3451,7 +3453,6 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {...@@ -3451,7 +3453,6 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {
3451TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {3453TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {
3452 assert(type_entry->id == TypeTableEntryIdUnion);3454 assert(type_entry->id == TypeTableEntryIdUnion);
3453 assert(type_entry->data.unionation.zero_bits_known);3455 assert(type_entry->data.unionation.zero_bits_known);
3454 assert(type_entry->data.unionation.gen_tag_index != SIZE_MAX);
3455 for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {3456 for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
3456 TypeUnionField *field = &type_entry->data.unionation.fields[i];3457 TypeUnionField *field = &type_entry->data.unionation.fields[i];
3457 if (bigint_cmp(&field->enum_field->value, tag) == CmpEQ) {3458 if (bigint_cmp(&field->enum_field->value, tag) == CmpEQ) {
src/ir.cpp+16-5
...@@ -4769,7 +4769,8 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -4769,7 +4769,8 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
4769}4769}
47704770
4771static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node,4771static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node,
4772 IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *target_value_ptr, IrInstruction *prong_value,4772 IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *var_is_comptime,
4773 IrInstruction *target_value_ptr, IrInstruction *prong_value,
4773 ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values)4774 ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values)
4774{4775{
4775 assert(switch_node->type == NodeTypeSwitchExpr);4776 assert(switch_node->type == NodeTypeSwitchExpr);
...@@ -4786,7 +4787,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit...@@ -4786,7 +4787,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
4786 bool is_shadowable = false;4787 bool is_shadowable = false;
4787 bool is_const = true;4788 bool is_const = true;
4788 VariableTableEntry *var = ir_create_var(irb, var_symbol_node, scope,4789 VariableTableEntry *var = ir_create_var(irb, var_symbol_node, scope,
4789 var_name, is_const, is_const, is_shadowable, is_comptime);4790 var_name, is_const, is_const, is_shadowable, var_is_comptime);
4790 child_scope = var->child_scope;4791 child_scope = var->child_scope;
4791 IrInstruction *var_value;4792 IrInstruction *var_value;
4792 if (prong_value) {4793 if (prong_value) {
...@@ -4827,10 +4828,13 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -4827,10 +4828,13 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
4827 ZigList<IrInstructionSwitchBrCase> cases = {0};4828 ZigList<IrInstructionSwitchBrCase> cases = {0};
48284829
4829 IrInstruction *is_comptime;4830 IrInstruction *is_comptime;
4831 IrInstruction *var_is_comptime;
4830 if (ir_should_inline(irb->exec, scope)) {4832 if (ir_should_inline(irb->exec, scope)) {
4831 is_comptime = ir_build_const_bool(irb, scope, node, true);4833 is_comptime = ir_build_const_bool(irb, scope, node, true);
4834 var_is_comptime = is_comptime;
4832 } else {4835 } else {
4833 is_comptime = ir_build_test_comptime(irb, scope, node, target_value);4836 is_comptime = ir_build_test_comptime(irb, scope, node, target_value);
4837 var_is_comptime = ir_build_test_comptime(irb, scope, node, target_value_ptr);
4834 }4838 }
48354839
4836 ZigList<IrInstruction *> incoming_values = {0};4840 ZigList<IrInstruction *> incoming_values = {0};
...@@ -4856,7 +4860,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -4856,7 +4860,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
4856 IrBasicBlock *prev_block = irb->current_basic_block;4860 IrBasicBlock *prev_block = irb->current_basic_block;
4857 ir_set_cursor_at_end_and_append_block(irb, else_block);4861 ir_set_cursor_at_end_and_append_block(irb, else_block);
4858 if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block,4862 if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block,
4859 is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))4863 is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))
4860 {4864 {
4861 return irb->codegen->invalid_instruction;4865 return irb->codegen->invalid_instruction;
4862 }4866 }
...@@ -4923,7 +4927,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -4923,7 +4927,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
49234927
4924 ir_set_cursor_at_end_and_append_block(irb, range_block_yes);4928 ir_set_cursor_at_end_and_append_block(irb, range_block_yes);
4925 if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block,4929 if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block,
4926 is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))4930 is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))
4927 {4931 {
4928 return irb->codegen->invalid_instruction;4932 return irb->codegen->invalid_instruction;
4929 }4933 }
...@@ -4967,7 +4971,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -4967,7 +4971,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
4967 IrBasicBlock *prev_block = irb->current_basic_block;4971 IrBasicBlock *prev_block = irb->current_basic_block;
4968 ir_set_cursor_at_end_and_append_block(irb, prong_block);4972 ir_set_cursor_at_end_and_append_block(irb, prong_block);
4969 if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block,4973 if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block,
4970 is_comptime, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values))4974 is_comptime, var_is_comptime, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values))
4971 {4975 {
4972 return irb->codegen->invalid_instruction;4976 return irb->codegen->invalid_instruction;
4973 }4977 }
...@@ -12254,11 +12258,18 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,...@@ -12254,11 +12258,18 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
12254 }12258 }
12255 TypeTableEntry *tag_type = target_type->data.unionation.tag_type;12259 TypeTableEntry *tag_type = target_type->data.unionation.tag_type;
12256 assert(tag_type != nullptr);12260 assert(tag_type != nullptr);
12261 assert(tag_type->id == TypeTableEntryIdEnum);
12257 if (pointee_val) {12262 if (pointee_val) {
12258 ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);12263 ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
12259 bigint_init_bigint(&out_val->data.x_enum_tag, &pointee_val->data.x_union.tag);12264 bigint_init_bigint(&out_val->data.x_enum_tag, &pointee_val->data.x_union.tag);
12260 return tag_type;12265 return tag_type;
12261 }12266 }
12267 if (tag_type->data.enumeration.src_field_count == 1) {
12268 ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
12269 TypeEnumField *only_field = &tag_type->data.enumeration.fields[0];
12270 bigint_init_bigint(&out_val->data.x_enum_tag, &only_field->value);
12271 return tag_type;
12272 }
1226212273
12263 IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,12274 IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
12264 switch_target_instruction->base.source_node, target_value_ptr);12275 switch_target_instruction->base.source_node, target_value_ptr);
test/cases/union.zig+27
...@@ -235,3 +235,30 @@ test "constant packed union" {...@@ -235,3 +235,30 @@ test "constant packed union" {
235fn testConstPackedUnion(expected_tokens: []const PackThis) {235fn testConstPackedUnion(expected_tokens: []const PackThis) {
236 assert(expected_tokens[0].StringLiteral == 1);236 assert(expected_tokens[0].StringLiteral == 1);
237}237}
238
239test "switch on union with only 1 field" {
240 var r: PartialInst = undefined;
241 r = PartialInst.Compiled;
242 switch (r) {
243 PartialInst.Compiled => {
244 var z: PartialInstWithPayload = undefined;
245 z = PartialInstWithPayload { .Compiled = 1234 };
246 switch (z) {
247 PartialInstWithPayload.Compiled => |x| {
248 assert(x == 1234);
249 return;
250 },
251 }
252 },
253 }
254 unreachable;
255}
256
257const PartialInst = union(enum) {
258 Compiled,
259};
260
261const PartialInstWithPayload = union(enum) {
262 Compiled: i32,
263};
264