diff --git a/CMakeLists.txt b/CMakeLists.txt index f891cfad0f..bb23006bdf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,8 +233,8 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/special/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}/special") install(FILES "${CMAKE_SOURCE_DIR}/std/special/builtin.zig" DESTINATION "${ZIG_STD_DEST}/special") install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}/special") -install(FILES "${CMAKE_SOURCE_DIR}/std/special/panic.zig" DESTINATION "${ZIG_STD_DEST}/special") install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/zigrt.zig" DESTINATION "${ZIG_STD_DEST}/special") install(FILES "${CMAKE_SOURCE_DIR}/std/target.zig" DESTINATION "${ZIG_STD_DEST}") add_executable(run_tests ${TEST_SOURCES}) diff --git a/doc/emacs/zig-mode.el b/doc/emacs/zig-mode.el index 6a695546b0..df94a44bd4 100644 --- a/doc/emacs/zig-mode.el +++ b/doc/emacs/zig-mode.el @@ -1,5 +1,5 @@ (setq zig - '(("\\b\\(@sizeOf\\|@alignOf\\|@maxValue\\|@minValue\\|@memberCount\\|@typeOf\\|@addWithOverflow\\|@subWithOverflow\\|@mulWithOverflow\\|@shlWithOverflow\\|@cInclude\\|@cDefine\\|@cUndef\\|@compileVar\\|@generatedCode\\|@ctz\\|@clz\\|@import\\|@cImport\\|@errorName\\|@typeName\\|@isInteger\\|@isFloat\\|@canImplicitCast\\|@embedFile\\|@cmpxchg\\|@fence\\|@divExact\\|@truncate\\|@compileError\\|@compileLog\\|@intType\\|@unreachable\\|@setFnTest\\|@setFnVisible\\|@setDebugSafety\\|@alloca\\|@setGlobalAlign\\|@setGlobalSection\\)" . font-lock-builtin-face) + '(("\\b\\(@sizeOf\\|@alignOf\\|@maxValue\\|@minValue\\|@memberCount\\|@typeOf\\|@addWithOverflow\\|@subWithOverflow\\|@mulWithOverflow\\|@shlWithOverflow\\|@cInclude\\|@cDefine\\|@cUndef\\|@compileVar\\|@generatedCode\\|@ctz\\|@clz\\|@import\\|@cImport\\|@errorName\\|@typeName\\|@isInteger\\|@isFloat\\|@canImplicitCast\\|@embedFile\\|@cmpxchg\\|@fence\\|@divExact\\|@truncate\\|@compileError\\|@compileLog\\|@intType\\|@unreachable\\|@setDebugSafety\\|@alloca\\|@setGlobalAlign\\|@setGlobalLinkage\\|@setGlobalSection\\)" . font-lock-builtin-face) ("\\b\\(fn\\|use\\|while\\|for\\|break\\|continue\\|goto\\|if\\|else\\|switch\\|try\\|return\\|defer\\|asm\\|unreachable\\|const\\|var\\|extern\\|packed\\|export\\|pub\\|noalias\\|inline\\|comptime\\|nakedcc\\|coldcc\\|volatile\\|struct\\|enum\\|union\\)\\b" . font-lock-keyword-face) diff --git a/doc/langref.md b/doc/langref.md index 73b456701e..7b6ba4b294 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -626,3 +626,10 @@ Sets the alignment property of a global variable. ### @setGlobalSection(global_variable_name, section_name: []u8) -> bool Puts the global variable in the specified section. + +### @panic(message: []const u8) -> noreturn + +Invokes the panic handler function. By default the panic handler function +calls the public `panic` function exposed in the root source file, or +if there is not one specified, invokes the one provided in +`std/special/panic.zig`. diff --git a/src/all_types.hpp b/src/all_types.hpp index 48fa3fb9f0..07c409c0f0 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -237,6 +237,13 @@ enum VisibMod { VisibModExport, }; +enum GlobalLinkageId { + GlobalLinkageIdInternal, + GlobalLinkageIdStrong, + GlobalLinkageIdWeak, + GlobalLinkageIdLinkOnce, +}; + enum TldId { TldIdVar, TldIdFn, @@ -273,6 +280,8 @@ struct TldVar { uint64_t alignment; AstNode *set_global_section_node; Buf *section_name; + AstNode *set_global_linkage_node; + GlobalLinkageId linkage; }; struct TldFn { @@ -1116,8 +1125,6 @@ struct FnTableEntry { Buf symbol_name; TypeTableEntry *type_entry; // function type TypeTableEntry *implicit_return_type; - bool internal_linkage; - bool disable_export; bool is_test; FnInline fn_inline; FnAnalState anal_state; @@ -1128,7 +1135,6 @@ struct FnTableEntry { Buf **param_names; AstNode *fn_no_inline_set_node; - AstNode *fn_export_set_node; AstNode *fn_static_eval_set_node; ZigList alloca_list; @@ -1138,6 +1144,8 @@ struct FnTableEntry { uint64_t alignment; AstNode *set_global_section_node; Buf *section_name; + AstNode *set_global_linkage_node; + GlobalLinkageId linkage; }; uint32_t fn_table_entry_hash(FnTableEntry*); @@ -1178,7 +1186,6 @@ enum BuiltinFnId { BuiltinFnIdDivExact, BuiltinFnIdTruncate, BuiltinFnIdIntType, - BuiltinFnIdSetFnVisible, BuiltinFnIdSetDebugSafety, BuiltinFnIdAlloca, BuiltinFnIdTypeName, @@ -1187,6 +1194,8 @@ enum BuiltinFnId { BuiltinFnIdCanImplicitCast, BuiltinFnIdSetGlobalAlign, BuiltinFnIdSetGlobalSection, + BuiltinFnIdSetGlobalLinkage, + BuiltinFnIdPanic, }; struct BuiltinFnEntry { @@ -1300,7 +1309,8 @@ struct CodeGen { HashMap memoized_fn_eval_table; HashMap llvm_fn_table; HashMap compile_vars; - HashMap external_symbol_names; + HashMap exported_symbol_names; + HashMap external_prototypes; ZigList import_queue; size_t import_queue_index; @@ -1346,6 +1356,7 @@ struct CodeGen { TypeTableEntry *entry_environ_enum; TypeTableEntry *entry_oformat_enum; TypeTableEntry *entry_atomic_order_enum; + TypeTableEntry *entry_global_linkage_enum; TypeTableEntry *entry_arg_tuple; } builtin_types; @@ -1378,7 +1389,7 @@ struct CodeGen { bool is_native_target; PackageTableEntry *root_package; PackageTableEntry *std_package; - PackageTableEntry *panic_package; + PackageTableEntry *zigrt_package; Buf *root_out_name; bool windows_subsystem_windows; bool windows_subsystem_console; @@ -1388,6 +1399,7 @@ struct CodeGen { Buf *mios_version_min; bool linker_rdynamic; const char *linker_script; + bool omit_zigrt; // The function definitions this module includes. There must be a corresponding // fn_protos entry. @@ -1401,7 +1413,8 @@ struct CodeGen { OutType out_type; FnTableEntry *cur_fn; FnTableEntry *main_fn; - FnTableEntry *panic_fn; + FnTableEntry *user_panic_fn; + FnTableEntry *extern_panic_fn; LLVMValueRef cur_ret_ptr; LLVMValueRef cur_fn_val; ZigList break_block_stack; @@ -1656,7 +1669,6 @@ enum IrInstructionId { IrInstructionIdTypeOf, IrInstructionIdToPtrType, IrInstructionIdPtrTypeChild, - IrInstructionIdSetFnVisible, IrInstructionIdSetDebugSafety, IrInstructionIdArrayType, IrInstructionIdSliceType, @@ -1718,7 +1730,9 @@ enum IrInstructionId { IrInstructionIdCanImplicitCast, IrInstructionIdSetGlobalAlign, IrInstructionIdSetGlobalSection, + IrInstructionIdSetGlobalLinkage, IrInstructionIdDeclRef, + IrInstructionIdPanic, }; struct IrInstruction { @@ -1999,13 +2013,6 @@ struct IrInstructionPtrTypeChild { IrInstruction *value; }; -struct IrInstructionSetFnVisible { - IrInstruction base; - - IrInstruction *fn_value; - IrInstruction *is_visible; -}; - struct IrInstructionSetDebugSafety { IrInstruction base; @@ -2439,6 +2446,13 @@ struct IrInstructionSetGlobalSection { IrInstruction *value; }; +struct IrInstructionSetGlobalLinkage { + IrInstruction base; + + Tld *tld; + IrInstruction *value; +}; + struct IrInstructionDeclRef { IrInstruction base; @@ -2446,6 +2460,12 @@ struct IrInstructionDeclRef { LVal lval; }; +struct IrInstructionPanic { + IrInstruction base; + + IrInstruction *msg; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 380e384644..fc7915da5a 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1762,7 +1762,7 @@ static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) { buf_append_buf(buf, tld->name); } -FnTableEntry *create_fn_raw(FnInline inline_value, bool internal_linkage) { +FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage) { FnTableEntry *fn_entry = allocate(1); fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc; @@ -1770,7 +1770,7 @@ FnTableEntry *create_fn_raw(FnInline inline_value, bool internal_linkage) { fn_entry->analyzed_executable.fn_entry = fn_entry; fn_entry->ir_executable.fn_entry = fn_entry; fn_entry->fn_inline = inline_value; - fn_entry->internal_linkage = internal_linkage; + fn_entry->linkage = linkage; return fn_entry; } @@ -1780,8 +1780,9 @@ FnTableEntry *create_fn(AstNode *proto_node) { AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; FnInline inline_value = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto; - bool internal_linkage = (fn_proto->visib_mod != VisibModExport && !proto_node->data.fn_proto.is_extern); - FnTableEntry *fn_entry = create_fn_raw(inline_value, internal_linkage); + GlobalLinkageId linkage = (fn_proto->visib_mod == VisibModExport || proto_node->data.fn_proto.is_extern) ? + GlobalLinkageIdStrong : GlobalLinkageIdInternal; + FnTableEntry *fn_entry = create_fn_raw(inline_value, linkage); fn_entry->proto_node = proto_node; fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : @@ -1807,12 +1808,10 @@ static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, TypeTableEntr buf_ptr(&fn_type->name))); } -static void typecheck_panic_fn(CodeGen *g) { - assert(g->panic_fn); - - AstNode *proto_node = g->panic_fn->proto_node; +static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) { + AstNode *proto_node = panic_fn->proto_node; assert(proto_node->type == NodeTypeFnProto); - TypeTableEntry *fn_type = g->panic_fn->type_entry; + TypeTableEntry *fn_type = panic_fn->type_entry; FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; if (fn_type_id->param_count != 1) { return wrong_panic_prototype(g, proto_node, fn_type); @@ -1862,6 +1861,8 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { add_node_error(g, param_node, buf_sprintf("missing parameter name")); } } + } else if (fn_table_entry->linkage != GlobalLinkageIdInternal) { + g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base); } Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope; @@ -1892,18 +1893,16 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { } } } else if (buf_eql_str(&fn_table_entry->symbol_name, "panic")) { - g->panic_fn = fn_table_entry; - typecheck_panic_fn(g); + typecheck_panic_fn(g, fn_table_entry); } - } else if (import->package == g->panic_package && scope_is_root_decls(tld_fn->base.parent_scope)) { - if (buf_eql_str(&fn_table_entry->symbol_name, "panic")) { - g->panic_fn = fn_table_entry; - typecheck_panic_fn(g); + } else if (import->package == g->zigrt_package && scope_is_root_decls(tld_fn->base.parent_scope)) { + if (buf_eql_str(&fn_table_entry->symbol_name, "__zig_panic")) { + g->extern_panic_fn = fn_table_entry; } } } } else if (source_node->type == NodeTypeTestDecl) { - FnTableEntry *fn_table_entry = create_fn_raw(FnInlineAuto, false); + FnTableEntry *fn_table_entry = create_fn_raw(FnInlineAuto, GlobalLinkageIdStrong); get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); @@ -1931,16 +1930,12 @@ static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { } static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { - if (tld->visib_mod == VisibModExport || - (buf_eql_str(tld->name, "panic") && - (decls_scope->import->package == g->panic_package || decls_scope->import == g->root_import)) || - (tld->id == TldIdVar && g->is_test_build)) - { + if (tld->visib_mod == VisibModExport || (tld->id == TldIdVar && g->is_test_build)) { g->resolve_queue.append(tld); } if (tld->visib_mod == VisibModExport) { - auto entry = g->external_symbol_names.put_unique(tld->name, tld); + auto entry = g->exported_symbol_names.put_unique(tld->name, tld); if (entry) { Tld *other_tld = entry->value; ErrorMsg *msg = add_node_error(g, tld->source_node, @@ -2060,6 +2055,15 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { TldFn *tld_fn = allocate(1); init_tld(&tld_fn->base, TldIdFn, fn_name, visib_mod, node, &decls_scope->base); add_top_level_decl(g, decls_scope, &tld_fn->base); + + ImportTableEntry *import = get_scope_import(&decls_scope->base); + if (import == g->root_import && scope_is_root_decls(&decls_scope->base) && + buf_eql_str(fn_name, "panic")) + { + g->compile_vars.put(buf_create_from_str("panic_implementation_provided"), + create_const_bool(g, true)); + } + break; } case NodeTypeUse: @@ -4206,3 +4210,36 @@ ConstParent *get_const_val_parent(ConstExprValue *value) { } return nullptr; } + +FnTableEntry *get_extern_panic_fn(CodeGen *g) { + if (g->extern_panic_fn) + return g->extern_panic_fn; + + FnTypeId fn_type_id = {0}; + fn_type_id.is_extern = true; + fn_type_id.is_cold = true; + fn_type_id.param_count = 2; + fn_type_id.param_info = allocate(2); + fn_type_id.next_param_index = 0; + fn_type_id.param_info[0].type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); + fn_type_id.param_info[1].type = g->builtin_types.entry_usize; + fn_type_id.return_type = g->builtin_types.entry_unreachable; + + TypeTableEntry *fn_type = get_fn_type(g, &fn_type_id); + assert(!type_is_invalid(fn_type)); + + FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, GlobalLinkageIdStrong); + buf_init_from_str(&fn_entry->symbol_name, "__zig_panic"); + + TldFn *tld_fn = allocate(1); + init_tld(&tld_fn->base, TldIdFn, &fn_entry->symbol_name, VisibModPrivate, nullptr, nullptr); + tld_fn->fn_entry = fn_entry; + + g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base); + + fn_entry->type_entry = fn_type; + + g->extern_panic_fn = fn_entry; + return g->extern_panic_fn; +} + diff --git a/src/analyze.hpp b/src/analyze.hpp index 67e36cce0c..574aa5ffb7 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -72,7 +72,7 @@ VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent bool is_const, ConstExprValue *init_value, Tld *src_tld); TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node); FnTableEntry *create_fn(AstNode *proto_node); -FnTableEntry *create_fn_raw(FnInline inline_value, bool internal_linkage); +FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage); void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_count_alloc); AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index); FnTableEntry *scope_get_fn_if_root(Scope *scope); @@ -148,5 +148,6 @@ void init_const_undefined(CodeGen *g, ConstExprValue *const_val); TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, size_t size_in_bits); ConstParent *get_const_val_parent(ConstExprValue *value); +FnTableEntry *get_extern_panic_fn(CodeGen *g); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index f6af44b4ed..d7e4dc17ec 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -67,7 +67,8 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { g->llvm_fn_table.init(16); g->memoized_fn_eval_table.init(16); g->compile_vars.init(16); - g->external_symbol_names.init(8); + g->exported_symbol_names.init(8); + g->external_prototypes.init(8); g->is_release_build = false; g->is_test_build = false; g->want_h_file = true; @@ -140,6 +141,10 @@ void codegen_set_is_release(CodeGen *g, bool is_release_build) { g->is_release_build = is_release_build; } +void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt) { + g->omit_zigrt = omit_zigrt; +} + void codegen_set_is_test(CodeGen *g, bool is_test_build) { g->is_test_build = is_test_build; } @@ -256,10 +261,22 @@ static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const c LLVMAddAttributeAtIndex(val, attr_index, llvm_attr); } +static void addLLVMAttrStr(LLVMValueRef val, LLVMAttributeIndex attr_index, + const char *attr_name, const char *attr_val) +{ + LLVMAttributeRef llvm_attr = LLVMCreateStringAttribute(LLVMGetGlobalContext(), + attr_name, strlen(attr_name), attr_val, strlen(attr_val)); + LLVMAddAttributeAtIndex(val, attr_index, llvm_attr); +} + static void addLLVMFnAttr(LLVMValueRef fn_val, const char *attr_name) { return addLLVMAttr(fn_val, -1, attr_name); } +static void addLLVMFnAttrStr(LLVMValueRef fn_val, const char *attr_name, const char *attr_val) { + return addLLVMAttrStr(fn_val, -1, attr_name, attr_val); +} + static void addLLVMArgAttr(LLVMValueRef arg_val, unsigned param_index, const char *attr_name) { return addLLVMAttr(arg_val, param_index + 1, attr_name); } @@ -271,15 +288,19 @@ static void addLLVMCallsiteAttr(LLVMValueRef call_instr, unsigned param_index, c LLVMAddCallSiteAttribute(call_instr, param_index + 1, llvm_attr); } +static bool is_symbol_available(CodeGen *g, Buf *name) { + return g->exported_symbol_names.maybe_get(name) == nullptr && g->external_prototypes.maybe_get(name) == nullptr; +} + static Buf *get_mangled_name(CodeGen *g, Buf *original_name, bool external_linkage) { - if (external_linkage || g->external_symbol_names.maybe_get(original_name) == nullptr) { + if (external_linkage || is_symbol_available(g, original_name)) { return original_name; } int n = 0; for (;; n += 1) { Buf *new_name = buf_sprintf("%s.%d", buf_ptr(original_name), n); - if (g->external_symbol_names.maybe_get(new_name) == nullptr) { + if (is_symbol_available(g, new_name)) { return new_name; } } @@ -289,11 +310,12 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { if (fn_table_entry->llvm_value) return fn_table_entry->llvm_value; - Buf *symbol_name = get_mangled_name(g, &fn_table_entry->symbol_name, !fn_table_entry->internal_linkage); + bool external_linkage = (fn_table_entry->linkage != GlobalLinkageIdInternal); + Buf *symbol_name = get_mangled_name(g, &fn_table_entry->symbol_name, external_linkage); TypeTableEntry *fn_type = fn_table_entry->type_entry; LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref; - if (!fn_table_entry->internal_linkage && fn_table_entry->body_node == nullptr) { + if (external_linkage && fn_table_entry->body_node == nullptr) { LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name)); if (existing_llvm_fn) { fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0)); @@ -318,12 +340,35 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { addLLVMFnAttr(fn_table_entry->llvm_value, "naked"); } - LLVMSetLinkage(fn_table_entry->llvm_value, fn_table_entry->internal_linkage ? - LLVMInternalLinkage : LLVMExternalLinkage); + switch (fn_table_entry->linkage) { + case GlobalLinkageIdInternal: + LLVMSetLinkage(fn_table_entry->llvm_value, LLVMInternalLinkage); + break; + case GlobalLinkageIdStrong: + LLVMSetLinkage(fn_table_entry->llvm_value, LLVMExternalLinkage); + break; + case GlobalLinkageIdWeak: + LLVMSetLinkage(fn_table_entry->llvm_value, LLVMWeakODRLinkage); + break; + case GlobalLinkageIdLinkOnce: + LLVMSetLinkage(fn_table_entry->llvm_value, LLVMLinkOnceODRLinkage); + break; + } if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) { addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn"); } + + if (fn_table_entry->body_node != nullptr) { + bool want_fn_safety = !g->is_release_build && !fn_table_entry->def_scope->safety_off; + if (want_fn_safety) { + if (g->link_libc) { + addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong"); + addLLVMFnAttrStr(fn_table_entry->llvm_value, "stack-protector-buffer-size", "4"); + } + } + } + LLVMSetFunctionCallConv(fn_table_entry->llvm_value, fn_type->data.fn.calling_convention); if (fn_type->data.fn.fn_type_id.is_cold) { ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value); @@ -363,10 +408,11 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { bool is_definition = fn_table_entry->body_node != nullptr; unsigned flags = 0; bool is_optimized = g->is_release_build; + bool is_internal_linkage = (fn_table_entry->linkage == GlobalLinkageIdInternal); ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder, get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "", import->di_file, line_number, - fn_table_entry->type_entry->di_type, fn_table_entry->internal_linkage, + fn_table_entry->type_entry->di_type, is_internal_linkage, is_definition, scope_line, flags, is_optimized, nullptr); scope->di_scope = ZigLLVMSubprogramToScope(subprogram); @@ -544,13 +590,28 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) { return val->llvm_global; } -static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) { - LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn); - LLVMValueRef msg_arg = get_panic_msg_ptr_val(g, msg_id); - ZigLLVMBuildCall(g->builder, fn_val, &msg_arg, 1, g->panic_fn->type_entry->data.fn.calling_convention, ""); +static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) { + FnTableEntry *panic_fn = get_extern_panic_fn(g); + LLVMValueRef fn_val = fn_llvm_value(g, panic_fn); + + TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true); + size_t ptr_index = str_type->data.structure.fields[slice_ptr_index].gen_index; + size_t len_index = str_type->data.structure.fields[slice_len_index].gen_index; + LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, msg_arg, ptr_index, ""); + LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, msg_arg, len_index, ""); + + LLVMValueRef args[] = { + LLVMBuildLoad(g->builder, ptr_ptr, ""), + LLVMBuildLoad(g->builder, len_ptr, ""), + }; + ZigLLVMBuildCall(g->builder, fn_val, args, 2, panic_fn->type_entry->data.fn.calling_convention, ""); LLVMBuildUnreachable(g->builder); } +static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) { + gen_panic(g, get_panic_msg_ptr_val(g, msg_id)); +} + static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, LLVMIntPredicate lower_pred, LLVMValueRef lower_value, LLVMIntPredicate upper_pred, LLVMValueRef upper_value) @@ -2564,6 +2625,11 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec return tmp_array_ptr; } +static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) { + gen_panic(g, ir_llvm_value(g, instruction->msg)); + return nullptr; +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -2584,7 +2650,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdToPtrType: case IrInstructionIdPtrTypeChild: case IrInstructionIdFieldPtr: - case IrInstructionIdSetFnVisible: case IrInstructionIdSetDebugSafety: case IrInstructionIdArrayType: case IrInstructionIdSliceType: @@ -2615,7 +2680,9 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdCanImplicitCast: case IrInstructionIdSetGlobalAlign: case IrInstructionIdSetGlobalSection: + case IrInstructionIdSetGlobalLinkage: case IrInstructionIdDeclRef: + case IrInstructionIdSwitchVar: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); @@ -2721,8 +2788,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_int_to_enum(g, executable, (IrInstructionIntToEnum *)instruction); case IrInstructionIdContainerInitList: return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction); - case IrInstructionIdSwitchVar: - zig_panic("TODO render switch var instruction to LLVM"); + case IrInstructionIdPanic: + return ir_render_panic(g, executable, (IrInstructionPanic *)instruction); } zig_unreachable(); } @@ -3659,6 +3726,18 @@ static const CIntTypeInfo c_int_type_infos[] = { static const bool is_signed_list[] = { false, true, }; +struct GlobalLinkageValue { + GlobalLinkageId id; + const char *name; +}; + +static const GlobalLinkageValue global_linkage_values[] = { + {GlobalLinkageIdInternal, "Internal"}, + {GlobalLinkageIdStrong, "Strong"}, + {GlobalLinkageIdWeak, "Weak"}, + {GlobalLinkageIdLinkOnce, "LinkOnce"}, +}; + static void define_builtin_types(CodeGen *g) { { // if this type is anywhere in the AST, we should never hit codegen. @@ -3995,6 +4074,30 @@ static void define_builtin_types(CodeGen *g) { g->primitive_type_table.put(&entry->name, entry); } + { + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); + entry->zero_bits = true; // only allowed at compile time + buf_init_from_str(&entry->name, "GlobalLinkage"); + uint32_t field_count = array_length(global_linkage_values); + entry->data.enumeration.src_field_count = field_count; + entry->data.enumeration.fields = allocate(field_count); + for (uint32_t i = 0; i < field_count; i += 1) { + TypeEnumField *type_enum_field = &entry->data.enumeration.fields[i]; + const GlobalLinkageValue *value = &global_linkage_values[i]; + type_enum_field->name = buf_create_from_str(value->name); + type_enum_field->value = i; + type_enum_field->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; + + g->builtin_types.entry_global_linkage_enum = entry; + g->primitive_type_table.put(&entry->name, entry); + } + { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); entry->zero_bits = true; // only allowed at compile time @@ -4145,11 +4248,12 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); create_builtin_fn(g, BuiltinFnIdIntType, "intType", 2); - create_builtin_fn(g, BuiltinFnIdSetFnVisible, "setFnVisible", 2); create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2); create_builtin_fn(g, BuiltinFnIdAlloca, "alloca", 2); create_builtin_fn(g, BuiltinFnIdSetGlobalAlign, "setGlobalAlign", 2); create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2); + create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2); + create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1); } static void add_compile_var(CodeGen *g, const char *name, ConstExprValue *value) { @@ -4180,6 +4284,7 @@ static void define_builtin_compile_vars(CodeGen *g) { add_compile_var(g, "link_libs", const_val); } + add_compile_var(g, "panic_implementation_provided", create_const_bool(g, false)); } static void init(CodeGen *g, Buf *source_path) { @@ -4309,9 +4414,10 @@ static PackageTableEntry *create_bootstrap_pkg(CodeGen *g) { return package; } -static PackageTableEntry *create_panic_pkg(CodeGen *g) { +static PackageTableEntry *create_zigrt_pkg(CodeGen *g) { PackageTableEntry *package = new_package(buf_ptr(g->zig_std_special_dir), ""); package->package_table.put(buf_create_from_str("std"), g->std_package); + package->package_table.put(buf_create_from_str("@root"), g->root_package); return package; } @@ -4337,9 +4443,9 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou if (!g->is_test_build && g->have_pub_main && (g->out_type == OutTypeObj || g->out_type == OutTypeExe)) { g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap.zig"); } - if (!g->have_pub_panic) { - g->panic_package = create_panic_pkg(g); - add_special_code(g, g->panic_package, "panic.zig"); + if (!g->omit_zigrt) { + g->zigrt_package = create_zigrt_pkg(g); + add_special_code(g, g->zigrt_package, "zigrt.zig"); } if (g->verbose) { @@ -4509,7 +4615,7 @@ void codegen_generate_h_file(CodeGen *g) { for (size_t fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) { FnTableEntry *fn_table_entry = g->fn_defs.at(fn_def_i); - if (fn_table_entry->internal_linkage) + if (fn_table_entry->linkage == GlobalLinkageIdInternal) continue; FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; diff --git a/src/codegen.hpp b/src/codegen.hpp index 72dacf71c4..5b39e3d36c 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -43,6 +43,7 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic); void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min); void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min); void codegen_set_linker_script(CodeGen *g, const char *linker_script); +void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt); void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code); diff --git a/src/ir.cpp b/src/ir.cpp index 326c7223f1..9e1ef9339e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -276,10 +276,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrTypeChild *) return IrInstructionIdPtrTypeChild; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFnVisible *) { - return IrInstructionIdSetFnVisible; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionSetDebugSafety *) { return IrInstructionIdSetDebugSafety; } @@ -528,10 +524,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalSection return IrInstructionIdSetGlobalSection; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalLinkage *) { + return IrInstructionIdSetGlobalLinkage; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclRef *) { return IrInstructionIdDeclRef; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionPanic *) { + return IrInstructionIdPanic; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -1147,19 +1151,6 @@ static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstN return &instruction->base; } -static IrInstruction *ir_build_set_fn_visible(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn_value, - IrInstruction *is_visible) -{ - IrInstructionSetFnVisible *instruction = ir_build_instruction(irb, scope, source_node); - instruction->fn_value = fn_value; - instruction->is_visible = is_visible; - - ir_ref_instruction(fn_value, irb->current_basic_block); - ir_ref_instruction(is_visible, irb->current_basic_block); - - return &instruction->base; -} - static IrInstruction *ir_build_set_debug_safety(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_value, IrInstruction *debug_safety_on) { @@ -2092,6 +2083,19 @@ static IrInstruction *ir_build_set_global_section(IrBuilder *irb, Scope *scope, return &instruction->base; } +static IrInstruction *ir_build_set_global_linkage(IrBuilder *irb, Scope *scope, AstNode *source_node, + Tld *tld, IrInstruction *value) +{ + IrInstructionSetGlobalLinkage *instruction = ir_build_instruction( + irb, scope, source_node); + instruction->tld = tld; + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, Tld *tld, LVal lval) { @@ -2103,6 +2107,17 @@ static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *s return &instruction->base; } +static IrInstruction *ir_build_panic(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *msg) { + IrInstructionPanic *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base.value.special = ConstValSpecialStatic; + instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable; + instruction->msg = msg; + + ir_ref_instruction(msg, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { return nullptr; } @@ -2287,14 +2302,6 @@ static IrInstruction *ir_instruction_ptrtypechild_get_dep(IrInstructionPtrTypeCh } } -static IrInstruction *ir_instruction_setfnvisible_get_dep(IrInstructionSetFnVisible *instruction, size_t index) { - switch (index) { - case 0: return instruction->fn_value; - case 1: return instruction->is_visible; - default: return nullptr; - } -} - static IrInstruction *ir_instruction_setdebugsafety_get_dep(IrInstructionSetDebugSafety *instruction, size_t index) { switch (index) { case 0: return instruction->scope_value; @@ -2742,10 +2749,24 @@ static IrInstruction *ir_instruction_setglobalsection_get_dep(IrInstructionSetGl } } +static IrInstruction *ir_instruction_setgloballinkage_get_dep(IrInstructionSetGlobalLinkage *instruction, size_t index) { + switch (index) { + case 0: return instruction->value; + default: return nullptr; + } +} + static IrInstruction *ir_instruction_declref_get_dep(IrInstructionDeclRef *instruction, size_t index) { return nullptr; } +static IrInstruction *ir_instruction_panic_get_dep(IrInstructionPanic *instruction, size_t index) { + switch (index) { + case 0: return instruction->msg; + default: return nullptr; + } +} + static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -2804,8 +2825,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_toptrtype_get_dep((IrInstructionToPtrType *) instruction, index); case IrInstructionIdPtrTypeChild: return ir_instruction_ptrtypechild_get_dep((IrInstructionPtrTypeChild *) instruction, index); - case IrInstructionIdSetFnVisible: - return ir_instruction_setfnvisible_get_dep((IrInstructionSetFnVisible *) instruction, index); case IrInstructionIdSetDebugSafety: return ir_instruction_setdebugsafety_get_dep((IrInstructionSetDebugSafety *) instruction, index); case IrInstructionIdArrayType: @@ -2928,8 +2947,12 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_setglobalalign_get_dep((IrInstructionSetGlobalAlign *) instruction, index); case IrInstructionIdSetGlobalSection: return ir_instruction_setglobalsection_get_dep((IrInstructionSetGlobalSection *) instruction, index); + case IrInstructionIdSetGlobalLinkage: + return ir_instruction_setgloballinkage_get_dep((IrInstructionSetGlobalLinkage *) instruction, index); case IrInstructionIdDeclRef: return ir_instruction_declref_get_dep((IrInstructionDeclRef *) instruction, index); + case IrInstructionIdPanic: + return ir_instruction_panic_get_dep((IrInstructionPanic *) instruction, index); } zig_unreachable(); } @@ -3759,20 +3782,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg; return ir_build_typeof(irb, scope, node, arg); } - case BuiltinFnIdSetFnVisible: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_instruction) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_instruction) - return arg1_value; - - return ir_build_set_fn_visible(irb, scope, node, arg0_value, arg1_value); - } case BuiltinFnIdSetDebugSafety: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -4145,6 +4154,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } case BuiltinFnIdSetGlobalAlign: case BuiltinFnIdSetGlobalSection: + case BuiltinFnIdSetGlobalLinkage: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); if (arg0_node->type != NodeTypeSymbol) { @@ -4170,10 +4180,23 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (builtin_fn->id == BuiltinFnIdSetGlobalAlign) { return ir_build_set_global_align(irb, scope, node, tld, arg1_value); - } else { + } else if (builtin_fn->id == BuiltinFnIdSetGlobalSection) { return ir_build_set_global_section(irb, scope, node, tld, arg1_value); + } else if (builtin_fn->id == BuiltinFnIdSetGlobalLinkage) { + return ir_build_set_global_linkage(irb, scope, node, tld, arg1_value); + } else { + zig_unreachable(); } } + case BuiltinFnIdPanic: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + return ir_build_panic(irb, scope, node, arg0_value); + } } zig_unreachable(); } @@ -4624,6 +4647,10 @@ static IrInstruction *ir_gen_this_literal(IrBuilder *irb, Scope *scope, AstNode if (fn_entry) return ir_build_const_fn(irb, scope, node, fn_entry); + while (scope->id != ScopeIdBlock && scope->id != ScopeIdDecls) { + scope = scope->parent; + } + if (scope->id == ScopeIdDecls) { ScopeDecls *decls_scope = (ScopeDecls *)scope; TypeTableEntry *container_type = decls_scope->container_type; @@ -7096,6 +7123,23 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic return true; } +static bool ir_resolve_global_linkage(IrAnalyze *ira, IrInstruction *value, GlobalLinkageId *out) { + if (type_is_invalid(value->value.type)) + return false; + + IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_global_linkage_enum); + if (type_is_invalid(casted_value->value.type)) + return false; + + ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); + if (!const_val) + return false; + + *out = (GlobalLinkageId)const_val->data.x_enum.tag; + return true; +} + + static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { if (type_is_invalid(value->value.type)) return nullptr; @@ -9557,42 +9601,6 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, return ira->codegen->builtin_types.entry_type; } -static TypeTableEntry *ir_analyze_instruction_set_fn_visible(IrAnalyze *ira, - IrInstructionSetFnVisible *set_fn_visible_instruction) -{ - IrInstruction *fn_value = set_fn_visible_instruction->fn_value->other; - IrInstruction *is_visible_value = set_fn_visible_instruction->is_visible->other; - - FnTableEntry *fn_entry = ir_resolve_fn(ira, fn_value); - if (!fn_entry) - return ira->codegen->builtin_types.entry_invalid; - - bool want_export; - if (!ir_resolve_bool(ira, is_visible_value, &want_export)) - return ira->codegen->builtin_types.entry_invalid; - - AstNode *source_node = set_fn_visible_instruction->base.source_node; - if (fn_entry->fn_export_set_node) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("function visibility set twice")); - add_error_note(ira->codegen, msg, fn_entry->fn_export_set_node, buf_sprintf("first set here")); - return ira->codegen->builtin_types.entry_invalid; - } - fn_entry->fn_export_set_node = source_node; - - AstNodeFnProto *fn_proto = &fn_entry->proto_node->data.fn_proto; - if (fn_proto->visib_mod != VisibModExport) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("function must be marked export to set function visibility")); - add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("function declared here")); - return ira->codegen->builtin_types.entry_invalid; - } - fn_entry->internal_linkage = !want_export; - - ir_build_const_from(ira, &set_fn_visible_instruction->base); - return ira->codegen->builtin_types.entry_void; -} - static TypeTableEntry *ir_analyze_instruction_set_global_align(IrAnalyze *ira, IrInstructionSetGlobalAlign *instruction) { @@ -9677,6 +9685,45 @@ static TypeTableEntry *ir_analyze_instruction_set_global_section(IrAnalyze *ira, return ira->codegen->builtin_types.entry_void; } +static TypeTableEntry *ir_analyze_instruction_set_global_linkage(IrAnalyze *ira, + IrInstructionSetGlobalLinkage *instruction) +{ + Tld *tld = instruction->tld; + IrInstruction *linkage_value = instruction->value->other; + + GlobalLinkageId linkage_scalar; + if (!ir_resolve_global_linkage(ira, linkage_value, &linkage_scalar)) + return ira->codegen->builtin_types.entry_invalid; + + AstNode **set_global_linkage_node; + GlobalLinkageId *dest_linkage_ptr; + if (tld->id == TldIdVar) { + TldVar *tld_var = (TldVar *)tld; + set_global_linkage_node = &tld_var->set_global_linkage_node; + dest_linkage_ptr = &tld_var->linkage; + } else if (tld->id == TldIdFn) { + TldFn *tld_fn = (TldFn *)tld; + FnTableEntry *fn_entry = tld_fn->fn_entry; + set_global_linkage_node = &fn_entry->set_global_linkage_node; + dest_linkage_ptr = &fn_entry->linkage; + } else { + // error is caught in pass1 IR gen + zig_unreachable(); + } + + AstNode *source_node = instruction->base.source_node; + if (*set_global_linkage_node) { + ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("linkage set twice")); + add_error_note(ira->codegen, msg, *set_global_linkage_node, buf_sprintf("first set here")); + return ira->codegen->builtin_types.entry_invalid; + } + *set_global_linkage_node = source_node; + *dest_linkage_ptr = linkage_scalar; + + ir_build_const_from(ira, &instruction->base); + return ira->codegen->builtin_types.entry_void; +} + static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, IrInstructionSetDebugSafety *set_debug_safety_instruction) { @@ -12147,6 +12194,22 @@ static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira, return ira->codegen->builtin_types.entry_bool; } +static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic *instruction) { + IrInstruction *msg = instruction->msg->other; + if (type_is_invalid(msg->value.type)) + return ira->codegen->builtin_types.entry_invalid; + + TypeTableEntry *str_type = get_slice_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true); + IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type); + if (type_is_invalid(casted_msg->value.type)) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *new_instruction = ir_build_panic(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, casted_msg); + ir_link_new_instruction(new_instruction, &instruction->base); + return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable); +} + static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira, IrInstructionDeclRef *instruction) { @@ -12266,12 +12329,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_to_ptr_type(ira, (IrInstructionToPtrType *)instruction); case IrInstructionIdPtrTypeChild: return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction); - case IrInstructionIdSetFnVisible: - return ir_analyze_instruction_set_fn_visible(ira, (IrInstructionSetFnVisible *)instruction); case IrInstructionIdSetGlobalAlign: return ir_analyze_instruction_set_global_align(ira, (IrInstructionSetGlobalAlign *)instruction); case IrInstructionIdSetGlobalSection: return ir_analyze_instruction_set_global_section(ira, (IrInstructionSetGlobalSection *)instruction); + case IrInstructionIdSetGlobalLinkage: + return ir_analyze_instruction_set_global_linkage(ira, (IrInstructionSetGlobalLinkage *)instruction); case IrInstructionIdSetDebugSafety: return ir_analyze_instruction_set_debug_safety(ira, (IrInstructionSetDebugSafety *)instruction); case IrInstructionIdSliceType: @@ -12384,6 +12447,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_can_implicit_cast(ira, (IrInstructionCanImplicitCast *)instruction); case IrInstructionIdDeclRef: return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction); + case IrInstructionIdPanic: + return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction); case IrInstructionIdMaybeWrap: case IrInstructionIdErrWrapCode: case IrInstructionIdErrWrapPayload: @@ -12482,7 +12547,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCall: case IrInstructionIdReturn: case IrInstructionIdUnreachable: - case IrInstructionIdSetFnVisible: case IrInstructionIdSetDebugSafety: case IrInstructionIdImport: case IrInstructionIdCompileErr: @@ -12500,6 +12564,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCheckSwitchProngs: case IrInstructionIdSetGlobalAlign: case IrInstructionIdSetGlobalSection: + case IrInstructionIdSetGlobalLinkage: + case IrInstructionIdPanic: return true; case IrInstructionIdPhi: case IrInstructionIdUnOp: @@ -12580,7 +12646,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { } FnTableEntry *ir_create_inline_fn(CodeGen *codegen, Buf *fn_name, VariableTableEntry *var, Scope *parent_scope) { - FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, true); + FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, GlobalLinkageIdInternal); buf_init_from_buf(&fn_entry->symbol_name, fn_name); fn_entry->fndef_scope = create_fndef_scope(nullptr, parent_scope, fn_entry); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index b0e5fdc6c0..376de228d2 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -339,14 +339,6 @@ static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *ins fprintf(irp->f, ")"); } -static void ir_print_set_fn_visible(IrPrint *irp, IrInstructionSetFnVisible *instruction) { - fprintf(irp->f, "@setFnVisible("); - ir_print_other_instruction(irp, instruction->fn_value); - fprintf(irp->f, ", "); - ir_print_other_instruction(irp, instruction->is_visible); - fprintf(irp->f, ")"); -} - static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) { fprintf(irp->f, "@setDebugSafety("); ir_print_other_instruction(irp, instruction->scope_value); @@ -849,6 +841,13 @@ static void ir_print_set_global_section(IrPrint *irp, IrInstructionSetGlobalSect fprintf(irp->f, ")"); } +static void ir_print_set_global_linkage(IrPrint *irp, IrInstructionSetGlobalLinkage *instruction) { + fprintf(irp->f, "@setGlobalLinkage(%s,", buf_ptr(instruction->tld->name)); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); +} + + static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) { const char *ptr_str = instruction->lval.is_ptr ? "ptr " : ""; const char *const_str = instruction->lval.is_const ? "const " : ""; @@ -856,6 +855,13 @@ static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) { fprintf(irp->f, "declref %s%s%s%s", const_str, volatile_str, ptr_str, buf_ptr(instruction->tld->name)); } +static void ir_print_panic(IrPrint *irp, IrInstructionPanic *instruction) { + fprintf(irp->f, "@panic("); + ir_print_other_instruction(irp, instruction->msg); + fprintf(irp->f, ")"); +} + + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -933,9 +939,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdEnumFieldPtr: ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction); break; - case IrInstructionIdSetFnVisible: - ir_print_set_fn_visible(irp, (IrInstructionSetFnVisible *)instruction); - break; case IrInstructionIdSetDebugSafety: ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction); break; @@ -1128,9 +1131,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdSetGlobalSection: ir_print_set_global_section(irp, (IrInstructionSetGlobalSection *)instruction); break; + case IrInstructionIdSetGlobalLinkage: + ir_print_set_global_linkage(irp, (IrInstructionSetGlobalLinkage *)instruction); + break; case IrInstructionIdDeclRef: ir_print_decl_ref(irp, (IrInstructionDeclRef *)instruction); break; + case IrInstructionIdPanic: + ir_print_panic(irp, (IrInstructionPanic *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/src/link.cpp b/src/link.cpp index faf9fd26e0..36cc103a2c 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -52,6 +52,7 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) { child_gen->link_libs.items[i] = parent_gen->link_libs.items[i]; } + codegen_set_omit_zigrt(child_gen, true); child_gen->want_h_file = false; codegen_set_is_release(child_gen, parent_gen->is_release_build); diff --git a/src/parseh.cpp b/src/parseh.cpp index b4582e26b4..77cc15cc0f 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -635,8 +635,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { } assert(fn_type->id == TypeTableEntryIdFn); - bool internal_linkage = false; - FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, internal_linkage); + FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, GlobalLinkageIdStrong); buf_init_from_buf(&fn_entry->symbol_name, fn_name); fn_entry->type_entry = fn_type; diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index c9a36a0703..92cac016d7 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -13,7 +13,7 @@ var argc: usize = undefined; var argv: &&u8 = undefined; export nakedcc fn _start() -> noreturn { - @setFnVisible(this, want_start_symbol); + @setGlobalLinkage(_start, if (want_start_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal); if (!want_start_symbol) { unreachable; } @@ -47,7 +47,7 @@ fn callMainAndExit() -> noreturn { } export fn main(c_argc: i32, c_argv: &&u8) -> i32 { - @setFnVisible(this, want_main_symbol); + @setGlobalLinkage(main, if (want_main_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal); if (!want_main_symbol) { unreachable; } diff --git a/std/special/builtin.zig b/std/special/builtin.zig index 136cbd9da4..26e5080d83 100644 --- a/std/special/builtin.zig +++ b/std/special/builtin.zig @@ -30,7 +30,6 @@ export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { d[index] = s[index]; } -// Avoid dragging in the debug safety mechanisms into this .o file. -pub fn panic(message: []const u8) -> noreturn { - unreachable; +export fn __stack_chk_fail() { + @panic("stack smashing detected"); } diff --git a/std/special/compiler_rt.zig b/std/special/compiler_rt.zig index f6e4c021d1..8f61876305 100644 --- a/std/special/compiler_rt.zig +++ b/std/special/compiler_rt.zig @@ -1,13 +1,3 @@ -// Avoid dragging in the debug safety mechanisms into this .o file, -// unless we're trying to test this file. -pub fn panic(message: []const u8) -> noreturn { - if (@compileVar("is_test")) { - @import("std").debug.panic(message); - } else { - unreachable; - } -} - const CHAR_BIT = 8; const du_int = u64; const di_int = i64; @@ -262,7 +252,7 @@ export nakedcc fn __aeabi_uidivmod() { unreachable; } - @setFnVisible(this, false); + @setGlobalLinkage(__aeabi_uidivmod, GlobalLinkage.Internal); } export fn __udivmodsi4(a: su_int, b: su_int, rem: &su_int) -> su_int { diff --git a/std/special/panic.zig b/std/special/panic.zig deleted file mode 100644 index 9b58a4d9c8..0000000000 --- a/std/special/panic.zig +++ /dev/null @@ -1,12 +0,0 @@ -// This file is included if and only if the user's main source file does not -// include a public panic function. -// If this file wants to import other files *by name*, support for that would -// have to be added in the compiler. - -pub coldcc fn panic(message: []const u8) -> noreturn { - if (@compileVar("os") == Os.freestanding) { - while (true) {} - } else { - @import("std").debug.panic(message); - } -} diff --git a/std/special/zigrt.zig b/std/special/zigrt.zig new file mode 100644 index 0000000000..148516eb40 --- /dev/null +++ b/std/special/zigrt.zig @@ -0,0 +1,16 @@ +// This file contains functions that zig depends on to coordinate between +// multiple .o files. The symbols are defined LinkOnce so that multiple +// instances of zig_rt.zig do not conflict with each other. + +export coldcc fn __zig_panic(message_ptr: &const u8, message_len: usize) -> noreturn { + @setGlobalLinkage(__zig_panic, GlobalLinkage.Weak); + @setDebugSafety(this, false); + + if (@compileVar("panic_implementation_provided")) { + @import("@root").panic(message_ptr[0...message_len]); + } else if (@compileVar("os") == Os.freestanding) { + while (true) {} + } else { + @import("std").debug.panic(message_ptr[0...message_len]); + } +} diff --git a/test/cases/misc.zig b/test/cases/misc.zig index c83e0374f6..c26ae8b04a 100644 --- a/test/cases/misc.zig +++ b/test/cases/misc.zig @@ -12,7 +12,7 @@ test "emptyFunctionWithComments" { } export fn disabledExternFn() { - @setFnVisible(this, false); + @setGlobalLinkage(disabledExternFn, GlobalLinkage.Internal); } test "callDisabledExternFn" { diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 8f5acab6d7..162ba24903 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1828,6 +1828,18 @@ export fn entry() { ////////////////////////////////////////////////////////////////////////////// static void add_debug_safety_test_cases(void) { + add_debug_safety_case("calling panic", R"SOURCE( +pub fn panic(message: []const u8) -> noreturn { + @breakpoint(); + while (true) {} +} +pub fn main(args: [][]u8) -> %void { + if (!@compileVar("is_release")) { + @panic("oh no"); + } +} + )SOURCE"); + add_debug_safety_case("out of bounds slice access", R"SOURCE( pub fn panic(message: []const u8) -> noreturn { @breakpoint();