From b738cbdc768796b59b19a07a29a95892937d6f11 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 15 Sep 2016 14:07:35 -0400 Subject: [PATCH] fix compiler crash involving slice with const slice child also fix compiler crash for multiple errors in main fn prototype closes #191 --- src/analyze.cpp | 176 ++++++++++++++++++------------- test/cases/const_slice_child.zig | 48 +++++++++ test/run_tests.cpp | 4 + test/self_hosted.zig | 1 + 4 files changed, 154 insertions(+), 75 deletions(-) create mode 100644 test/cases/const_slice_child.zig diff --git a/src/analyze.cpp b/src/analyze.cpp index b39bc584ac..ec6fed7d74 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -558,100 +558,125 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c } else { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); + // 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; + assert(ptr_type->id == TypeTableEntryIdPointer); + if (ptr_type->data.pointer.is_const) { + TypeTableEntry *non_const_child_type = get_slice_type(g, + ptr_type->data.pointer.child_type, false); + TypeTableEntry *var_peer = get_slice_type(g, non_const_child_type, false); + + entry->type_ref = var_peer->type_ref; + entry->di_type = var_peer->di_type; + } + } + buf_resize(&entry->name, 0); buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name)); - entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name)); - - ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit); - ZigLLVMDIFile *di_file = nullptr; - unsigned line = 0; - entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, - ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name), - compile_unit_scope, di_file, line); + slice_type_common_init(g, child_type, is_const, entry); if (child_type->zero_bits) { - LLVMTypeRef element_types[] = { - g->builtin_types.entry_usize->type_ref, - }; - 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); - uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0); + if (!entry->type_ref) { + entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name)); - 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); + ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit); + ZigLLVMDIFile *di_file = nullptr; + unsigned line = 0; + entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, + ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name), + compile_unit_scope, di_file, line); - ZigLLVMDIType *di_element_types[] = { - ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type), - "len", di_file, line, - len_debug_size_in_bits, - len_debug_align_in_bits, - len_offset_in_bits, - 0, usize_type->di_type), - }; - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - compile_unit_scope, - buf_ptr(&entry->name), - di_file, line, debug_size_in_bits, debug_align_in_bits, 0, - nullptr, di_element_types, 1, 0, nullptr, ""); + if (child_type->zero_bits) { + LLVMTypeRef element_types[] = { + g->builtin_types.entry_usize->type_ref, + }; + LLVMStructSetBody(entry->type_ref, element_types, 1, false); - ZigLLVMReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type); - entry->di_type = replacement_di_type; - } else { - TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const); + slice_type_common_init(g, child_type, is_const, entry); - unsigned element_count = 2; - LLVMTypeRef element_types[] = { - pointer_type->type_ref, - g->builtin_types.entry_usize->type_ref, - }; - LLVMStructSetBody(entry->type_ref, element_types, element_count, false); + entry->data.structure.gen_field_count = 1; + entry->data.structure.fields[0].gen_index = -1; + entry->data.structure.fields[1].gen_index = 0; - slice_type_common_init(g, child_type, is_const, entry); + 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); + uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0); + + 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); + + ZigLLVMDIType *di_element_types[] = { + ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type), + "len", di_file, line, + len_debug_size_in_bits, + len_debug_align_in_bits, + len_offset_in_bits, + 0, usize_type->di_type), + }; + ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, + compile_unit_scope, + buf_ptr(&entry->name), + di_file, line, debug_size_in_bits, debug_align_in_bits, 0, + nullptr, di_element_types, 1, 0, nullptr, ""); + + ZigLLVMReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type); + entry->di_type = replacement_di_type; + } else { + TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const); + + unsigned element_count = 2; + LLVMTypeRef element_types[] = { + pointer_type->type_ref, + g->builtin_types.entry_usize->type_ref, + }; + 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); - uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0); + 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); + uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 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); - uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 1); + 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); + uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 1); - 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); + 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); - ZigLLVMDIType *di_element_types[] = { - ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type), - "ptr", di_file, line, - ptr_debug_size_in_bits, - ptr_debug_align_in_bits, - ptr_offset_in_bits, - 0, pointer_type->di_type), - ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type), - "len", di_file, line, - len_debug_size_in_bits, - len_debug_align_in_bits, - len_offset_in_bits, - 0, usize_type->di_type), - }; - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - compile_unit_scope, - buf_ptr(&entry->name), - di_file, line, debug_size_in_bits, debug_align_in_bits, 0, - nullptr, di_element_types, 2, 0, nullptr, ""); + ZigLLVMDIType *di_element_types[] = { + ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type), + "ptr", di_file, line, + ptr_debug_size_in_bits, + ptr_debug_align_in_bits, + ptr_offset_in_bits, + 0, pointer_type->di_type), + ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type), + "len", di_file, line, + len_debug_size_in_bits, + len_debug_align_in_bits, + len_offset_in_bits, + 0, usize_type->di_type), + }; + ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, + compile_unit_scope, + buf_ptr(&entry->name), + di_file, line, debug_size_in_bits, debug_align_in_bits, 0, + nullptr, di_element_types, 2, 0, nullptr, ""); - ZigLLVMReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type); - entry->di_type = replacement_di_type; + ZigLLVMReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type); + entry->di_type = replacement_di_type; + } } @@ -1695,6 +1720,7 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN bool is_main_fn = !is_generic_instance && !parent_decl && (import == g->root_import) && + !proto_node->data.fn_proto.skip && buf_eql_str(proto_name, "main"); if (is_main_fn) { g->main_fn = fn_table_entry; diff --git a/test/cases/const_slice_child.zig b/test/cases/const_slice_child.zig new file mode 100644 index 0000000000..97b37028d1 --- /dev/null +++ b/test/cases/const_slice_child.zig @@ -0,0 +1,48 @@ +const assert = @import("std").debug.assert; + +var argv: &&const u8 = undefined; + +#attribute("test") +fn constSliceChild() { + const strs = ([]&const u8) { + c"one", + c"two", + c"three", + }; + argv = &strs[0]; + bar(strs.len); +} + +#static_eval_enable(false) +fn foo(args: [][]const u8) { + assert(args.len == 3); + assert(streql(args[0], "one")); + assert(streql(args[1], "two")); + assert(streql(args[2], "three")); +} + +#static_eval_enable(false) +fn bar(argc: usize) { + var args: [argc][]u8 = undefined; + for (args) |_, i| { + const ptr = argv[i]; + args[i] = ptr[0...strlen(ptr)]; + } + foo(args); +} + +#static_eval_enable(false) +fn strlen(ptr: &const u8) -> usize { + var count: usize = 0; + while (ptr[count] != 0; count += 1) {} + return count; +} + +#static_eval_enable(false) +fn streql(a: []const u8, b: []const u8) -> bool { + if (a.len != b.len) return false; + for (a) |item, index| { + if (b[index] != item) return false; + } + return true; +} diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 95fc6fc3d4..730b032758 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1491,6 +1491,10 @@ pub fn f() { cstr[0] = 'W'; } )SOURCE", 1, ".tmp_source.zig:4:7: error: cannot assign to constant"); + + add_compile_fail_case("main function with bogus args type", R"SOURCE( +pub fn main(args: [][]bogus) -> %void {} + )SOURCE", 1, ".tmp_source.zig:2:23: error: use of undeclared identifier 'bogus'"); } ////////////////////////////////////////////////////////////////////////////// diff --git a/test/self_hosted.zig b/test/self_hosted.zig index bc69642b7f..9fe94edb92 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -10,6 +10,7 @@ const test_sizeof_and_typeof = @import("cases/sizeof_and_typeof.zig"); const test_maybe_return = @import("cases/maybe_return.zig"); const test_max_value_type = @import("cases/max_value_type.zig"); const test_var_params = @import("cases/var_params.zig"); +const test_const_slice_child = @import("cases/const_slice_child.zig"); // normal comment /// this is a documentation comment