From 3f776af3fa58b47d15a81b17c15e5b0e1c5ccf28 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 14 Sep 2018 18:56:30 -0400 Subject: fix alignment of structs closes #1248 closes #1052 closes #1154 --- src/analyze.cpp | 387 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 218 insertions(+), 169 deletions(-) (limited to 'src/analyze.cpp') 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 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(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(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 -- cgit v1.2.3