| author | |
| committer | |
| log | 5a4968484b1ff761766180204151e77a701cff68 |
| tree | c98f5386609d3fed67da3a27be0ac9b1ea3402bb |
| parent | 793f031c4ca7fdd230ef262895acf3e454be49dd |
| parent | 6ec9933fd80013104982debab9fbff1463582f19 |
27 files changed, 605 insertions(+), 181 deletions(-)
build.zig+6-6| ... | ... | @@ -10,7 +10,7 @@ const ArrayList = std.ArrayList; |
| 10 | 10 | const Buffer = std.Buffer; |
| 11 | 11 | const io = std.io; |
| 12 | 12 | |
| 13 | pub fn build(b: &Builder) { | |
| 13 | pub fn build(b: &Builder) -> %void { | |
| 14 | 14 | const mode = b.standardReleaseOptions(); |
| 15 | 15 | |
| 16 | 16 | var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); |
| ... | ... | @@ -36,7 +36,7 @@ pub fn build(b: &Builder) { |
| 36 | 36 | const test_step = b.step("test", "Run all the tests"); |
| 37 | 37 | |
| 38 | 38 | // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library |
| 39 | const build_info = b.exec([][]const u8{b.zig_exe, "BUILD_INFO"}); | |
| 39 | const build_info = try b.exec([][]const u8{b.zig_exe, "BUILD_INFO"}); | |
| 40 | 40 | var index: usize = 0; |
| 41 | 41 | const cmake_binary_dir = nextValue(&index, build_info); |
| 42 | 42 | const cxx_compiler = nextValue(&index, build_info); |
| ... | ... | @@ -68,7 +68,7 @@ pub fn build(b: &Builder) { |
| 68 | 68 | dependOnLib(exe, llvm); |
| 69 | 69 | |
| 70 | 70 | if (exe.target.getOs() == builtin.Os.linux) { |
| 71 | const libstdcxx_path_padded = b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"}); | |
| 71 | const libstdcxx_path_padded = try b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"}); | |
| 72 | 72 | const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next(); |
| 73 | 73 | exe.addObjectFile(libstdcxx_path); |
| 74 | 74 | |
| ... | ... | @@ -155,9 +155,9 @@ const LibraryDep = struct { |
| 155 | 155 | }; |
| 156 | 156 | |
| 157 | 157 | fn findLLVM(b: &Builder, llvm_config_exe: []const u8) -> %LibraryDep { |
| 158 | const libs_output = b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"}); | |
| 159 | const includes_output = b.exec([][]const u8{llvm_config_exe, "--includedir"}); | |
| 160 | const libdir_output = b.exec([][]const u8{llvm_config_exe, "--libdir"}); | |
| 158 | const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"}); | |
| 159 | const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"}); | |
| 160 | const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"}); | |
| 161 | 161 | |
| 162 | 162 | var result = LibraryDep { |
| 163 | 163 | .libs = ArrayList([]const u8).init(b.allocator), |
doc/langref.html.in+8| ... | ... | @@ -142,6 +142,7 @@ |
| 142 | 142 | <li><a href="#builtin-TagType">@TagType</a></li> |
| 143 | 143 | <li><a href="#builtin-EnumTagType">@EnumTagType</a></li> |
| 144 | 144 | <li><a href="#builtin-errorName">@errorName</a></li> |
| 145 | <li><a href="#builtin-errorReturnTrace">@errorReturnTrace</a></li> | |
| 145 | 146 | <li><a href="#builtin-fence">@fence</a></li> |
| 146 | 147 | <li><a href="#builtin-fieldParentPtr">@fieldParentPtr</a></li> |
| 147 | 148 | <li><a href="#builtin-frameAddress">@frameAddress</a></li> |
| ... | ... | @@ -4412,6 +4413,13 @@ test.zig:6:2: error: found compile log statement |
| 4412 | 4413 | or all calls have a compile-time known value for <code>err</code>, then no |
| 4413 | 4414 | error name table will be generated. |
| 4414 | 4415 | </p> |
| 4416 | <h3 id="builtin-errorReturnTrace">@errorReturnTrace</h3> | |
| 4417 | <pre><code class="zig">@errorReturnTrace() -&gt; ?&amp;builtin.StackTrace</code></pre> | |
| 4418 | <p> | |
| 4419 | If the binary is built with error return tracing, and this function is invoked in a | |
| 4420 | function that calls a function with an error or error union return type, returns a | |
| 4421 | stack trace object. Otherwise returns `null`. | |
| 4422 | </p> | |
| 4415 | 4423 | <h3 id="builtin-fence">@fence</h3> |
| 4416 | 4424 | <pre><code class="zig">@fence(order: AtomicOrder)</code></pre> |
| 4417 | 4425 | <p> |
example/mix_o_files/build.zig+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | |
| 3 | pub fn build(b: &Builder) { | |
| 3 | pub fn build(b: &Builder) -> %void { | |
| 4 | 4 | const obj = b.addObject("base64", "base64.zig"); |
| 5 | 5 | |
| 6 | 6 | const exe = b.addCExecutable("test"); |
example/shared_library/build.zig+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | |
| 3 | pub fn build(b: &Builder) { | |
| 3 | pub fn build(b: &Builder) -> %void { | |
| 4 | 4 | const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0)); |
| 5 | 5 | |
| 6 | 6 | const exe = b.addCExecutable("test"); |
src/all_types.hpp+13| ... | ... | @@ -1205,6 +1205,7 @@ struct FnTableEntry { |
| 1205 | 1205 | uint32_t alignstack_value; |
| 1206 | 1206 | |
| 1207 | 1207 | ZigList<FnExport> export_list; |
| 1208 | bool calls_errorable_function; | |
| 1208 | 1209 | }; |
| 1209 | 1210 | |
| 1210 | 1211 | uint32_t fn_table_entry_hash(FnTableEntry*); |
| ... | ... | @@ -1273,6 +1274,7 @@ enum BuiltinFnId { |
| 1273 | 1274 | BuiltinFnIdSetAlignStack, |
| 1274 | 1275 | BuiltinFnIdArgType, |
| 1275 | 1276 | BuiltinFnIdExport, |
| 1277 | BuiltinFnIdErrorReturnTrace, | |
| 1276 | 1278 | }; |
| 1277 | 1279 | |
| 1278 | 1280 | struct BuiltinFnEntry { |
| ... | ... | @@ -1498,6 +1500,7 @@ struct CodeGen { |
| 1498 | 1500 | Buf triple_str; |
| 1499 | 1501 | BuildMode build_mode; |
| 1500 | 1502 | bool is_test_build; |
| 1503 | bool have_err_ret_tracing; | |
| 1501 | 1504 | uint32_t target_os_index; |
| 1502 | 1505 | uint32_t target_arch_index; |
| 1503 | 1506 | uint32_t target_environ_index; |
| ... | ... | @@ -1530,6 +1533,7 @@ struct CodeGen { |
| 1530 | 1533 | FnTableEntry *panic_fn; |
| 1531 | 1534 | LLVMValueRef cur_ret_ptr; |
| 1532 | 1535 | LLVMValueRef cur_fn_val; |
| 1536 | LLVMValueRef cur_err_ret_trace_val; | |
| 1533 | 1537 | bool c_want_stdint; |
| 1534 | 1538 | bool c_want_stdbool; |
| 1535 | 1539 | AstNode *root_export_decl; |
| ... | ... | @@ -1572,6 +1576,8 @@ struct CodeGen { |
| 1572 | 1576 | size_t largest_err_name_len; |
| 1573 | 1577 | LLVMValueRef safety_crash_err_fn; |
| 1574 | 1578 | |
| 1579 | LLVMValueRef return_err_fn; | |
| 1580 | ||
| 1575 | 1581 | IrInstruction *invalid_instruction; |
| 1576 | 1582 | ConstExprValue const_void_val; |
| 1577 | 1583 | |
| ... | ... | @@ -1595,6 +1601,8 @@ struct CodeGen { |
| 1595 | 1601 | ZigList<AstNode *> tld_ref_source_node_stack; |
| 1596 | 1602 | |
| 1597 | 1603 | TypeTableEntry *align_amt_type; |
| 1604 | TypeTableEntry *stack_trace_type; | |
| 1605 | TypeTableEntry *ptr_to_stack_trace_type; | |
| 1598 | 1606 | }; |
| 1599 | 1607 | |
| 1600 | 1608 | enum VarLinkage { |
| ... | ... | @@ -1896,6 +1904,7 @@ enum IrInstructionId { |
| 1896 | 1904 | IrInstructionIdSetAlignStack, |
| 1897 | 1905 | IrInstructionIdArgType, |
| 1898 | 1906 | IrInstructionIdExport, |
| 1907 | IrInstructionIdErrorReturnTrace, | |
| 1899 | 1908 | }; |
| 1900 | 1909 | |
| 1901 | 1910 | struct IrInstruction { |
| ... | ... | @@ -2717,6 +2726,10 @@ struct IrInstructionExport { |
| 2717 | 2726 | IrInstruction *target; |
| 2718 | 2727 | }; |
| 2719 | 2728 | |
| 2729 | struct IrInstructionErrorReturnTrace { | |
| 2730 | IrInstruction base; | |
| 2731 | }; | |
| 2732 | ||
| 2720 | 2733 | static const size_t slice_ptr_index = 0; |
| 2721 | 2734 | static const size_t slice_len_index = 1; |
| 2722 | 2735 |
src/analyze.cpp+47-12| ... | ... | @@ -869,6 +869,16 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) { |
| 869 | 869 | zig_unreachable(); |
| 870 | 870 | } |
| 871 | 871 | |
| 872 | TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g) { | |
| 873 | if (g->stack_trace_type == nullptr) { | |
| 874 | ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace"); | |
| 875 | assert(stack_trace_type_val->type->id == TypeTableEntryIdMetaType); | |
| 876 | g->stack_trace_type = stack_trace_type_val->data.x_type; | |
| 877 | g->ptr_to_stack_trace_type = get_pointer_to_type(g, g->stack_trace_type, false); | |
| 878 | } | |
| 879 | return g->ptr_to_stack_trace_type; | |
| 880 | } | |
| 881 | ||
| 872 | 882 | TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 873 | 883 | auto table_entry = g->fn_type_table.maybe_get(fn_type_id); |
| 874 | 884 | if (table_entry) { |
| ... | ... | @@ -915,10 +925,16 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 915 | 925 | if (!skip_debug_info) { |
| 916 | 926 | bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) && |
| 917 | 927 | handle_is_ptr(fn_type_id->return_type); |
| 928 | bool prefix_arg_error_return_trace = g->have_err_ret_tracing && | |
| 929 | (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion || | |
| 930 | fn_type_id->return_type->id == TypeTableEntryIdPureError); | |
| 918 | 931 | // +1 for maybe making the first argument the return value |
| 919 | LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count); | |
| 920 | // +1 because 0 is the return type and +1 for maybe making first arg ret val | |
| 921 | ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(2 + fn_type_id->param_count); | |
| 932 | // +1 for maybe last argument the error return trace | |
| 933 | LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(2 + fn_type_id->param_count); | |
| 934 | // +1 because 0 is the return type and | |
| 935 | // +1 for maybe making first arg ret val and | |
| 936 | // +1 for maybe last argument the error return trace | |
| 937 | ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(3 + fn_type_id->param_count); | |
| 922 | 938 | param_di_types[0] = fn_type_id->return_type->di_type; |
| 923 | 939 | size_t gen_param_index = 0; |
| 924 | 940 | TypeTableEntry *gen_return_type; |
| ... | ... | @@ -936,6 +952,14 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 936 | 952 | } |
| 937 | 953 | fn_type->data.fn.gen_return_type = gen_return_type; |
| 938 | 954 | |
| 955 | if (prefix_arg_error_return_trace) { | |
| 956 | TypeTableEntry *gen_type = get_ptr_to_stack_trace_type(g); | |
| 957 | gen_param_types[gen_param_index] = gen_type->type_ref; | |
| 958 | gen_param_index += 1; | |
| 959 | // after the gen_param_index += 1 because 0 is the return type | |
| 960 | param_di_types[gen_param_index] = gen_type->di_type; | |
| 961 | } | |
| 962 | ||
| 939 | 963 | fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count); |
| 940 | 964 | for (size_t i = 0; i < fn_type_id->param_count; i += 1) { |
| 941 | 965 | FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i]; |
| ... | ... | @@ -1168,6 +1192,9 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1168 | 1192 | } |
| 1169 | 1193 | |
| 1170 | 1194 | TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type); |
| 1195 | if (type_is_invalid(type_entry)) { | |
| 1196 | return g->builtin_types.entry_invalid; | |
| 1197 | } | |
| 1171 | 1198 | if (fn_type_id.cc != CallingConventionUnspecified) { |
| 1172 | 1199 | type_ensure_zero_bits_known(g, type_entry); |
| 1173 | 1200 | if (!type_has_bits(type_entry)) { |
| ... | ... | @@ -2558,7 +2585,7 @@ static bool scope_is_root_decls(Scope *scope) { |
| 2558 | 2585 | |
| 2559 | 2586 | static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, TypeTableEntry *fn_type) { |
| 2560 | 2587 | add_node_error(g, proto_node, |
| 2561 | buf_sprintf("expected 'fn([]const u8) -> unreachable', found '%s'", | |
| 2588 | buf_sprintf("expected 'fn([]const u8, ?&builtin.StackTrace) -> unreachable', found '%s'", | |
| 2562 | 2589 | buf_ptr(&fn_type->name))); |
| 2563 | 2590 | } |
| 2564 | 2591 | |
| ... | ... | @@ -2567,7 +2594,7 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) { |
| 2567 | 2594 | assert(proto_node->type == NodeTypeFnProto); |
| 2568 | 2595 | TypeTableEntry *fn_type = panic_fn->type_entry; |
| 2569 | 2596 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; |
| 2570 | if (fn_type_id->param_count != 1) { | |
| 2597 | if (fn_type_id->param_count != 2) { | |
| 2571 | 2598 | return wrong_panic_prototype(g, proto_node, fn_type); |
| 2572 | 2599 | } |
| 2573 | 2600 | TypeTableEntry *const_u8_ptr = get_pointer_to_type(g, g->builtin_types.entry_u8, true); |
| ... | ... | @@ -2576,6 +2603,11 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) { |
| 2576 | 2603 | return wrong_panic_prototype(g, proto_node, fn_type); |
| 2577 | 2604 | } |
| 2578 | 2605 | |
| 2606 | TypeTableEntry *nullable_ptr_to_stack_trace_type = get_maybe_type(g, get_ptr_to_stack_trace_type(g)); | |
| 2607 | if (fn_type_id->param_info[1].type != nullable_ptr_to_stack_trace_type) { | |
| 2608 | return wrong_panic_prototype(g, proto_node, fn_type); | |
| 2609 | } | |
| 2610 | ||
| 2579 | 2611 | TypeTableEntry *actual_return_type = fn_type_id->return_type; |
| 2580 | 2612 | if (actual_return_type != g->builtin_types.entry_unreachable) { |
| 2581 | 2613 | return wrong_panic_prototype(g, proto_node, fn_type); |
| ... | ... | @@ -2680,13 +2712,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2680 | 2712 | { |
| 2681 | 2713 | if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) { |
| 2682 | 2714 | g->main_fn = fn_table_entry; |
| 2683 | TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); | |
| 2684 | TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; | |
| 2685 | if (actual_return_type != err_void) { | |
| 2686 | add_node_error(g, fn_proto->return_type, | |
| 2687 | buf_sprintf("expected return type of main to be '%%void', instead is '%s'", | |
| 2688 | buf_ptr(&actual_return_type->name))); | |
| 2689 | } | |
| 2690 | 2715 | } else if ((import->package == g->panic_package || g->have_pub_panic) && |
| 2691 | 2716 | buf_eql_str(&fn_table_entry->symbol_name, "panic")) |
| 2692 | 2717 | { |
| ... | ... | @@ -5527,3 +5552,13 @@ bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) { |
| 5527 | 5552 | return a == b; |
| 5528 | 5553 | } |
| 5529 | 5554 | |
| 5555 | ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { | |
| 5556 | Tld *tld = codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str(name)); | |
| 5557 | resolve_top_level_decl(codegen, tld, false, nullptr); | |
| 5558 | assert(tld->id == TldIdVar); | |
| 5559 | TldVar *tld_var = (TldVar *)tld; | |
| 5560 | ConstExprValue *var_value = tld_var->var->value; | |
| 5561 | assert(var_value != nullptr); | |
| 5562 | return var_value; | |
| 5563 | } | |
| 5564 |
src/analyze.hpp+5| ... | ... | @@ -185,4 +185,9 @@ PackageTableEntry *new_anonymous_package(void); |
| 185 | 185 | Buf *const_value_to_buffer(ConstExprValue *const_val); |
| 186 | 186 | void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc); |
| 187 | 187 | |
| 188 | ||
| 189 | ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name); | |
| 190 | TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g); | |
| 191 | ||
| 192 | ||
| 188 | 193 | #endif |
src/codegen.cpp+231-16| ... | ... | @@ -404,6 +404,19 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) { |
| 404 | 404 | zig_unreachable(); |
| 405 | 405 | } |
| 406 | 406 | |
| 407 | static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_entry) { | |
| 408 | if (!g->have_err_ret_tracing) { | |
| 409 | return UINT32_MAX; | |
| 410 | } | |
| 411 | TypeTableEntry *fn_type = fn_table_entry->type_entry; | |
| 412 | TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; | |
| 413 | if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdPureError) { | |
| 414 | return UINT32_MAX; | |
| 415 | } | |
| 416 | bool first_arg_ret = type_has_bits(return_type) && handle_is_ptr(return_type); | |
| 417 | return first_arg_ret ? 1 : 0; | |
| 418 | } | |
| 419 | ||
| 407 | 420 | static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 408 | 421 | if (fn_table_entry->llvm_value) |
| 409 | 422 | return fn_table_entry->llvm_value; |
| ... | ... | @@ -483,7 +496,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 483 | 496 | LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true); |
| 484 | 497 | } |
| 485 | 498 | |
| 486 | if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) { | |
| 499 | TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; | |
| 500 | if (return_type->id == TypeTableEntryIdUnreachable) { | |
| 487 | 501 | addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn"); |
| 488 | 502 | } |
| 489 | 503 | |
| ... | ... | @@ -520,13 +534,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 520 | 534 | // use the ABI alignment, which is fine. |
| 521 | 535 | } |
| 522 | 536 | |
| 523 | if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) { | |
| 537 | if (!type_has_bits(return_type)) { | |
| 524 | 538 | // nothing to do |
| 525 | } else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer || | |
| 526 | fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdFn) | |
| 527 | { | |
| 539 | } else if (return_type->id == TypeTableEntryIdPointer || return_type->id == TypeTableEntryIdFn) { | |
| 528 | 540 | addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); |
| 529 | } else if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type) && | |
| 541 | } else if (handle_is_ptr(return_type) && | |
| 530 | 542 | calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc)) |
| 531 | 543 | { |
| 532 | 544 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); |
| ... | ... | @@ -563,6 +575,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 563 | 575 | } |
| 564 | 576 | } |
| 565 | 577 | |
| 578 | uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); | |
| 579 | if (err_ret_trace_arg_index != UINT32_MAX) { | |
| 580 | addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull"); | |
| 581 | } | |
| 582 | ||
| 566 | 583 | return fn_table_entry->llvm_value; |
| 567 | 584 | } |
| 568 | 585 | |
| ... | ... | @@ -864,16 +881,25 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) { |
| 864 | 881 | return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0)); |
| 865 | 882 | } |
| 866 | 883 | |
| 867 | static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) { | |
| 884 | static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) { | |
| 868 | 885 | assert(g->panic_fn != nullptr); |
| 869 | 886 | LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn); |
| 870 | 887 | LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc); |
| 871 | ZigLLVMBuildCall(g->builder, fn_val, &msg_arg, 1, llvm_cc, ZigLLVM_FnInlineAuto, ""); | |
| 888 | if (stack_trace_arg == nullptr) { | |
| 889 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); | |
| 890 | stack_trace_arg = LLVMConstNull(ptr_to_stack_trace_type->type_ref); | |
| 891 | } | |
| 892 | LLVMValueRef args[] = { | |
| 893 | msg_arg, | |
| 894 | stack_trace_arg, | |
| 895 | }; | |
| 896 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, ""); | |
| 897 | LLVMSetTailCall(call_instruction, true); | |
| 872 | 898 | LLVMBuildUnreachable(g->builder); |
| 873 | 899 | } |
| 874 | 900 | |
| 875 | 901 | static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) { |
| 876 | gen_panic(g, get_panic_msg_ptr_val(g, msg_id)); | |
| 902 | gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr); | |
| 877 | 903 | } |
| 878 | 904 | |
| 879 | 905 | static LLVMValueRef get_memcpy_fn_val(CodeGen *g) { |
| ... | ... | @@ -895,6 +921,87 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) { |
| 895 | 921 | return g->memcpy_fn_val; |
| 896 | 922 | } |
| 897 | 923 | |
| 924 | static LLVMValueRef get_return_err_fn(CodeGen *g) { | |
| 925 | if (g->return_err_fn != nullptr) | |
| 926 | return g->return_err_fn; | |
| 927 | ||
| 928 | assert(g->err_tag_type != nullptr); | |
| 929 | ||
| 930 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); | |
| 931 | ||
| 932 | LLVMTypeRef arg_types[] = { | |
| 933 | // error return trace pointer | |
| 934 | get_ptr_to_stack_trace_type(g)->type_ref, | |
| 935 | // return address | |
| 936 | ptr_u8, | |
| 937 | }; | |
| 938 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); | |
| 939 | ||
| 940 | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false); | |
| 941 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); | |
| 942 | addLLVMFnAttr(fn_val, "cold"); | |
| 943 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); | |
| 944 | LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); | |
| 945 | addLLVMFnAttr(fn_val, "nounwind"); | |
| 946 | add_uwtable_attr(g, fn_val); | |
| 947 | addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); | |
| 948 | addLLVMArgAttr(fn_val, (unsigned)1, "nonnull"); | |
| 949 | if (g->build_mode == BuildModeDebug) { | |
| 950 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); | |
| 951 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr); | |
| 952 | } | |
| 953 | ||
| 954 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); | |
| 955 | LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); | |
| 956 | LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); | |
| 957 | LLVMPositionBuilderAtEnd(g->builder, entry_block); | |
| 958 | ZigLLVMClearCurrentDebugLocation(g->builder); | |
| 959 | ||
| 960 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref; | |
| 961 | ||
| 962 | // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address; | |
| 963 | ||
| 964 | LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0); | |
| 965 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; | |
| 966 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, ""); | |
| 967 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; | |
| 968 | LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)addresses_field_index, ""); | |
| 969 | ||
| 970 | TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; | |
| 971 | size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; | |
| 972 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, ""); | |
| 973 | size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index; | |
| 974 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, ""); | |
| 975 | ||
| 976 | LLVMValueRef len_value = gen_load_untyped(g, len_field_ptr, 0, false, ""); | |
| 977 | LLVMValueRef index_val = gen_load_untyped(g, index_field_ptr, 0, false, ""); | |
| 978 | LLVMValueRef modded_val = LLVMBuildURem(g->builder, index_val, len_value, ""); | |
| 979 | LLVMValueRef address_indices[] = { | |
| 980 | modded_val, | |
| 981 | }; | |
| 982 | ||
| 983 | LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, ""); | |
| 984 | LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, ""); | |
| 985 | ||
| 986 | LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, LLVMGetParam(fn_val, 1), usize_type_ref, ""); | |
| 987 | ||
| 988 | LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, return_address, usize_type_ref, ""); | |
| 989 | gen_store_untyped(g, address_value, address_slot, 0, false); | |
| 990 | ||
| 991 | // stack_trace.index += 1; | |
| 992 | LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), ""); | |
| 993 | gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false); | |
| 994 | ||
| 995 | // return; | |
| 996 | LLVMBuildRetVoid(g->builder); | |
| 997 | ||
| 998 | LLVMPositionBuilderAtEnd(g->builder, prev_block); | |
| 999 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); | |
| 1000 | ||
| 1001 | g->return_err_fn = fn_val; | |
| 1002 | return fn_val; | |
| 1003 | } | |
| 1004 | ||
| 898 | 1005 | static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 899 | 1006 | if (g->safety_crash_err_fn != nullptr) |
| 900 | 1007 | return g->safety_crash_err_fn; |
| ... | ... | @@ -953,7 +1060,11 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 953 | 1060 | LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_array, offset_ptr_indices, 2); |
| 954 | 1061 | |
| 955 | 1062 | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false); |
| 956 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), &g->err_tag_type->type_ref, 1, false); | |
| 1063 | LLVMTypeRef arg_types[] = { | |
| 1064 | g->ptr_to_stack_trace_type->type_ref, | |
| 1065 | g->err_tag_type->type_ref, | |
| 1066 | }; | |
| 1067 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); | |
| 957 | 1068 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); |
| 958 | 1069 | addLLVMFnAttr(fn_val, "noreturn"); |
| 959 | 1070 | addLLVMFnAttr(fn_val, "cold"); |
| ... | ... | @@ -975,7 +1086,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 975 | 1086 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 976 | 1087 | ZigLLVMClearCurrentDebugLocation(g->builder); |
| 977 | 1088 | |
| 978 | LLVMValueRef err_val = LLVMGetParam(fn_val, 0); | |
| 1089 | LLVMValueRef err_val = LLVMGetParam(fn_val, 1); | |
| 979 | 1090 | |
| 980 | 1091 | LLVMValueRef err_table_indices[] = { |
| 981 | 1092 | LLVMConstNull(g->builtin_types.entry_usize->type_ref), |
| ... | ... | @@ -1005,7 +1116,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 1005 | 1116 | LLVMValueRef global_slice_len_field_ptr = LLVMBuildStructGEP(g->builder, global_slice, slice_len_index, ""); |
| 1006 | 1117 | gen_store(g, full_buf_len, global_slice_len_field_ptr, u8_ptr_type); |
| 1007 | 1118 | |
| 1008 | gen_panic(g, global_slice); | |
| 1119 | gen_panic(g, global_slice, LLVMGetParam(fn_val, 0)); | |
| 1009 | 1120 | |
| 1010 | 1121 | LLVMPositionBuilderAtEnd(g->builder, prev_block); |
| 1011 | 1122 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); |
| ... | ... | @@ -1016,8 +1127,18 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 1016 | 1127 | |
| 1017 | 1128 | static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { |
| 1018 | 1129 | LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); |
| 1019 | ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified), | |
| 1130 | LLVMValueRef err_ret_trace_val = g->cur_err_ret_trace_val; | |
| 1131 | if (err_ret_trace_val == nullptr) { | |
| 1132 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); | |
| 1133 | err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref); | |
| 1134 | } | |
| 1135 | LLVMValueRef args[] = { | |
| 1136 | err_ret_trace_val, | |
| 1137 | err_val, | |
| 1138 | }; | |
| 1139 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2, get_llvm_cc(g, CallingConventionUnspecified), | |
| 1020 | 1140 | ZigLLVM_FnInlineAuto, ""); |
| 1141 | LLVMSetTailCall(call_instruction, true); | |
| 1021 | 1142 | LLVMBuildUnreachable(g->builder); |
| 1022 | 1143 | } |
| 1023 | 1144 | |
| ... | ... | @@ -1296,6 +1417,35 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { |
| 1296 | 1417 | static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { |
| 1297 | 1418 | LLVMValueRef value = ir_llvm_value(g, return_instruction->value); |
| 1298 | 1419 | TypeTableEntry *return_type = return_instruction->value->value.type; |
| 1420 | ||
| 1421 | if (g->have_err_ret_tracing) { | |
| 1422 | bool is_err_return = false; | |
| 1423 | if (return_type->id == TypeTableEntryIdErrorUnion) { | |
| 1424 | if (return_instruction->value->value.special == ConstValSpecialStatic) { | |
| 1425 | is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr; | |
| 1426 | } else if (return_instruction->value->value.special == ConstValSpecialRuntime) { | |
| 1427 | is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError; | |
| 1428 | // TODO: emit a branch to check if the return value is an error | |
| 1429 | } | |
| 1430 | } else if (return_type->id == TypeTableEntryIdPureError) { | |
| 1431 | is_err_return = true; | |
| 1432 | } | |
| 1433 | if (is_err_return) { | |
| 1434 | LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnError"); | |
| 1435 | LLVMValueRef block_address = LLVMBlockAddress(g->cur_fn_val, return_block); | |
| 1436 | ||
| 1437 | LLVMValueRef return_err_fn = get_return_err_fn(g); | |
| 1438 | LLVMValueRef args[] = { | |
| 1439 | g->cur_err_ret_trace_val, | |
| 1440 | block_address, | |
| 1441 | }; | |
| 1442 | LLVMBuildBr(g->builder, return_block); | |
| 1443 | LLVMPositionBuilderAtEnd(g->builder, return_block); | |
| 1444 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 2, | |
| 1445 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 1446 | LLVMSetTailCall(call_instruction, true); | |
| 1447 | } | |
| 1448 | } | |
| 1299 | 1449 | if (handle_is_ptr(return_type)) { |
| 1300 | 1450 | if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) { |
| 1301 | 1451 | assert(g->cur_ret_ptr); |
| ... | ... | @@ -2330,7 +2480,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 2330 | 2480 | TypeTableEntry *src_return_type = fn_type_id->return_type; |
| 2331 | 2481 | bool ret_has_bits = type_has_bits(src_return_type); |
| 2332 | 2482 | bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type); |
| 2333 | size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0); | |
| 2483 | bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdPureError); | |
| 2484 | size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0); | |
| 2334 | 2485 | bool is_var_args = fn_type_id->is_var_args; |
| 2335 | 2486 | LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count); |
| 2336 | 2487 | size_t gen_param_index = 0; |
| ... | ... | @@ -2338,6 +2489,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 2338 | 2489 | gen_param_values[gen_param_index] = instruction->tmp_ptr; |
| 2339 | 2490 | gen_param_index += 1; |
| 2340 | 2491 | } |
| 2492 | if (prefix_arg_err_ret_stack) { | |
| 2493 | gen_param_values[gen_param_index] = g->cur_err_ret_trace_val; | |
| 2494 | gen_param_index += 1; | |
| 2495 | } | |
| 2341 | 2496 | for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) { |
| 2342 | 2497 | IrInstruction *param_instruction = instruction->args[call_i]; |
| 2343 | 2498 | TypeTableEntry *param_type = param_instruction->value.type; |
| ... | ... | @@ -2881,6 +3036,16 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I |
| 2881 | 3036 | return target_val; |
| 2882 | 3037 | } |
| 2883 | 3038 | |
| 3039 | static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable, | |
| 3040 | IrInstructionErrorReturnTrace *instruction) | |
| 3041 | { | |
| 3042 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); | |
| 3043 | if (g->cur_err_ret_trace_val == nullptr) { | |
| 3044 | return LLVMConstNull(ptr_to_stack_trace_type->type_ref); | |
| 3045 | } | |
| 3046 | return g->cur_err_ret_trace_val; | |
| 3047 | } | |
| 3048 | ||
| 2884 | 3049 | static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { |
| 2885 | 3050 | switch (atomic_order) { |
| 2886 | 3051 | case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered; |
| ... | ... | @@ -3474,7 +3639,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec |
| 3474 | 3639 | } |
| 3475 | 3640 | |
| 3476 | 3641 | static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) { |
| 3477 | gen_panic(g, ir_llvm_value(g, instruction->msg)); | |
| 3642 | gen_panic(g, ir_llvm_value(g, instruction->msg), nullptr); | |
| 3478 | 3643 | return nullptr; |
| 3479 | 3644 | } |
| 3480 | 3645 | |
| ... | ... | @@ -3654,6 +3819,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3654 | 3819 | return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction); |
| 3655 | 3820 | case IrInstructionIdAlignCast: |
| 3656 | 3821 | return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction); |
| 3822 | case IrInstructionIdErrorReturnTrace: | |
| 3823 | return ir_render_error_return_trace(g, executable, (IrInstructionErrorReturnTrace *)instruction); | |
| 3657 | 3824 | } |
| 3658 | 3825 | zig_unreachable(); |
| 3659 | 3826 | } |
| ... | ... | @@ -4493,7 +4660,8 @@ static void do_code_gen(CodeGen *g) { |
| 4493 | 4660 | LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); |
| 4494 | 4661 | g->cur_fn = fn_table_entry; |
| 4495 | 4662 | g->cur_fn_val = fn; |
| 4496 | if (handle_is_ptr(fn_table_entry->type_entry->data.fn.fn_type_id.return_type)) { | |
| 4663 | TypeTableEntry *return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; | |
| 4664 | if (handle_is_ptr(return_type)) { | |
| 4497 | 4665 | g->cur_ret_ptr = LLVMGetParam(fn, 0); |
| 4498 | 4666 | } else { |
| 4499 | 4667 | g->cur_ret_ptr = nullptr; |
| ... | ... | @@ -4502,6 +4670,42 @@ static void do_code_gen(CodeGen *g) { |
| 4502 | 4670 | build_all_basic_blocks(g, fn_table_entry); |
| 4503 | 4671 | clear_debug_source_node(g); |
| 4504 | 4672 | |
| 4673 | uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); | |
| 4674 | if (err_ret_trace_arg_index != UINT32_MAX) { | |
| 4675 | g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index); | |
| 4676 | } else if (g->have_err_ret_tracing && fn_table_entry->calls_errorable_function) { | |
| 4677 | // TODO call graph analysis to find out what this number needs to be for every function | |
| 4678 | static const size_t stack_trace_ptr_count = 30; | |
| 4679 | ||
| 4680 | TypeTableEntry *usize = g->builtin_types.entry_usize; | |
| 4681 | TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count); | |
| 4682 | LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", | |
| 4683 | get_abi_alignment(g, array_type)); | |
| 4684 | g->cur_err_ret_trace_val = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type)); | |
| 4685 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; | |
| 4686 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, ""); | |
| 4687 | gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false); | |
| 4688 | ||
| 4689 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; | |
| 4690 | LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)addresses_field_index, ""); | |
| 4691 | ||
| 4692 | TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; | |
| 4693 | size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; | |
| 4694 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, ""); | |
| 4695 | LLVMValueRef zero = LLVMConstNull(usize->type_ref); | |
| 4696 | LLVMValueRef indices[] = {zero, zero}; | |
| 4697 | LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val, | |
| 4698 | indices, 2, ""); | |
| 4699 | gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr, | |
| 4700 | get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false)); | |
| 4701 | ||
| 4702 | size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index; | |
| 4703 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, ""); | |
| 4704 | gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); | |
| 4705 | } else { | |
| 4706 | g->cur_err_ret_trace_val = nullptr; | |
| 4707 | } | |
| 4708 | ||
| 4505 | 4709 | // allocate temporary stack data |
| 4506 | 4710 | for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) { |
| 4507 | 4711 | IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i); |
| ... | ... | @@ -5064,6 +5268,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 5064 | 5268 | create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); |
| 5065 | 5269 | create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2); |
| 5066 | 5270 | create_builtin_fn(g, BuiltinFnIdExport, "export", 3); |
| 5271 | create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0); | |
| 5067 | 5272 | } |
| 5068 | 5273 | |
| 5069 | 5274 | static const char *bool_to_str(bool b) { |
| ... | ... | @@ -5088,6 +5293,12 @@ static void define_builtin_compile_vars(CodeGen *g) { |
| 5088 | 5293 | os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path); |
| 5089 | 5294 | Buf *contents = buf_alloc(); |
| 5090 | 5295 | |
| 5296 | buf_append_str(contents, | |
| 5297 | "pub const StackTrace = struct {\n" | |
| 5298 | " index: usize,\n" | |
| 5299 | " instruction_addresses: []usize,\n" | |
| 5300 | "};\n\n"); | |
| 5301 | ||
| 5091 | 5302 | const char *cur_os = nullptr; |
| 5092 | 5303 | { |
| 5093 | 5304 | buf_appendf(contents, "pub const Os = enum {\n"); |
| ... | ... | @@ -5233,6 +5444,7 @@ static void define_builtin_compile_vars(CodeGen *g) { |
| 5233 | 5444 | buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt); |
| 5234 | 5445 | buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode)); |
| 5235 | 5446 | buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr)); |
| 5447 | buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing)); | |
| 5236 | 5448 | |
| 5237 | 5449 | buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n"); |
| 5238 | 5450 | |
| ... | ... | @@ -5251,6 +5463,7 @@ static void define_builtin_compile_vars(CodeGen *g) { |
| 5251 | 5463 | g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); |
| 5252 | 5464 | g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); |
| 5253 | 5465 | g->compile_var_import = add_source_file(g, g->compile_var_package, abs_full_path, contents); |
| 5466 | scan_import(g, g->compile_var_import); | |
| 5254 | 5467 | } |
| 5255 | 5468 | |
| 5256 | 5469 | static void init(CodeGen *g) { |
| ... | ... | @@ -5359,6 +5572,8 @@ static void init(CodeGen *g) { |
| 5359 | 5572 | } |
| 5360 | 5573 | } |
| 5361 | 5574 | |
| 5575 | g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease; | |
| 5576 | ||
| 5362 | 5577 | define_builtin_fns(g); |
| 5363 | 5578 | define_builtin_compile_vars(g); |
| 5364 | 5579 | } |
src/ir.cpp+47-10| ... | ... | @@ -572,6 +572,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArgType *) { |
| 572 | 572 | return IrInstructionIdArgType; |
| 573 | 573 | } |
| 574 | 574 | |
| 575 | static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace *) { | |
| 576 | return IrInstructionIdErrorReturnTrace; | |
| 577 | } | |
| 578 | ||
| 575 | 579 | template<typename T> |
| 576 | 580 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 577 | 581 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -2305,6 +2309,12 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s |
| 2305 | 2309 | return &instruction->base; |
| 2306 | 2310 | } |
| 2307 | 2311 | |
| 2312 | static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node) { | |
| 2313 | IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node); | |
| 2314 | ||
| 2315 | return &instruction->base; | |
| 2316 | } | |
| 2317 | ||
| 2308 | 2318 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2309 | 2319 | results[ReturnKindUnconditional] = 0; |
| 2310 | 2320 | results[ReturnKindError] = 0; |
| ... | ... | @@ -3731,6 +3741,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 3731 | 3741 | |
| 3732 | 3742 | return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value); |
| 3733 | 3743 | } |
| 3744 | case BuiltinFnIdErrorReturnTrace: | |
| 3745 | { | |
| 3746 | return ir_build_error_return_trace(irb, scope, node); | |
| 3747 | } | |
| 3734 | 3748 | } |
| 3735 | 3749 | zig_unreachable(); |
| 3736 | 3750 | } |
| ... | ... | @@ -8230,16 +8244,6 @@ static bool ir_resolve_comptime(IrAnalyze *ira, IrInstruction *value, bool *out) |
| 8230 | 8244 | return ir_resolve_bool(ira, value, out); |
| 8231 | 8245 | } |
| 8232 | 8246 | |
| 8233 | static ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { | |
| 8234 | Tld *tld = codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str(name)); | |
| 8235 | resolve_top_level_decl(codegen, tld, false, nullptr); | |
| 8236 | assert(tld->id == TldIdVar); | |
| 8237 | TldVar *tld_var = (TldVar *)tld; | |
| 8238 | ConstExprValue *var_value = tld_var->var->value; | |
| 8239 | assert(var_value != nullptr); | |
| 8240 | return var_value; | |
| 8241 | } | |
| 8242 | ||
| 8243 | 8247 | static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) { |
| 8244 | 8248 | if (type_is_invalid(value->value.type)) |
| 8245 | 8249 | return false; |
| ... | ... | @@ -9578,6 +9582,24 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi |
| 9578 | 9582 | return ira->codegen->builtin_types.entry_void; |
| 9579 | 9583 | } |
| 9580 | 9584 | |
| 9585 | static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, | |
| 9586 | IrInstructionErrorReturnTrace *instruction) | |
| 9587 | { | |
| 9588 | FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); | |
| 9589 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen); | |
| 9590 | TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type); | |
| 9591 | if (fn_entry == nullptr || !fn_entry->calls_errorable_function || !ira->codegen->have_err_ret_tracing) { | |
| 9592 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 9593 | out_val->data.x_maybe = nullptr; | |
| 9594 | return nullable_type; | |
| 9595 | } | |
| 9596 | ||
| 9597 | IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope, | |
| 9598 | instruction->base.source_node); | |
| 9599 | ir_link_new_instruction(new_instruction, &instruction->base); | |
| 9600 | return nullable_type; | |
| 9601 | } | |
| 9602 | ||
| 9581 | 9603 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, |
| 9582 | 9604 | IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i) |
| 9583 | 9605 | { |
| ... | ... | @@ -10053,9 +10075,21 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 10053 | 10075 | TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; |
| 10054 | 10076 | ir_add_alloca(ira, new_call_instruction, return_type); |
| 10055 | 10077 | |
| 10078 | if (return_type->id == TypeTableEntryIdPureError || return_type->id == TypeTableEntryIdErrorUnion) { | |
| 10079 | parent_fn_entry->calls_errorable_function = true; | |
| 10080 | } | |
| 10081 | ||
| 10056 | 10082 | return ir_finish_anal(ira, return_type); |
| 10057 | 10083 | } |
| 10058 | 10084 | |
| 10085 | FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec); | |
| 10086 | assert(fn_type_id->return_type != nullptr); | |
| 10087 | assert(parent_fn_entry != nullptr); | |
| 10088 | if (fn_type_id->return_type->id == TypeTableEntryIdPureError || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) { | |
| 10089 | parent_fn_entry->calls_errorable_function = true; | |
| 10090 | } | |
| 10091 | ||
| 10092 | ||
| 10059 | 10093 | IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count); |
| 10060 | 10094 | size_t next_arg_index = 0; |
| 10061 | 10095 | if (first_arg_ptr) { |
| ... | ... | @@ -15322,6 +15356,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15322 | 15356 | return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction); |
| 15323 | 15357 | case IrInstructionIdExport: |
| 15324 | 15358 | return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction); |
| 15359 | case IrInstructionIdErrorReturnTrace: | |
| 15360 | return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction); | |
| 15325 | 15361 | } |
| 15326 | 15362 | zig_unreachable(); |
| 15327 | 15363 | } |
| ... | ... | @@ -15505,6 +15541,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15505 | 15541 | case IrInstructionIdOpaqueType: |
| 15506 | 15542 | case IrInstructionIdArgType: |
| 15507 | 15543 | case IrInstructionIdTagType: |
| 15544 | case IrInstructionIdErrorReturnTrace: | |
| 15508 | 15545 | return false; |
| 15509 | 15546 | case IrInstructionIdAsm: |
| 15510 | 15547 | { |
src/ir_print.cpp+7| ... | ... | @@ -996,6 +996,10 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) { |
| 996 | 996 | } |
| 997 | 997 | } |
| 998 | 998 | |
| 999 | static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) { | |
| 1000 | fprintf(irp->f, "@errorReturnTrace()"); | |
| 1001 | } | |
| 1002 | ||
| 999 | 1003 | |
| 1000 | 1004 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1001 | 1005 | ir_print_prefix(irp, instruction); |
| ... | ... | @@ -1308,6 +1312,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1308 | 1312 | case IrInstructionIdExport: |
| 1309 | 1313 | ir_print_export(irp, (IrInstructionExport *)instruction); |
| 1310 | 1314 | break; |
| 1315 | case IrInstructionIdErrorReturnTrace: | |
| 1316 | ir_print_error_return_trace(irp, (IrInstructionErrorReturnTrace *)instruction); | |
| 1317 | break; | |
| 1311 | 1318 | } |
| 1312 | 1319 | fprintf(irp->f, "\n"); |
| 1313 | 1320 | } |
std/build.zig+4-6| ... | ... | @@ -247,11 +247,11 @@ pub const Builder = struct { |
| 247 | 247 | defer wanted_steps.deinit(); |
| 248 | 248 | |
| 249 | 249 | if (step_names.len == 0) { |
| 250 | wanted_steps.append(&self.default_step) catch unreachable; | |
| 250 | try wanted_steps.append(&self.default_step); | |
| 251 | 251 | } else { |
| 252 | 252 | for (step_names) |step_name| { |
| 253 | 253 | const s = try self.getTopLevelStepByName(step_name); |
| 254 | wanted_steps.append(s) catch unreachable; | |
| 254 | try wanted_steps.append(s); | |
| 255 | 255 | } |
| 256 | 256 | } |
| 257 | 257 | |
| ... | ... | @@ -721,11 +721,9 @@ pub const Builder = struct { |
| 721 | 721 | return error.FileNotFound; |
| 722 | 722 | } |
| 723 | 723 | |
| 724 | pub fn exec(self: &Builder, argv: []const []const u8) -> []u8 { | |
| 724 | pub fn exec(self: &Builder, argv: []const []const u8) -> %[]u8 { | |
| 725 | 725 | const max_output_size = 100 * 1024; |
| 726 | const result = os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size) catch |err| { | |
| 727 | std.debug.panic("Unable to spawn {}: {}", argv[0], @errorName(err)); | |
| 728 | }; | |
| 726 | const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size); | |
| 729 | 727 | switch (result.term) { |
| 730 | 728 | os.ChildProcess.Term.Exited => |code| { |
| 731 | 729 | if (code != 0) { |
std/debug/index.zig+149-63| ... | ... | @@ -13,6 +13,10 @@ pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator; |
| 13 | 13 | error MissingDebugInfo; |
| 14 | 14 | error InvalidDebugInfo; |
| 15 | 15 | error UnsupportedDebugInfo; |
| 16 | error UnknownObjectFormat; | |
| 17 | error TodoSupportCoffDebugInfo; | |
| 18 | error TodoSupportMachoDebugInfo; | |
| 19 | error TodoSupportCOFFDebugInfo; | |
| 16 | 20 | |
| 17 | 21 | |
| 18 | 22 | /// Tries to write to stderr, unbuffered, and ignores any error returned. |
| ... | ... | @@ -37,10 +41,43 @@ fn getStderrStream() -> %&io.OutStream { |
| 37 | 41 | } |
| 38 | 42 | } |
| 39 | 43 | |
| 44 | var self_debug_info: ?&ElfStackTrace = null; | |
| 45 | pub fn getSelfDebugInfo() -> %&ElfStackTrace { | |
| 46 | if (self_debug_info) |info| { | |
| 47 | return info; | |
| 48 | } else { | |
| 49 | const info = try openSelfDebugInfo(global_allocator); | |
| 50 | self_debug_info = info; | |
| 51 | return info; | |
| 52 | } | |
| 53 | } | |
| 54 | ||
| 55 | /// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned. | |
| 56 | pub fn dumpCurrentStackTrace() { | |
| 57 | const stderr = getStderrStream() catch return; | |
| 58 | const debug_info = getSelfDebugInfo() catch |err| { | |
| 59 | stderr.print("Unable to open debug info: {}\n", @errorName(err)) catch return; | |
| 60 | return; | |
| 61 | }; | |
| 62 | defer debug_info.close(); | |
| 63 | writeCurrentStackTrace(stderr, global_allocator, debug_info, stderr_file.isTty(), 1) catch |err| { | |
| 64 | stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return; | |
| 65 | return; | |
| 66 | }; | |
| 67 | } | |
| 68 | ||
| 40 | 69 | /// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned. |
| 41 | pub fn dumpStackTrace() { | |
| 70 | pub fn dumpStackTrace(stack_trace: &const builtin.StackTrace) { | |
| 42 | 71 | const stderr = getStderrStream() catch return; |
| 43 | writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch return; | |
| 72 | const debug_info = getSelfDebugInfo() catch |err| { | |
| 73 | stderr.print("Unable to open debug info: {}\n", @errorName(err)) catch return; | |
| 74 | return; | |
| 75 | }; | |
| 76 | defer debug_info.close(); | |
| 77 | writeStackTrace(stack_trace, stderr, global_allocator, debug_info, stderr_file.isTty()) catch |err| { | |
| 78 | stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return; | |
| 79 | return; | |
| 80 | }; | |
| 44 | 81 | } |
| 45 | 82 | |
| 46 | 83 | /// This function invokes undefined behavior when `ok` is `false`. |
| ... | ... | @@ -88,7 +125,21 @@ pub fn panic(comptime format: []const u8, args: ...) -> noreturn { |
| 88 | 125 | |
| 89 | 126 | const stderr = getStderrStream() catch os.abort(); |
| 90 | 127 | stderr.print(format ++ "\n", args) catch os.abort(); |
| 91 | writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch os.abort(); | |
| 128 | dumpCurrentStackTrace(); | |
| 129 | ||
| 130 | os.abort(); | |
| 131 | } | |
| 132 | ||
| 133 | pub fn panicWithTrace(trace: &const builtin.StackTrace, comptime format: []const u8, args: ...) -> noreturn { | |
| 134 | if (panicking) { | |
| 135 | os.abort(); | |
| 136 | } else { | |
| 137 | panicking = true; | |
| 138 | } | |
| 139 | const stderr = getStderrStream() catch os.abort(); | |
| 140 | stderr.print(format ++ "\n", args) catch os.abort(); | |
| 141 | dumpStackTrace(trace); | |
| 142 | dumpCurrentStackTrace(); | |
| 92 | 143 | |
| 93 | 144 | os.abort(); |
| 94 | 145 | } |
| ... | ... | @@ -101,12 +152,91 @@ const RESET = "\x1b[0m"; |
| 101 | 152 | error PathNotFound; |
| 102 | 153 | error InvalidDebugInfo; |
| 103 | 154 | |
| 104 | pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool, | |
| 105 | ignore_frame_count: usize) -> %void | |
| 155 | pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator, | |
| 156 | debug_info: &ElfStackTrace, tty_color: bool) -> %void | |
| 106 | 157 | { |
| 158 | var frame_index: usize = undefined; | |
| 159 | var frames_left: usize = undefined; | |
| 160 | if (stack_trace.index < stack_trace.instruction_addresses.len) { | |
| 161 | frame_index = 0; | |
| 162 | frames_left = stack_trace.index; | |
| 163 | } else { | |
| 164 | frame_index = (stack_trace.index + 1) % stack_trace.instruction_addresses.len; | |
| 165 | frames_left = stack_trace.instruction_addresses.len; | |
| 166 | } | |
| 167 | ||
| 168 | while (frames_left != 0) : ({ | |
| 169 | frames_left -= 1; | |
| 170 | frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len; | |
| 171 | }) { | |
| 172 | const return_address = stack_trace.instruction_addresses[frame_index]; | |
| 173 | try printSourceAtAddress(debug_info, out_stream, return_address); | |
| 174 | } | |
| 175 | } | |
| 176 | ||
| 177 | pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, | |
| 178 | debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) -> %void | |
| 179 | { | |
| 180 | var ignored_count: usize = 0; | |
| 181 | ||
| 182 | var fp = @ptrToInt(@frameAddress()); | |
| 183 | while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) { | |
| 184 | if (ignored_count < ignore_frame_count) { | |
| 185 | ignored_count += 1; | |
| 186 | continue; | |
| 187 | } | |
| 188 | ||
| 189 | const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize)); | |
| 190 | try printSourceAtAddress(debug_info, out_stream, return_address); | |
| 191 | } | |
| 192 | } | |
| 193 | ||
| 194 | fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, address: usize) -> %void { | |
| 195 | if (builtin.os == builtin.Os.windows) { | |
| 196 | return error.UnsupportedDebugInfo; | |
| 197 | } | |
| 198 | // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal | |
| 199 | // at compile time. I'll call it issue #313 | |
| 200 | const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}"; | |
| 201 | ||
| 202 | const compile_unit = findCompileUnit(debug_info, address) catch { | |
| 203 | try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n", | |
| 204 | address); | |
| 205 | return; | |
| 206 | }; | |
| 207 | const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name); | |
| 208 | if (getLineNumberInfo(debug_info, compile_unit, address - 1)) |line_info| { | |
| 209 | defer line_info.deinit(); | |
| 210 | try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ | |
| 211 | DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n", | |
| 212 | line_info.file_name, line_info.line, line_info.column, | |
| 213 | address, compile_unit_name); | |
| 214 | if (printLineFromFile(debug_info.allocator(), out_stream, line_info)) { | |
| 215 | if (line_info.column == 0) { | |
| 216 | try out_stream.write("\n"); | |
| 217 | } else { | |
| 218 | {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) { | |
| 219 | try out_stream.writeByte(' '); | |
| 220 | }} | |
| 221 | try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n"); | |
| 222 | } | |
| 223 | } else |err| switch (err) { | |
| 224 | error.EndOfFile, error.PathNotFound => {}, | |
| 225 | else => return err, | |
| 226 | } | |
| 227 | } else |err| switch (err) { | |
| 228 | error.MissingDebugInfo, error.InvalidDebugInfo => { | |
| 229 | try out_stream.print(ptr_hex ++ " in ??? ({})\n", address, compile_unit_name); | |
| 230 | }, | |
| 231 | else => return err, | |
| 232 | } | |
| 233 | } | |
| 234 | ||
| 235 | pub fn openSelfDebugInfo(allocator: &mem.Allocator) -> %&ElfStackTrace { | |
| 107 | 236 | switch (builtin.object_format) { |
| 108 | 237 | builtin.ObjectFormat.elf => { |
| 109 | var stack_trace = ElfStackTrace { | |
| 238 | const st = try allocator.create(ElfStackTrace); | |
| 239 | *st = ElfStackTrace { | |
| 110 | 240 | .self_exe_file = undefined, |
| 111 | 241 | .elf = undefined, |
| 112 | 242 | .debug_info = undefined, |
| ... | ... | @@ -117,12 +247,11 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty |
| 117 | 247 | .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator), |
| 118 | 248 | .compile_unit_list = ArrayList(CompileUnit).init(allocator), |
| 119 | 249 | }; |
| 120 | const st = &stack_trace; | |
| 121 | 250 | st.self_exe_file = try os.openSelfExe(); |
| 122 | defer st.self_exe_file.close(); | |
| 251 | %defer st.self_exe_file.close(); | |
| 123 | 252 | |
| 124 | 253 | try st.elf.openFile(allocator, &st.self_exe_file); |
| 125 | defer st.elf.close(); | |
| 254 | %defer st.elf.close(); | |
| 126 | 255 | |
| 127 | 256 | st.debug_info = (try st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo; |
| 128 | 257 | st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo; |
| ... | ... | @@ -130,67 +259,19 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty |
| 130 | 259 | st.debug_line = (try st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo; |
| 131 | 260 | st.debug_ranges = (try st.elf.findSection(".debug_ranges")); |
| 132 | 261 | try scanAllCompileUnits(st); |
| 133 | ||
| 134 | var ignored_count: usize = 0; | |
| 135 | ||
| 136 | var fp = @ptrToInt(@frameAddress()); | |
| 137 | while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) { | |
| 138 | if (ignored_count < ignore_frame_count) { | |
| 139 | ignored_count += 1; | |
| 140 | continue; | |
| 141 | } | |
| 142 | ||
| 143 | const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize)); | |
| 144 | ||
| 145 | // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal | |
| 146 | // at compile time. I'll call it issue #313 | |
| 147 | const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}"; | |
| 148 | ||
| 149 | const compile_unit = findCompileUnit(st, return_address) catch { | |
| 150 | try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n", | |
| 151 | return_address); | |
| 152 | continue; | |
| 153 | }; | |
| 154 | const compile_unit_name = try compile_unit.die.getAttrString(st, DW.AT_name); | |
| 155 | if (getLineNumberInfo(st, compile_unit, usize(return_address) - 1)) |line_info| { | |
| 156 | defer line_info.deinit(); | |
| 157 | try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ | |
| 158 | DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n", | |
| 159 | line_info.file_name, line_info.line, line_info.column, | |
| 160 | return_address, compile_unit_name); | |
| 161 | if (printLineFromFile(st.allocator(), out_stream, line_info)) { | |
| 162 | if (line_info.column == 0) { | |
| 163 | try out_stream.write("\n"); | |
| 164 | } else { | |
| 165 | {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) { | |
| 166 | try out_stream.writeByte(' '); | |
| 167 | }} | |
| 168 | try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n"); | |
| 169 | } | |
| 170 | } else |err| switch (err) { | |
| 171 | error.EndOfFile, error.PathNotFound => {}, | |
| 172 | else => return err, | |
| 173 | } | |
| 174 | } else |err| switch (err) { | |
| 175 | error.MissingDebugInfo, error.InvalidDebugInfo => { | |
| 176 | try out_stream.print(ptr_hex ++ " in ??? ({})\n", | |
| 177 | return_address, compile_unit_name); | |
| 178 | }, | |
| 179 | else => return err, | |
| 180 | } | |
| 181 | } | |
| 262 | return st; | |
| 182 | 263 | }, |
| 183 | 264 | builtin.ObjectFormat.coff => { |
| 184 | try out_stream.write("(stack trace unavailable for COFF object format)\n"); | |
| 265 | return error.TodoSupportCoffDebugInfo; | |
| 185 | 266 | }, |
| 186 | 267 | builtin.ObjectFormat.macho => { |
| 187 | try out_stream.write("(stack trace unavailable for Mach-O object format)\n"); | |
| 268 | return error.TodoSupportMachoDebugInfo; | |
| 188 | 269 | }, |
| 189 | 270 | builtin.ObjectFormat.wasm => { |
| 190 | try out_stream.write("(stack trace unavailable for WASM object format)\n"); | |
| 271 | return error.TodoSupportCOFFDebugInfo; | |
| 191 | 272 | }, |
| 192 | 273 | builtin.ObjectFormat.unknown => { |
| 193 | try out_stream.write("(stack trace unavailable for unknown object format)\n"); | |
| 274 | return error.UnknownObjectFormat; | |
| 194 | 275 | }, |
| 195 | 276 | } |
| 196 | 277 | } |
| ... | ... | @@ -228,7 +309,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_ |
| 228 | 309 | } |
| 229 | 310 | } |
| 230 | 311 | |
| 231 | const ElfStackTrace = struct { | |
| 312 | pub const ElfStackTrace = struct { | |
| 232 | 313 | self_exe_file: io.File, |
| 233 | 314 | elf: elf.Elf, |
| 234 | 315 | debug_info: &elf.SectionHeader, |
| ... | ... | @@ -248,6 +329,11 @@ const ElfStackTrace = struct { |
| 248 | 329 | const in_stream = &in_file_stream.stream; |
| 249 | 330 | return readStringRaw(self.allocator(), in_stream); |
| 250 | 331 | } |
| 332 | ||
| 333 | pub fn close(self: &ElfStackTrace) { | |
| 334 | self.self_exe_file.close(); | |
| 335 | self.elf.close(); | |
| 336 | } | |
| 251 | 337 | }; |
| 252 | 338 | |
| 253 | 339 | const PcRange = struct { |
std/io.zig+1-1| ... | ... | @@ -224,7 +224,7 @@ pub const File = struct { |
| 224 | 224 | }; |
| 225 | 225 | } |
| 226 | 226 | }, |
| 227 | else => @compileError("unsupported OS"), | |
| 227 | else => @compileError("unsupported OS: " ++ @tagName(builtin.os)), | |
| 228 | 228 | } |
| 229 | 229 | } |
| 230 | 230 |
std/os/index.zig+2-9| ... | ... | @@ -148,7 +148,7 @@ pub coldcc fn abort() -> noreturn { |
| 148 | 148 | } |
| 149 | 149 | |
| 150 | 150 | /// Exits the program cleanly with the specified status code. |
| 151 | pub coldcc fn exit(status: i32) -> noreturn { | |
| 151 | pub coldcc fn exit(status: u8) -> noreturn { | |
| 152 | 152 | if (builtin.link_libc) { |
| 153 | 153 | c.exit(status); |
| 154 | 154 | } |
| ... | ... | @@ -157,14 +157,7 @@ pub coldcc fn exit(status: i32) -> noreturn { |
| 157 | 157 | posix.exit(status); |
| 158 | 158 | }, |
| 159 | 159 | Os.windows => { |
| 160 | // Map a possibly negative status code to a non-negative status for the systems default | |
| 161 | // integer width. | |
| 162 | const p_status = if (@sizeOf(c_uint) < @sizeOf(u32)) | |
| 163 | @truncate(c_uint, @bitCast(u32, status)) | |
| 164 | else | |
| 165 | c_uint(@bitCast(u32, status)); | |
| 166 | ||
| 167 | windows.ExitProcess(p_status); | |
| 160 | windows.ExitProcess(status); | |
| 168 | 161 | }, |
| 169 | 162 | else => @compileError("Unsupported OS"), |
| 170 | 163 | } |
std/special/bootstrap.zig+35-10| ... | ... | @@ -21,8 +21,7 @@ comptime { |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | 23 | extern fn zenMain() -> noreturn { |
| 24 | root.main() catch std.os.posix.exit(1); | |
| 25 | std.os.posix.exit(0); | |
| 24 | std.os.posix.exit(callMain()); | |
| 26 | 25 | } |
| 27 | 26 | |
| 28 | 27 | nakedcc fn _start() -> noreturn { |
| ... | ... | @@ -43,29 +42,55 @@ nakedcc fn _start() -> noreturn { |
| 43 | 42 | extern fn WinMainCRTStartup() -> noreturn { |
| 44 | 43 | @setAlignStack(16); |
| 45 | 44 | |
| 46 | root.main() catch std.os.windows.ExitProcess(1); | |
| 47 | std.os.windows.ExitProcess(0); | |
| 45 | std.os.windows.ExitProcess(callMain()); | |
| 48 | 46 | } |
| 49 | 47 | |
| 50 | 48 | fn posixCallMainAndExit() -> noreturn { |
| 51 | 49 | const argc = *argc_ptr; |
| 52 | 50 | const argv = @ptrCast(&&u8, &argc_ptr[1]); |
| 53 | 51 | const envp = @ptrCast(&?&u8, &argv[argc + 1]); |
| 54 | callMain(argc, argv, envp) catch std.os.posix.exit(1); | |
| 55 | std.os.posix.exit(0); | |
| 52 | std.os.posix.exit(callMainWithArgs(argc, argv, envp)); | |
| 56 | 53 | } |
| 57 | 54 | |
| 58 | fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { | |
| 55 | fn callMainWithArgs(argc: usize, argv: &&u8, envp: &?&u8) -> u8 { | |
| 59 | 56 | std.os.ArgIteratorPosix.raw = argv[0..argc]; |
| 60 | 57 | |
| 61 | 58 | var env_count: usize = 0; |
| 62 | 59 | while (envp[env_count] != null) : (env_count += 1) {} |
| 63 | 60 | std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count]; |
| 64 | 61 | |
| 65 | return root.main(); | |
| 62 | return callMain(); | |
| 66 | 63 | } |
| 67 | 64 | |
| 68 | 65 | extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { |
| 69 | callMain(usize(c_argc), c_argv, c_envp) catch return 1; | |
| 70 | return 0; | |
| 66 | return callMainWithArgs(usize(c_argc), c_argv, c_envp); | |
| 67 | } | |
| 68 | ||
| 69 | fn callMain() -> u8 { | |
| 70 | switch (@typeId(@typeOf(root.main).ReturnType)) { | |
| 71 | builtin.TypeId.NoReturn => { | |
| 72 | root.main(); | |
| 73 | }, | |
| 74 | builtin.TypeId.Void => { | |
| 75 | root.main(); | |
| 76 | return 0; | |
| 77 | }, | |
| 78 | builtin.TypeId.Int => { | |
| 79 | if (@typeOf(root.main).ReturnType.bit_count != 8) { | |
| 80 | @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"); | |
| 81 | } | |
| 82 | return root.main(); | |
| 83 | }, | |
| 84 | builtin.TypeId.ErrorUnion => { | |
| 85 | root.main() catch |err| { | |
| 86 | std.debug.warn("error: {}\n", @errorName(err)); | |
| 87 | if (@errorReturnTrace()) |trace| { | |
| 88 | std.debug.dumpStackTrace(trace); | |
| 89 | } | |
| 90 | return 1; | |
| 91 | }; | |
| 92 | return 0; | |
| 93 | }, | |
| 94 | else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"), | |
| 95 | } | |
| 71 | 96 | } |
std/special/build_runner.zig+4-4| ... | ... | @@ -14,7 +14,7 @@ pub fn main() -> %void { |
| 14 | 14 | var arg_it = os.args(); |
| 15 | 15 | |
| 16 | 16 | // TODO use a more general purpose allocator here |
| 17 | var inc_allocator = std.heap.IncrementingAllocator.init(40 * 1024 * 1024) catch unreachable; | |
| 17 | var inc_allocator = try std.heap.IncrementingAllocator.init(40 * 1024 * 1024); | |
| 18 | 18 | defer inc_allocator.deinit(); |
| 19 | 19 | |
| 20 | 20 | const allocator = &inc_allocator.allocator; |
| ... | ... | @@ -107,12 +107,12 @@ pub fn main() -> %void { |
| 107 | 107 | return usageAndErr(&builder, false, try stderr_stream); |
| 108 | 108 | } |
| 109 | 109 | } else { |
| 110 | targets.append(arg) catch unreachable; | |
| 110 | try targets.append(arg); | |
| 111 | 111 | } |
| 112 | 112 | } |
| 113 | 113 | |
| 114 | 114 | builder.setInstallPrefix(prefix); |
| 115 | root.build(&builder); | |
| 115 | try root.build(&builder); | |
| 116 | 116 | |
| 117 | 117 | if (builder.validateUserInputDidItFail()) |
| 118 | 118 | return usageAndErr(&builder, true, try stderr_stream); |
| ... | ... | @@ -129,7 +129,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) |
| 129 | 129 | // run the build script to collect the options |
| 130 | 130 | if (!already_ran_build) { |
| 131 | 131 | builder.setInstallPrefix(null); |
| 132 | root.build(builder); | |
| 132 | try root.build(builder); | |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | 135 | // This usage text has to be synchronized with src/main.cpp |
std/special/builtin.zig+1-1| ... | ... | @@ -5,7 +5,7 @@ const builtin = @import("builtin"); |
| 5 | 5 | |
| 6 | 6 | // Avoid dragging in the debug safety mechanisms into this .o file, |
| 7 | 7 | // unless we're trying to test this file. |
| 8 | pub coldcc fn panic(msg: []const u8) -> noreturn { | |
| 8 | pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn { | |
| 9 | 9 | if (builtin.is_test) { |
| 10 | 10 | @import("std").debug.panic("{}", msg); |
| 11 | 11 | } else { |
std/special/compiler_rt/index.zig+1-1| ... | ... | @@ -74,7 +74,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; |
| 74 | 74 | |
| 75 | 75 | // Avoid dragging in the debug safety mechanisms into this .o file, |
| 76 | 76 | // unless we're trying to test this file. |
| 77 | pub coldcc fn panic(msg: []const u8) -> noreturn { | |
| 77 | pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn { | |
| 78 | 78 | if (is_test) { |
| 79 | 79 | @import("std").debug.panic("{}", msg); |
| 80 | 80 | } else { |
std/special/panic.zig+5-1| ... | ... | @@ -4,14 +4,18 @@ |
| 4 | 4 | // have to be added in the compiler. |
| 5 | 5 | |
| 6 | 6 | const builtin = @import("builtin"); |
| 7 | const std = @import("std"); | |
| 7 | 8 | |
| 8 | pub coldcc fn panic(msg: []const u8) -> noreturn { | |
| 9 | pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn { | |
| 9 | 10 | switch (builtin.os) { |
| 10 | 11 | // TODO: fix panic in zen. |
| 11 | 12 | builtin.Os.freestanding, builtin.Os.zen => { |
| 12 | 13 | while (true) {} |
| 13 | 14 | }, |
| 14 | 15 | else => { |
| 16 | if (error_return_trace) |trace| { | |
| 17 | @import("std").debug.panicWithTrace(trace, "{}", msg); | |
| 18 | } | |
| 15 | 19 | @import("std").debug.panic("{}", msg); |
| 16 | 20 | }, |
| 17 | 21 | } |
std/special/test_runner.zig+1-4| ... | ... | @@ -8,10 +8,7 @@ pub fn main() -> %void { |
| 8 | 8 | for (test_fn_list) |test_fn, i| { |
| 9 | 9 | warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name); |
| 10 | 10 | |
| 11 | test_fn.func() catch |err| { | |
| 12 | warn("{}\n", err); | |
| 13 | return err; | |
| 14 | }; | |
| 11 | try test_fn.func(); | |
| 15 | 12 | |
| 16 | 13 | warn("OK\n"); |
| 17 | 14 | } |
test/compile_errors.zig+9-9| ... | ... | @@ -1,6 +1,15 @@ |
| 1 | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | |
| 3 | 3 | pub fn addCases(cases: &tests.CompileErrorContext) { |
| 4 | cases.add("wrong return type for main", | |
| 5 | \\pub fn main() -> f32 { } | |
| 6 | , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"); | |
| 7 | ||
| 8 | cases.add("double ?? on main return value", | |
| 9 | \\pub fn main() -> ??void { | |
| 10 | \\} | |
| 11 | , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"); | |
| 12 | ||
| 4 | 13 | cases.add("bad identifier in function with struct defined inside function which references local const", |
| 5 | 14 | \\export fn entry() { |
| 6 | 15 | \\ const BlockKind = u32; |
| ... | ... | @@ -1059,15 +1068,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1059 | 1068 | , |
| 1060 | 1069 | ".tmp_source.zig:2:5: error: expected type 'void', found 'error'"); |
| 1061 | 1070 | |
| 1062 | cases.add("wrong return type for main", | |
| 1063 | \\pub fn main() { } | |
| 1064 | , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'"); | |
| 1065 | ||
| 1066 | cases.add("double ?? on main return value", | |
| 1067 | \\pub fn main() -> ??void { | |
| 1068 | \\} | |
| 1069 | , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'"); | |
| 1070 | ||
| 1071 | 1071 | cases.add("invalid pointer for var type", |
| 1072 | 1072 | \\extern fn ext() -> usize; |
| 1073 | 1073 | \\var bytes: [ext()]u8 = undefined; |
test/debug_safety.zig+20-20| ... | ... | @@ -2,7 +2,7 @@ const tests = @import("tests.zig"); |
| 2 | 2 | |
| 3 | 3 | pub fn addCases(cases: &tests.CompareOutputContext) { |
| 4 | 4 | cases.addDebugSafety("calling panic", |
| 5 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 5 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 6 | 6 | \\ @import("std").os.exit(126); |
| 7 | 7 | \\} |
| 8 | 8 | \\pub fn main() -> %void { |
| ... | ... | @@ -11,7 +11,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 11 | 11 | ); |
| 12 | 12 | |
| 13 | 13 | cases.addDebugSafety("out of bounds slice access", |
| 14 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 14 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 15 | 15 | \\ @import("std").os.exit(126); |
| 16 | 16 | \\} |
| 17 | 17 | \\pub fn main() -> %void { |
| ... | ... | @@ -25,7 +25,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 25 | 25 | ); |
| 26 | 26 | |
| 27 | 27 | cases.addDebugSafety("integer addition overflow", |
| 28 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 28 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 29 | 29 | \\ @import("std").os.exit(126); |
| 30 | 30 | \\} |
| 31 | 31 | \\error Whatever; |
| ... | ... | @@ -39,7 +39,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 39 | 39 | ); |
| 40 | 40 | |
| 41 | 41 | cases.addDebugSafety("integer subtraction overflow", |
| 42 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 42 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 43 | 43 | \\ @import("std").os.exit(126); |
| 44 | 44 | \\} |
| 45 | 45 | \\error Whatever; |
| ... | ... | @@ -53,7 +53,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 53 | 53 | ); |
| 54 | 54 | |
| 55 | 55 | cases.addDebugSafety("integer multiplication overflow", |
| 56 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 56 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 57 | 57 | \\ @import("std").os.exit(126); |
| 58 | 58 | \\} |
| 59 | 59 | \\error Whatever; |
| ... | ... | @@ -67,7 +67,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 67 | 67 | ); |
| 68 | 68 | |
| 69 | 69 | cases.addDebugSafety("integer negation overflow", |
| 70 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 70 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 71 | 71 | \\ @import("std").os.exit(126); |
| 72 | 72 | \\} |
| 73 | 73 | \\error Whatever; |
| ... | ... | @@ -81,7 +81,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 81 | 81 | ); |
| 82 | 82 | |
| 83 | 83 | cases.addDebugSafety("signed integer division overflow", |
| 84 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 84 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 85 | 85 | \\ @import("std").os.exit(126); |
| 86 | 86 | \\} |
| 87 | 87 | \\error Whatever; |
| ... | ... | @@ -95,7 +95,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 95 | 95 | ); |
| 96 | 96 | |
| 97 | 97 | cases.addDebugSafety("signed shift left overflow", |
| 98 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 98 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 99 | 99 | \\ @import("std").os.exit(126); |
| 100 | 100 | \\} |
| 101 | 101 | \\error Whatever; |
| ... | ... | @@ -109,7 +109,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 109 | 109 | ); |
| 110 | 110 | |
| 111 | 111 | cases.addDebugSafety("unsigned shift left overflow", |
| 112 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 112 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 113 | 113 | \\ @import("std").os.exit(126); |
| 114 | 114 | \\} |
| 115 | 115 | \\error Whatever; |
| ... | ... | @@ -123,7 +123,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 123 | 123 | ); |
| 124 | 124 | |
| 125 | 125 | cases.addDebugSafety("signed shift right overflow", |
| 126 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 126 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 127 | 127 | \\ @import("std").os.exit(126); |
| 128 | 128 | \\} |
| 129 | 129 | \\error Whatever; |
| ... | ... | @@ -137,7 +137,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 137 | 137 | ); |
| 138 | 138 | |
| 139 | 139 | cases.addDebugSafety("unsigned shift right overflow", |
| 140 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 140 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 141 | 141 | \\ @import("std").os.exit(126); |
| 142 | 142 | \\} |
| 143 | 143 | \\error Whatever; |
| ... | ... | @@ -151,7 +151,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 151 | 151 | ); |
| 152 | 152 | |
| 153 | 153 | cases.addDebugSafety("integer division by zero", |
| 154 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 154 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 155 | 155 | \\ @import("std").os.exit(126); |
| 156 | 156 | \\} |
| 157 | 157 | \\error Whatever; |
| ... | ... | @@ -164,7 +164,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 164 | 164 | ); |
| 165 | 165 | |
| 166 | 166 | cases.addDebugSafety("exact division failure", |
| 167 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 167 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 168 | 168 | \\ @import("std").os.exit(126); |
| 169 | 169 | \\} |
| 170 | 170 | \\error Whatever; |
| ... | ... | @@ -178,7 +178,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 178 | 178 | ); |
| 179 | 179 | |
| 180 | 180 | cases.addDebugSafety("cast []u8 to bigger slice of wrong size", |
| 181 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 181 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 182 | 182 | \\ @import("std").os.exit(126); |
| 183 | 183 | \\} |
| 184 | 184 | \\error Whatever; |
| ... | ... | @@ -192,7 +192,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 192 | 192 | ); |
| 193 | 193 | |
| 194 | 194 | cases.addDebugSafety("value does not fit in shortening cast", |
| 195 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 195 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 196 | 196 | \\ @import("std").os.exit(126); |
| 197 | 197 | \\} |
| 198 | 198 | \\error Whatever; |
| ... | ... | @@ -206,7 +206,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 206 | 206 | ); |
| 207 | 207 | |
| 208 | 208 | cases.addDebugSafety("signed integer not fitting in cast to unsigned integer", |
| 209 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 209 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 210 | 210 | \\ @import("std").os.exit(126); |
| 211 | 211 | \\} |
| 212 | 212 | \\error Whatever; |
| ... | ... | @@ -220,7 +220,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 220 | 220 | ); |
| 221 | 221 | |
| 222 | 222 | cases.addDebugSafety("unwrap error", |
| 223 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 223 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 224 | 224 | \\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) { |
| 225 | 225 | \\ @import("std").os.exit(126); // good |
| 226 | 226 | \\ } |
| ... | ... | @@ -236,7 +236,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 236 | 236 | ); |
| 237 | 237 | |
| 238 | 238 | cases.addDebugSafety("cast integer to error and no code matches", |
| 239 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 239 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 240 | 240 | \\ @import("std").os.exit(126); |
| 241 | 241 | \\} |
| 242 | 242 | \\pub fn main() -> %void { |
| ... | ... | @@ -248,7 +248,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 248 | 248 | ); |
| 249 | 249 | |
| 250 | 250 | cases.addDebugSafety("@alignCast misaligned", |
| 251 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 251 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 252 | 252 | \\ @import("std").os.exit(126); |
| 253 | 253 | \\} |
| 254 | 254 | \\error Wrong; |
| ... | ... | @@ -265,7 +265,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 265 | 265 | ); |
| 266 | 266 | |
| 267 | 267 | cases.addDebugSafety("bad union field access", |
| 268 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 268 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { | |
| 269 | 269 | \\ @import("std").os.exit(126); |
| 270 | 270 | \\} |
| 271 | 271 | \\ |
test/standalone/issue_339/build.zig+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | |
| 3 | pub fn build(b: &Builder) { | |
| 3 | pub fn build(b: &Builder) -> %void { | |
| 4 | 4 | const obj = b.addObject("test", "test.zig"); |
| 5 | 5 | |
| 6 | 6 | const test_step = b.step("test", "Test the program"); |
test/standalone/issue_339/test.zig+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | pub fn panic(msg: []const u8) -> noreturn { @breakpoint(); while (true) {} } | |
| 1 | const StackTrace = @import("builtin").StackTrace; | |
| 2 | pub fn panic(msg: []const u8, stack_trace: ?&StackTrace) -> noreturn { @breakpoint(); while (true) {} } | |
| 2 | 3 | |
| 3 | 4 | fn bar() -> %void {} |
| 4 | 5 |
test/standalone/pkg_import/build.zig+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | |
| 3 | pub fn build(b: &Builder) { | |
| 3 | pub fn build(b: &Builder) -> %void { | |
| 4 | 4 | const exe = b.addExecutable("test", "test.zig"); |
| 5 | 5 | exe.addPackagePath("my_pkg", "pkg.zig"); |
| 6 | 6 |
test/standalone/use_alias/build.zig+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | |
| 3 | pub fn build(b: &Builder) { | |
| 3 | pub fn build(b: &Builder) -> %void { | |
| 4 | 4 | b.addCIncludePath("."); |
| 5 | 5 | |
| 6 | 6 | const main = b.addTest("main.zig"); |
test/tests.zig+2-2| ... | ... | @@ -45,6 +45,7 @@ const test_targets = []TestTarget { |
| 45 | 45 | }; |
| 46 | 46 | |
| 47 | 47 | error TestFailed; |
| 48 | error CompilationIncorrectlySucceeded; | |
| 48 | 49 | |
| 49 | 50 | const max_stdout_size = 1 * 1024 * 1024; // 1 MB |
| 50 | 51 | |
| ... | ... | @@ -602,8 +603,7 @@ pub const CompileErrorContext = struct { |
| 602 | 603 | switch (term) { |
| 603 | 604 | Term.Exited => |code| { |
| 604 | 605 | if (code == 0) { |
| 605 | warn("Compilation incorrectly succeeded\n"); | |
| 606 | return error.TestFailed; | |
| 606 | return error.CompilationIncorrectlySucceeded; | |
| 607 | 607 | } |
| 608 | 608 | }, |
| 609 | 609 | else => { |