Skip to content

Commit

Permalink
fix incorrect union const value generation
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
andrewrk committed Sep 11, 2018
1 parent c4f96ea commit dd1338b
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 3 deletions.
15 changes: 12 additions & 3 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions test/behavior.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
21 changes: 21 additions & 0 deletions test/cases/bugs/1381.zig
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit dd1338b

Please sign in to comment.