Skip to content

Commit 459045a

Browse files
committed
Merge branch 'kristate-zig-backport-issue1832'
2 parents 8768816 + 0f54194 commit 459045a

File tree

3 files changed

+86
-22
lines changed

3 files changed

+86
-22
lines changed

src/analyze.cpp

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2681,39 +2681,50 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
26812681
assert(decl_node->type == NodeTypeContainerDecl);
26822682
assert(struct_type->di_type);
26832683

2684+
size_t field_count = struct_type->data.structure.src_field_count;
26842685
if (struct_type->data.structure.layout == ContainerLayoutPacked) {
26852686
struct_type->data.structure.abi_alignment = 1;
2686-
}
2687-
2688-
size_t field_count = struct_type->data.structure.src_field_count;
2689-
for (size_t i = 0; i < field_count; i += 1) {
2690-
TypeStructField *field = &struct_type->data.structure.fields[i];
2691-
2692-
// If this assertion trips, look up the call stack. Probably something is
2693-
// calling type_resolve with ResolveStatusAlignmentKnown when it should only
2694-
// be resolving ResolveStatusZeroBitsKnown
2695-
assert(field->type_entry != nullptr);
2696-
2697-
if (type_is_invalid(field->type_entry)) {
2698-
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
2699-
break;
2687+
for (size_t i = 0; i < field_count; i += 1) {
2688+
TypeStructField *field = &struct_type->data.structure.fields[i];
2689+
if (field->type_entry != nullptr && type_is_invalid(field->type_entry)) {
2690+
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
2691+
break;
2692+
}
27002693
}
2694+
} else for (size_t i = 0; i < field_count; i += 1) {
2695+
TypeStructField *field = &struct_type->data.structure.fields[i];
2696+
uint32_t this_field_align;
2697+
2698+
// TODO If we have no type_entry for the field, we've already failed to
2699+
// compile the program correctly. This stage1 compiler needs a deeper
2700+
// reworking to make this correct, or we can ignore the problem
2701+
// and make sure it is fixed in stage2. This workaround is for when
2702+
// there is a false positive of a dependency loop, of alignment depending
2703+
// on itself. When this false positive happens we assume a pointer-aligned
2704+
// field, which is usually fine but could be incorrectly over-aligned or
2705+
// even under-aligned. See https://github.com/ziglang/zig/issues/1512
2706+
if (field->type_entry == nullptr) {
2707+
this_field_align = LLVMABIAlignmentOfType(g->target_data_ref, LLVMPointerType(LLVMInt8Type(), 0));
2708+
} else {
2709+
if (type_is_invalid(field->type_entry)) {
2710+
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
2711+
break;
2712+
}
27012713

2702-
if (!type_has_bits(field->type_entry))
2703-
continue;
2714+
if (!type_has_bits(field->type_entry))
2715+
continue;
27042716

2705-
// alignment of structs is the alignment of the most-aligned field
2706-
if (struct_type->data.structure.layout != ContainerLayoutPacked) {
27072717
if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) {
27082718
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
27092719
break;
27102720
}
27112721

2712-
uint32_t this_field_align = get_abi_alignment(g, field->type_entry);
2722+
this_field_align = get_abi_alignment(g, field->type_entry);
27132723
assert(this_field_align != 0);
2714-
if (this_field_align > struct_type->data.structure.abi_alignment) {
2715-
struct_type->data.structure.abi_alignment = this_field_align;
2716-
}
2724+
}
2725+
// alignment of structs is the alignment of the most-aligned field
2726+
if (this_field_align > struct_type->data.structure.abi_alignment) {
2727+
struct_type->data.structure.abi_alignment = this_field_align;
27172728
}
27182729
}
27192730

std/array_list.zig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,3 +398,14 @@ test "std.ArrayList.insertSlice" {
398398
assert(list.len == 6);
399399
assert(list.items[0] == 1);
400400
}
401+
402+
const Item = struct {
403+
integer: i32,
404+
sub_items: ArrayList(Item),
405+
};
406+
407+
test "std.ArrayList: ArrayList(T) of struct T" {
408+
var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(debug.global_allocator) };
409+
try root.sub_items.append( Item{ .integer = 42, .sub_items = ArrayList(Item).init(debug.global_allocator) } );
410+
assert(root.sub_items.items[0].integer == 42);
411+
}

test/cases/struct_contains_slice_of_itself.zig

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ const Node = struct {
55
children: []Node,
66
};
77

8+
const NodeAligned = struct {
9+
payload: i32,
10+
children: []align(@alignOf(NodeAligned)) NodeAligned,
11+
};
12+
813
test "struct contains slice of itself" {
914
var other_nodes = []Node{
1015
Node{
@@ -41,3 +46,40 @@ test "struct contains slice of itself" {
4146
assert(root.children[2].children[0].payload == 31);
4247
assert(root.children[2].children[1].payload == 32);
4348
}
49+
50+
test "struct contains aligned slice of itself" {
51+
var other_nodes = []NodeAligned{
52+
NodeAligned{
53+
.payload = 31,
54+
.children = []NodeAligned{},
55+
},
56+
NodeAligned{
57+
.payload = 32,
58+
.children = []NodeAligned{},
59+
},
60+
};
61+
var nodes = []NodeAligned{
62+
NodeAligned{
63+
.payload = 1,
64+
.children = []NodeAligned{},
65+
},
66+
NodeAligned{
67+
.payload = 2,
68+
.children = []NodeAligned{},
69+
},
70+
NodeAligned{
71+
.payload = 3,
72+
.children = other_nodes[0..],
73+
},
74+
};
75+
const root = NodeAligned{
76+
.payload = 1234,
77+
.children = nodes[0..],
78+
};
79+
assert(root.payload == 1234);
80+
assert(root.children[0].payload == 1);
81+
assert(root.children[1].payload == 2);
82+
assert(root.children[2].payload == 3);
83+
assert(root.children[2].children[0].payload == 31);
84+
assert(root.children[2].children[1].payload == 32);
85+
}

0 commit comments

Comments
 (0)