Commit a32b5929cc
Changed files (19)
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)
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`.
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<IrInstruction *> 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<Scope *, IrInstruction *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table;
HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table;
HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> compile_vars;
- HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_symbol_names;
+ HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> exported_symbol_names;
+ HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
ZigList<ImportTableEntry *> 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<LLVMBasicBlockRef> 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;
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<FnTableEntry>(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<TldFn>(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<FnTypeParamInfo>(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<TldFn>(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;
+}
+
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
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<TypeEnumField>(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;
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);
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<typename T>
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate<T>(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<IrInstructionSetFnVisible>(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<IrInstructionSetGlobalLinkage>(
+ 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<IrInstructionPanic>(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);
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");
}
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);
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;
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;
}
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");
}
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 {
std/special/panic.zig
@@ -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);
- }
-}
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]);
+ }
+}
test/cases/misc.zig
@@ -12,7 +12,7 @@ test "emptyFunctionWithComments" {
}
export fn disabledExternFn() {
- @setFnVisible(this, false);
+ @setGlobalLinkage(disabledExternFn, GlobalLinkage.Internal);
}
test "callDisabledExternFn" {
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();
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})