From dd1338b0e6280b10b9b62ca73bf9ece34bd8524e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Sep 2018 12:57:53 -0400 Subject: [PATCH] fix incorrect union const value generation closes #1381 The union was generated as a 3 byte struct when it needed to be 4 bytes so that the packed struct bitcast could work correctly. Now it recognizes this situation and adds padding bytes to become the correct size so that it can fit into an array. --- src/codegen.cpp | 15 ++++++++++++--- test/behavior.zig | 1 + test/cases/bugs/1381.zig | 21 +++++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 test/cases/bugs/1381.zig diff --git a/src/codegen.cpp b/src/codegen.cpp index 71caf18e286e7e63bec8ef2a55d60c4ec3f5e928..2548b3fa8c9e2651b3ddc618a464eb7bf67ae21e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3218,7 +3218,8 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, assert(var->value->type == init_value->value.type); ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false, PtrLenSingle, var->align_bytes, 0, 0); - gen_assign_raw(g, var->value_ref, var_ptr_type, ir_llvm_value(g, init_value)); + LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value); + gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val); } else { bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base); if (want_safe) { @@ -5863,12 +5864,20 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref, &const_val->data.x_union.tag); - LLVMValueRef fields[2]; + LLVMValueRef fields[3]; fields[type_entry->data.unionation.gen_union_index] = union_value_ref; fields[type_entry->data.unionation.gen_tag_index] = tag_value; if (make_unnamed_struct) { - return LLVMConstStruct(fields, 2, false); + LLVMValueRef result = LLVMConstStruct(fields, 2, false); + size_t expected_sz = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref); + size_t actual_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(result)); + if (actual_sz < expected_sz) { + unsigned pad_sz = expected_sz - actual_sz; + fields[2] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz)); + result = LLVMConstStruct(fields, 3, false); + } + return result; } else { return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); } diff --git a/test/behavior.zig b/test/behavior.zig index 25997a2a4b24119ea108bbf856fbfc9ef989ede2..cae8c4b0f35a5e5d2fdfaed74a4f1b12bf36cfcf 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -10,6 +10,7 @@ comptime { _ = @import("cases/bool.zig"); _ = @import("cases/bugs/1111.zig"); _ = @import("cases/bugs/1277.zig"); + _ = @import("cases/bugs/1381.zig"); _ = @import("cases/bugs/1421.zig"); _ = @import("cases/bugs/394.zig"); _ = @import("cases/bugs/655.zig"); diff --git a/test/cases/bugs/1381.zig b/test/cases/bugs/1381.zig new file mode 100644 index 0000000000000000000000000000000000000000..2d452da15610e28f13c2a5d9811791435f0b757b --- /dev/null +++ b/test/cases/bugs/1381.zig @@ -0,0 +1,21 @@ +const std = @import("std"); + +const B = union(enum) { + D: u8, + E: u16, +}; + +const A = union(enum) { + B: B, + C: u8, +}; + +test "union that needs padding bytes inside an array" { + var as = []A{ + A{ .B = B{ .D = 1 } }, + A{ .B = B{ .D = 1 } }, + }; + + const a = as[0].B; + std.debug.assertOrPanic(a.D == 1); +} -- 2.54.0