diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-12-28 01:15:09 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-12-28 01:15:09 -0500 |
| commit | 25a5fc32fe68f911f7ac34e513e98cacb0ca17b1 (patch) | |
| tree | f709bc56d497216944224b8a1c3706431e684c27 /src | |
| parent | 15f843e70f18fe0cd7ee31a67af6eb8d6302dcbc (diff) | |
| download | zig-25a5fc32fe68f911f7ac34e513e98cacb0ca17b1.tar.gz zig-25a5fc32fe68f911f7ac34e513e98cacb0ca17b1.zip | |
IR: pass passSliceOfEmptyStructToFn test
Diffstat (limited to 'src')
| -rw-r--r-- | src/all_types.hpp | 10 | ||||
| -rw-r--r-- | src/analyze.cpp | 302 | ||||
| -rw-r--r-- | src/analyze.hpp | 2 | ||||
| -rw-r--r-- | src/codegen.cpp | 14 | ||||
| -rw-r--r-- | src/ir.cpp | 1 | ||||
| -rw-r--r-- | src/parseh.cpp | 2 |
6 files changed, 247 insertions, 84 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index 9c8a02f1aa..fc1abfc565 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -235,6 +235,7 @@ struct TypeEnumField { Buf *name; TypeTableEntry *type_entry; uint32_t value; + uint32_t gen_index; }; enum NodeType { @@ -813,6 +814,9 @@ struct TypeTableEntryStruct { bool reported_infinite_err; // whether we've finished resolving it bool complete; + + bool zero_bits_loop_flag; + bool zero_bits_known; }; struct TypeTableEntryMaybe { @@ -840,6 +844,9 @@ struct TypeTableEntryEnum { bool reported_infinite_err; // whether we've finished resolving it bool complete; + + bool zero_bits_loop_flag; + bool zero_bits_known; }; struct TypeTableEntryEnumTag { @@ -862,6 +869,9 @@ struct TypeTableEntryUnion { bool reported_infinite_err; // whether we've finished resolving it bool complete; + + bool zero_bits_loop_flag; + bool zero_bits_known; }; struct FnGenParamInfo { diff --git a/src/analyze.cpp b/src/analyze.cpp index c1cced1251..450bc2b3cd 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -20,6 +20,10 @@ static const size_t default_backward_branch_quota = 1000; static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type); static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type); +static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type); +static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type); +static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type); + AstNode *first_executing_node(AstNode *node) { switch (node->type) { case NodeTypeFnCallExpr: @@ -257,6 +261,44 @@ bool type_is_complete(TypeTableEntry *type_entry) { zig_unreachable(); } +bool type_has_zero_bits_known(TypeTableEntry *type_entry) { + switch (type_entry->id) { + case TypeTableEntryIdInvalid: + case TypeTableEntryIdVar: + zig_unreachable(); + case TypeTableEntryIdStruct: + return type_entry->data.structure.zero_bits_known; + case TypeTableEntryIdEnum: + return type_entry->data.enumeration.zero_bits_known; + case TypeTableEntryIdUnion: + return type_entry->data.unionation.zero_bits_known; + case TypeTableEntryIdMetaType: + case TypeTableEntryIdVoid: + case TypeTableEntryIdBool: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdPointer: + case TypeTableEntryIdArray: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdMaybe: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdPureError: + case TypeTableEntryIdFn: + case TypeTableEntryIdTypeDecl: + case TypeTableEntryIdNamespace: + case TypeTableEntryIdBlock: + case TypeTableEntryIdBoundFn: + case TypeTableEntryIdEnumTag: + return true; + } + zig_unreachable(); +} + + uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) { if (type_has_bits(type_entry)) { return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref); @@ -475,13 +517,14 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t return entry; } else { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray); - entry->type_ref = child_type->type_ref ? LLVMArrayType(child_type->type_ref, array_size) : nullptr; entry->zero_bits = (array_size == 0) || child_type->zero_bits; buf_resize(&entry->name, 0); buf_appendf(&entry->name, "[%" PRIu64 "]%s", array_size, buf_ptr(&child_type->name)); if (!entry->zero_bits) { + entry->type_ref = child_type->type_ref ? LLVMArrayType(child_type->type_ref, array_size) : nullptr; + uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref); @@ -507,14 +550,21 @@ static void slice_type_common_init(CodeGen *g, TypeTableEntry *child_type, entry->data.structure.src_field_count = element_count; entry->data.structure.gen_field_count = element_count; entry->data.structure.fields = allocate<TypeStructField>(element_count); - entry->data.structure.fields[0].name = buf_create_from_str("ptr"); - entry->data.structure.fields[0].type_entry = pointer_type; - entry->data.structure.fields[0].src_index = 0; - entry->data.structure.fields[0].gen_index = 0; - entry->data.structure.fields[1].name = buf_create_from_str("len"); - entry->data.structure.fields[1].type_entry = g->builtin_types.entry_usize; - entry->data.structure.fields[1].src_index = 1; - entry->data.structure.fields[1].gen_index = 1; + entry->data.structure.fields[slice_ptr_index].name = buf_create_from_str("ptr"); + entry->data.structure.fields[slice_ptr_index].type_entry = pointer_type; + entry->data.structure.fields[slice_ptr_index].src_index = slice_ptr_index; + entry->data.structure.fields[slice_ptr_index].gen_index = 0; + entry->data.structure.fields[slice_len_index].name = buf_create_from_str("len"); + entry->data.structure.fields[slice_len_index].type_entry = g->builtin_types.entry_usize; + entry->data.structure.fields[slice_len_index].src_index = slice_len_index; + entry->data.structure.fields[slice_len_index].gen_index = 1; + + assert(type_has_zero_bits_known(child_type)); + if (child_type->zero_bits) { + 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; + } } TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { @@ -535,6 +585,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c entry->type_ref = var_peer->type_ref; entry->di_type = var_peer->di_type; entry->data.structure.complete = true; + entry->data.structure.zero_bits_known = true; *parent_pointer = entry; return entry; @@ -544,7 +595,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c // If the child type is []const T then we need to make sure the type ref // and debug info is the same as if the child type were []T. if (is_slice(child_type)) { - TypeTableEntry *ptr_type = child_type->data.structure.fields[0].type_entry; + TypeTableEntry *ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry; assert(ptr_type->id == TypeTableEntryIdPointer); if (ptr_type->data.pointer.is_const) { TypeTableEntry *non_const_child_type = get_slice_type(g, @@ -560,11 +611,6 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name)); slice_type_common_init(g, child_type, is_const, entry); - if (child_type->zero_bits) { - entry->data.structure.gen_field_count = 1; - entry->data.structure.fields[0].gen_index = SIZE_MAX; - entry->data.structure.fields[1].gen_index = 0; - } if (!entry->type_ref) { entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name)); @@ -582,12 +628,6 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c }; LLVMStructSetBody(entry->type_ref, element_types, 1, false); - slice_type_common_init(g, child_type, is_const, entry); - - entry->data.structure.gen_field_count = 1; - entry->data.structure.fields[0].gen_index = -1; - entry->data.structure.fields[1].gen_index = 0; - TypeTableEntry *usize_type = g->builtin_types.entry_usize; uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, usize_type->type_ref); uint64_t len_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, usize_type->type_ref); @@ -622,8 +662,6 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c }; LLVMStructSetBody(entry->type_ref, element_types, element_count, false); - slice_type_common_init(g, child_type, is_const, entry); - uint64_t ptr_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, pointer_type->type_ref); uint64_t ptr_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, pointer_type->type_ref); @@ -664,6 +702,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c entry->data.structure.complete = true; + entry->data.structure.zero_bits_known = true; *parent_pointer = entry; return entry; @@ -706,6 +745,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { if (table_entry) { return table_entry->value; } + ensure_complete_type(g, fn_type_id->return_type); TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn); fn_type->data.fn.fn_type_id = *fn_type_id; @@ -750,7 +790,6 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { // next, loop over the parameters again and compute debug information // and codegen information if (!skip_debug_info) { - ensure_complete_type(g, fn_type_id->return_type); bool first_arg_return = !fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type); // +1 for maybe making the first argument the return value LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count); @@ -1056,33 +1095,31 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { // if you change this logic you likely must also change similar logic in parseh.cpp assert(enum_type->id == TypeTableEntryIdEnum); + resolve_enum_zero_bits(g, enum_type); + if (enum_type->data.enumeration.is_invalid) + return; + AstNode *decl_node = enum_type->data.enumeration.decl_node; if (enum_type->data.enumeration.embedded_in_current) { if (!enum_type->data.enumeration.reported_infinite_err) { enum_type->data.enumeration.reported_infinite_err = true; - add_node_error(g, decl_node, buf_sprintf("enum has infinite size")); + add_node_error(g, decl_node, buf_sprintf("enum contains itself")); } return; } - if (enum_type->data.enumeration.fields) { - // we already resolved this type. skip - return; - } - + assert(!enum_type->data.enumeration.zero_bits_loop_flag); assert(decl_node->type == NodeTypeContainerDecl); assert(enum_type->di_type); - uint32_t field_count = decl_node->data.container_decl.fields.length; + uint32_t field_count = enum_type->data.enumeration.src_field_count; - enum_type->data.enumeration.src_field_count = field_count; - enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count); + assert(enum_type->data.enumeration.fields); ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count); - // we possibly allocate too much here since gen_field_count can be lower than field_count. - // the only problem is potential wasted space though. - ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(field_count); + uint32_t gen_field_count = enum_type->data.enumeration.gen_field_count; + ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count); TypeTableEntry *biggest_union_member = nullptr; uint64_t biggest_align_in_bits = 0; @@ -1094,14 +1131,10 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { // set temporary flag enum_type->data.enumeration.embedded_in_current = true; - size_t gen_field_index = 0; for (uint32_t i = 0; i < field_count; i += 1) { AstNode *field_node = decl_node->data.container_decl.fields.at(i); TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i]; - type_enum_field->name = field_node->data.struct_field.name; - TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); - type_enum_field->type_entry = field_type; - type_enum_field->value = i; + TypeTableEntry *field_type = type_enum_field->type_entry; di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i); @@ -1120,7 +1153,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { assert(debug_size_in_bits > 0); assert(debug_align_in_bits > 0); - union_inner_di_types[gen_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, + union_inner_di_types[type_enum_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(enum_type->di_type), buf_ptr(type_enum_field->name), import->di_file, field_node->line + 1, debug_size_in_bits, @@ -1136,8 +1169,6 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { biggest_union_member = field_type; biggest_union_member_size_in_bits = debug_size_in_bits; } - - gen_field_index += 1; } // unset temporary flag @@ -1145,7 +1176,6 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { enum_type->data.enumeration.complete = true; if (!enum_type->data.enumeration.is_invalid) { - enum_type->data.enumeration.gen_field_count = gen_field_index; enum_type->data.enumeration.union_type = biggest_union_member; TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count); @@ -1176,7 +1206,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion", import->di_file, decl_node->line + 1, biggest_union_member_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types, - gen_field_index, 0, ""); + gen_field_count, 0, ""); // create debug types for members of root struct uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref, 0); @@ -1233,9 +1263,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type); enum_type->di_type = tag_di_type; - } - } } @@ -1244,51 +1272,38 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { // parseh.cpp assert(struct_type->id == TypeTableEntryIdStruct); + resolve_struct_zero_bits(g, struct_type); + if (struct_type->data.structure.is_invalid) + return; + 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; - add_node_error(g, decl_node, - buf_sprintf("struct has infinite size")); + add_node_error(g, decl_node, buf_sprintf("struct contains itself")); } return; } - if (struct_type->data.structure.fields) { - // we already resolved this type. skip - return; - } - + assert(!struct_type->data.structure.zero_bits_loop_flag); + assert(struct_type->data.enumeration.fields); assert(decl_node->type == NodeTypeContainerDecl); - assert(struct_type->di_type); - - size_t field_count = decl_node->data.container_decl.fields.length; - struct_type->data.structure.src_field_count = field_count; - struct_type->data.structure.fields = allocate<TypeStructField>(field_count); + size_t field_count = struct_type->data.structure.src_field_count; - // we possibly allocate too much here since gen_field_count can be lower than field_count. - // the only problem is potential wasted space though. - LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count); + 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; - ImportTableEntry *import = get_scope_import(scope); - size_t gen_field_index = 0; for (size_t i = 0; i < field_count; i += 1) { - AstNode *field_node = decl_node->data.container_decl.fields.at(i); TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; - type_struct_field->name = field_node->data.struct_field.name; - TypeTableEntry *field_type = analyze_type_expr(g, scope, - field_node->data.struct_field.type); - type_struct_field->type_entry = field_type; - type_struct_field->src_index = i; - type_struct_field->gen_index = SIZE_MAX; + TypeTableEntry *field_type = type_struct_field->type_entry; ensure_complete_type(g, field_type); if (field_type->id == TypeTableEntryIdInvalid) { @@ -1299,31 +1314,31 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { if (!type_has_bits(field_type)) continue; - type_struct_field->gen_index = gen_field_index; - - element_types[gen_field_index] = field_type->type_ref; - assert(element_types[gen_field_index]); - - gen_field_index += 1; + element_types[type_struct_field->gen_index] = field_type->type_ref; + assert(element_types[type_struct_field->gen_index]); } struct_type->data.structure.embedded_in_current = false; - - struct_type->data.structure.gen_field_count = gen_field_index; struct_type->data.structure.complete = true; - if (struct_type->data.structure.is_invalid) { + if (struct_type->data.structure.is_invalid) + return; + + if (struct_type->zero_bits) { + struct_type->type_ref = LLVMVoidType(); + struct_type->di_type = g->builtin_types.entry_void->di_type; return; } + assert(struct_type->di_type); - size_t gen_field_count = gen_field_index; LLVMStructSetBody(struct_type->type_ref, element_types, gen_field_count, false); ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(gen_field_count); + ImportTableEntry *import = get_scope_import(scope); for (size_t i = 0; i < field_count; i += 1) { AstNode *field_node = decl_node->data.container_decl.fields.at(i); TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; - gen_field_index = type_struct_field->gen_index; + size_t gen_field_index = type_struct_field->gen_index; if (gen_field_index == SIZE_MAX) { continue; } @@ -1362,13 +1377,122 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { ZigLLVMReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type); struct_type->di_type = replacement_di_type; - struct_type->zero_bits = (debug_size_in_bits == 0); + assert((debug_size_in_bits == 0) == struct_type->zero_bits); } static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { zig_panic("TODO"); } +static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { + assert(enum_type->id == TypeTableEntryIdEnum); + + if (enum_type->data.enumeration.zero_bits_known) + return; + + if (enum_type->data.enumeration.zero_bits_loop_flag) { + enum_type->data.enumeration.zero_bits_known = true; + return; + } + + enum_type->data.enumeration.zero_bits_loop_flag = true; + + AstNode *decl_node = enum_type->data.enumeration.decl_node; + assert(decl_node->type == NodeTypeContainerDecl); + assert(enum_type->di_type); + + assert(!enum_type->data.enumeration.fields); + uint32_t field_count = decl_node->data.container_decl.fields.length; + enum_type->data.enumeration.src_field_count = field_count; + enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count); + + Scope *scope = &enum_type->data.enumeration.decls_scope->base; + + uint32_t gen_field_index = 0; + for (uint32_t i = 0; i < field_count; i += 1) { + AstNode *field_node = decl_node->data.container_decl.fields.at(i); + TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i]; + type_enum_field->name = field_node->data.struct_field.name; + TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); + type_enum_field->type_entry = field_type; + type_enum_field->value = i; + + type_ensure_zero_bits_known(g, field_type); + if (field_type->id == TypeTableEntryIdInvalid) { + enum_type->data.enumeration.is_invalid = true; + continue; + } + + if (!type_has_bits(field_type)) + continue; + + type_enum_field->gen_index = gen_field_index; + gen_field_index += 1; + } + + enum_type->data.enumeration.zero_bits_loop_flag = false; + enum_type->data.enumeration.gen_field_count = gen_field_index; + enum_type->zero_bits = (gen_field_index == 0 && field_count < 2); + enum_type->data.enumeration.zero_bits_known = true; +} + +static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { + assert(struct_type->id == TypeTableEntryIdStruct); + + if (struct_type->data.structure.zero_bits_known) + return; + + if (struct_type->data.structure.zero_bits_loop_flag) { + struct_type->data.structure.zero_bits_known = true; + return; + } + + struct_type->data.structure.zero_bits_loop_flag = true; + + AstNode *decl_node = struct_type->data.structure.decl_node; + assert(decl_node->type == NodeTypeContainerDecl); + assert(struct_type->di_type); + + assert(!struct_type->data.structure.fields); + size_t field_count = decl_node->data.container_decl.fields.length; + struct_type->data.structure.src_field_count = field_count; + struct_type->data.structure.fields = allocate<TypeStructField>(field_count); + + Scope *scope = &struct_type->data.structure.decls_scope->base; + + size_t gen_field_index = 0; + for (size_t i = 0; i < field_count; i += 1) { + AstNode *field_node = decl_node->data.container_decl.fields.at(i); + TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; + type_struct_field->name = field_node->data.struct_field.name; + TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); + type_struct_field->type_entry = field_type; + type_struct_field->src_index = i; + type_struct_field->gen_index = SIZE_MAX; + + type_ensure_zero_bits_known(g, field_type); + if (field_type->id == TypeTableEntryIdInvalid) { + struct_type->data.structure.is_invalid = true; + continue; + } + + if (!type_has_bits(field_type)) + continue; + + 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.gen_field_count = gen_field_index; + struct_type->zero_bits = (gen_field_index == 0); + struct_type->data.structure.zero_bits_known = true; +} + +static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { + zig_panic("TODO resolve_union_zero_bits"); +} + static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) { if (!scope) return; @@ -3064,6 +3188,16 @@ void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry) { } } +void type_ensure_zero_bits_known(CodeGen *g, TypeTableEntry *type_entry) { + if (type_entry->id == TypeTableEntryIdStruct) { + resolve_struct_zero_bits(g, type_entry); + } else if (type_entry->id == TypeTableEntryIdEnum) { + resolve_enum_zero_bits(g, type_entry); + } else if (type_entry->id == TypeTableEntryIdUnion) { + resolve_union_zero_bits(g, type_entry); + } +} + bool ir_get_var_is_comptime(VariableTableEntry *var) { if (!var->is_comptime) return false; diff --git a/src/analyze.hpp b/src/analyze.hpp index ffc2c960f8..4ee03abcd1 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -54,6 +54,7 @@ bool type_is_codegen_pointer(TypeTableEntry *type); TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry); TypeTableEntry *container_ref_type(TypeTableEntry *type_entry); bool type_is_complete(TypeTableEntry *type_entry); +bool type_has_zero_bits_known(TypeTableEntry *type_entry); void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry); TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name); ScopeDecls *get_container_scope(TypeTableEntry *type_entry); @@ -75,6 +76,7 @@ AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index); FnTableEntry *scope_get_fn_if_root(Scope *scope); bool type_requires_comptime(TypeTableEntry *type_entry); void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry); +void type_ensure_zero_bits_known(CodeGen *g, TypeTableEntry *type_entry); void complete_enum(CodeGen *g, TypeTableEntry *enum_type); bool ir_get_var_is_comptime(VariableTableEntry *var); bool const_values_equal(ConstExprValue *a, ConstExprValue *b); diff --git a/src/codegen.cpp b/src/codegen.cpp index 070ad98a7c..21389aa89e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2404,6 +2404,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) { static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { TypeTableEntry *canon_type = get_underlying_type(const_val->type); + assert(!canon_type->zero_bits); switch (const_val->special) { case ConstValSpecialRuntime: @@ -2557,6 +2558,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { } else { ConstExprValue *array_const_val = const_val->data.x_ptr.base_ptr; assert(array_const_val->type->id == TypeTableEntryIdArray); + if (array_const_val->type->zero_bits) { + // make this a null pointer + TypeTableEntry *usize_type = g->builtin_types.entry_usize; + const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize_type->type_ref), + const_val->type->type_ref); + render_const_val_global(g, const_val); + return const_val->llvm_value; + } render_const_val(g, array_const_val); render_const_val_global(g, array_const_val); TypeTableEntry *usize = g->builtin_types.entry_usize; @@ -3369,6 +3378,7 @@ static void define_builtin_types(CodeGen *g) { } } entry->data.enumeration.complete = true; + entry->data.enumeration.zero_bits_known = true; TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count); entry->data.enumeration.tag_type = tag_type_entry; @@ -3402,6 +3412,7 @@ static void define_builtin_types(CodeGen *g) { } } entry->data.enumeration.complete = true; + entry->data.enumeration.zero_bits_known = true; TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count); entry->data.enumeration.tag_type = tag_type_entry; @@ -3429,6 +3440,7 @@ static void define_builtin_types(CodeGen *g) { } } entry->data.enumeration.complete = true; + entry->data.enumeration.zero_bits_known = true; TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count); entry->data.enumeration.tag_type = tag_type_entry; @@ -3456,6 +3468,7 @@ static void define_builtin_types(CodeGen *g) { } } entry->data.enumeration.complete = true; + entry->data.enumeration.zero_bits_known = true; TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count); entry->data.enumeration.tag_type = tag_type_entry; @@ -3491,6 +3504,7 @@ static void define_builtin_types(CodeGen *g) { entry->data.enumeration.fields[5].type_entry = g->builtin_types.entry_void; entry->data.enumeration.complete = true; + entry->data.enumeration.zero_bits_known = true; TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count); entry->data.enumeration.tag_type = tag_type_entry; diff --git a/src/ir.cpp b/src/ir.cpp index 8f31bf3b45..79fe3411d4 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7941,6 +7941,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, case TypeTableEntryIdBoundFn: case TypeTableEntryIdEnumTag: { + type_ensure_zero_bits_known(ira->codegen, resolved_child_type); TypeTableEntry *result_type = get_slice_type(ira->codegen, resolved_child_type, is_const); ConstExprValue *out_val = ir_build_const_from(ira, &slice_type_instruction->base, child_type->value.depends_on_compile_var); diff --git a/src/parseh.cpp b/src/parseh.cpp index f84391aba9..eb51769f4b 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -717,6 +717,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) enum_type->data.enumeration.gen_field_count = 0; enum_type->data.enumeration.complete = true; + enum_type->data.enumeration.zero_bits_known = true; enum_type->data.enumeration.tag_type = tag_type_entry; enum_type->data.enumeration.src_field_count = field_count; @@ -937,6 +938,7 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_ struct_type->data.structure.gen_field_count = field_count; struct_type->data.structure.complete = true; + struct_type->data.structure.zero_bits_known = true; uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(c->codegen->target_data_ref, struct_type->type_ref); uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(c->codegen->target_data_ref, struct_type->type_ref); |
