aboutsummaryrefslogtreecommitdiff
path: root/src/analyze.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/analyze.cpp')
-rw-r--r--src/analyze.cpp387
1 files changed, 218 insertions, 169 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp
index d403433c5c..c9ae865390 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -23,6 +23,7 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type);
static Error resolve_struct_type(CodeGen *g, ZigType *struct_type);
static Error ATTRIBUTE_MUST_USE resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type);
+static Error ATTRIBUTE_MUST_USE resolve_struct_alignment(CodeGen *g, ZigType *struct_type);
static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type);
static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *union_type);
static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);
@@ -254,18 +255,42 @@ AstNode *type_decl_node(ZigType *type_entry) {
zig_unreachable();
}
-bool type_is_complete(ZigType *type_entry) {
+bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
switch (type_entry->id) {
case ZigTypeIdInvalid:
zig_unreachable();
case ZigTypeIdStruct:
- return type_entry->data.structure.complete;
+ return type_entry->data.structure.resolve_status >= status;
case ZigTypeIdEnum:
- return type_entry->data.enumeration.complete;
+ switch (status) {
+ case ResolveStatusUnstarted:
+ return true;
+ case ResolveStatusInvalid:
+ zig_unreachable();
+ case ResolveStatusZeroBitsKnown:
+ return type_entry->data.enumeration.zero_bits_known;
+ case ResolveStatusAlignmentKnown:
+ return type_entry->data.enumeration.zero_bits_known;
+ case ResolveStatusSizeKnown:
+ return type_entry->data.enumeration.complete;
+ }
+ zig_unreachable();
case ZigTypeIdUnion:
- return type_entry->data.unionation.complete;
+ switch (status) {
+ case ResolveStatusUnstarted:
+ return true;
+ case ResolveStatusInvalid:
+ zig_unreachable();
+ case ResolveStatusZeroBitsKnown:
+ return type_entry->data.unionation.zero_bits_known;
+ case ResolveStatusAlignmentKnown:
+ return type_entry->data.unionation.zero_bits_known;
+ case ResolveStatusSizeKnown:
+ return type_entry->data.unionation.complete;
+ }
+ zig_unreachable();
case ZigTypeIdOpaque:
- return false;
+ return status < ResolveStatusSizeKnown;
case ZigTypeIdMetaType:
case ZigTypeIdVoid:
case ZigTypeIdBool:
@@ -291,43 +316,10 @@ bool type_is_complete(ZigType *type_entry) {
zig_unreachable();
}
-bool type_has_zero_bits_known(ZigType *type_entry) {
- switch (type_entry->id) {
- case ZigTypeIdInvalid:
- zig_unreachable();
- case ZigTypeIdStruct:
- return type_entry->data.structure.zero_bits_known;
- case ZigTypeIdEnum:
- return type_entry->data.enumeration.zero_bits_known;
- case ZigTypeIdUnion:
- return type_entry->data.unionation.zero_bits_known;
- case ZigTypeIdMetaType:
- case ZigTypeIdVoid:
- case ZigTypeIdBool:
- case ZigTypeIdUnreachable:
- case ZigTypeIdInt:
- case ZigTypeIdFloat:
- case ZigTypeIdPointer:
- case ZigTypeIdArray:
- case ZigTypeIdComptimeFloat:
- case ZigTypeIdComptimeInt:
- case ZigTypeIdUndefined:
- case ZigTypeIdNull:
- case ZigTypeIdOptional:
- case ZigTypeIdErrorUnion:
- case ZigTypeIdErrorSet:
- case ZigTypeIdFn:
- case ZigTypeIdNamespace:
- case ZigTypeIdBoundFn:
- case ZigTypeIdArgTuple:
- case ZigTypeIdOpaque:
- case ZigTypeIdPromise:
- return true;
- }
- zig_unreachable();
+bool type_is_complete(ZigType *type_entry) {
+ return type_is_resolved(type_entry, ResolveStatusSizeKnown);
}
-
uint64_t type_size(CodeGen *g, ZigType *type_entry) {
assert(type_is_complete(type_entry));
@@ -376,7 +368,7 @@ uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) {
Result<bool> type_is_copyable(CodeGen *g, ZigType *type_entry) {
Error err;
- if ((err = type_ensure_zero_bits_known(g, type_entry)))
+ if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
return err;
if (!type_has_bits(type_entry))
@@ -431,10 +423,15 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
assert(!type_is_invalid(child_type));
assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque);
+ if (byte_alignment != 0) {
+ uint32_t abi_alignment = get_abi_alignment(g, child_type);
+ if (byte_alignment == abi_alignment)
+ byte_alignment = 0;
+ }
+
TypeId type_id = {};
ZigType **parent_pointer = nullptr;
- uint32_t abi_alignment = get_abi_alignment(g, child_type);
- if (unaligned_bit_count != 0 || is_volatile || byte_alignment != abi_alignment || ptr_len != PtrLenSingle) {
+ if (unaligned_bit_count != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle) {
type_id.id = ZigTypeIdPointer;
type_id.data.pointer.child_type = child_type;
type_id.data.pointer.is_const = is_const;
@@ -451,12 +448,12 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
assert(bit_offset == 0);
parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)];
if (*parent_pointer) {
- assert((*parent_pointer)->data.pointer.alignment == byte_alignment);
+ assert((*parent_pointer)->data.pointer.explicit_alignment == 0);
return *parent_pointer;
}
}
- assertNoError(type_ensure_zero_bits_known(g, child_type));
+ assert(type_is_resolved(child_type, ResolveStatusZeroBitsKnown));
ZigType *entry = new_type_table_entry(ZigTypeIdPointer);
entry->is_copyable = true;
@@ -465,11 +462,14 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
const char *const_str = is_const ? "const " : "";
const char *volatile_str = is_volatile ? "volatile " : "";
buf_resize(&entry->name, 0);
- if (unaligned_bit_count == 0 && byte_alignment == abi_alignment) {
+ if (unaligned_bit_count == 0 && byte_alignment == 0) {
buf_appendf(&entry->name, "%s%s%s%s", star_str, const_str, volatile_str, buf_ptr(&child_type->name));
} else if (unaligned_bit_count == 0) {
buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s", star_str, byte_alignment,
const_str, volatile_str, buf_ptr(&child_type->name));
+ } else if (byte_alignment == 0) {
+ buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str,
+ bit_offset, bit_offset + unaligned_bit_count, const_str, volatile_str, buf_ptr(&child_type->name));
} else {
buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, byte_alignment,
bit_offset, bit_offset + unaligned_bit_count, const_str, volatile_str, buf_ptr(&child_type->name));
@@ -480,8 +480,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
entry->zero_bits = !type_has_bits(child_type);
if (!entry->zero_bits) {
- assert(byte_alignment > 0);
- if (is_const || is_volatile || unaligned_bit_count != 0 || byte_alignment != abi_alignment ||
+ if (is_const || is_volatile || unaligned_bit_count != 0 || byte_alignment != 0 ||
ptr_len != PtrLenSingle)
{
ZigType *peer_type = get_pointer_to_type(g, child_type, false);
@@ -505,7 +504,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
entry->data.pointer.child_type = child_type;
entry->data.pointer.is_const = is_const;
entry->data.pointer.is_volatile = is_volatile;
- entry->data.pointer.alignment = byte_alignment;
+ entry->data.pointer.explicit_alignment = byte_alignment;
entry->data.pointer.bit_offset = bit_offset;
entry->data.pointer.unaligned_bit_count = unaligned_bit_count;
@@ -518,8 +517,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
}
ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) {
- return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle,
- get_abi_alignment(g, child_type), 0, 0);
+ return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0);
}
ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type) {
@@ -800,8 +798,7 @@ static void slice_type_common_init(CodeGen *g, ZigType *pointer_type, ZigType *e
entry->data.structure.fields_by_name.put(ptr_field_name, &entry->data.structure.fields[slice_ptr_index]);
entry->data.structure.fields_by_name.put(len_field_name, &entry->data.structure.fields[slice_len_index]);
- assert(type_has_zero_bits_known(pointer_type->data.pointer.child_type));
- if (pointer_type->data.pointer.child_type->zero_bits) {
+ if (!type_has_bits(pointer_type->data.pointer.child_type)) {
entry->data.structure.gen_field_count = 1;
entry->data.structure.fields[slice_ptr_index].gen_index = SIZE_MAX;
entry->data.structure.fields[slice_len_index].gen_index = 0;
@@ -826,20 +823,18 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
buf_appendf(&entry->name, "[]%s", buf_ptr(&ptr_type->name) + name_offset);
ZigType *child_type = ptr_type->data.pointer.child_type;
- uint32_t abi_alignment = get_abi_alignment(g, child_type);
if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile ||
- ptr_type->data.pointer.alignment != abi_alignment)
+ ptr_type->data.pointer.explicit_alignment != 0)
{
ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false,
- PtrLenUnknown, abi_alignment, 0, 0);
+ PtrLenUnknown, 0, 0, 0);
ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
slice_type_common_init(g, ptr_type, entry);
entry->type_ref = peer_slice_type->type_ref;
entry->di_type = peer_slice_type->di_type;
- entry->data.structure.complete = true;
- entry->data.structure.zero_bits_known = true;
+ entry->data.structure.resolve_status = ResolveStatusSizeKnown;
entry->data.structure.abi_alignment = peer_slice_type->data.structure.abi_alignment;
*parent_pointer = entry;
@@ -851,15 +846,15 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
if (is_slice(child_type)) {
ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry;
assert(child_ptr_type->id == ZigTypeIdPointer);
- ZigType *grand_child_type = child_ptr_type->data.pointer.child_type;
if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile ||
- child_ptr_type->data.pointer.alignment != get_abi_alignment(g, grand_child_type))
+ child_ptr_type->data.pointer.explicit_alignment != 0)
{
+ ZigType *grand_child_type = child_ptr_type->data.pointer.child_type;
ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false,
- PtrLenUnknown, get_abi_alignment(g, grand_child_type), 0, 0);
+ PtrLenUnknown, 0, 0, 0);
ZigType *bland_child_slice = get_slice_type(g, bland_child_ptr_type);
ZigType *peer_ptr_type = get_pointer_to_type_extra(g, bland_child_slice, false, false,
- PtrLenUnknown, get_abi_alignment(g, bland_child_slice), 0, 0);
+ PtrLenUnknown, 0, 0, 0);
ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
entry->type_ref = peer_slice_type->type_ref;
@@ -961,8 +956,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
}
- entry->data.structure.complete = true;
- entry->data.structure.zero_bits_known = true;
+ entry->data.structure.resolve_status = ResolveStatusSizeKnown;
*parent_pointer = entry;
return entry;
@@ -1367,7 +1361,7 @@ static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_
static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **out_buffer) {
ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
- PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
+ PtrLenUnknown, 0, 0, 0);
ZigType *str_type = get_slice_type(g, ptr_type);
IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr);
if (type_is_invalid(instr->value.type))
@@ -1576,7 +1570,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
return g->builtin_types.entry_invalid;
}
if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
- if ((err = type_ensure_zero_bits_known(g, type_entry)))
+ if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
return g->builtin_types.entry_invalid;
if (!type_has_bits(type_entry)) {
add_node_error(g, param_node->data.param_decl.type,
@@ -1624,7 +1618,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdPromise:
- if ((err = type_ensure_zero_bits_known(g, type_entry)))
+ if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
return g->builtin_types.entry_invalid;
if (type_requires_comptime(type_entry)) {
add_node_error(g, param_node->data.param_decl.type,
@@ -1714,7 +1708,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdPromise:
- if ((err = type_ensure_zero_bits_known(g, fn_type_id.return_type)))
+ if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusZeroBitsKnown)))
return g->builtin_types.entry_invalid;
if (type_requires_comptime(fn_type_id.return_type)) {
return get_generic_fn_type(g, &fn_type_id);
@@ -1740,7 +1734,7 @@ bool type_is_invalid(ZigType *type_entry) {
case ZigTypeIdInvalid:
return true;
case ZigTypeIdStruct:
- return type_entry->data.structure.is_invalid;
+ return type_entry->data.structure.resolve_status == ResolveStatusInvalid;
case ZigTypeIdEnum:
return type_entry->data.enumeration.is_invalid;
case ZigTypeIdUnion:
@@ -1855,8 +1849,7 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
struct_type->data.structure.src_field_count = field_count;
struct_type->data.structure.gen_field_count = 0;
- struct_type->data.structure.zero_bits_known = true;
- struct_type->data.structure.complete = true;
+ struct_type->data.structure.resolve_status = ResolveStatusSizeKnown;
struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
struct_type->data.structure.fields_by_name.init(field_count);
@@ -1928,26 +1921,29 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
assert(struct_type->id == ZigTypeIdStruct);
- if (struct_type->data.structure.complete)
+ Error err;
+
+ if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
+ return ErrorSemanticAnalyzeFail;
+ if (struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown)
return ErrorNone;
- Error err;
- if ((err = resolve_struct_zero_bits(g, struct_type)))
+ if ((err = resolve_struct_alignment(g, struct_type)))
return err;
AstNode *decl_node = struct_type->data.structure.decl_node;
- if (struct_type->data.structure.embedded_in_current) {
- struct_type->data.structure.is_invalid = true;
- if (!struct_type->data.structure.reported_infinite_err) {
- struct_type->data.structure.reported_infinite_err = true;
+ if (struct_type->data.structure.resolve_loop_flag) {
+ if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
+ struct_type->data.structure.resolve_status = ResolveStatusInvalid;
add_node_error(g, decl_node,
- buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
+ buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
}
return ErrorSemanticAnalyzeFail;
}
- assert(!struct_type->data.structure.zero_bits_loop_flag);
+ struct_type->data.structure.resolve_loop_flag = true;
+
assert(struct_type->data.structure.fields || struct_type->data.structure.src_field_count == 0);
assert(decl_node->type == NodeTypeContainerDecl);
@@ -1956,9 +1952,6 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
size_t gen_field_count = struct_type->data.structure.gen_field_count;
LLVMTypeRef *element_types = allocate<LLVMTypeRef>(gen_field_count);
- // this field should be set to true only during the recursive calls to resolve_struct_type
- struct_type->data.structure.embedded_in_current = true;
-
Scope *scope = &struct_type->data.structure.decls_scope->base;
size_t gen_field_index = 0;
@@ -1972,7 +1965,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
ZigType *field_type = type_struct_field->type_entry;
if ((err = ensure_complete_type(g, field_type))) {
- struct_type->data.structure.is_invalid = true;
+ struct_type->data.structure.resolve_status = ResolveStatusInvalid;
break;
}
@@ -1982,7 +1975,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
add_node_error(g, field_source_node,
buf_sprintf("extern structs cannot contain fields of type '%s'",
buf_ptr(&field_type->name)));
- struct_type->data.structure.is_invalid = true;
+ struct_type->data.structure.resolve_status = ResolveStatusInvalid;
break;
}
}
@@ -1998,7 +1991,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
add_node_error(g, field_source_node,
buf_sprintf("packed structs cannot contain fields of type '%s'",
buf_ptr(&field_type->name)));
- struct_type->data.structure.is_invalid = true;
+ struct_type->data.structure.resolve_status = ResolveStatusInvalid;
break;
}
@@ -2049,12 +2042,13 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
gen_field_index += 1;
}
- struct_type->data.structure.embedded_in_current = false;
- struct_type->data.structure.complete = true;
+ struct_type->data.structure.resolve_loop_flag = false;
- if (struct_type->data.structure.is_invalid)
+ if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
return ErrorSemanticAnalyzeFail;
+ struct_type->data.structure.resolve_status = ResolveStatusSizeKnown;
+
if (struct_type->zero_bits) {
struct_type->type_ref = LLVMVoidType();
@@ -2116,7 +2110,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
assert(field_type->type_ref);
assert(struct_type->type_ref);
- assert(struct_type->data.structure.complete);
+ assert(struct_type->data.structure.resolve_status == ResolveStatusSizeKnown);
uint64_t debug_size_in_bits;
uint64_t debug_align_in_bits;
uint64_t debug_offset_in_bits;
@@ -2570,30 +2564,18 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
Error err;
- if (struct_type->data.structure.is_invalid)
+ if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
return ErrorSemanticAnalyzeFail;
-
- if (struct_type->data.structure.zero_bits_known)
+ if (struct_type->data.structure.resolve_status >= ResolveStatusZeroBitsKnown)
return ErrorNone;
- if (struct_type->data.structure.zero_bits_loop_flag) {
- // If we get here it's due to recursion. This is a design flaw in the compiler,
- // we should be able to still figure out alignment, but here we give up and say that
- // the alignment is pointer width, then assert that the first field is within that
- // alignment
- struct_type->data.structure.zero_bits_known = true;
- struct_type->data.structure.zero_bits_loop_flag = false;
- if (struct_type->data.structure.abi_alignment == 0) {
- if (struct_type->data.structure.layout == ContainerLayoutPacked) {
- struct_type->data.structure.abi_alignment = 1;
- } else {
- struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, LLVMPointerType(LLVMInt8Type(), 0));
- }
- }
+ if (struct_type->data.structure.resolve_loop_flag) {
+ struct_type->data.structure.resolve_status = ResolveStatusZeroBitsKnown;
+ struct_type->data.structure.resolve_loop_flag = false;
return ErrorNone;
}
- struct_type->data.structure.zero_bits_loop_flag = true;
+ struct_type->data.structure.resolve_loop_flag = true;
AstNode *decl_node = struct_type->data.structure.decl_node;
assert(decl_node->type == NodeTypeContainerDecl);
@@ -2616,7 +2598,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
if (field_node->data.struct_field.type == nullptr) {
add_node_error(g, field_node, buf_sprintf("struct field missing type"));
- struct_type->data.structure.is_invalid = true;
+ struct_type->data.structure.resolve_status = ResolveStatusInvalid;
continue;
}
@@ -2625,7 +2607,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
ErrorMsg *msg = add_node_error(g, field_node,
buf_sprintf("duplicate struct field: '%s'", buf_ptr(type_struct_field->name)));
add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
- struct_type->data.structure.is_invalid = true;
+ struct_type->data.structure.resolve_status = ResolveStatusInvalid;
continue;
}
@@ -2639,8 +2621,8 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
buf_sprintf("enums, not structs, support field assignment"));
}
- if ((err = type_ensure_zero_bits_known(g, field_type))) {
- struct_type->data.structure.is_invalid = true;
+ if ((err = type_resolve(g, field_type, ResolveStatusZeroBitsKnown))) {
+ struct_type->data.structure.resolve_status = ResolveStatusInvalid;
continue;
}
@@ -2651,36 +2633,87 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
if (!type_has_bits(field_type))
continue;
- if (gen_field_index == 0) {
- if (struct_type->data.structure.layout == ContainerLayoutPacked) {
- struct_type->data.structure.abi_alignment = 1;
- } else if (struct_type->data.structure.abi_alignment == 0) {
- // Alignment of structs is the alignment of the first field, for now.
- // TODO change this when we re-order struct fields (issue #168)
- struct_type->data.structure.abi_alignment = get_abi_alignment(g, field_type);
- assert(struct_type->data.structure.abi_alignment != 0);
- } else {
- // due to a design flaw in the compiler we assumed that alignment was
- // pointer width, so we assert that this wasn't violated.
- if (get_abi_alignment(g, field_type) > struct_type->data.structure.abi_alignment) {
- zig_panic("compiler design flaw: incorrect alignment assumption");
- }
- }
- }
-
type_struct_field->gen_index = gen_field_index;
gen_field_index += 1;
}
- struct_type->data.structure.zero_bits_loop_flag = false;
+ struct_type->data.structure.resolve_loop_flag = false;
struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index;
struct_type->zero_bits = (gen_field_index == 0);
- struct_type->data.structure.zero_bits_known = true;
- if (struct_type->data.structure.is_invalid) {
+ if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
+ return ErrorSemanticAnalyzeFail;
+
+ struct_type->data.structure.resolve_status = ResolveStatusZeroBitsKnown;
+ return ErrorNone;
+}
+
+static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
+ assert(struct_type->id == ZigTypeIdStruct);
+
+ Error err;
+
+ if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
+ return ErrorSemanticAnalyzeFail;
+ if (struct_type->data.structure.resolve_status >= ResolveStatusAlignmentKnown)
+ return ErrorNone;
+
+ if ((err = resolve_struct_zero_bits(g, struct_type)))
+ return err;
+
+ AstNode *decl_node = struct_type->data.structure.decl_node;
+
+ if (struct_type->data.structure.resolve_loop_flag) {
+ if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
+ struct_type->data.structure.resolve_status = ResolveStatusInvalid;
+ add_node_error(g, decl_node,
+ buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
+ }
return ErrorSemanticAnalyzeFail;
}
+ struct_type->data.structure.resolve_loop_flag = true;
+ assert(decl_node->type == NodeTypeContainerDecl);
+ assert(struct_type->di_type);
+
+ 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_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);
+ assert(this_field_align != 0);
+ if (this_field_align > struct_type->data.structure.abi_alignment) {
+ struct_type->data.structure.abi_alignment = this_field_align;
+ }
+ }
+ }
+
+ struct_type->data.structure.resolve_loop_flag = false;
+
+ if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) {
+ return ErrorSemanticAnalyzeFail;
+ }
+
+ struct_type->data.structure.resolve_status = ResolveStatusAlignmentKnown;
return ErrorNone;
}
@@ -2807,7 +2840,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
return ErrorSemanticAnalyzeFail;
}
- if ((err = type_ensure_zero_bits_known(g, enum_type))) {
+ if ((err = type_resolve(g, enum_type, ResolveStatusAlignmentKnown))) {
assert(g->errors.length != 0);
return err;
}
@@ -2848,7 +2881,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
}
} else {
field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
- if ((err = type_ensure_zero_bits_known(g, field_type))) {
+ if ((err = type_resolve(g, field_type, ResolveStatusAlignmentKnown))) {
union_type->data.unionation.is_invalid = true;
continue;
}
@@ -3111,7 +3144,7 @@ static void typecheck_panic_fn(CodeGen *g, ZigFn *panic_fn) {
return wrong_panic_prototype(g, proto_node, fn_type);
}
ZigType *const_u8_ptr = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
- PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
+ PtrLenUnknown, 0, 0, 0);
ZigType *const_u8_slice = get_slice_type(g, const_u8_ptr);
if (fn_type_id->param_info[0].type != const_u8_slice) {
return wrong_panic_prototype(g, proto_node, fn_type);
@@ -3801,7 +3834,7 @@ TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name) {
TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name) {
assert(type_entry->id == ZigTypeIdStruct);
- assert(type_entry->data.structure.complete);
+ assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
if (type_entry->data.structure.src_field_count == 0)
return nullptr;
auto entry = type_entry->data.structure.fields_by_name.maybe_get(name);
@@ -3956,9 +3989,12 @@ bool type_is_codegen_pointer(ZigType *type) {
uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
ZigType *ptr_type = get_codegen_ptr_type(type);
if (ptr_type->id == ZigTypeIdPointer) {
- return ptr_type->data.pointer.alignment;
+ return (ptr_type->data.pointer.explicit_alignment == 0) ?
+ get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment;
} else if (ptr_type->id == ZigTypeIdFn) {
- return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment;
+ return (ptr_type->data.fn.fn_type_id.alignment == 0) ?
+ LLVMABIAlignmentOfType(g->target_data_ref, ptr_type->data.fn.raw_type_ref) :
+ ptr_type->data.fn.fn_type_id.alignment;
} else if (ptr_type->id == ZigTypeIdPromise) {
return get_coro_frame_align_bytes(g);
} else {
@@ -5023,8 +5059,8 @@ bool fn_eval_eql(Scope *a, Scope *b) {
bool type_has_bits(ZigType *type_entry) {
assert(type_entry);
- assert(type_entry->id != ZigTypeIdInvalid);
- assert(type_has_zero_bits_known(type_entry));
+ assert(!type_is_invalid(type_entry));
+ assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
return !type_entry->zero_bits;
}
@@ -5045,10 +5081,10 @@ bool type_requires_comptime(ZigType *type_entry) {
case ZigTypeIdArray:
return type_requires_comptime(type_entry->data.array.child_type);
case ZigTypeIdStruct:
- assert(type_has_zero_bits_known(type_entry));
+ assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
return type_entry->data.structure.requires_comptime;
case ZigTypeIdUnion:
- assert(type_has_zero_bits_known(type_entry));
+ assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
return type_entry->data.unionation.requires_comptime;
case ZigTypeIdOptional:
return type_requires_comptime(type_entry->data.maybe.child_type);
@@ -5124,7 +5160,7 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
const_val->special = ConstValSpecialStatic;
// TODO make this `[*]null u8` instead of `[*]u8`
const_val->type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
- PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
+ PtrLenUnknown, 0, 0, 0);
const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
const_val->data.x_ptr.data.base_array.array_val = array_val;
const_val->data.x_ptr.data.base_array.elem_index = 0;
@@ -5269,8 +5305,7 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr
assert(array_val->type->id == ZigTypeIdArray);
ZigType *ptr_type = get_pointer_to_type_extra(g, array_val->type->data.array.child_type,
- is_const, false, PtrLenUnknown, get_abi_alignment(g, array_val->type->data.array.child_type),
- 0, 0);
+ is_const, false, PtrLenUnknown, 0, 0, 0);
const_val->special = ConstValSpecialStatic;
const_val->type = get_slice_type(g, ptr_type);
@@ -5295,7 +5330,7 @@ void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue
const_val->special = ConstValSpecialStatic;
const_val->type = get_pointer_to_type_extra(g, child_type, is_const, false,
- ptr_len, get_abi_alignment(g, child_type), 0, 0);
+ ptr_len, 0, 0, 0);
const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
const_val->data.x_ptr.data.base_array.array_val = array_val;
const_val->data.x_ptr.data.base_array.elem_index = elem_index;
@@ -5394,32 +5429,46 @@ ConstExprValue *create_const_vals(size_t count) {
}
Error ensure_complete_type(CodeGen *g, ZigType *type_entry) {
- if (type_is_invalid(type_entry))
- return ErrorSemanticAnalyzeFail;
- if (type_entry->id == ZigTypeIdStruct) {
- if (!type_entry->data.structure.complete)
- return resolve_struct_type(g, type_entry);
- } else if (type_entry->id == ZigTypeIdEnum) {
- if (!type_entry->data.enumeration.complete)
- return resolve_enum_type(g, type_entry);
- } else if (type_entry->id == ZigTypeIdUnion) {
- if (!type_entry->data.unionation.complete)
- return resolve_union_type(g, type_entry);
- }
- return ErrorNone;
+ return type_resolve(g, type_entry, ResolveStatusSizeKnown);
}
-Error type_ensure_zero_bits_known(CodeGen *g, ZigType *type_entry) {
- if (type_is_invalid(type_entry))
+Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
+ if (type_is_invalid(ty))
return ErrorSemanticAnalyzeFail;
- if (type_entry->id == ZigTypeIdStruct) {
- return resolve_struct_zero_bits(g, type_entry);
- } else if (type_entry->id == ZigTypeIdEnum) {
- return resolve_enum_zero_bits(g, type_entry);
- } else if (type_entry->id == ZigTypeIdUnion) {
- return resolve_union_zero_bits(g, type_entry);
+ switch (status) {
+ case ResolveStatusUnstarted:
+ return ErrorNone;
+ case ResolveStatusInvalid:
+ zig_unreachable();
+ case ResolveStatusZeroBitsKnown:
+ if (ty->id == ZigTypeIdStruct) {
+ return resolve_struct_zero_bits(g, ty);
+ } else if (ty->id == ZigTypeIdEnum) {
+ return resolve_enum_zero_bits(g, ty);
+ } else if (ty->id == ZigTypeIdUnion) {
+ return resolve_union_zero_bits(g, ty);
+ }
+ return ErrorNone;
+ case ResolveStatusAlignmentKnown:
+ if (ty->id == ZigTypeIdStruct) {
+ return resolve_struct_alignment(g, ty);
+ } else if (ty->id == ZigTypeIdEnum) {
+ return resolve_enum_zero_bits(g, ty);
+ } else if (ty->id == ZigTypeIdUnion) {
+ return resolve_union_zero_bits(g, ty);
+ }
+ return ErrorNone;
+ case ResolveStatusSizeKnown:
+ if (ty->id == ZigTypeIdStruct) {
+ return resolve_struct_type(g, ty);
+ } else if (ty->id == ZigTypeIdEnum) {
+ return resolve_enum_type(g, ty);
+ } else if (ty->id == ZigTypeIdUnion) {
+ return resolve_union_type(g, ty);
+ }
+ return ErrorNone;
}
- return ErrorNone;
+ zig_unreachable();
}
bool ir_get_var_is_comptime(ZigVar *var) {
@@ -6262,7 +6311,7 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {
}
uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry) {
- assertNoError(type_ensure_zero_bits_known(g, type_entry));
+ assert(type_is_resolved(type_entry, ResolveStatusAlignmentKnown));
if (type_entry->zero_bits) return 0;
// We need to make this function work without requiring ensure_complete_type