Skip to content

stage1: support @alignOf(T) aligned member inside struct T #1845

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions src/analyze.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2686,13 +2686,22 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
}

size_t field_count = struct_type->data.structure.src_field_count;
bool self_resolving = false;
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 we have no type_entry for the field, assume that we are in the
// midst of resolving this struct. We further assume that since the
// resolved alignment of the other fields of this struct is ultimately
// equal to the resolved alignment of this struct, we can safely ignore.
//
// If this struct is used down-stream in aligning a sub-struct, ignoring
// this struct in the context of a sub struct has the same effect since
// the other fields will be calculated and bubble-up.
if (nullptr == field->type_entry) {
self_resolving = true;
continue;
}

if (type_is_invalid(field->type_entry)) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
Expand Down Expand Up @@ -2723,6 +2732,14 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
return ErrorSemanticAnalyzeFail;
}

if ( self_resolving
&& field_count > 0
) {
// If we get here it's due to self-referencing this struct before it has been fully resolved.
// In this case, set alignment to target pointer default.
struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref,
LLVMPointerType(LLVMInt8Type(), 0));
}
struct_type->data.structure.resolve_status = ResolveStatusAlignmentKnown;
return ErrorNone;
}
Expand Down
11 changes: 11 additions & 0 deletions std/array_list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
42 changes: 42 additions & 0 deletions test/cases/struct_contains_slice_of_itself.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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);
}