authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-06-14 00:04:34-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-06-14 00:04:34-04:00
log6a93dda3e1c0ff5f400da25a5d14c907fc9a6fdf
tree08260222b967ccf73f237ae97824c054c023c9b8
parent199bbb6292896330ced71dec2e5c58a49af5907e

progress toward windows hello world working


28 files changed, 515 insertions(+), 235 deletions(-)

CMakeLists.txt-1
...@@ -244,7 +244,6 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/special/builtin.zig" DESTINATION "${ZIG_S...@@ -244,7 +244,6 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/special/builtin.zig" DESTINATION "${ZIG_S
244install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}/special")244install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}/special")
245install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special")245install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special")
246install(FILES "${CMAKE_SOURCE_DIR}/std/special/zigrt.zig" DESTINATION "${ZIG_STD_DEST}/special")246install(FILES "${CMAKE_SOURCE_DIR}/std/special/zigrt.zig" DESTINATION "${ZIG_STD_DEST}/special")
247install(FILES "${CMAKE_SOURCE_DIR}/std/target.zig" DESTINATION "${ZIG_STD_DEST}")
248247
249if (ZIG_TEST_COVERAGE)248if (ZIG_TEST_COVERAGE)
250 add_custom_target(coverage249 add_custom_target(coverage
doc/langref.md+2-2
...@@ -23,9 +23,9 @@ ContainerField = Symbol option(":" Expression) ","...@@ -23,9 +23,9 @@ ContainerField = Symbol option(":" Expression) ","
2323
24UseDecl = "use" Expression ";"24UseDecl = "use" Expression ";"
2525
26ExternDecl = "extern" (FnProto | VariableDeclaration) ";"26ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
2727
28FnProto = option("coldcc" | "nakedcc") "fn" option(Symbol) ParamDeclList option("->" TypeExpr)28FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("->" TypeExpr)
2929
30VisibleMod = "pub" | "export"30VisibleMod = "pub" | "export"
3131
src/all_types.hpp+27-8
...@@ -304,12 +304,14 @@ struct TldVar {...@@ -304,12 +304,14 @@ struct TldVar {
304 Buf *section_name;304 Buf *section_name;
305 AstNode *set_global_linkage_node;305 AstNode *set_global_linkage_node;
306 GlobalLinkageId linkage;306 GlobalLinkageId linkage;
307 Buf *extern_lib_name;
307};308};
308309
309struct TldFn {310struct TldFn {
310 Tld base;311 Tld base;
311312
312 FnTableEntry *fn_entry;313 FnTableEntry *fn_entry;
314 Buf *extern_lib_name;
313};315};
314316
315struct TldContainer {317struct TldContainer {
...@@ -387,6 +389,14 @@ struct AstNodeRoot {...@@ -387,6 +389,14 @@ struct AstNodeRoot {
387 ZigList<AstNode *> top_level_decls;389 ZigList<AstNode *> top_level_decls;
388};390};
389391
392enum CallingConvention {
393 CallingConventionUnspecified,
394 CallingConventionC,
395 CallingConventionCold,
396 CallingConventionNaked,
397 CallingConventionStdcall,
398};
399
390struct AstNodeFnProto {400struct AstNodeFnProto {
391 VisibMod visib_mod;401 VisibMod visib_mod;
392 Buf *name;402 Buf *name;
...@@ -395,9 +405,10 @@ struct AstNodeFnProto {...@@ -395,9 +405,10 @@ struct AstNodeFnProto {
395 bool is_var_args;405 bool is_var_args;
396 bool is_extern;406 bool is_extern;
397 bool is_inline;407 bool is_inline;
398 bool is_coldcc;408 CallingConvention cc;
399 bool is_nakedcc;
400 AstNode *fn_def_node;409 AstNode *fn_def_node;
410 // populated if this is an extern declaration
411 Buf *lib_name;
401};412};
402413
403struct AstNodeFnDef {414struct AstNodeFnDef {
...@@ -451,6 +462,8 @@ struct AstNodeVariableDeclaration {...@@ -451,6 +462,8 @@ struct AstNodeVariableDeclaration {
451 // one or both of type and expr will be non null462 // one or both of type and expr will be non null
452 AstNode *type;463 AstNode *type;
453 AstNode *expr;464 AstNode *expr;
465 // populated if this is an extern declaration
466 Buf *lib_name;
454};467};
455468
456struct AstNodeErrorValueDecl {469struct AstNodeErrorValueDecl {
...@@ -879,9 +892,7 @@ struct FnTypeId {...@@ -879,9 +892,7 @@ struct FnTypeId {
879 size_t param_count;892 size_t param_count;
880 size_t next_param_index;893 size_t next_param_index;
881 bool is_var_args;894 bool is_var_args;
882 bool is_naked;895 CallingConvention cc;
883 bool is_cold;
884 bool is_extern;
885};896};
886897
887uint32_t fn_type_id_hash(FnTypeId*);898uint32_t fn_type_id_hash(FnTypeId*);
...@@ -1013,7 +1024,6 @@ struct TypeTableEntryFn {...@@ -1013,7 +1024,6 @@ struct TypeTableEntryFn {
1013 FnGenParamInfo *gen_param_info;1024 FnGenParamInfo *gen_param_info;
10141025
1015 LLVMTypeRef raw_type_ref;1026 LLVMTypeRef raw_type_ref;
1016 LLVMCallConv calling_convention;
10171027
1018 TypeTableEntry *bound_fn_parent;1028 TypeTableEntry *bound_fn_parent;
1019};1029};
...@@ -1316,6 +1326,13 @@ enum BuildMode {...@@ -1316,6 +1326,13 @@ enum BuildMode {
1316 BuildModeSafeRelease,1326 BuildModeSafeRelease,
1317};1327};
13181328
1329struct LinkLib {
1330 Buf *name;
1331 Buf *path;
1332 ZigList<Buf *> symbols; // the list of symbols that we depend on from this lib
1333 bool provided_explicitly;
1334};
1335
1319struct CodeGen {1336struct CodeGen {
1320 LLVMModuleRef module;1337 LLVMModuleRef module;
1321 ZigList<ErrorMsg*> errors;1338 ZigList<ErrorMsg*> errors;
...@@ -1324,7 +1341,9 @@ struct CodeGen {...@@ -1324,7 +1341,9 @@ struct CodeGen {
1324 ZigLLVMDICompileUnit *compile_unit;1341 ZigLLVMDICompileUnit *compile_unit;
1325 ZigLLVMDIFile *compile_unit_file;1342 ZigLLVMDIFile *compile_unit_file;
13261343
1327 ZigList<Buf *> link_libs; // non-libc link libs1344 ZigList<LinkLib *> link_libs_list;
1345 LinkLib *libc_link_lib;
1346
1328 // add -framework [name] args to linker1347 // add -framework [name] args to linker
1329 ZigList<Buf *> darwin_frameworks;1348 ZigList<Buf *> darwin_frameworks;
1330 // add -rpath [name] args to linker1349 // add -rpath [name] args to linker
...@@ -1344,6 +1363,7 @@ struct CodeGen {...@@ -1344,6 +1363,7 @@ struct CodeGen {
1344 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> exported_symbol_names;1363 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> exported_symbol_names;
1345 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;1364 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
13461365
1366
1347 ZigList<ImportTableEntry *> import_queue;1367 ZigList<ImportTableEntry *> import_queue;
1348 size_t import_queue_index;1368 size_t import_queue_index;
1349 ZigList<Tld *> resolve_queue;1369 ZigList<Tld *> resolve_queue;
...@@ -1402,7 +1422,6 @@ struct CodeGen {...@@ -1402,7 +1422,6 @@ struct CodeGen {
1402 bool have_pub_main;1422 bool have_pub_main;
1403 bool have_c_main;1423 bool have_c_main;
1404 bool have_pub_panic;1424 bool have_pub_panic;
1405 bool link_libc;
1406 Buf *libc_lib_dir;1425 Buf *libc_lib_dir;
1407 Buf *libc_static_lib_dir;1426 Buf *libc_static_lib_dir;
1408 Buf *libc_include_dir;1427 Buf *libc_include_dir;
src/analyze.cpp+108-62
...@@ -802,6 +802,21 @@ TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry) {...@@ -802,6 +802,21 @@ TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry) {
802 return bound_fn_type;802 return bound_fn_type;
803}803}
804804
805bool calling_convention_does_first_arg_return(CallingConvention cc) {
806 return cc == CallingConventionUnspecified;
807}
808
809static const char *calling_convention_name(CallingConvention cc) {
810 switch (cc) {
811 case CallingConventionUnspecified: return "undefined";
812 case CallingConventionC: return "ccc";
813 case CallingConventionCold: return "coldcc";
814 case CallingConventionNaked: return "nakedcc";
815 case CallingConventionStdcall: return "stdcallcc";
816 default: zig_unreachable();
817 }
818}
819
805TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {820TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
806 auto table_entry = g->fn_type_table.maybe_get(fn_type_id);821 auto table_entry = g->fn_type_table.maybe_get(fn_type_id);
807 if (table_entry) {822 if (table_entry) {
...@@ -813,30 +828,29 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -813,30 +828,29 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
813 fn_type->is_copyable = true;828 fn_type->is_copyable = true;
814 fn_type->data.fn.fn_type_id = *fn_type_id;829 fn_type->data.fn.fn_type_id = *fn_type_id;
815830
816 if (fn_type_id->is_cold) {
817 // cold calling convention only works on x86.
818 // but we can add the cold attribute later.
819 if (g->zig_target.arch.arch == ZigLLVM_x86 ||
820 g->zig_target.arch.arch == ZigLLVM_x86_64)
821 {
822 fn_type->data.fn.calling_convention = LLVMColdCallConv;
823 } else {
824 fn_type->data.fn.calling_convention = LLVMFastCallConv;
825 }
826 } else if (fn_type_id->is_extern) {
827 fn_type->data.fn.calling_convention = LLVMCCallConv;
828 } else {
829 fn_type->data.fn.calling_convention = LLVMFastCallConv;
830 }
831
832 bool skip_debug_info = false;831 bool skip_debug_info = false;
833832
834 // populate the name of the type833 // populate the name of the type
835 buf_resize(&fn_type->name, 0);834 buf_resize(&fn_type->name, 0);
836 const char *extern_str = fn_type_id->is_extern ? "extern " : "";835 const char *cc_str;
837 const char *naked_str = fn_type_id->is_naked ? "nakedcc " : "";836 switch (fn_type->data.fn.fn_type_id.cc) {
838 const char *cold_str = fn_type_id->is_cold ? "coldcc " : "";837 case CallingConventionUnspecified:
839 buf_appendf(&fn_type->name, "%s%s%sfn(", extern_str, naked_str, cold_str);838 cc_str = "";
839 break;
840 case CallingConventionC:
841 cc_str = "extern ";
842 break;
843 case CallingConventionCold:
844 cc_str = "coldcc ";
845 break;
846 case CallingConventionNaked:
847 cc_str = "nakedcc ";
848 break;
849 case CallingConventionStdcall:
850 cc_str = "stdcallcc ";
851 break;
852 }
853 buf_appendf(&fn_type->name, "%sfn(", cc_str);
840 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {854 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
841 FnTypeParamInfo *param_info = &fn_type_id->param_info[i];855 FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
842856
...@@ -861,7 +875,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -861,7 +875,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
861 // next, loop over the parameters again and compute debug information875 // next, loop over the parameters again and compute debug information
862 // and codegen information876 // and codegen information
863 if (!skip_debug_info) {877 if (!skip_debug_info) {
864 bool first_arg_return = !fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type);878 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&
879 handle_is_ptr(fn_type_id->return_type);
865 // +1 for maybe making the first argument the return value880 // +1 for maybe making the first argument the return value
866 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count);881 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count);
867 // +1 because 0 is the return type and +1 for maybe making first arg ret val882 // +1 because 0 is the return type and +1 for maybe making first arg ret val
...@@ -1013,9 +1028,13 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou...@@ -1013,9 +1028,13 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou
1013 assert(proto_node->type == NodeTypeFnProto);1028 assert(proto_node->type == NodeTypeFnProto);
1014 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;1029 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
10151030
1016 fn_type_id->is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport);1031 if (fn_proto->cc == CallingConventionUnspecified) {
1017 fn_type_id->is_naked = fn_proto->is_nakedcc;1032 bool extern_abi = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport);
1018 fn_type_id->is_cold = fn_proto->is_coldcc;1033 fn_type_id->cc = extern_abi ? CallingConventionC : CallingConventionUnspecified;
1034 } else {
1035 fn_type_id->cc = fn_proto->cc;
1036 }
1037
1019 fn_type_id->param_count = fn_proto->params.length;1038 fn_type_id->param_count = fn_proto->params.length;
1020 fn_type_id->param_info = allocate_nonzero<FnTypeParamInfo>(param_count_alloc);1039 fn_type_id->param_info = allocate_nonzero<FnTypeParamInfo>(param_count_alloc);
1021 fn_type_id->next_param_index = 0;1040 fn_type_id->next_param_index = 0;
...@@ -1037,18 +1056,24 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1037,18 +1056,24 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1037 bool param_is_var_args = param_node->data.param_decl.is_var_args;1056 bool param_is_var_args = param_node->data.param_decl.is_var_args;
10381057
1039 if (param_is_comptime) {1058 if (param_is_comptime) {
1040 if (fn_type_id.is_extern) {1059 if (fn_type_id.cc != CallingConventionUnspecified) {
1041 add_node_error(g, param_node,1060 add_node_error(g, param_node,
1042 buf_sprintf("comptime parameter not allowed in extern function"));1061 buf_sprintf("comptime parameter not allowed in function with calling convention '%s'",
1062 calling_convention_name(fn_type_id.cc)));
1043 return g->builtin_types.entry_invalid;1063 return g->builtin_types.entry_invalid;
1044 }1064 }
1045 return get_generic_fn_type(g, &fn_type_id);1065 return get_generic_fn_type(g, &fn_type_id);
1046 } else if (param_is_var_args) {1066 } else if (param_is_var_args) {
1047 if (fn_type_id.is_extern) {1067 if (fn_type_id.cc == CallingConventionC) {
1048 fn_type_id.param_count = fn_type_id.next_param_index;1068 fn_type_id.param_count = fn_type_id.next_param_index;
1049 continue;1069 continue;
1050 } else {1070 } else if (fn_type_id.cc == CallingConventionUnspecified) {
1051 return get_generic_fn_type(g, &fn_type_id);1071 return get_generic_fn_type(g, &fn_type_id);
1072 } else {
1073 add_node_error(g, param_node,
1074 buf_sprintf("var args not allowed in function with calling convention '%s'",
1075 calling_convention_name(fn_type_id.cc)));
1076 return g->builtin_types.entry_invalid;
1052 }1077 }
1053 }1078 }
10541079
...@@ -1066,9 +1091,10 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1066,9 +1091,10 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1066 buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name)));1091 buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name)));
1067 return g->builtin_types.entry_invalid;1092 return g->builtin_types.entry_invalid;
1068 case TypeTableEntryIdVar:1093 case TypeTableEntryIdVar:
1069 if (fn_type_id.is_extern) {1094 if (fn_type_id.cc != CallingConventionUnspecified) {
1070 add_node_error(g, param_node->data.param_decl.type,1095 add_node_error(g, param_node->data.param_decl.type,
1071 buf_sprintf("parameter of type 'var' not allowed in extern function"));1096 buf_sprintf("parameter of type 'var' not allowed in function with calling convention '%s'",
1097 calling_convention_name(fn_type_id.cc)));
1072 return g->builtin_types.entry_invalid;1098 return g->builtin_types.entry_invalid;
1073 }1099 }
1074 return get_generic_fn_type(g, &fn_type_id);1100 return get_generic_fn_type(g, &fn_type_id);
...@@ -1097,7 +1123,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1097,7 +1123,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1097 case TypeTableEntryIdFn:1123 case TypeTableEntryIdFn:
1098 case TypeTableEntryIdEnumTag:1124 case TypeTableEntryIdEnumTag:
1099 ensure_complete_type(g, type_entry);1125 ensure_complete_type(g, type_entry);
1100 if (!fn_type_id.is_extern && !type_is_copyable(g, type_entry)) {1126 if (fn_type_id.cc == CallingConventionUnspecified && !type_is_copyable(g, type_entry)) {
1101 add_node_error(g, param_node->data.param_decl.type,1127 add_node_error(g, param_node->data.param_decl.type,
1102 buf_sprintf("type '%s' is not copyable; cannot pass by value", buf_ptr(&type_entry->name)));1128 buf_sprintf("type '%s' is not copyable; cannot pass by value", buf_ptr(&type_entry->name)));
1103 return g->builtin_types.entry_invalid;1129 return g->builtin_types.entry_invalid;
...@@ -1130,10 +1156,11 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1130,10 +1156,11 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1130 case TypeTableEntryIdBoundFn:1156 case TypeTableEntryIdBoundFn:
1131 case TypeTableEntryIdVar:1157 case TypeTableEntryIdVar:
1132 case TypeTableEntryIdMetaType:1158 case TypeTableEntryIdMetaType:
1133 if (fn_type_id.is_extern) {1159 if (fn_type_id.cc != CallingConventionUnspecified) {
1134 add_node_error(g, fn_proto->return_type,1160 add_node_error(g, fn_proto->return_type,
1135 buf_sprintf("return type '%s' not allowed in extern function",1161 buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",
1136 buf_ptr(&fn_type_id.return_type->name)));1162 buf_ptr(&fn_type_id.return_type->name),
1163 calling_convention_name(fn_type_id.cc)));
1137 return g->builtin_types.entry_invalid;1164 return g->builtin_types.entry_invalid;
1138 }1165 }
1139 return get_generic_fn_type(g, &fn_type_id);1166 return get_generic_fn_type(g, &fn_type_id);
...@@ -1947,7 +1974,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -1947,7 +1974,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
1947 if (buf_eql_str(&fn_table_entry->symbol_name, "main")) {1974 if (buf_eql_str(&fn_table_entry->symbol_name, "main")) {
1948 g->main_fn = fn_table_entry;1975 g->main_fn = fn_table_entry;
19491976
1950 if (!g->link_libc && tld_fn->base.visib_mod != VisibModExport) {1977 if (g->libc_link_lib == nullptr && tld_fn->base.visib_mod != VisibModExport) {
1951 TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);1978 TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);
1952 TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;1979 TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
1953 if (actual_return_type != err_void) {1980 if (actual_return_type != err_void) {
...@@ -2109,6 +2136,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -2109,6 +2136,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
2109 VisibMod visib_mod = node->data.variable_declaration.visib_mod;2136 VisibMod visib_mod = node->data.variable_declaration.visib_mod;
2110 TldVar *tld_var = allocate<TldVar>(1);2137 TldVar *tld_var = allocate<TldVar>(1);
2111 init_tld(&tld_var->base, TldIdVar, name, visib_mod, node, &decls_scope->base);2138 init_tld(&tld_var->base, TldIdVar, name, visib_mod, node, &decls_scope->base);
2139 tld_var->extern_lib_name = node->data.variable_declaration.lib_name;
2112 add_top_level_decl(g, decls_scope, &tld_var->base);2140 add_top_level_decl(g, decls_scope, &tld_var->base);
2113 break;2141 break;
2114 }2142 }
...@@ -2124,6 +2152,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -2124,6 +2152,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
2124 VisibMod visib_mod = node->data.fn_proto.visib_mod;2152 VisibMod visib_mod = node->data.fn_proto.visib_mod;
2125 TldFn *tld_fn = allocate<TldFn>(1);2153 TldFn *tld_fn = allocate<TldFn>(1);
2126 init_tld(&tld_fn->base, TldIdFn, fn_name, visib_mod, node, &decls_scope->base);2154 init_tld(&tld_fn->base, TldIdFn, fn_name, visib_mod, node, &decls_scope->base);
2155 tld_fn->extern_lib_name = node->data.fn_proto.lib_name;
2127 add_top_level_decl(g, decls_scope, &tld_fn->base);2156 add_top_level_decl(g, decls_scope, &tld_fn->base);
21282157
2129 ImportTableEntry *import = get_scope_import(&decls_scope->base);2158 ImportTableEntry *import = get_scope_import(&decls_scope->base);
...@@ -2497,13 +2526,7 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *...@@ -2497,13 +2526,7 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
2497 if (expected_type->id == TypeTableEntryIdFn &&2526 if (expected_type->id == TypeTableEntryIdFn &&
2498 actual_type->id == TypeTableEntryIdFn)2527 actual_type->id == TypeTableEntryIdFn)
2499 {2528 {
2500 if (expected_type->data.fn.fn_type_id.is_extern != actual_type->data.fn.fn_type_id.is_extern) {2529 if (expected_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
2501 return false;
2502 }
2503 if (expected_type->data.fn.fn_type_id.is_naked != actual_type->data.fn.fn_type_id.is_naked) {
2504 return false;
2505 }
2506 if (expected_type->data.fn.fn_type_id.is_cold != actual_type->data.fn.fn_type_id.is_cold) {
2507 return false;2530 return false;
2508 }2531 }
2509 if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {2532 if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
...@@ -2780,11 +2803,6 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari...@@ -2780,11 +2803,6 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari
2780 add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter"));2803 add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter"));
2781 }2804 }
27822805
2783 if (fn_type_id->is_extern && handle_is_ptr(param_type)) {
2784 add_node_error(g, param_decl_node,
2785 buf_sprintf("byvalue types not yet supported on extern function parameters"));
2786 }
2787
2788 VariableTableEntry *var = add_variable(g, param_decl_node, fn_table_entry->child_scope,2806 VariableTableEntry *var = add_variable(g, param_decl_node, fn_table_entry->child_scope,
2789 param_name, true, create_const_runtime(param_type), nullptr);2807 param_name, true, create_const_runtime(param_type), nullptr);
2790 var->src_arg_index = i;2808 var->src_arg_index = i;
...@@ -2849,12 +2867,6 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -2849,12 +2867,6 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
28492867
2850 TypeTableEntry *fn_type = fn_table_entry->type_entry;2868 TypeTableEntry *fn_type = fn_table_entry->type_entry;
2851 assert(!fn_type->data.fn.is_generic);2869 assert(!fn_type->data.fn.is_generic);
2852 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
2853
2854 if (fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type)) {
2855 add_node_error(g, return_type_node,
2856 buf_sprintf("byvalue types not yet supported on extern function return values"));
2857 }
28582870
2859 ir_gen_fn(g, fn_table_entry);2871 ir_gen_fn(g, fn_table_entry);
2860 if (fn_table_entry->ir_executable.invalid) {2872 if (fn_table_entry->ir_executable.invalid) {
...@@ -3018,7 +3030,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a...@@ -3018,7 +3030,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a
3018 g->have_pub_panic = true;3030 g->have_pub_panic = true;
3019 }3031 }
3020 } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && buf_eql_str(proto_name, "main") &&3032 } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && buf_eql_str(proto_name, "main") &&
3021 g->link_libc)3033 g->libc_link_lib != nullptr)
3022 {3034 {
3023 g->have_c_main = true;3035 g->have_c_main = true;
3024 }3036 }
...@@ -3189,9 +3201,7 @@ bool fn_table_entry_eql(FnTableEntry *a, FnTableEntry *b) {...@@ -3189,9 +3201,7 @@ bool fn_table_entry_eql(FnTableEntry *a, FnTableEntry *b) {
31893201
3190uint32_t fn_type_id_hash(FnTypeId *id) {3202uint32_t fn_type_id_hash(FnTypeId *id) {
3191 uint32_t result = 0;3203 uint32_t result = 0;
3192 result += id->is_extern ? (uint32_t)3349388391 : 0;3204 result += ((uint32_t)(id->cc)) * (uint32_t)3349388391;
3193 result += id->is_naked ? (uint32_t)608688877 : 0;
3194 result += id->is_cold ? (uint32_t)3605523458 : 0;
3195 result += id->is_var_args ? (uint32_t)1931444534 : 0;3205 result += id->is_var_args ? (uint32_t)1931444534 : 0;
3196 result += hash_ptr(id->return_type);3206 result += hash_ptr(id->return_type);
3197 for (size_t i = 0; i < id->param_count; i += 1) {3207 for (size_t i = 0; i < id->param_count; i += 1) {
...@@ -3203,9 +3213,7 @@ uint32_t fn_type_id_hash(FnTypeId *id) {...@@ -3203,9 +3213,7 @@ uint32_t fn_type_id_hash(FnTypeId *id) {
3203}3213}
32043214
3205bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {3215bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
3206 if (a->is_extern != b->is_extern ||3216 if (a->cc != b->cc ||
3207 a->is_naked != b->is_naked ||
3208 a->is_cold != b->is_cold ||
3209 a->return_type != b->return_type ||3217 a->return_type != b->return_type ||
3210 a->is_var_args != b->is_var_args ||3218 a->is_var_args != b->is_var_args ||
3211 a->param_count != b->param_count)3219 a->param_count != b->param_count)
...@@ -4344,8 +4352,7 @@ FnTableEntry *get_extern_panic_fn(CodeGen *g) {...@@ -4344,8 +4352,7 @@ FnTableEntry *get_extern_panic_fn(CodeGen *g) {
4344 return g->extern_panic_fn;4352 return g->extern_panic_fn;
43454353
4346 FnTypeId fn_type_id = {0};4354 FnTypeId fn_type_id = {0};
4347 fn_type_id.is_extern = true;4355 fn_type_id.cc = CallingConventionCold;
4348 fn_type_id.is_cold = true;
4349 fn_type_id.param_count = 2;4356 fn_type_id.param_count = 2;
4350 fn_type_id.param_info = allocate<FnTypeParamInfo>(2);4357 fn_type_id.param_info = allocate<FnTypeParamInfo>(2);
4351 fn_type_id.next_param_index = 0;4358 fn_type_id.next_param_index = 0;
...@@ -4525,3 +4532,42 @@ const char *type_id_name(TypeTableEntryId id) {...@@ -4525,3 +4532,42 @@ const char *type_id_name(TypeTableEntryId id) {
4525 }4532 }
4526 zig_unreachable();4533 zig_unreachable();
4527}4534}
4535
4536LinkLib *create_link_lib(Buf *name) {
4537 LinkLib *link_lib = allocate<LinkLib>(1);
4538 link_lib->name = name;
4539 return link_lib;
4540}
4541
4542LinkLib *add_link_lib(CodeGen *g, Buf *name) {
4543 bool is_libc = buf_eql_str(name, "c");
4544
4545 if (is_libc && g->libc_link_lib != nullptr)
4546 return g->libc_link_lib;
4547
4548 for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
4549 LinkLib *existing_lib = g->link_libs_list.at(i);
4550 if (buf_eql_buf(existing_lib->name, name)) {
4551 return existing_lib;
4552 }
4553 }
4554
4555 LinkLib *link_lib = create_link_lib(name);
4556 g->link_libs_list.append(link_lib);
4557
4558 if (is_libc)
4559 g->libc_link_lib = link_lib;
4560
4561 return link_lib;
4562}
4563
4564void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name) {
4565 LinkLib *link_lib = add_link_lib(g, lib_name);
4566 for (size_t i = 0; i < link_lib->symbols.length; i += 1) {
4567 Buf *existing_symbol_name = link_lib->symbols.at(i);
4568 if (buf_eql_buf(existing_symbol_name, symbol_name)) {
4569 return;
4570 }
4571 }
4572 link_lib->symbols.append(symbol_name);
4573}
src/analyze.hpp+4
...@@ -168,5 +168,9 @@ size_t type_id_len();...@@ -168,5 +168,9 @@ size_t type_id_len();
168size_t type_id_index(TypeTableEntryId id);168size_t type_id_index(TypeTableEntryId id);
169TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);169TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);
170bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry);170bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry);
171LinkLib *create_link_lib(Buf *name);
172bool calling_convention_does_first_arg_return(CallingConvention cc);
173LinkLib *add_link_lib(CodeGen *codegen, Buf *lib);
174void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name);
171175
172#endif176#endif
src/ast_render.cpp+13-4
...@@ -118,6 +118,17 @@ static const char *extern_string(bool is_extern) {...@@ -118,6 +118,17 @@ static const char *extern_string(bool is_extern) {
118 return is_extern ? "extern " : "";118 return is_extern ? "extern " : "";
119}119}
120120
121static const char *calling_convention_string(CallingConvention cc) {
122 switch (cc) {
123 case CallingConventionUnspecified: return "";
124 case CallingConventionC: return "extern ";
125 case CallingConventionCold: return "coldcc ";
126 case CallingConventionNaked: return "nakedcc ";
127 case CallingConventionStdcall: return "stdcallcc ";
128 }
129 zig_unreachable();
130}
131
121static const char *inline_string(bool is_inline) {132static const char *inline_string(bool is_inline) {
122 return is_inline ? "inline " : "";133 return is_inline ? "inline " : "";
123}134}
...@@ -951,10 +962,8 @@ static void ast_render_tld_fn(AstRender *ar, Buf *name, TldFn *tld_fn) {...@@ -951,10 +962,8 @@ static void ast_render_tld_fn(AstRender *ar, Buf *name, TldFn *tld_fn) {
951 FnTableEntry *fn_entry = tld_fn->fn_entry;962 FnTableEntry *fn_entry = tld_fn->fn_entry;
952 FnTypeId *fn_type_id = &fn_entry->type_entry->data.fn.fn_type_id;963 FnTypeId *fn_type_id = &fn_entry->type_entry->data.fn.fn_type_id;
953 const char *visib_mod_str = visib_mod_string(tld_fn->base.visib_mod);964 const char *visib_mod_str = visib_mod_string(tld_fn->base.visib_mod);
954 const char *extern_str = extern_string(fn_type_id->is_extern);965 const char *cc_str = calling_convention_string(fn_type_id->cc);
955 const char *coldcc_str = fn_type_id->is_cold ? "coldcc " : "";966 fprintf(ar->f, "%s%sfn %s(", visib_mod_str, cc_str, buf_ptr(&fn_entry->symbol_name));
956 const char *nakedcc_str = fn_type_id->is_naked ? "nakedcc " : "";
957 fprintf(ar->f, "%s%s%s%sfn %s(", visib_mod_str, extern_str, coldcc_str, nakedcc_str, buf_ptr(&fn_entry->symbol_name));
958 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {967 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
959 FnTypeParamInfo *param_info = &fn_type_id->param_info[i];968 FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
960 if (i != 0) {969 if (i != 0) {
src/codegen.cpp+58-33
...@@ -138,8 +138,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out...@@ -138,8 +138,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
138 g->zig_target.os == ZigLLVM_MacOSX ||138 g->zig_target.os == ZigLLVM_MacOSX ||
139 g->zig_target.os == ZigLLVM_IOS)139 g->zig_target.os == ZigLLVM_IOS)
140 {140 {
141 g->link_libc = true;141 g->libc_link_lib = create_link_lib(buf_create_from_str("c"));
142 g->link_libs.append(buf_create_from_str("c"));
143 }142 }
144143
145 return g;144 return g;
...@@ -234,13 +233,8 @@ void codegen_add_rpath(CodeGen *g, const char *name) {...@@ -234,13 +233,8 @@ void codegen_add_rpath(CodeGen *g, const char *name) {
234 g->rpath_list.append(buf_create_from_str(name));233 g->rpath_list.append(buf_create_from_str(name));
235}234}
236235
237void codegen_add_link_lib(CodeGen *g, const char *lib) {236LinkLib *codegen_add_link_lib(CodeGen *g, Buf *name) {
238 if (strcmp(lib, "c") == 0) {237 return add_link_lib(g, name);
239 if (g->link_libc)
240 return;
241 g->link_libc = true;
242 }
243 g->link_libs.append(buf_create_from_str(lib));
244}238}
245239
246void codegen_add_framework(CodeGen *g, const char *framework) {240void codegen_add_framework(CodeGen *g, const char *framework) {
...@@ -334,6 +328,33 @@ static Buf *get_mangled_name(CodeGen *g, Buf *original_name, bool external_linka...@@ -334,6 +328,33 @@ static Buf *get_mangled_name(CodeGen *g, Buf *original_name, bool external_linka
334 }328 }
335}329}
336330
331static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
332 switch (cc) {
333 case CallingConventionUnspecified: return LLVMFastCallConv;
334 case CallingConventionC: return LLVMCCallConv;
335 case CallingConventionCold:
336 // cold calling convention only works on x86.
337 if (g->zig_target.arch.arch == ZigLLVM_x86 ||
338 g->zig_target.arch.arch == ZigLLVM_x86_64)
339 {
340 return LLVMColdCallConv;
341 } else {
342 return LLVMCCallConv;
343 }
344 break;
345 case CallingConventionNaked:
346 zig_unreachable();
347 case CallingConventionStdcall:
348 // stdcall calling convention only works on x86.
349 if (g->zig_target.arch.arch == ZigLLVM_x86) {
350 return LLVMX86StdcallCallConv;
351 } else {
352 return LLVMCCallConv;
353 }
354 }
355 zig_unreachable();
356}
357
337static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {358static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
338 if (fn_table_entry->llvm_value)359 if (fn_table_entry->llvm_value)
339 return fn_table_entry->llvm_value;360 return fn_table_entry->llvm_value;
...@@ -355,6 +376,16 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -355,6 +376,16 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
355 }376 }
356 fn_table_entry->llvm_name = LLVMGetValueName(fn_table_entry->llvm_value);377 fn_table_entry->llvm_name = LLVMGetValueName(fn_table_entry->llvm_value);
357378
379 //if (buf_eql_str(&fn_table_entry->symbol_name, "ExitProcess") ||
380 // buf_eql_str(&fn_table_entry->symbol_name, "GetConsoleMode") ||
381 // buf_eql_str(&fn_table_entry->symbol_name, "GetStdHandle") ||
382 // buf_eql_str(&fn_table_entry->symbol_name, "GetFileInformationByHandleEx") ||
383 // buf_eql_str(&fn_table_entry->symbol_name, "GetLastError") ||
384 // buf_eql_str(&fn_table_entry->symbol_name, "WriteFile"))
385 //{
386 // LLVMSetDLLStorageClass(fn_table_entry->llvm_value, LLVMDLLImportStorageClass);
387 //}
388
358 switch (fn_table_entry->fn_inline) {389 switch (fn_table_entry->fn_inline) {
359 case FnInlineAlways:390 case FnInlineAlways:
360 addLLVMFnAttr(fn_table_entry->llvm_value, "alwaysinline");391 addLLVMFnAttr(fn_table_entry->llvm_value, "alwaysinline");
...@@ -366,8 +397,14 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -366,8 +397,14 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
366 case FnInlineAuto:397 case FnInlineAuto:
367 break;398 break;
368 }399 }
369 if (fn_type->data.fn.fn_type_id.is_naked) {400
401 if (fn_type->data.fn.fn_type_id.cc == CallingConventionNaked) {
370 addLLVMFnAttr(fn_table_entry->llvm_value, "naked");402 addLLVMFnAttr(fn_table_entry->llvm_value, "naked");
403 } else {
404 LLVMSetFunctionCallConv(fn_table_entry->llvm_value, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc));
405 if (fn_type->data.fn.fn_type_id.cc == CallingConventionCold) {
406 ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value);
407 }
371 }408 }
372409
373 switch (fn_table_entry->linkage) {410 switch (fn_table_entry->linkage) {
...@@ -393,17 +430,13 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -393,17 +430,13 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
393 if (fn_table_entry->body_node != nullptr) {430 if (fn_table_entry->body_node != nullptr) {
394 bool want_fn_safety = g->build_mode != BuildModeFastRelease && !fn_table_entry->def_scope->safety_off;431 bool want_fn_safety = g->build_mode != BuildModeFastRelease && !fn_table_entry->def_scope->safety_off;
395 if (want_fn_safety) {432 if (want_fn_safety) {
396 if (g->link_libc) {433 if (g->libc_link_lib != nullptr) {
397 addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong");434 addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong");
398 addLLVMFnAttrStr(fn_table_entry->llvm_value, "stack-protector-buffer-size", "4");435 addLLVMFnAttrStr(fn_table_entry->llvm_value, "stack-protector-buffer-size", "4");
399 }436 }
400 }437 }
401 }438 }
402439
403 LLVMSetFunctionCallConv(fn_table_entry->llvm_value, fn_type->data.fn.calling_convention);
404 if (fn_type->data.fn.fn_type_id.is_cold) {
405 ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value);
406 }
407 addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind");440 addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind");
408 if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) {441 if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) {
409 ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");442 ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");
...@@ -700,7 +733,8 @@ static void gen_panic_raw(CodeGen *g, LLVMValueRef msg_ptr, LLVMValueRef msg_len...@@ -700,7 +733,8 @@ static void gen_panic_raw(CodeGen *g, LLVMValueRef msg_ptr, LLVMValueRef msg_len
700 FnTableEntry *panic_fn = get_extern_panic_fn(g);733 FnTableEntry *panic_fn = get_extern_panic_fn(g);
701 LLVMValueRef fn_val = fn_llvm_value(g, panic_fn);734 LLVMValueRef fn_val = fn_llvm_value(g, panic_fn);
702 LLVMValueRef args[] = { msg_ptr, msg_len };735 LLVMValueRef args[] = { msg_ptr, msg_len };
703 ZigLLVMBuildCall(g->builder, fn_val, args, 2, panic_fn->type_entry->data.fn.calling_convention, false, "");736 LLVMCallConv llvm_cc = get_llvm_cc(g, panic_fn->type_entry->data.fn.fn_type_id.cc);
737 ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, false, "");
704 LLVMBuildUnreachable(g->builder);738 LLVMBuildUnreachable(g->builder);
705}739}
706740
...@@ -1100,15 +1134,14 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {...@@ -1100,15 +1134,14 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
1100static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {1134static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
1101 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);1135 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
1102 TypeTableEntry *return_type = return_instruction->value->value.type;1136 TypeTableEntry *return_type = return_instruction->value->value.type;
1103 bool is_extern = g->cur_fn->type_entry->data.fn.fn_type_id.is_extern;
1104 if (handle_is_ptr(return_type)) {1137 if (handle_is_ptr(return_type)) {
1105 if (is_extern) {1138 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
1106 LLVMValueRef by_val_value = LLVMBuildLoad(g->builder, value, "");
1107 LLVMBuildRet(g->builder, by_val_value);
1108 } else {
1109 assert(g->cur_ret_ptr);1139 assert(g->cur_ret_ptr);
1110 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);1140 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
1111 LLVMBuildRetVoid(g->builder);1141 LLVMBuildRetVoid(g->builder);
1142 } else {
1143 LLVMValueRef by_val_value = LLVMBuildLoad(g->builder, value, "");
1144 LLVMBuildRet(g->builder, by_val_value);
1112 }1145 }
1113 } else {1146 } else {
1114 LLVMBuildRet(g->builder, value);1147 LLVMBuildRet(g->builder, value);
...@@ -2059,9 +2092,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -2059,9 +2092,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
2059 bool want_always_inline = (instruction->fn_entry != nullptr &&2092 bool want_always_inline = (instruction->fn_entry != nullptr &&
2060 instruction->fn_entry->fn_inline == FnInlineAlways) || instruction->is_inline;2093 instruction->fn_entry->fn_inline == FnInlineAlways) || instruction->is_inline;
20612094
2095 LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
2062 LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,2096 LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,
2063 gen_param_values, (unsigned)gen_param_index, fn_type->data.fn.calling_convention,2097 gen_param_values, (unsigned)gen_param_index, llvm_cc, want_always_inline, "");
2064 want_always_inline, "");
20652098
2066 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {2099 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
2067 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];2100 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
...@@ -3893,7 +3926,7 @@ static void do_code_gen(CodeGen *g) {...@@ -3893,7 +3926,7 @@ static void do_code_gen(CodeGen *g) {
3893 {3926 {
3894 addLLVMAttr(fn_val, 0, "nonnull");3927 addLLVMAttr(fn_val, 0, "nonnull");
3895 } else if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type) &&3928 } else if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type) &&
3896 !fn_type->data.fn.fn_type_id.is_extern)3929 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
3897 {3930 {
3898 addLLVMArgAttr(fn_val, 0, "sret");3931 addLLVMArgAttr(fn_val, 0, "sret");
3899 addLLVMArgAttr(fn_val, 0, "nonnull");3932 addLLVMArgAttr(fn_val, 0, "nonnull");
...@@ -4648,15 +4681,7 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -4648,15 +4681,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
4648 buf_appendf(contents, "pub const environ = Environ.%s;\n", cur_environ);4681 buf_appendf(contents, "pub const environ = Environ.%s;\n", cur_environ);
4649 buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);4682 buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
4650 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));4683 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
46514684 buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr));
4652 {
4653 buf_appendf(contents, "pub const link_libs = [][]const u8 {\n");
4654 for (size_t i = 0; i < g->link_libs.length; i += 1) {
4655 Buf *link_lib_buf = g->link_libs.at(i);
4656 buf_appendf(contents, " \"%s\",\n", buf_ptr(link_lib_buf));
4657 }
4658 buf_appendf(contents, "};\n");
4659 }
46604685
4661 buf_appendf(contents, "pub const __zig_panic_implementation_provided = %s; // overwritten later\n",4686 buf_appendf(contents, "pub const __zig_panic_implementation_provided = %s; // overwritten later\n",
4662 bool_to_str(false));4687 bool_to_str(false));
src/codegen.hpp+1-1
...@@ -33,7 +33,7 @@ void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker);...@@ -33,7 +33,7 @@ void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker);
33void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole);33void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole);
34void codegen_set_windows_unicode(CodeGen *g, bool municode);34void codegen_set_windows_unicode(CodeGen *g, bool municode);
35void codegen_add_lib_dir(CodeGen *codegen, const char *dir);35void codegen_add_lib_dir(CodeGen *codegen, const char *dir);
36void codegen_add_link_lib(CodeGen *codegen, const char *lib);36LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);
37void codegen_add_framework(CodeGen *codegen, const char *name);37void codegen_add_framework(CodeGen *codegen, const char *name);
38void codegen_add_rpath(CodeGen *codegen, const char *name);38void codegen_add_rpath(CodeGen *codegen, const char *name);
39void codegen_set_mlinker_version(CodeGen *g, Buf *darwin_linker_version);39void codegen_set_mlinker_version(CodeGen *g, Buf *darwin_linker_version);
src/ir.cpp+22-4
...@@ -9044,7 +9044,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -9044,7 +9044,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
90449044
9045 if (comptime_fn_call) {9045 if (comptime_fn_call) {
9046 // No special handling is needed for compile time evaluation of generic functions.9046 // No special handling is needed for compile time evaluation of generic functions.
9047 if (!fn_entry || fn_entry->type_entry->data.fn.fn_type_id.is_extern) {9047 if (!fn_entry || fn_entry->body_node == nullptr) {
9048 ir_add_error(ira, fn_ref, buf_sprintf("unable to evaluate constant expression"));9048 ir_add_error(ira, fn_ref, buf_sprintf("unable to evaluate constant expression"));
9049 return ira->codegen->builtin_types.entry_invalid;9049 return ira->codegen->builtin_types.entry_invalid;
9050 }9050 }
...@@ -10129,6 +10129,10 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source...@@ -10129,6 +10129,10 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
10129 {10129 {
10130 TldVar *tld_var = (TldVar *)tld;10130 TldVar *tld_var = (TldVar *)tld;
10131 VariableTableEntry *var = tld_var->var;10131 VariableTableEntry *var = tld_var->var;
10132 if (tld_var->extern_lib_name != nullptr) {
10133 add_link_lib_symbol(ira->codegen, tld_var->extern_lib_name, &var->name);
10134 }
10135
10132 return ir_analyze_var_ptr(ira, source_instruction, var, false, false);10136 return ir_analyze_var_ptr(ira, source_instruction, var, false, false);
10133 }10137 }
10134 case TldIdFn:10138 case TldIdFn:
...@@ -10147,6 +10151,10 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source...@@ -10147,6 +10151,10 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
10147 const_val->type = fn_entry->type_entry;10151 const_val->type = fn_entry->type_entry;
10148 const_val->data.x_fn.fn_entry = fn_entry;10152 const_val->data.x_fn.fn_entry = fn_entry;
1014910153
10154 if (tld_fn->extern_lib_name != nullptr) {
10155 add_link_lib_symbol(ira->codegen, tld_fn->extern_lib_name, &fn_entry->symbol_name);
10156 }
10157
10150 bool ptr_is_const = true;10158 bool ptr_is_const = true;
10151 bool ptr_is_volatile = false;10159 bool ptr_is_volatile = false;
10152 return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry,10160 return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry,
...@@ -13167,13 +13175,15 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc...@@ -13167,13 +13175,15 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
1316713175
13168 bool param_is_var_args = param_node->data.param_decl.is_var_args;13176 bool param_is_var_args = param_node->data.param_decl.is_var_args;
13169 if (param_is_var_args) {13177 if (param_is_var_args) {
13170 if (fn_type_id.is_extern) {13178 if (fn_type_id.cc == CallingConventionC) {
13171 fn_type_id.param_count = fn_type_id.next_param_index;13179 fn_type_id.param_count = fn_type_id.next_param_index;
13172 continue;13180 continue;
13173 } else {13181 } else if (fn_type_id.cc == CallingConventionUnspecified) {
13174 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);13182 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
13175 out_val->data.x_type = get_generic_fn_type(ira->codegen, &fn_type_id);13183 out_val->data.x_type = get_generic_fn_type(ira->codegen, &fn_type_id);
13176 return ira->codegen->builtin_types.entry_type;13184 return ira->codegen->builtin_types.entry_type;
13185 } else {
13186 zig_unreachable();
13177 }13187 }
13178 }13188 }
13179 IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->other;13189 IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->other;
...@@ -13484,6 +13494,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,...@@ -13484,6 +13494,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
13484 if (type_is_invalid(var_ptr->value.type))13494 if (type_is_invalid(var_ptr->value.type))
13485 return ira->codegen->builtin_types.entry_invalid;13495 return ira->codegen->builtin_types.entry_invalid;
1348613496
13497 if (tld_var->extern_lib_name != nullptr) {
13498 add_link_lib_symbol(ira->codegen, tld_var->extern_lib_name, &var->name);
13499 }
13500
13487 if (lval.is_ptr) {13501 if (lval.is_ptr) {
13488 ir_link_new_instruction(var_ptr, &instruction->base);13502 ir_link_new_instruction(var_ptr, &instruction->base);
13489 return var_ptr->value.type;13503 return var_ptr->value.type;
...@@ -13499,6 +13513,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,...@@ -13499,6 +13513,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
13499 FnTableEntry *fn_entry = tld_fn->fn_entry;13513 FnTableEntry *fn_entry = tld_fn->fn_entry;
13500 assert(fn_entry->type_entry);13514 assert(fn_entry->type_entry);
1350113515
13516 if (tld_fn->extern_lib_name != nullptr) {
13517 add_link_lib_symbol(ira->codegen, tld_fn->extern_lib_name, &fn_entry->symbol_name);
13518 }
13519
13502 IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope,13520 IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope,
13503 instruction->base.source_node, fn_entry);13521 instruction->base.source_node, fn_entry);
13504 if (lval.is_ptr) {13522 if (lval.is_ptr) {
...@@ -13896,7 +13914,7 @@ FnTableEntry *ir_create_inline_fn(CodeGen *codegen, Buf *fn_name, VariableTableE...@@ -13896,7 +13914,7 @@ FnTableEntry *ir_create_inline_fn(CodeGen *codegen, Buf *fn_name, VariableTableE
13896 assert(src_fn_type->id == TypeTableEntryIdFn);13914 assert(src_fn_type->id == TypeTableEntryIdFn);
1389713915
13898 FnTypeId new_fn_type = src_fn_type->data.fn.fn_type_id;13916 FnTypeId new_fn_type = src_fn_type->data.fn.fn_type_id;
13899 new_fn_type.is_extern = false;13917 new_fn_type.cc = CallingConventionUnspecified;
1390013918
13901 fn_entry->type_entry = get_fn_type(codegen, &new_fn_type);13919 fn_entry->type_entry = get_fn_type(codegen, &new_fn_type);
1390213920
src/link.cpp+46-34
...@@ -38,12 +38,6 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) {...@@ -38,12 +38,6 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) {
3838
39 ZigTarget *child_target = parent_gen->is_native_target ? nullptr : &parent_gen->zig_target;39 ZigTarget *child_target = parent_gen->is_native_target ? nullptr : &parent_gen->zig_target;
40 CodeGen *child_gen = codegen_create(full_path, child_target, OutTypeObj, parent_gen->build_mode);40 CodeGen *child_gen = codegen_create(full_path, child_target, OutTypeObj, parent_gen->build_mode);
41 child_gen->link_libc = parent_gen->link_libc;
42
43 child_gen->link_libs.resize(parent_gen->link_libs.length);
44 for (size_t i = 0; i < parent_gen->link_libs.length; i += 1) {
45 child_gen->link_libs.items[i] = parent_gen->link_libs.items[i];
46 }
4741
48 codegen_set_omit_zigrt(child_gen, true);42 codegen_set_omit_zigrt(child_gen, true);
49 child_gen->want_h_file = false;43 child_gen->want_h_file = false;
...@@ -215,13 +209,13 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -215,13 +209,13 @@ static void construct_linker_job_elf(LinkJob *lj) {
215 if (g->each_lib_rpath) {209 if (g->each_lib_rpath) {
216 for (size_t i = 0; i < g->lib_dirs.length; i += 1) {210 for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
217 const char *lib_dir = g->lib_dirs.at(i);211 const char *lib_dir = g->lib_dirs.at(i);
218 for (size_t i = 0; i < g->link_libs.length; i += 1) {212 for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
219 Buf *link_lib = g->link_libs.at(i);213 LinkLib *link_lib = g->link_libs_list.at(i);
220 if (buf_eql_str(link_lib, "c")) {214 if (buf_eql_str(link_lib->name, "c")) {
221 continue;215 continue;
222 }216 }
223 bool does_exist;217 bool does_exist;
224 Buf *test_path = buf_sprintf("%s/lib%s.so", lib_dir, buf_ptr(link_lib));218 Buf *test_path = buf_sprintf("%s/lib%s.so", lib_dir, buf_ptr(link_lib->name));
225 if (os_file_exists(test_path, &does_exist) != ErrorNone) {219 if (os_file_exists(test_path, &does_exist) != ErrorNone) {
226 zig_panic("link: unable to check if file exists: %s", buf_ptr(test_path));220 zig_panic("link: unable to check if file exists: %s", buf_ptr(test_path));
227 }221 }
...@@ -239,7 +233,7 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -239,7 +233,7 @@ static void construct_linker_job_elf(LinkJob *lj) {
239 lj->args.append(lib_dir);233 lj->args.append(lib_dir);
240 }234 }
241235
242 if (g->link_libc) {236 if (g->libc_link_lib != nullptr) {
243 lj->args.append("-L");237 lj->args.append("-L");
244 lj->args.append(buf_ptr(g->libc_lib_dir));238 lj->args.append(buf_ptr(g->libc_lib_dir));
245239
...@@ -265,7 +259,7 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -265,7 +259,7 @@ static void construct_linker_job_elf(LinkJob *lj) {
265 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));259 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
266 }260 }
267261
268 if (!g->link_libc && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) {262 if (g->libc_link_lib == nullptr && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) {
269 Buf *builtin_o_path = build_o(g, "builtin");263 Buf *builtin_o_path = build_o(g, "builtin");
270 lj->args.append(buf_ptr(builtin_o_path));264 lj->args.append(buf_ptr(builtin_o_path));
271265
...@@ -273,25 +267,25 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -273,25 +267,25 @@ static void construct_linker_job_elf(LinkJob *lj) {
273 lj->args.append(buf_ptr(compiler_rt_o_path));267 lj->args.append(buf_ptr(compiler_rt_o_path));
274 }268 }
275269
276 for (size_t i = 0; i < g->link_libs.length; i += 1) {270 for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
277 Buf *link_lib = g->link_libs.at(i);271 LinkLib *link_lib = g->link_libs_list.at(i);
278 if (buf_eql_str(link_lib, "c")) {272 if (buf_eql_str(link_lib->name, "c")) {
279 continue;273 continue;
280 }274 }
281 Buf *arg;275 Buf *arg;
282 if (buf_starts_with_str(link_lib, "/") || buf_ends_with_str(link_lib, ".a") ||276 if (buf_starts_with_str(link_lib->name, "/") || buf_ends_with_str(link_lib->name, ".a") ||
283 buf_ends_with_str(link_lib, ".so"))277 buf_ends_with_str(link_lib->name, ".so"))
284 {278 {
285 arg = link_lib;279 arg = link_lib->name;
286 } else {280 } else {
287 arg = buf_sprintf("-l%s", buf_ptr(link_lib));281 arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
288 }282 }
289 lj->args.append(buf_ptr(arg));283 lj->args.append(buf_ptr(arg));
290 }284 }
291285
292286
293 // libc dep287 // libc dep
294 if (g->link_libc) {288 if (g->libc_link_lib != nullptr) {
295 if (g->is_static) {289 if (g->is_static) {
296 lj->args.append("--start-group");290 lj->args.append("--start-group");
297 lj->args.append("-lgcc");291 lj->args.append("-lgcc");
...@@ -394,7 +388,7 @@ static void construct_linker_job_coff(LinkJob *lj) {...@@ -394,7 +388,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
394 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", lib_dir)));388 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", lib_dir)));
395 }389 }
396390
397 if (g->link_libc) {391 if (g->libc_link_lib != nullptr) {
398 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));392 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));
399 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));393 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));
400 }394 }
...@@ -403,7 +397,7 @@ static void construct_linker_job_coff(LinkJob *lj) {...@@ -403,7 +397,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
403 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));397 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
404 }398 }
405399
406 if (!g->link_libc && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) {400 if (g->libc_link_lib == nullptr && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) {
407 Buf *builtin_o_path = build_o(g, "builtin");401 Buf *builtin_o_path = build_o(g, "builtin");
408 lj->args.append(buf_ptr(builtin_o_path));402 lj->args.append(buf_ptr(builtin_o_path));
409403
...@@ -411,17 +405,35 @@ static void construct_linker_job_coff(LinkJob *lj) {...@@ -411,17 +405,35 @@ static void construct_linker_job_coff(LinkJob *lj) {
411 lj->args.append(buf_ptr(compiler_rt_o_path));405 lj->args.append(buf_ptr(compiler_rt_o_path));
412 }406 }
413407
414408 Buf *def_contents = buf_alloc();
415 for (size_t i = 0; i < g->link_libs.length; i += 1) {409 for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) {
416 Buf *link_lib = g->link_libs.at(i);410 LinkLib *link_lib = g->link_libs_list.at(lib_i);
417 if (buf_eql_str(link_lib, "c")) {411 if (buf_eql_str(link_lib->name, "c")) {
418 continue;412 continue;
419 }413 }
420 Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib));414 if (link_lib->provided_explicitly) {
421 lj->args.append(buf_ptr(arg));415 Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
416 lj->args.append(buf_ptr(arg));
417 } else {
418 buf_appendf(def_contents, "LIBRARY %s\nEXPORTS\n", buf_ptr(link_lib->name));
419 for (size_t exp_i = 0; exp_i < link_lib->symbols.length; exp_i += 1) {
420 Buf *symbol_name = link_lib->symbols.at(exp_i);
421 buf_appendf(def_contents, "%s\n", buf_ptr(symbol_name));
422 }
423 buf_appendf(def_contents, "\n");
424 }
425 }
426 if (buf_len(def_contents) != 0) {
427 Buf *dll_path = buf_alloc();
428 os_path_join(g->cache_dir, buf_create_from_str("all.dll"), dll_path);
429 ZigLLDDefToLib(def_contents, dll_path);
430
431 Buf *all_lib_path = buf_alloc();
432 os_path_join(g->cache_dir, buf_create_from_str("all.lib"), all_lib_path);
433 lj->args.append(buf_ptr(all_lib_path));
422 }434 }
423435
424 if (g->link_libc) {436 if (g->libc_link_lib != nullptr) {
425 if (g->is_static) {437 if (g->is_static) {
426 lj->args.append("--start-group");438 lj->args.append("--start-group");
427 }439 }
...@@ -664,12 +676,12 @@ static void construct_linker_job_macho(LinkJob *lj) {...@@ -664,12 +676,12 @@ static void construct_linker_job_macho(LinkJob *lj) {
664 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));676 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
665 }677 }
666678
667 for (size_t i = 0; i < g->link_libs.length; i += 1) {679 for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
668 Buf *link_lib = g->link_libs.at(i);680 LinkLib *link_lib = g->link_libs_list.at(i);
669 if (buf_eql_str(link_lib, "c")) {681 if (buf_eql_str(link_lib->name, "c")) {
670 continue;682 continue;
671 }683 }
672 Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib));684 Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
673 lj->args.append(buf_ptr(arg));685 lj->args.append(buf_ptr(arg));
674 }686 }
675687
...@@ -771,7 +783,7 @@ void codegen_link(CodeGen *g, const char *out_file) {...@@ -771,7 +783,7 @@ void codegen_link(CodeGen *g, const char *out_file) {
771 return;783 return;
772 }784 }
773785
774 lj.link_in_crt = (g->link_libc && g->out_type == OutTypeExe);786 lj.link_in_crt = (g->libc_link_lib != nullptr && g->out_type == OutTypeExe);
775787
776 construct_linker_job(&lj);788 construct_linker_job(&lj);
777789
src/main.cpp+2-1
...@@ -601,7 +601,8 @@ int main(int argc, char **argv) {...@@ -601,7 +601,8 @@ int main(int argc, char **argv) {
601 codegen_add_lib_dir(g, lib_dirs.at(i));601 codegen_add_lib_dir(g, lib_dirs.at(i));
602 }602 }
603 for (size_t i = 0; i < link_libs.length; i += 1) {603 for (size_t i = 0; i < link_libs.length; i += 1) {
604 codegen_add_link_lib(g, link_libs.at(i));604 LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i)));
605 link_lib->provided_explicitly = true;
605 }606 }
606 for (size_t i = 0; i < frameworks.length; i += 1) {607 for (size_t i = 0; i < frameworks.length; i += 1) {
607 codegen_add_framework(g, frameworks.at(i));608 codegen_add_framework(g, frameworks.at(i));
src/parseh.cpp+2-3
...@@ -477,8 +477,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const...@@ -477,8 +477,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const
477 }477 }
478478
479 FnTypeId fn_type_id = {0};479 FnTypeId fn_type_id = {0};
480 fn_type_id.is_naked = false;480 fn_type_id.cc = CallingConventionC;
481 fn_type_id.is_extern = true;
482 fn_type_id.is_var_args = fn_proto_ty->isVariadic();481 fn_type_id.is_var_args = fn_proto_ty->isVariadic();
483 fn_type_id.param_count = fn_proto_ty->getNumParams();482 fn_type_id.param_count = fn_proto_ty->getNumParams();
484483
...@@ -619,7 +618,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {...@@ -619,7 +618,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
619 buf_init_from_buf(&fn_entry->symbol_name, fn_name);618 buf_init_from_buf(&fn_entry->symbol_name, fn_name);
620 fn_entry->type_entry = fn_type;619 fn_entry->type_entry = fn_type;
621620
622 assert(!fn_type->data.fn.fn_type_id.is_naked);621 assert(fn_type->data.fn.fn_type_id.cc != CallingConventionNaked);
623622
624 size_t arg_count = fn_type->data.fn.fn_type_id.param_count;623 size_t arg_count = fn_type->data.fn.fn_type_id.param_count;
625 fn_entry->param_names = allocate<Buf *>(arg_count);624 fn_entry->param_names = allocate<Buf *>(arg_count);
src/parser.cpp+20-8
...@@ -2123,25 +2123,29 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand...@@ -2123,25 +2123,29 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
2123}2123}
21242124
2125/*2125/*
2126FnProto = option("coldcc" | "nakedcc") "fn" option(Symbol) ParamDeclList option("->" TypeExpr)2126FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("->" TypeExpr)
2127*/2127*/
2128static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {2128static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
2129 Token *first_token = &pc->tokens->at(*token_index);2129 Token *first_token = &pc->tokens->at(*token_index);
2130 Token *fn_token;2130 Token *fn_token;
21312131
2132 bool is_coldcc = false;2132 CallingConvention cc;
2133 bool is_nakedcc = false;
2134 if (first_token->id == TokenIdKeywordColdCC) {2133 if (first_token->id == TokenIdKeywordColdCC) {
2135 *token_index += 1;2134 *token_index += 1;
2136 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);2135 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
2137 is_coldcc = true;2136 cc = CallingConventionCold;
2138 } else if (first_token->id == TokenIdKeywordNakedCC) {2137 } else if (first_token->id == TokenIdKeywordNakedCC) {
2139 *token_index += 1;2138 *token_index += 1;
2140 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);2139 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
2141 is_nakedcc = true;2140 cc = CallingConventionNaked;
2141 } else if (first_token->id == TokenIdKeywordStdcallCC) {
2142 *token_index += 1;
2143 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
2144 cc = CallingConventionStdcall;
2142 } else if (first_token->id == TokenIdKeywordFn) {2145 } else if (first_token->id == TokenIdKeywordFn) {
2143 fn_token = first_token;2146 fn_token = first_token;
2144 *token_index += 1;2147 *token_index += 1;
2148 cc = CallingConventionUnspecified;
2145 } else if (mandatory) {2149 } else if (mandatory) {
2146 ast_expect_token(pc, first_token, TokenIdKeywordFn);2150 ast_expect_token(pc, first_token, TokenIdKeywordFn);
2147 zig_unreachable();2151 zig_unreachable();
...@@ -2151,8 +2155,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m...@@ -2151,8 +2155,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
21512155
2152 AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);2156 AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);
2153 node->data.fn_proto.visib_mod = visib_mod;2157 node->data.fn_proto.visib_mod = visib_mod;
2154 node->data.fn_proto.is_coldcc = is_coldcc;2158 node->data.fn_proto.cc = cc;
2155 node->data.fn_proto.is_nakedcc = is_nakedcc;
21562159
2157 Token *fn_name = &pc->tokens->at(*token_index);2160 Token *fn_name = &pc->tokens->at(*token_index);
2158 if (fn_name->id == TokenIdSymbol) {2161 if (fn_name->id == TokenIdSymbol) {
...@@ -2220,7 +2223,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool man...@@ -2220,7 +2223,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool man
2220}2223}
22212224
2222/*2225/*
2223ExternDecl = "extern" (FnProto | VariableDeclaration) ";"2226ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
2224*/2227*/
2225static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {2228static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
2226 Token *extern_kw = &pc->tokens->at(*token_index);2229 Token *extern_kw = &pc->tokens->at(*token_index);
...@@ -2233,11 +2236,19 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo...@@ -2233,11 +2236,19 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo
2233 }2236 }
2234 *token_index += 1;2237 *token_index += 1;
22352238
2239 Token *lib_name_tok = &pc->tokens->at(*token_index);
2240 Buf *lib_name = nullptr;
2241 if (lib_name_tok->id == TokenIdStringLiteral) {
2242 lib_name = token_buf(lib_name_tok);
2243 *token_index += 1;
2244 }
2245
2236 AstNode *fn_proto_node = ast_parse_fn_proto(pc, token_index, false, visib_mod);2246 AstNode *fn_proto_node = ast_parse_fn_proto(pc, token_index, false, visib_mod);
2237 if (fn_proto_node) {2247 if (fn_proto_node) {
2238 ast_eat_token(pc, token_index, TokenIdSemicolon);2248 ast_eat_token(pc, token_index, TokenIdSemicolon);
22392249
2240 fn_proto_node->data.fn_proto.is_extern = true;2250 fn_proto_node->data.fn_proto.is_extern = true;
2251 fn_proto_node->data.fn_proto.lib_name = lib_name;
22412252
2242 return fn_proto_node;2253 return fn_proto_node;
2243 }2254 }
...@@ -2247,6 +2258,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo...@@ -2247,6 +2258,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo
2247 ast_eat_token(pc, token_index, TokenIdSemicolon);2258 ast_eat_token(pc, token_index, TokenIdSemicolon);
22482259
2249 var_decl_node->data.variable_declaration.is_extern = true;2260 var_decl_node->data.variable_declaration.is_extern = true;
2261 var_decl_node->data.variable_declaration.lib_name = lib_name;
22502262
2251 return var_decl_node;2263 return var_decl_node;
2252 }2264 }
src/tokenizer.cpp+2
...@@ -133,6 +133,7 @@ static const struct ZigKeyword zig_keywords[] = {...@@ -133,6 +133,7 @@ static const struct ZigKeyword zig_keywords[] = {
133 {"packed", TokenIdKeywordPacked},133 {"packed", TokenIdKeywordPacked},
134 {"pub", TokenIdKeywordPub},134 {"pub", TokenIdKeywordPub},
135 {"return", TokenIdKeywordReturn},135 {"return", TokenIdKeywordReturn},
136 {"stdcallcc", TokenIdKeywordStdcallCC},
136 {"struct", TokenIdKeywordStruct},137 {"struct", TokenIdKeywordStruct},
137 {"switch", TokenIdKeywordSwitch},138 {"switch", TokenIdKeywordSwitch},
138 {"test", TokenIdKeywordTest},139 {"test", TokenIdKeywordTest},
...@@ -1471,6 +1472,7 @@ const char * token_name(TokenId id) {...@@ -1471,6 +1472,7 @@ const char * token_name(TokenId id) {
1471 case TokenIdKeywordPacked: return "packed";1472 case TokenIdKeywordPacked: return "packed";
1472 case TokenIdKeywordPub: return "pub";1473 case TokenIdKeywordPub: return "pub";
1473 case TokenIdKeywordReturn: return "return";1474 case TokenIdKeywordReturn: return "return";
1475 case TokenIdKeywordStdcallCC: return "stdcallcc";
1474 case TokenIdKeywordStruct: return "struct";1476 case TokenIdKeywordStruct: return "struct";
1475 case TokenIdKeywordSwitch: return "switch";1477 case TokenIdKeywordSwitch: return "switch";
1476 case TokenIdKeywordTest: return "test";1478 case TokenIdKeywordTest: return "test";
src/tokenizer.hpp+1
...@@ -71,6 +71,7 @@ enum TokenId {...@@ -71,6 +71,7 @@ enum TokenId {
71 TokenIdKeywordPacked,71 TokenIdKeywordPacked,
72 TokenIdKeywordPub,72 TokenIdKeywordPub,
73 TokenIdKeywordReturn,73 TokenIdKeywordReturn,
74 TokenIdKeywordStdcallCC,
74 TokenIdKeywordStruct,75 TokenIdKeywordStruct,
75 TokenIdKeywordSwitch,76 TokenIdKeywordSwitch,
76 TokenIdKeywordTest,77 TokenIdKeywordTest,
src/zig_llvm.cpp+149
...@@ -38,6 +38,7 @@...@@ -38,6 +38,7 @@
38#include <llvm/Support/FileSystem.h>38#include <llvm/Support/FileSystem.h>
39#include <llvm/Support/TargetParser.h>39#include <llvm/Support/TargetParser.h>
40#include <llvm/Support/raw_ostream.h>40#include <llvm/Support/raw_ostream.h>
41#include <llvm/Support/COFF.h>
41#include <llvm/Target/TargetMachine.h>42#include <llvm/Target/TargetMachine.h>
42#include <llvm/Transforms/IPO.h>43#include <llvm/Transforms/IPO.h>
43#include <llvm/Transforms/IPO/PassManagerBuilder.h>44#include <llvm/Transforms/IPO/PassManagerBuilder.h>
...@@ -791,3 +792,151 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_...@@ -791,3 +792,151 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_
791 }792 }
792 zig_unreachable();793 zig_unreachable();
793}794}
795
796// workaround for LLD not exposing ability to convert .def to .lib
797
798#include <set>
799
800namespace lld {
801namespace coff {
802
803class SymbolBody;
804class StringChunk;
805struct Symbol;
806
807struct Export {
808 StringRef Name; // N in /export:N or /export:E=N
809 StringRef ExtName; // E in /export:E=N
810 SymbolBody *Sym = nullptr;
811 uint16_t Ordinal = 0;
812 bool Noname = false;
813 bool Data = false;
814 bool Private = false;
815
816 // If an export is a form of /export:foo=dllname.bar, that means
817 // that foo should be exported as an alias to bar in the DLL.
818 // ForwardTo is set to "dllname.bar" part. Usually empty.
819 StringRef ForwardTo;
820 StringChunk *ForwardChunk = nullptr;
821
822 // True if this /export option was in .drectves section.
823 bool Directives = false;
824 StringRef SymbolName;
825 StringRef ExportName; // Name in DLL
826
827 bool operator==(const Export &E) {
828 return (Name == E.Name && ExtName == E.ExtName &&
829 Ordinal == E.Ordinal && Noname == E.Noname &&
830 Data == E.Data && Private == E.Private);
831 }
832};
833
834enum class DebugType {
835 None = 0x0,
836 CV = 0x1, /// CodeView
837 PData = 0x2, /// Procedure Data
838 Fixup = 0x4, /// Relocation Table
839};
840
841struct Configuration {
842 enum ManifestKind { SideBySide, Embed, No };
843 llvm::COFF::MachineTypes Machine = llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
844 bool Verbose = false;
845 llvm::COFF::WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
846 SymbolBody *Entry = nullptr;
847 bool NoEntry = false;
848 std::string OutputFile;
849 bool DoGC = true;
850 bool DoICF = true;
851 bool Relocatable = true;
852 bool Force = false;
853 bool Debug = false;
854 bool WriteSymtab = true;
855 unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
856 StringRef PDBPath;
857
858 // Symbols in this set are considered as live by the garbage collector.
859 std::set<SymbolBody *> GCRoot;
860
861 std::set<StringRef> NoDefaultLibs;
862 bool NoDefaultLibAll = false;
863
864 // True if we are creating a DLL.
865 bool DLL = false;
866 StringRef Implib;
867 std::vector<Export> Exports;
868 std::set<std::string> DelayLoads;
869 std::map<std::string, int> DLLOrder;
870 SymbolBody *DelayLoadHelper = nullptr;
871
872 // Used for SafeSEH.
873 Symbol *SEHTable = nullptr;
874 Symbol *SEHCount = nullptr;
875
876 // Used for /opt:lldlto=N
877 unsigned LTOOptLevel = 2;
878
879 // Used for /opt:lldltojobs=N
880 unsigned LTOJobs = 1;
881
882 // Used for /merge:from=to (e.g. /merge:.rdata=.text)
883 std::map<StringRef, StringRef> Merge;
884
885 // Used for /section=.name,{DEKPRSW} to set section attributes.
886 std::map<StringRef, uint32_t> Section;
887
888 // Options for manifest files.
889 ManifestKind Manifest = SideBySide;
890 int ManifestID = 1;
891 StringRef ManifestDependency;
892 bool ManifestUAC = true;
893 std::vector<std::string> ManifestInput;
894 StringRef ManifestLevel = "'asInvoker'";
895 StringRef ManifestUIAccess = "'false'";
896 StringRef ManifestFile;
897
898 // Used for /failifmismatch.
899 std::map<StringRef, StringRef> MustMatch;
900
901 // Used for /alternatename.
902 std::map<StringRef, StringRef> AlternateNames;
903
904 uint64_t ImageBase = -1;
905 uint64_t StackReserve = 1024 * 1024;
906 uint64_t StackCommit = 4096;
907 uint64_t HeapReserve = 1024 * 1024;
908 uint64_t HeapCommit = 4096;
909 uint32_t MajorImageVersion = 0;
910 uint32_t MinorImageVersion = 0;
911 uint32_t MajorOSVersion = 6;
912 uint32_t MinorOSVersion = 0;
913 bool DynamicBase = true;
914 bool AllowBind = true;
915 bool NxCompat = true;
916 bool AllowIsolation = true;
917 bool TerminalServerAware = true;
918 bool LargeAddressAware = false;
919 bool HighEntropyVA = false;
920
921 // This is for debugging.
922 bool DebugPdb = false;
923 bool DumpPdb = false;
924};
925
926extern Configuration *Config;
927
928void writeImportLibrary();
929void parseModuleDefs(MemoryBufferRef MB);
930
931} // namespace coff
932} // namespace lld
933
934// writes the output to dll_path with .dll replaced with .lib
935void ZigLLDDefToLib(Buf *def_contents, Buf *dll_path) {
936 lld::coff::Config = new lld::coff::Configuration;
937 auto mem_buf = MemoryBuffer::getMemBuffer(buf_ptr(def_contents));
938 MemoryBufferRef mbref(*mem_buf);
939 lld::coff::parseModuleDefs(mbref);
940 lld::coff::Config->OutputFile = buf_ptr(dll_path);
941 lld::coff::writeImportLibrary();
942}
src/zig_llvm.hpp+1
...@@ -359,5 +359,6 @@ void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *su...@@ -359,5 +359,6 @@ void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *su
359 ZigLLVM_VendorType *vendor_type, ZigLLVM_OSType *os_type, ZigLLVM_EnvironmentType *environ_type,359 ZigLLVM_VendorType *vendor_type, ZigLLVM_OSType *os_type, ZigLLVM_EnvironmentType *environ_type,
360 ZigLLVM_ObjectFormatType *oformat);360 ZigLLVM_ObjectFormatType *oformat);
361361
362void ZigLLDDefToLib(Buf *def_contents, Buf *dll_path);
362363
363#endif364#endif
std/c/darwin.zig+2-2
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1pub extern fn getrandom(buf_ptr: &u8, buf_len: usize) -> c_int;1pub extern "c" fn getrandom(buf_ptr: &u8, buf_len: usize) -> c_int;
2fn extern "c" __error() -> &c_int;
23
3extern fn __error() -> &c_int;
4pub const _errno = __error;4pub const _errno = __error;
std/c/index.zig+1-2
...@@ -9,7 +9,6 @@ pub use switch(builtin.os) {...@@ -9,7 +9,6 @@ pub use switch(builtin.os) {
9 else => empty_import,9 else => empty_import,
10};10};
1111
12pub extern fn abort() -> noreturn;12pub extern "c" fn abort() -> noreturn;
13
1413
15const empty_import = @import("../empty.zig");14const empty_import = @import("../empty.zig");
std/c/linux.zig+2-3
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1pub extern fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) -> c_int;1pub extern "c" fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) -> c_int;
22extern "c" fn __errno_location() -> &c_int;
3extern fn __errno_location() -> &c_int;
4pub const _errno = __errno_location;3pub const _errno = __errno_location;
std/c/windows.zig+1-1
...@@ -1 +1 @@...@@ -1 +1 @@
1pub extern fn _errno() -> &c_int;1pub extern "c" fn _errno() -> &c_int;
std/debug.zig+3-1
...@@ -16,7 +16,9 @@ pub fn assert(ok: bool) {...@@ -16,7 +16,9 @@ pub fn assert(ok: bool) {
1616
17var panicking = false;17var panicking = false;
18/// This is the default panic implementation.18/// This is the default panic implementation.
19pub coldcc fn panic(comptime format: []const u8, args: ...) -> noreturn {19pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
20 // TODO an intrinsic that labels this as unlikely to be reached
21
20 // TODO22 // TODO
21 // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }23 // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }
22 if (panicking) {24 if (panicking) {
std/index.zig-2
...@@ -22,7 +22,6 @@ pub const net = @import("net.zig");...@@ -22,7 +22,6 @@ pub const net = @import("net.zig");
22pub const os = @import("os/index.zig");22pub const os = @import("os/index.zig");
23pub const rand = @import("rand.zig");23pub const rand = @import("rand.zig");
24pub const sort = @import("sort.zig");24pub const sort = @import("sort.zig");
25pub const target = @import("target.zig");
2625
27test "std" {26test "std" {
28 // run tests from these27 // run tests from these
...@@ -50,5 +49,4 @@ test "std" {...@@ -50,5 +49,4 @@ test "std" {
50 _ = @import("os/index.zig");49 _ = @import("os/index.zig");
51 _ = @import("rand.zig");50 _ = @import("rand.zig");
52 _ = @import("sort.zig");51 _ = @import("sort.zig");
53 _ = @import("target.zig");
54}52}
std/os/index.zig+3-4
...@@ -24,7 +24,6 @@ const debug = @import("../debug.zig");...@@ -24,7 +24,6 @@ const debug = @import("../debug.zig");
24const assert = debug.assert;24const assert = debug.assert;
2525
26const errno = @import("errno.zig");26const errno = @import("errno.zig");
27const linking_libc = @import("../target.zig").linking_libc;
28const c = @import("../c/index.zig");27const c = @import("../c/index.zig");
2928
30const mem = @import("../mem.zig");29const mem = @import("../mem.zig");
...@@ -60,14 +59,14 @@ pub fn getRandomBytes(buf: []u8) -> %void {...@@ -60,14 +59,14 @@ pub fn getRandomBytes(buf: []u8) -> %void {
60 while (true) {59 while (true) {
61 const err = switch (builtin.os) {60 const err = switch (builtin.os) {
62 Os.linux => {61 Os.linux => {
63 if (linking_libc) {62 if (builtin.link_libc) {
64 if (c.getrandom(buf.ptr, buf.len, 0) == -1) *c._errno() else 063 if (c.getrandom(buf.ptr, buf.len, 0) == -1) *c._errno() else 0
65 } else {64 } else {
66 posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0))65 posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0))
67 }66 }
68 },67 },
69 Os.darwin, Os.macosx, Os.ios => {68 Os.darwin, Os.macosx, Os.ios => {
70 if (linking_libc) {69 if (builtin.link_libc) {
71 if (posix.getrandom(buf.ptr, buf.len) == -1) *c._errno() else 070 if (posix.getrandom(buf.ptr, buf.len) == -1) *c._errno() else 0
72 } else {71 } else {
73 posix.getErrno(posix.getrandom(buf.ptr, buf.len))72 posix.getErrno(posix.getrandom(buf.ptr, buf.len))
...@@ -103,7 +102,7 @@ pub fn getRandomBytes(buf: []u8) -> %void {...@@ -103,7 +102,7 @@ pub fn getRandomBytes(buf: []u8) -> %void {
103/// If linking against libc, this calls the abort() libc function. Otherwise102/// If linking against libc, this calls the abort() libc function. Otherwise
104/// it uses the zig standard library implementation.103/// it uses the zig standard library implementation.
105pub coldcc fn abort() -> noreturn {104pub coldcc fn abort() -> noreturn {
106 if (linking_libc) {105 if (builtin.link_libc) {
107 c.abort();106 c.abort();
108 }107 }
109 switch (builtin.os) {108 switch (builtin.os) {
std/os/windows/index.zig+26-14
...@@ -1,39 +1,50 @@...@@ -1,39 +1,50 @@
1pub const ERROR = @import("error.zig");1pub const ERROR = @import("error.zig");
22
3pub extern fn CryptAcquireContext(phProv: &HCRYPTPROV, pszContainer: LPCTSTR,3pub extern "kernel32" stdcallcc fn CryptAcquireContext(phProv: &HCRYPTPROV, pszContainer: LPCTSTR,
4 pszProvider: LPCTSTR, dwProvType: DWORD, dwFlags: DWORD) -> bool;4 pszProvider: LPCTSTR, dwProvType: DWORD, dwFlags: DWORD) -> bool;
55
6pub extern fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> bool;6pub extern "kernel32" stdcallcc fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> bool;
77
8pub extern fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: &BYTE) -> bool;8pub extern "kernel32" stdcallcc fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: &BYTE) -> bool;
99
10pub extern fn ExitProcess(exit_code: UINT) -> noreturn;10pub extern "kernel32" fn ExitProcess(exit_code: UINT) -> noreturn;
1111
12pub extern fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: &DWORD) -> bool;12pub extern "kernel32" stdcallcc fn GetCommandLine() -> LPTSTR;
13
14pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: &DWORD) -> bool;
1315
14/// Retrieves the calling thread's last-error code value. The last-error code is maintained on a per-thread basis.16/// Retrieves the calling thread's last-error code value. The last-error code is maintained on a per-thread basis.
15/// Multiple threads do not overwrite each other's last-error code.17/// Multiple threads do not overwrite each other's last-error code.
16pub extern fn GetLastError() -> DWORD;18pub extern "kernel32" stdcallcc fn GetLastError() -> DWORD;
1719
18/// Retrieves file information for the specified file.20/// Retrieves file information for the specified file.
19pub extern fn GetFileInformationByHandleEx(in_hFile: HANDLE, in_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,21pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(in_hFile: HANDLE,
20 out_lpFileInformation: &c_void, in_dwBufferSize: DWORD) -> bool;22 in_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, out_lpFileInformation: &c_void,
23 in_dwBufferSize: DWORD) -> bool;
2124
22/// Retrieves a handle to the specified standard device (standard input, standard output, or standard error).25/// Retrieves a handle to the specified standard device (standard input, standard output, or standard error).
23pub extern fn GetStdHandle(in_nStdHandle: DWORD) -> ?HANDLE;26pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) -> ?HANDLE;
2427
25/// Reads data from the specified file or input/output (I/O) device. Reads occur at the position specified by the file pointer if supported by the device.28/// Reads data from the specified file or input/output (I/O) device. Reads occur at the position specified by the file pointer if supported by the device.
26/// This function is designed for both synchronous and asynchronous operations. For a similar function designed solely for asynchronous operation, see ReadFileEx.29/// This function is designed for both synchronous and asynchronous operations. For a similar function designed solely for asynchronous operation, see ReadFileEx.
27pub extern fn ReadFile(in_hFile: HANDLE, out_lpBuffer: LPVOID, in_nNumberOfBytesToRead: DWORD,30pub extern "kernel32" stdcallcc fn ReadFile(in_hFile: HANDLE, out_lpBuffer: LPVOID,
28 out_lpNumberOfBytesRead: &DWORD, in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL;31 in_nNumberOfBytesToRead: DWORD, out_lpNumberOfBytesRead: &DWORD,
32 in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL;
2933
30/// Writes data to the specified file or input/output (I/O) device.34/// Writes data to the specified file or input/output (I/O) device.
31/// This function is designed for both synchronous and asynchronous operation. For a similar function designed solely for asynchronous operation, see WriteFileEx.35/// This function is designed for both synchronous and asynchronous operation. For a similar function designed solely for asynchronous operation, see WriteFileEx.
32pub extern fn WriteFile(in_hFile: HANDLE, in_lpBuffer: &const c_void, in_nNumberOfBytesToWrite: DWORD,36pub extern "kernel32" stdcallcc fn WriteFile(in_hFile: HANDLE, in_lpBuffer: &const c_void,
33 out_lpNumberOfBytesWritten: ?&DWORD, in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL;37 in_nNumberOfBytesToWrite: DWORD, out_lpNumberOfBytesWritten: ?&DWORD,
38 in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL;
3439
35pub const PROV_RSA_FULL = 1;40pub const PROV_RSA_FULL = 1;
3641
42pub const UNICODE = false;
43pub const LPTSTR = if (unicode) LPWSTR else LPSTR;
44pub const LPWSTR = &WCHAR;
45pub const LPSTR = &CHAR;
46pub const CHAR = u8;
47
3748
38pub const BOOL = bool;49pub const BOOL = bool;
39pub const BYTE = u8;50pub const BYTE = u8;
...@@ -45,12 +56,13 @@ pub const LPCTSTR = &const TCHAR;...@@ -45,12 +56,13 @@ pub const LPCTSTR = &const TCHAR;
45pub const LPDWORD = &DWORD;56pub const LPDWORD = &DWORD;
46pub const LPVOID = &c_void;57pub const LPVOID = &c_void;
47pub const PVOID = &c_void;58pub const PVOID = &c_void;
48pub const TCHAR = u8; // TODO something about unicode WCHAR vs char59pub const TCHAR = if (UNICODE) WCHAR else u8;
49pub const UINT = c_uint;60pub const UINT = c_uint;
50pub const ULONG_PTR = usize;61pub const ULONG_PTR = usize;
51pub const WCHAR = u16;62pub const WCHAR = u16;
52pub const LPCVOID = &const c_void;63pub const LPCVOID = &const c_void;
5364
65
54/// The standard input device. Initially, this is the console input buffer, CONIN$.66/// The standard input device. Initially, this is the console input buffer, CONIN$.
55pub const STD_INPUT_HANDLE = @maxValue(DWORD) - 10 + 1;67pub const STD_INPUT_HANDLE = @maxValue(DWORD) - 10 + 1;
5668
std/special/bootstrap.zig+17-15
...@@ -5,19 +5,23 @@ const root = @import("@root");...@@ -5,19 +5,23 @@ const root = @import("@root");
5const std = @import("std");5const std = @import("std");
6const builtin = @import("builtin");6const builtin = @import("builtin");
77
8const want_main_symbol = std.target.linking_libc;8const want_main_symbol = builtin.link_libc;
9const want_start_symbol = !want_main_symbol;9const want_start_symbol = !want_main_symbol;
1010
11const posix_exit = std.os.posix.exit;
12
13var argc_ptr: &usize = undefined;11var argc_ptr: &usize = undefined;
1412
13const is_windows = builtin.os == builtin.Os.windows;
14
15export nakedcc fn _start() -> noreturn {15export nakedcc fn _start() -> noreturn {
16 if (!want_start_symbol) {16 if (!want_start_symbol) {
17 @setGlobalLinkage(_start, builtin.GlobalLinkage.Internal);17 @setGlobalLinkage(_start, builtin.GlobalLinkage.Internal);
18 unreachable;18 unreachable;
19 }19 }
2020
21 if (is_windows) {
22 windowsCallMainAndExit()
23 }
24
21 switch (builtin.arch) {25 switch (builtin.arch) {
22 builtin.Arch.x86_64 => {26 builtin.Arch.x86_64 => {
23 argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize));27 argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize));
...@@ -27,23 +31,21 @@ export nakedcc fn _start() -> noreturn {...@@ -27,23 +31,21 @@ export nakedcc fn _start() -> noreturn {
27 },31 },
28 else => @compileError("unsupported arch"),32 else => @compileError("unsupported arch"),
29 }33 }
30 callMainAndExit()34 posixCallMainAndExit()
35}
36
37fn windowsCallMainAndExit() -> noreturn {
38 std.debug.user_main_fn = root.main;
39 root.main() %% std.os.windows.ExitProcess(1);
40 std.os.windows.ExitProcess(0);
31}41}
3242
33fn callMainAndExit() -> noreturn {43fn posixCallMainAndExit() -> noreturn {
34 const argc = *argc_ptr;44 const argc = *argc_ptr;
35 const argv = @ptrCast(&&u8, &argc_ptr[1]);45 const argv = @ptrCast(&&u8, &argc_ptr[1]);
36 const envp = @ptrCast(&?&u8, &argv[argc + 1]);46 const envp = @ptrCast(&?&u8, &argv[argc + 1]);
37 callMain(argc, argv, envp) %% exit(true);47 callMain(argc, argv, envp) %% std.os.posix.exit(1);
38 exit(false);48 std.os.posix.exit(0);
39}
40
41fn exit(failure: bool) -> noreturn {
42 if (builtin.os == builtin.Os.windows) {
43 std.os.windows.ExitProcess(c_uint(failure));
44 } else {
45 posix_exit(i32(failure));
46 }
47}49}
4850
49fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {51fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {
std/target.zig deleted-16
...@@ -1,16 +0,0 @@
1const mem = @import("mem.zig");
2const builtin = @import("builtin");
3
4pub const linking_libc = linkingLibrary("c");
5
6pub fn linkingLibrary(lib_name: []const u8) -> bool {
7 // TODO shouldn't need this if
8 if (builtin.link_libs.len != 0) {
9 for (builtin.link_libs) |link_lib| {
10 if (mem.eql(u8, link_lib, lib_name)) {
11 return true;
12 }
13 }
14 }
15 return false;
16}
test/compile_errors.zig+2-14
...@@ -409,18 +409,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -409,18 +409,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
409 ".tmp_source.zig:2:1: error: redefinition of 'a'",409 ".tmp_source.zig:2:1: error: redefinition of 'a'",
410 ".tmp_source.zig:1:1: note: previous definition is here");410 ".tmp_source.zig:1:1: note: previous definition is here");
411411
412 cases.add("byvalue struct parameter in exported function",
413 \\const A = struct { x : i32, };
414 \\export fn f(a : A) {}
415 , ".tmp_source.zig:2:13: error: byvalue types not yet supported on extern function parameters");
416
417 cases.add("byvalue struct return value in exported function",
418 \\const A = struct { x: i32, };
419 \\export fn f() -> A {
420 \\ A {.x = 1234 }
421 \\}
422 , ".tmp_source.zig:2:18: error: byvalue types not yet supported on extern function return values");
423
424 cases.add("duplicate field in struct value expression",412 cases.add("duplicate field in struct value expression",
425 \\const A = struct {413 \\const A = struct {
426 \\ x : i32,414 \\ x : i32,
...@@ -1070,7 +1058,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1070,7 +1058,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1070 \\export fn foo(comptime x: i32, y: i32) -> i32{1058 \\export fn foo(comptime x: i32, y: i32) -> i32{
1071 \\ x + y1059 \\ x + y
1072 \\}1060 \\}
1073 , ".tmp_source.zig:1:15: error: comptime parameter not allowed in extern function");1061 , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'");
10741062
1075 cases.add("extern function with comptime parameter",1063 cases.add("extern function with comptime parameter",
1076 \\extern fn foo(comptime x: i32, y: i32) -> i32;1064 \\extern fn foo(comptime x: i32, y: i32) -> i32;
...@@ -1078,7 +1066,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1078,7 +1066,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1078 \\ foo(1, 2)1066 \\ foo(1, 2)
1079 \\}1067 \\}
1080 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }1068 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1081 , ".tmp_source.zig:1:15: error: comptime parameter not allowed in extern function");1069 , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'");
10821070
1083 cases.add("convert fixed size array to slice with invalid size",1071 cases.add("convert fixed size array to slice with invalid size",
1084 \\export fn f() {1072 \\export fn f() {