aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2018-12-20 12:36:30 -0500
committerAndrew Kelley <andrew@ziglang.org>2018-12-20 12:36:30 -0500
commit459045aa40d64ac883d3908ddcbfcb8aa3867c0d (patch)
tree5d421882b9195d98e530e1374f0d0db14275f271
parent8768816d69ddf3253d2598923643f390cc18082c (diff)
parent0f54194e6ab2b0cbdc798b84cc4213a07ed1d0c1 (diff)
downloadzig-459045aa40d64ac883d3908ddcbfcb8aa3867c0d.tar.gz
zig-459045aa40d64ac883d3908ddcbfcb8aa3867c0d.zip
Merge branch 'kristate-zig-backport-issue1832'
-rw-r--r--src/analyze.cpp55
-rw-r--r--std/array_list.zig11
-rw-r--r--test/cases/struct_contains_slice_of_itself.zig42
3 files changed, 86 insertions, 22 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 46686ce772..9c24f3cc8d 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -2681,39 +2681,50 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
assert(decl_node->type == NodeTypeContainerDecl);
assert(struct_type->di_type);
+ size_t field_count = struct_type->data.structure.src_field_count;
if (struct_type->data.structure.layout == ContainerLayoutPacked) {
struct_type->data.structure.abi_alignment = 1;
- }
-
- size_t field_count = struct_type->data.structure.src_field_count;
- for (size_t i = 0; i < field_count; i += 1) {
- TypeStructField *field = &struct_type->data.structure.fields[i];
-
- // If this assertion trips, look up the call stack. Probably something is
- // calling type_resolve with ResolveStatusAlignmentKnown when it should only
- // be resolving ResolveStatusZeroBitsKnown
- assert(field->type_entry != nullptr);
-
- if (type_is_invalid(field->type_entry)) {
- struct_type->data.structure.resolve_status = ResolveStatusInvalid;
- break;
+ for (size_t i = 0; i < field_count; i += 1) {
+ TypeStructField *field = &struct_type->data.structure.fields[i];
+ if (field->type_entry != nullptr && type_is_invalid(field->type_entry)) {
+ struct_type->data.structure.resolve_status = ResolveStatusInvalid;
+ break;
+ }
}
+ } else for (size_t i = 0; i < field_count; i += 1) {
+ TypeStructField *field = &struct_type->data.structure.fields[i];
+ uint32_t this_field_align;
+
+ // TODO If we have no type_entry for the field, we've already failed to
+ // compile the program correctly. This stage1 compiler needs a deeper
+ // reworking to make this correct, or we can ignore the problem
+ // and make sure it is fixed in stage2. This workaround is for when
+ // there is a false positive of a dependency loop, of alignment depending
+ // on itself. When this false positive happens we assume a pointer-aligned
+ // field, which is usually fine but could be incorrectly over-aligned or
+ // even under-aligned. See https://github.com/ziglang/zig/issues/1512
+ if (field->type_entry == nullptr) {
+ this_field_align = LLVMABIAlignmentOfType(g->target_data_ref, LLVMPointerType(LLVMInt8Type(), 0));
+ } else {
+ if (type_is_invalid(field->type_entry)) {
+ struct_type->data.structure.resolve_status = ResolveStatusInvalid;
+ break;
+ }
- if (!type_has_bits(field->type_entry))
- continue;
+ if (!type_has_bits(field->type_entry))
+ continue;
- // alignment of structs is the alignment of the most-aligned field
- if (struct_type->data.structure.layout != ContainerLayoutPacked) {
if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
break;
}
- uint32_t this_field_align = get_abi_alignment(g, field->type_entry);
+ this_field_align = get_abi_alignment(g, field->type_entry);
assert(this_field_align != 0);
- if (this_field_align > struct_type->data.structure.abi_alignment) {
- struct_type->data.structure.abi_alignment = this_field_align;
- }
+ }
+ // alignment of structs is the alignment of the most-aligned field
+ if (this_field_align > struct_type->data.structure.abi_alignment) {
+ struct_type->data.structure.abi_alignment = this_field_align;
}
}
diff --git a/std/array_list.zig b/std/array_list.zig
index 3ee425fe14..ddad9c989c 100644
--- a/std/array_list.zig
+++ b/std/array_list.zig
@@ -398,3 +398,14 @@ test "std.ArrayList.insertSlice" {
assert(list.len == 6);
assert(list.items[0] == 1);
}
+
+const Item = struct {
+ integer: i32,
+ sub_items: ArrayList(Item),
+};
+
+test "std.ArrayList: ArrayList(T) of struct T" {
+ var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(debug.global_allocator) };
+ try root.sub_items.append( Item{ .integer = 42, .sub_items = ArrayList(Item).init(debug.global_allocator) } );
+ assert(root.sub_items.items[0].integer == 42);
+}
diff --git a/test/cases/struct_contains_slice_of_itself.zig b/test/cases/struct_contains_slice_of_itself.zig
index 07987ae32b..aa3075312c 100644
--- a/test/cases/struct_contains_slice_of_itself.zig
+++ b/test/cases/struct_contains_slice_of_itself.zig
@@ -5,6 +5,11 @@ const Node = struct {
children: []Node,
};
+const NodeAligned = struct {
+ payload: i32,
+ children: []align(@alignOf(NodeAligned)) NodeAligned,
+};
+
test "struct contains slice of itself" {
var other_nodes = []Node{
Node{
@@ -41,3 +46,40 @@ test "struct contains slice of itself" {
assert(root.children[2].children[0].payload == 31);
assert(root.children[2].children[1].payload == 32);
}
+
+test "struct contains aligned slice of itself" {
+ var other_nodes = []NodeAligned{
+ NodeAligned{
+ .payload = 31,
+ .children = []NodeAligned{},
+ },
+ NodeAligned{
+ .payload = 32,
+ .children = []NodeAligned{},
+ },
+ };
+ var nodes = []NodeAligned{
+ NodeAligned{
+ .payload = 1,
+ .children = []NodeAligned{},
+ },
+ NodeAligned{
+ .payload = 2,
+ .children = []NodeAligned{},
+ },
+ NodeAligned{
+ .payload = 3,
+ .children = other_nodes[0..],
+ },
+ };
+ const root = NodeAligned{
+ .payload = 1234,
+ .children = nodes[0..],
+ };
+ assert(root.payload == 1234);
+ assert(root.children[0].payload == 1);
+ assert(root.children[1].payload == 2);
+ assert(root.children[2].payload == 3);
+ assert(root.children[2].children[0].payload == 31);
+ assert(root.children[2].children[1].payload == 32);
+}