authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-01-17 00:20:06+13:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-01-17 00:20:06+13:00
log66a24c9c00d63853cd50f792847f52f7b2d06cb3
tree63224d479e266886257d6b403034dfa222094ee6
parentfa7b33549e43abbdb4fba1d686dfd63c2ca8e8ca
parent92fc5947fc18ea077f0e02bc4758e9050270e4bb

Merge branch 'master' into blake2


50 files changed, 873 insertions(+), 361 deletions(-)

README.md+1-1
...@@ -54,7 +54,7 @@ that counts as "freestanding" for the purposes of this table....@@ -54,7 +54,7 @@ that counts as "freestanding" for the purposes of this table.
5454
55| | freestanding | linux | macosx | windows | other |55| | freestanding | linux | macosx | windows | other |
56|-------------|--------------|---------|---------|---------|---------|56|-------------|--------------|---------|---------|---------|---------|
57|i386 | OK | planned | OK | OK | planned |57|i386 | OK | planned | OK | planned | planned |
58|x86_64 | OK | OK | OK | OK | planned |58|x86_64 | OK | OK | OK | OK | planned |
59|arm | OK | planned | planned | N/A | planned |59|arm | OK | planned | planned | N/A | planned |
60|aarch64 | OK | planned | planned | planned | planned |60|aarch64 | OK | planned | planned | planned | planned |
build.zig+6-6
...@@ -10,7 +10,7 @@ const ArrayList = std.ArrayList;...@@ -10,7 +10,7 @@ const ArrayList = std.ArrayList;
10const Buffer = std.Buffer;10const Buffer = std.Buffer;
11const io = std.io;11const io = std.io;
1212
13pub fn build(b: &Builder) {13pub fn build(b: &Builder) -> %void {
14 const mode = b.standardReleaseOptions();14 const mode = b.standardReleaseOptions();
1515
16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
...@@ -36,7 +36,7 @@ pub fn build(b: &Builder) {...@@ -36,7 +36,7 @@ pub fn build(b: &Builder) {
36 const test_step = b.step("test", "Run all the tests");36 const test_step = b.step("test", "Run all the tests");
3737
38 // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library38 // 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 var index: usize = 0;40 var index: usize = 0;
41 const cmake_binary_dir = nextValue(&index, build_info);41 const cmake_binary_dir = nextValue(&index, build_info);
42 const cxx_compiler = nextValue(&index, build_info);42 const cxx_compiler = nextValue(&index, build_info);
...@@ -68,7 +68,7 @@ pub fn build(b: &Builder) {...@@ -68,7 +68,7 @@ pub fn build(b: &Builder) {
68 dependOnLib(exe, llvm);68 dependOnLib(exe, llvm);
6969
70 if (exe.target.getOs() == builtin.Os.linux) {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 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();72 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();
73 exe.addObjectFile(libstdcxx_path);73 exe.addObjectFile(libstdcxx_path);
7474
...@@ -155,9 +155,9 @@ const LibraryDep = struct {...@@ -155,9 +155,9 @@ const LibraryDep = struct {
155};155};
156156
157fn findLLVM(b: &Builder, llvm_config_exe: []const u8) -> %LibraryDep {157fn findLLVM(b: &Builder, llvm_config_exe: []const u8) -> %LibraryDep {
158 const libs_output = b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});158 const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
159 const includes_output = b.exec([][]const u8{llvm_config_exe, "--includedir"});159 const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"});
160 const libdir_output = b.exec([][]const u8{llvm_config_exe, "--libdir"});160 const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"});
161161
162 var result = LibraryDep {162 var result = LibraryDep {
163 .libs = ArrayList([]const u8).init(b.allocator),163 .libs = ArrayList([]const u8).init(b.allocator),
doc/langref.html.in+8
...@@ -142,6 +142,7 @@...@@ -142,6 +142,7 @@
142 <li><a href="#builtin-TagType">@TagType</a></li>142 <li><a href="#builtin-TagType">@TagType</a></li>
143 <li><a href="#builtin-EnumTagType">@EnumTagType</a></li>143 <li><a href="#builtin-EnumTagType">@EnumTagType</a></li>
144 <li><a href="#builtin-errorName">@errorName</a></li>144 <li><a href="#builtin-errorName">@errorName</a></li>
145 <li><a href="#builtin-errorReturnTrace">@errorReturnTrace</a></li>
145 <li><a href="#builtin-fence">@fence</a></li>146 <li><a href="#builtin-fence">@fence</a></li>
146 <li><a href="#builtin-fieldParentPtr">@fieldParentPtr</a></li>147 <li><a href="#builtin-fieldParentPtr">@fieldParentPtr</a></li>
147 <li><a href="#builtin-frameAddress">@frameAddress</a></li>148 <li><a href="#builtin-frameAddress">@frameAddress</a></li>
...@@ -4412,6 +4413,13 @@ test.zig:6:2: error: found compile log statement...@@ -4412,6 +4413,13 @@ test.zig:6:2: error: found compile log statement
4412 or all calls have a compile-time known value for <code>err</code>, then no4413 or all calls have a compile-time known value for <code>err</code>, then no
4413 error name table will be generated.4414 error name table will be generated.
4414 </p>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 <h3 id="builtin-fence">@fence</h3>4423 <h3 id="builtin-fence">@fence</h3>
4416 <pre><code class="zig">@fence(order: AtomicOrder)</code></pre>4424 <pre><code class="zig">@fence(order: AtomicOrder)</code></pre>
4417 <p>4425 <p>
example/mix_o_files/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {3pub fn build(b: &Builder) -> %void {
4 const obj = b.addObject("base64", "base64.zig");4 const obj = b.addObject("base64", "base64.zig");
55
6 const exe = b.addCExecutable("test");6 const exe = b.addCExecutable("test");
example/shared_library/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {3pub fn build(b: &Builder) -> %void {
4 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));4 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
55
6 const exe = b.addCExecutable("test");6 const exe = b.addCExecutable("test");
src-self-hosted/parser.zig-6
...@@ -1146,12 +1146,6 @@ fn testCanonical(source: []const u8) {...@@ -1146,12 +1146,6 @@ fn testCanonical(source: []const u8) {
1146}1146}
11471147
1148test "zig fmt" {1148test "zig fmt" {
1149 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1150 // TODO get this test passing
1151 // https://github.com/zig-lang/zig/issues/537
1152 return;
1153 }
1154
1155 testCanonical(1149 testCanonical(
1156 \\extern fn puts(s: &const u8) -> c_int;1150 \\extern fn puts(s: &const u8) -> c_int;
1157 \\1151 \\
src/all_types.hpp+13
...@@ -1205,6 +1205,7 @@ struct FnTableEntry {...@@ -1205,6 +1205,7 @@ struct FnTableEntry {
1205 uint32_t alignstack_value;1205 uint32_t alignstack_value;
12061206
1207 ZigList<FnExport> export_list;1207 ZigList<FnExport> export_list;
1208 bool calls_errorable_function;
1208};1209};
12091210
1210uint32_t fn_table_entry_hash(FnTableEntry*);1211uint32_t fn_table_entry_hash(FnTableEntry*);
...@@ -1273,6 +1274,7 @@ enum BuiltinFnId {...@@ -1273,6 +1274,7 @@ enum BuiltinFnId {
1273 BuiltinFnIdSetAlignStack,1274 BuiltinFnIdSetAlignStack,
1274 BuiltinFnIdArgType,1275 BuiltinFnIdArgType,
1275 BuiltinFnIdExport,1276 BuiltinFnIdExport,
1277 BuiltinFnIdErrorReturnTrace,
1276};1278};
12771279
1278struct BuiltinFnEntry {1280struct BuiltinFnEntry {
...@@ -1498,6 +1500,7 @@ struct CodeGen {...@@ -1498,6 +1500,7 @@ struct CodeGen {
1498 Buf triple_str;1500 Buf triple_str;
1499 BuildMode build_mode;1501 BuildMode build_mode;
1500 bool is_test_build;1502 bool is_test_build;
1503 bool have_err_ret_tracing;
1501 uint32_t target_os_index;1504 uint32_t target_os_index;
1502 uint32_t target_arch_index;1505 uint32_t target_arch_index;
1503 uint32_t target_environ_index;1506 uint32_t target_environ_index;
...@@ -1530,6 +1533,7 @@ struct CodeGen {...@@ -1530,6 +1533,7 @@ struct CodeGen {
1530 FnTableEntry *panic_fn;1533 FnTableEntry *panic_fn;
1531 LLVMValueRef cur_ret_ptr;1534 LLVMValueRef cur_ret_ptr;
1532 LLVMValueRef cur_fn_val;1535 LLVMValueRef cur_fn_val;
1536 LLVMValueRef cur_err_ret_trace_val;
1533 bool c_want_stdint;1537 bool c_want_stdint;
1534 bool c_want_stdbool;1538 bool c_want_stdbool;
1535 AstNode *root_export_decl;1539 AstNode *root_export_decl;
...@@ -1572,6 +1576,8 @@ struct CodeGen {...@@ -1572,6 +1576,8 @@ struct CodeGen {
1572 size_t largest_err_name_len;1576 size_t largest_err_name_len;
1573 LLVMValueRef safety_crash_err_fn;1577 LLVMValueRef safety_crash_err_fn;
15741578
1579 LLVMValueRef return_err_fn;
1580
1575 IrInstruction *invalid_instruction;1581 IrInstruction *invalid_instruction;
1576 ConstExprValue const_void_val;1582 ConstExprValue const_void_val;
15771583
...@@ -1595,6 +1601,8 @@ struct CodeGen {...@@ -1595,6 +1601,8 @@ struct CodeGen {
1595 ZigList<AstNode *> tld_ref_source_node_stack;1601 ZigList<AstNode *> tld_ref_source_node_stack;
15961602
1597 TypeTableEntry *align_amt_type;1603 TypeTableEntry *align_amt_type;
1604 TypeTableEntry *stack_trace_type;
1605 TypeTableEntry *ptr_to_stack_trace_type;
1598};1606};
15991607
1600enum VarLinkage {1608enum VarLinkage {
...@@ -1896,6 +1904,7 @@ enum IrInstructionId {...@@ -1896,6 +1904,7 @@ enum IrInstructionId {
1896 IrInstructionIdSetAlignStack,1904 IrInstructionIdSetAlignStack,
1897 IrInstructionIdArgType,1905 IrInstructionIdArgType,
1898 IrInstructionIdExport,1906 IrInstructionIdExport,
1907 IrInstructionIdErrorReturnTrace,
1899};1908};
19001909
1901struct IrInstruction {1910struct IrInstruction {
...@@ -2717,6 +2726,10 @@ struct IrInstructionExport {...@@ -2717,6 +2726,10 @@ struct IrInstructionExport {
2717 IrInstruction *target;2726 IrInstruction *target;
2718};2727};
27192728
2729struct IrInstructionErrorReturnTrace {
2730 IrInstruction base;
2731};
2732
2720static const size_t slice_ptr_index = 0;2733static const size_t slice_ptr_index = 0;
2721static const size_t slice_len_index = 1;2734static const size_t slice_len_index = 1;
27222735
src/analyze.cpp+48-12
...@@ -869,6 +869,16 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) {...@@ -869,6 +869,16 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) {
869 zig_unreachable();869 zig_unreachable();
870}870}
871871
872TypeTableEntry *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
872TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {882TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
873 auto table_entry = g->fn_type_table.maybe_get(fn_type_id);883 auto table_entry = g->fn_type_table.maybe_get(fn_type_id);
874 if (table_entry) {884 if (table_entry) {
...@@ -915,10 +925,16 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -915,10 +925,16 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
915 if (!skip_debug_info) {925 if (!skip_debug_info) {
916 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&926 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&
917 handle_is_ptr(fn_type_id->return_type);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 // +1 for maybe making the first argument the return value931 // +1 for maybe making the first argument the return value
919 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count);932 // +1 for maybe last argument the error return trace
920 // +1 because 0 is the return type and +1 for maybe making first arg ret val933 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(2 + fn_type_id->param_count);
921 ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(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 param_di_types[0] = fn_type_id->return_type->di_type;938 param_di_types[0] = fn_type_id->return_type->di_type;
923 size_t gen_param_index = 0;939 size_t gen_param_index = 0;
924 TypeTableEntry *gen_return_type;940 TypeTableEntry *gen_return_type;
...@@ -936,6 +952,14 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -936,6 +952,14 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
936 }952 }
937 fn_type->data.fn.gen_return_type = gen_return_type;953 fn_type->data.fn.gen_return_type = gen_return_type;
938954
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 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);963 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
940 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {964 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
941 FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];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,6 +1192,9 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1168 }1192 }
11691193
1170 TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);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 if (fn_type_id.cc != CallingConventionUnspecified) {1198 if (fn_type_id.cc != CallingConventionUnspecified) {
1172 type_ensure_zero_bits_known(g, type_entry);1199 type_ensure_zero_bits_known(g, type_entry);
1173 if (!type_has_bits(type_entry)) {1200 if (!type_has_bits(type_entry)) {
...@@ -2204,6 +2231,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {...@@ -2204,6 +2231,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
2204 // is a pointer to this very struct, or a function pointer with parameters that2231 // is a pointer to this very struct, or a function pointer with parameters that
2205 // reference such a type.2232 // reference such a type.
2206 union_type->data.unionation.zero_bits_known = true;2233 union_type->data.unionation.zero_bits_known = true;
2234 union_type->data.unionation.zero_bits_loop_flag = false;
2207 if (union_type->data.unionation.abi_alignment == 0) {2235 if (union_type->data.unionation.abi_alignment == 0) {
2208 if (union_type->data.unionation.layout == ContainerLayoutPacked) {2236 if (union_type->data.unionation.layout == ContainerLayoutPacked) {
2209 union_type->data.unionation.abi_alignment = 1;2237 union_type->data.unionation.abi_alignment = 1;
...@@ -2558,7 +2586,7 @@ static bool scope_is_root_decls(Scope *scope) {...@@ -2558,7 +2586,7 @@ static bool scope_is_root_decls(Scope *scope) {
25582586
2559static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, TypeTableEntry *fn_type) {2587static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, TypeTableEntry *fn_type) {
2560 add_node_error(g, proto_node,2588 add_node_error(g, proto_node,
2561 buf_sprintf("expected 'fn([]const u8) -> unreachable', found '%s'",2589 buf_sprintf("expected 'fn([]const u8, ?&builtin.StackTrace) -> unreachable', found '%s'",
2562 buf_ptr(&fn_type->name)));2590 buf_ptr(&fn_type->name)));
2563}2591}
25642592
...@@ -2567,7 +2595,7 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {...@@ -2567,7 +2595,7 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
2567 assert(proto_node->type == NodeTypeFnProto);2595 assert(proto_node->type == NodeTypeFnProto);
2568 TypeTableEntry *fn_type = panic_fn->type_entry;2596 TypeTableEntry *fn_type = panic_fn->type_entry;
2569 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;2597 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
2570 if (fn_type_id->param_count != 1) {2598 if (fn_type_id->param_count != 2) {
2571 return wrong_panic_prototype(g, proto_node, fn_type);2599 return wrong_panic_prototype(g, proto_node, fn_type);
2572 }2600 }
2573 TypeTableEntry *const_u8_ptr = get_pointer_to_type(g, g->builtin_types.entry_u8, true);2601 TypeTableEntry *const_u8_ptr = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
...@@ -2576,6 +2604,11 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {...@@ -2576,6 +2604,11 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
2576 return wrong_panic_prototype(g, proto_node, fn_type);2604 return wrong_panic_prototype(g, proto_node, fn_type);
2577 }2605 }
25782606
2607 TypeTableEntry *nullable_ptr_to_stack_trace_type = get_maybe_type(g, get_ptr_to_stack_trace_type(g));
2608 if (fn_type_id->param_info[1].type != nullable_ptr_to_stack_trace_type) {
2609 return wrong_panic_prototype(g, proto_node, fn_type);
2610 }
2611
2579 TypeTableEntry *actual_return_type = fn_type_id->return_type;2612 TypeTableEntry *actual_return_type = fn_type_id->return_type;
2580 if (actual_return_type != g->builtin_types.entry_unreachable) {2613 if (actual_return_type != g->builtin_types.entry_unreachable) {
2581 return wrong_panic_prototype(g, proto_node, fn_type);2614 return wrong_panic_prototype(g, proto_node, fn_type);
...@@ -2680,13 +2713,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -2680,13 +2713,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
2680 {2713 {
2681 if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {2714 if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {
2682 g->main_fn = fn_table_entry;2715 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 } else if ((import->package == g->panic_package || g->have_pub_panic) &&2716 } else if ((import->package == g->panic_package || g->have_pub_panic) &&
2691 buf_eql_str(&fn_table_entry->symbol_name, "panic"))2717 buf_eql_str(&fn_table_entry->symbol_name, "panic"))
2692 {2718 {
...@@ -5527,3 +5553,13 @@ bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) {...@@ -5527,3 +5553,13 @@ bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) {
5527 return a == b;5553 return a == b;
5528}5554}
55295555
5556ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
5557 Tld *tld = codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str(name));
5558 resolve_top_level_decl(codegen, tld, false, nullptr);
5559 assert(tld->id == TldIdVar);
5560 TldVar *tld_var = (TldVar *)tld;
5561 ConstExprValue *var_value = tld_var->var->value;
5562 assert(var_value != nullptr);
5563 return var_value;
5564}
5565
src/analyze.hpp+5
...@@ -185,4 +185,9 @@ PackageTableEntry *new_anonymous_package(void);...@@ -185,4 +185,9 @@ PackageTableEntry *new_anonymous_package(void);
185Buf *const_value_to_buffer(ConstExprValue *const_val);185Buf *const_value_to_buffer(ConstExprValue *const_val);
186void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc);186void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc);
187187
188
189ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
190TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g);
191
192
188#endif193#endif
src/codegen.cpp+231-16
...@@ -404,6 +404,19 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {...@@ -404,6 +404,19 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
404 zig_unreachable();404 zig_unreachable();
405}405}
406406
407static 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
407static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {420static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
408 if (fn_table_entry->llvm_value)421 if (fn_table_entry->llvm_value)
409 return fn_table_entry->llvm_value;422 return fn_table_entry->llvm_value;
...@@ -483,7 +496,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -483,7 +496,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
483 LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true);496 LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true);
484 }497 }
485498
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 addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn");501 addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn");
488 }502 }
489503
...@@ -520,13 +534,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -520,13 +534,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
520 // use the ABI alignment, which is fine.534 // use the ABI alignment, which is fine.
521 }535 }
522536
523 if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {537 if (!type_has_bits(return_type)) {
524 // nothing to do538 // nothing to do
525 } else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer ||539 } else if (return_type->id == TypeTableEntryIdPointer || return_type->id == TypeTableEntryIdFn) {
526 fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdFn)
527 {
528 addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");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 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))542 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
531 {543 {
532 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");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,6 +575,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
563 }575 }
564 }576 }
565577
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 return fn_table_entry->llvm_value;583 return fn_table_entry->llvm_value;
567}584}
568585
...@@ -864,16 +881,25 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {...@@ -864,16 +881,25 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
864 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));881 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));
865}882}
866883
867static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {884static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {
868 assert(g->panic_fn != nullptr);885 assert(g->panic_fn != nullptr);
869 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);886 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
870 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);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 LLVMBuildUnreachable(g->builder);898 LLVMBuildUnreachable(g->builder);
873}899}
874900
875static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) {901static 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}
878904
879static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {905static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
...@@ -895,6 +921,87 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {...@@ -895,6 +921,87 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
895 return g->memcpy_fn_val;921 return g->memcpy_fn_val;
896}922}
897923
924static 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
898static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {1005static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
899 if (g->safety_crash_err_fn != nullptr)1006 if (g->safety_crash_err_fn != nullptr)
900 return g->safety_crash_err_fn;1007 return g->safety_crash_err_fn;
...@@ -953,7 +1060,11 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -953,7 +1060,11 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
953 LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_array, offset_ptr_indices, 2);1060 LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_array, offset_ptr_indices, 2);
9541061
955 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false);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 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);1068 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
958 addLLVMFnAttr(fn_val, "noreturn");1069 addLLVMFnAttr(fn_val, "noreturn");
959 addLLVMFnAttr(fn_val, "cold");1070 addLLVMFnAttr(fn_val, "cold");
...@@ -975,7 +1086,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -975,7 +1086,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
975 LLVMPositionBuilderAtEnd(g->builder, entry_block);1086 LLVMPositionBuilderAtEnd(g->builder, entry_block);
976 ZigLLVMClearCurrentDebugLocation(g->builder);1087 ZigLLVMClearCurrentDebugLocation(g->builder);
9771088
978 LLVMValueRef err_val = LLVMGetParam(fn_val, 0);1089 LLVMValueRef err_val = LLVMGetParam(fn_val, 1);
9791090
980 LLVMValueRef err_table_indices[] = {1091 LLVMValueRef err_table_indices[] = {
981 LLVMConstNull(g->builtin_types.entry_usize->type_ref),1092 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
...@@ -1005,7 +1116,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1005,7 +1116,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
1005 LLVMValueRef global_slice_len_field_ptr = LLVMBuildStructGEP(g->builder, global_slice, slice_len_index, "");1116 LLVMValueRef global_slice_len_field_ptr = LLVMBuildStructGEP(g->builder, global_slice, slice_len_index, "");
1006 gen_store(g, full_buf_len, global_slice_len_field_ptr, u8_ptr_type);1117 gen_store(g, full_buf_len, global_slice_len_field_ptr, u8_ptr_type);
10071118
1008 gen_panic(g, global_slice);1119 gen_panic(g, global_slice, LLVMGetParam(fn_val, 0));
10091120
1010 LLVMPositionBuilderAtEnd(g->builder, prev_block);1121 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1011 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);1122 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
...@@ -1016,8 +1127,18 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1016,8 +1127,18 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
10161127
1017static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {1128static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
1018 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);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 ZigLLVM_FnInlineAuto, "");1140 ZigLLVM_FnInlineAuto, "");
1141 LLVMSetTailCall(call_instruction, true);
1021 LLVMBuildUnreachable(g->builder);1142 LLVMBuildUnreachable(g->builder);
1022}1143}
10231144
...@@ -1296,6 +1417,35 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {...@@ -1296,6 +1417,35 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
1296static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {1417static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
1297 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);1418 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
1298 TypeTableEntry *return_type = return_instruction->value->value.type;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 if (handle_is_ptr(return_type)) {1449 if (handle_is_ptr(return_type)) {
1300 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {1450 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
1301 assert(g->cur_ret_ptr);1451 assert(g->cur_ret_ptr);
...@@ -2330,7 +2480,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -2330,7 +2480,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
2330 TypeTableEntry *src_return_type = fn_type_id->return_type;2480 TypeTableEntry *src_return_type = fn_type_id->return_type;
2331 bool ret_has_bits = type_has_bits(src_return_type);2481 bool ret_has_bits = type_has_bits(src_return_type);
2332 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);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 bool is_var_args = fn_type_id->is_var_args;2485 bool is_var_args = fn_type_id->is_var_args;
2335 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);2486 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
2336 size_t gen_param_index = 0;2487 size_t gen_param_index = 0;
...@@ -2338,6 +2489,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -2338,6 +2489,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
2338 gen_param_values[gen_param_index] = instruction->tmp_ptr;2489 gen_param_values[gen_param_index] = instruction->tmp_ptr;
2339 gen_param_index += 1;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 for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {2496 for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
2342 IrInstruction *param_instruction = instruction->args[call_i];2497 IrInstruction *param_instruction = instruction->args[call_i];
2343 TypeTableEntry *param_type = param_instruction->value.type;2498 TypeTableEntry *param_type = param_instruction->value.type;
...@@ -2881,6 +3036,16 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I...@@ -2881,6 +3036,16 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
2881 return target_val;3036 return target_val;
2882}3037}
28833038
3039static 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
2884static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {3049static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
2885 switch (atomic_order) {3050 switch (atomic_order) {
2886 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;3051 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
...@@ -3474,7 +3639,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec...@@ -3474,7 +3639,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
3474}3639}
34753640
3476static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {3641static 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 return nullptr;3643 return nullptr;
3479}3644}
34803645
...@@ -3654,6 +3819,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -3654,6 +3819,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
3654 return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction);3819 return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction);
3655 case IrInstructionIdAlignCast:3820 case IrInstructionIdAlignCast:
3656 return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);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 zig_unreachable();3825 zig_unreachable();
3659}3826}
...@@ -4493,7 +4660,8 @@ static void do_code_gen(CodeGen *g) {...@@ -4493,7 +4660,8 @@ static void do_code_gen(CodeGen *g) {
4493 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);4660 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
4494 g->cur_fn = fn_table_entry;4661 g->cur_fn = fn_table_entry;
4495 g->cur_fn_val = fn;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 g->cur_ret_ptr = LLVMGetParam(fn, 0);4665 g->cur_ret_ptr = LLVMGetParam(fn, 0);
4498 } else {4666 } else {
4499 g->cur_ret_ptr = nullptr;4667 g->cur_ret_ptr = nullptr;
...@@ -4502,6 +4670,42 @@ static void do_code_gen(CodeGen *g) {...@@ -4502,6 +4670,42 @@ static void do_code_gen(CodeGen *g) {
4502 build_all_basic_blocks(g, fn_table_entry);4670 build_all_basic_blocks(g, fn_table_entry);
4503 clear_debug_source_node(g);4671 clear_debug_source_node(g);
45044672
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 // allocate temporary stack data4709 // allocate temporary stack data
4506 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {4710 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {
4507 IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);4711 IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);
...@@ -5064,6 +5268,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -5064,6 +5268,7 @@ static void define_builtin_fns(CodeGen *g) {
5064 create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);5268 create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);
5065 create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2);5269 create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2);
5066 create_builtin_fn(g, BuiltinFnIdExport, "export", 3);5270 create_builtin_fn(g, BuiltinFnIdExport, "export", 3);
5271 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
5067}5272}
50685273
5069static const char *bool_to_str(bool b) {5274static const char *bool_to_str(bool b) {
...@@ -5088,6 +5293,12 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -5088,6 +5293,12 @@ static void define_builtin_compile_vars(CodeGen *g) {
5088 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);5293 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
5089 Buf *contents = buf_alloc();5294 Buf *contents = buf_alloc();
50905295
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 const char *cur_os = nullptr;5302 const char *cur_os = nullptr;
5092 {5303 {
5093 buf_appendf(contents, "pub const Os = enum {\n");5304 buf_appendf(contents, "pub const Os = enum {\n");
...@@ -5233,6 +5444,7 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -5233,6 +5444,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
5233 buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);5444 buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
5234 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));5445 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
5235 buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr));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));
52365448
5237 buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");5449 buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");
52385450
...@@ -5251,6 +5463,7 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -5251,6 +5463,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
5251 g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);5463 g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
5252 g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);5464 g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
5253 g->compile_var_import = add_source_file(g, g->compile_var_package, abs_full_path, contents);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}
52555468
5256static void init(CodeGen *g) {5469static void init(CodeGen *g) {
...@@ -5359,6 +5572,8 @@ static void init(CodeGen *g) {...@@ -5359,6 +5572,8 @@ static void init(CodeGen *g) {
5359 }5572 }
5360 }5573 }
53615574
5575 g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease;
5576
5362 define_builtin_fns(g);5577 define_builtin_fns(g);
5363 define_builtin_compile_vars(g);5578 define_builtin_compile_vars(g);
5364}5579}
src/ir.cpp+49-12
...@@ -572,6 +572,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArgType *) {...@@ -572,6 +572,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArgType *) {
572 return IrInstructionIdArgType;572 return IrInstructionIdArgType;
573}573}
574574
575static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace *) {
576 return IrInstructionIdErrorReturnTrace;
577}
578
575template<typename T>579template<typename T>
576static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {580static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
577 T *special_instruction = allocate<T>(1);581 T *special_instruction = allocate<T>(1);
...@@ -2305,6 +2309,12 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s...@@ -2305,6 +2309,12 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s
2305 return &instruction->base;2309 return &instruction->base;
2306}2310}
23072311
2312static 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
2308static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2318static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2309 results[ReturnKindUnconditional] = 0;2319 results[ReturnKindUnconditional] = 0;
2310 results[ReturnKindError] = 0;2320 results[ReturnKindError] = 0;
...@@ -3731,6 +3741,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -3731,6 +3741,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37313741
3732 return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value);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 zig_unreachable();3749 zig_unreachable();
3736}3750}
...@@ -8230,16 +8244,6 @@ static bool ir_resolve_comptime(IrAnalyze *ira, IrInstruction *value, bool *out)...@@ -8230,16 +8244,6 @@ static bool ir_resolve_comptime(IrAnalyze *ira, IrInstruction *value, bool *out)
8230 return ir_resolve_bool(ira, value, out);8244 return ir_resolve_bool(ira, value, out);
8231}8245}
82328246
8233static 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
8243static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) {8247static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) {
8244 if (type_is_invalid(value->value.type))8248 if (type_is_invalid(value->value.type))
8245 return false;8249 return false;
...@@ -9578,6 +9582,24 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi...@@ -9578,6 +9582,24 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
9578 return ira->codegen->builtin_types.entry_void;9582 return ira->codegen->builtin_types.entry_void;
9579}9583}
95809584
9585static 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
9581static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,9603static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
9582 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)9604 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
9583{9605{
...@@ -9836,7 +9858,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -9836,7 +9858,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
98369858
9837 if (fn_proto_node->data.fn_proto.is_var_args) {9859 if (fn_proto_node->data.fn_proto.is_var_args) {
9838 ir_add_error(ira, &call_instruction->base,9860 ir_add_error(ira, &call_instruction->base,
9839 buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/andrewrk/zig/issues/313"));9861 buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/zig-lang/zig/issues/313"));
9840 return ira->codegen->builtin_types.entry_invalid;9862 return ira->codegen->builtin_types.entry_invalid;
9841 }9863 }
98429864
...@@ -10053,9 +10075,21 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -10053,9 +10075,21 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
10053 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;10075 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
10054 ir_add_alloca(ira, new_call_instruction, return_type);10076 ir_add_alloca(ira, new_call_instruction, return_type);
1005510077
10078 if (return_type->id == TypeTableEntryIdPureError || return_type->id == TypeTableEntryIdErrorUnion) {
10079 parent_fn_entry->calls_errorable_function = true;
10080 }
10081
10056 return ir_finish_anal(ira, return_type);10082 return ir_finish_anal(ira, return_type);
10057 }10083 }
1005810084
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 IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);10093 IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
10060 size_t next_arg_index = 0;10094 size_t next_arg_index = 0;
10061 if (first_arg_ptr) {10095 if (first_arg_ptr) {
...@@ -13977,7 +14011,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc...@@ -13977,7 +14011,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
13977 return ira->codegen->builtin_types.entry_invalid;14011 return ira->codegen->builtin_types.entry_invalid;
13978 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);14012 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
1397914013
13980 ensure_complete_type(ira->codegen, type_entry);14014 type_ensure_zero_bits_known(ira->codegen, type_entry);
13981 if (type_is_invalid(type_entry))14015 if (type_is_invalid(type_entry))
13982 return ira->codegen->builtin_types.entry_invalid;14016 return ira->codegen->builtin_types.entry_invalid;
1398314017
...@@ -15322,6 +15356,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -15322,6 +15356,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
15322 return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction);15356 return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction);
15323 case IrInstructionIdExport:15357 case IrInstructionIdExport:
15324 return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction);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 zig_unreachable();15362 zig_unreachable();
15327}15363}
...@@ -15505,6 +15541,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -15505,6 +15541,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
15505 case IrInstructionIdOpaqueType:15541 case IrInstructionIdOpaqueType:
15506 case IrInstructionIdArgType:15542 case IrInstructionIdArgType:
15507 case IrInstructionIdTagType:15543 case IrInstructionIdTagType:
15544 case IrInstructionIdErrorReturnTrace:
15508 return false;15545 return false;
15509 case IrInstructionIdAsm:15546 case IrInstructionIdAsm:
15510 {15547 {
src/ir_print.cpp+7
...@@ -996,6 +996,10 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {...@@ -996,6 +996,10 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {
996 }996 }
997}997}
998998
999static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {
1000 fprintf(irp->f, "@errorReturnTrace()");
1001}
1002
9991003
1000static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1004static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1001 ir_print_prefix(irp, instruction);1005 ir_print_prefix(irp, instruction);
...@@ -1308,6 +1312,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1308,6 +1312,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1308 case IrInstructionIdExport:1312 case IrInstructionIdExport:
1309 ir_print_export(irp, (IrInstructionExport *)instruction);1313 ir_print_export(irp, (IrInstructionExport *)instruction);
1310 break;1314 break;
1315 case IrInstructionIdErrorReturnTrace:
1316 ir_print_error_return_trace(irp, (IrInstructionErrorReturnTrace *)instruction);
1317 break;
1311 }1318 }
1312 fprintf(irp->f, "\n");1319 fprintf(irp->f, "\n");
1313}1320}
std/build.zig+4-6
...@@ -247,11 +247,11 @@ pub const Builder = struct {...@@ -247,11 +247,11 @@ pub const Builder = struct {
247 defer wanted_steps.deinit();247 defer wanted_steps.deinit();
248248
249 if (step_names.len == 0) {249 if (step_names.len == 0) {
250 wanted_steps.append(&self.default_step) catch unreachable;250 try wanted_steps.append(&self.default_step);
251 } else {251 } else {
252 for (step_names) |step_name| {252 for (step_names) |step_name| {
253 const s = try self.getTopLevelStepByName(step_name);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 }
257257
...@@ -721,11 +721,9 @@ pub const Builder = struct {...@@ -721,11 +721,9 @@ pub const Builder = struct {
721 return error.FileNotFound;721 return error.FileNotFound;
722 }722 }
723723
724 pub fn exec(self: &Builder, argv: []const []const u8) -> []u8 {724 pub fn exec(self: &Builder, argv: []const []const u8) -> %[]u8 {
725 const max_output_size = 100 * 1024;725 const max_output_size = 100 * 1024;
726 const result = os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size) catch |err| {726 const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size);
727 std.debug.panic("Unable to spawn {}: {}", argv[0], @errorName(err));
728 };
729 switch (result.term) {727 switch (result.term) {
730 os.ChildProcess.Term.Exited => |code| {728 os.ChildProcess.Term.Exited => |code| {
731 if (code != 0) {729 if (code != 0) {
std/crypto/sha2.zig-40
...@@ -267,22 +267,12 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {...@@ -267,22 +267,12 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
267};}267};}
268268
269test "sha224 single" {269test "sha224 single" {
270 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
271 // https://github.com/zig-lang/zig/issues/537
272 return;
273 }
274
275 htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "");270 htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "");
276 htest.assertEqualHash(Sha224, "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc");271 htest.assertEqualHash(Sha224, "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc");
277 htest.assertEqualHash(Sha224, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");272 htest.assertEqualHash(Sha224, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
278}273}
279274
280test "sha224 streaming" {275test "sha224 streaming" {
281 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
282 // https://github.com/zig-lang/zig/issues/537
283 return;
284 }
285
286 var h = Sha224.init();276 var h = Sha224.init();
287 var out: [28]u8 = undefined;277 var out: [28]u8 = undefined;
288278
...@@ -303,22 +293,12 @@ test "sha224 streaming" {...@@ -303,22 +293,12 @@ test "sha224 streaming" {
303}293}
304294
305test "sha256 single" {295test "sha256 single" {
306 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
307 // https://github.com/zig-lang/zig/issues/537
308 return;
309 }
310
311 htest.assertEqualHash(Sha256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "");296 htest.assertEqualHash(Sha256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "");
312 htest.assertEqualHash(Sha256, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc");297 htest.assertEqualHash(Sha256, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc");
313 htest.assertEqualHash(Sha256, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");298 htest.assertEqualHash(Sha256, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
314}299}
315300
316test "sha256 streaming" {301test "sha256 streaming" {
317 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
318 // https://github.com/zig-lang/zig/issues/537
319 return;
320 }
321
322 var h = Sha256.init();302 var h = Sha256.init();
323 var out: [32]u8 = undefined;303 var out: [32]u8 = undefined;
324304
...@@ -622,11 +602,6 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {...@@ -622,11 +602,6 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
622};}602};}
623603
624test "sha384 single" {604test "sha384 single" {
625 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
626 // https://github.com/zig-lang/zig/issues/537
627 return;
628 }
629
630 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";605 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
631 htest.assertEqualHash(Sha384, h1, "");606 htest.assertEqualHash(Sha384, h1, "");
632607
...@@ -638,11 +613,6 @@ test "sha384 single" {...@@ -638,11 +613,6 @@ test "sha384 single" {
638}613}
639614
640test "sha384 streaming" {615test "sha384 streaming" {
641 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
642 // https://github.com/zig-lang/zig/issues/537
643 return;
644 }
645
646 var h = Sha384.init();616 var h = Sha384.init();
647 var out: [48]u8 = undefined;617 var out: [48]u8 = undefined;
648618
...@@ -666,11 +636,6 @@ test "sha384 streaming" {...@@ -666,11 +636,6 @@ test "sha384 streaming" {
666}636}
667637
668test "sha512 single" {638test "sha512 single" {
669 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
670 // https://github.com/zig-lang/zig/issues/537
671 return;
672 }
673
674 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";639 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
675 htest.assertEqualHash(Sha512, h1, "");640 htest.assertEqualHash(Sha512, h1, "");
676641
...@@ -682,11 +647,6 @@ test "sha512 single" {...@@ -682,11 +647,6 @@ test "sha512 single" {
682}647}
683648
684test "sha512 streaming" {649test "sha512 streaming" {
685 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
686 // https://github.com/zig-lang/zig/issues/537
687 return;
688 }
689
690 var h = Sha512.init();650 var h = Sha512.init();
691 var out: [64]u8 = undefined;651 var out: [64]u8 = undefined;
692652
std/debug/index.zig+149-63
...@@ -13,6 +13,10 @@ pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;...@@ -13,6 +13,10 @@ pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
13error MissingDebugInfo;13error MissingDebugInfo;
14error InvalidDebugInfo;14error InvalidDebugInfo;
15error UnsupportedDebugInfo;15error UnsupportedDebugInfo;
16error UnknownObjectFormat;
17error TodoSupportCoffDebugInfo;
18error TodoSupportMachoDebugInfo;
19error TodoSupportCOFFDebugInfo;
1620
1721
18/// Tries to write to stderr, unbuffered, and ignores any error returned.22/// Tries to write to stderr, unbuffered, and ignores any error returned.
...@@ -37,10 +41,43 @@ fn getStderrStream() -> %&io.OutStream {...@@ -37,10 +41,43 @@ fn getStderrStream() -> %&io.OutStream {
37 }41 }
38}42}
3943
44var self_debug_info: ?&ElfStackTrace = null;
45pub 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.
56pub 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/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.69/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
41pub fn dumpStackTrace() {70pub fn dumpStackTrace(stack_trace: &const builtin.StackTrace) {
42 const stderr = getStderrStream() catch return;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}
4582
46/// This function invokes undefined behavior when `ok` is `false`.83/// This function invokes undefined behavior when `ok` is `false`.
...@@ -88,7 +125,21 @@ pub fn panic(comptime format: []const u8, args: ...) -> noreturn {...@@ -88,7 +125,21 @@ pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
88125
89 const stderr = getStderrStream() catch os.abort();126 const stderr = getStderrStream() catch os.abort();
90 stderr.print(format ++ "\n", args) catch os.abort();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
133pub 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();
92143
93 os.abort();144 os.abort();
94}145}
...@@ -101,12 +152,91 @@ const RESET = "\x1b[0m";...@@ -101,12 +152,91 @@ const RESET = "\x1b[0m";
101error PathNotFound;152error PathNotFound;
102error InvalidDebugInfo;153error InvalidDebugInfo;
103154
104pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,155pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator,
105 ignore_frame_count: usize) -> %void156 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
177pub 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
194fn 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
235pub fn openSelfDebugInfo(allocator: &mem.Allocator) -> %&ElfStackTrace {
107 switch (builtin.object_format) {236 switch (builtin.object_format) {
108 builtin.ObjectFormat.elf => {237 builtin.ObjectFormat.elf => {
109 var stack_trace = ElfStackTrace {238 const st = try allocator.create(ElfStackTrace);
239 *st = ElfStackTrace {
110 .self_exe_file = undefined,240 .self_exe_file = undefined,
111 .elf = undefined,241 .elf = undefined,
112 .debug_info = undefined,242 .debug_info = undefined,
...@@ -117,12 +247,11 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty...@@ -117,12 +247,11 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
117 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),247 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
118 .compile_unit_list = ArrayList(CompileUnit).init(allocator),248 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
119 };249 };
120 const st = &stack_trace;
121 st.self_exe_file = try os.openSelfExe();250 st.self_exe_file = try os.openSelfExe();
122 defer st.self_exe_file.close();251 %defer st.self_exe_file.close();
123252
124 try st.elf.openFile(allocator, &st.self_exe_file);253 try st.elf.openFile(allocator, &st.self_exe_file);
125 defer st.elf.close();254 %defer st.elf.close();
126255
127 st.debug_info = (try st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;256 st.debug_info = (try st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
128 st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;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,67 +259,19 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
130 st.debug_line = (try st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;259 st.debug_line = (try st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
131 st.debug_ranges = (try st.elf.findSection(".debug_ranges"));260 st.debug_ranges = (try st.elf.findSection(".debug_ranges"));
132 try scanAllCompileUnits(st);261 try scanAllCompileUnits(st);
133262 return st;
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 }
182 },263 },
183 builtin.ObjectFormat.coff => {264 builtin.ObjectFormat.coff => {
184 try out_stream.write("(stack trace unavailable for COFF object format)\n");265 return error.TodoSupportCoffDebugInfo;
185 },266 },
186 builtin.ObjectFormat.macho => {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 builtin.ObjectFormat.wasm => {270 builtin.ObjectFormat.wasm => {
190 try out_stream.write("(stack trace unavailable for WASM object format)\n");271 return error.TodoSupportCOFFDebugInfo;
191 },272 },
192 builtin.ObjectFormat.unknown => {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,7 +309,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_
228 }309 }
229}310}
230311
231const ElfStackTrace = struct {312pub const ElfStackTrace = struct {
232 self_exe_file: io.File,313 self_exe_file: io.File,
233 elf: elf.Elf,314 elf: elf.Elf,
234 debug_info: &elf.SectionHeader,315 debug_info: &elf.SectionHeader,
...@@ -248,6 +329,11 @@ const ElfStackTrace = struct {...@@ -248,6 +329,11 @@ const ElfStackTrace = struct {
248 const in_stream = &in_file_stream.stream;329 const in_stream = &in_file_stream.stream;
249 return readStringRaw(self.allocator(), in_stream);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};
252338
253const PcRange = struct {339const PcRange = struct {
std/io.zig+1-1
...@@ -224,7 +224,7 @@ pub const File = struct {...@@ -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 }
230230
std/io_test.zig-5
...@@ -8,11 +8,6 @@ const os = std.os;...@@ -8,11 +8,6 @@ const os = std.os;
8const builtin = @import("builtin");8const builtin = @import("builtin");
99
10test "write a file, read it, then delete it" {10test "write a file, read it, then delete it" {
11 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
12 // TODO get this test passing
13 // https://github.com/zig-lang/zig/issues/537
14 return;
15 }
16 var data: [1024]u8 = undefined;11 var data: [1024]u8 = undefined;
17 var rng = Rand.init(1234);12 var rng = Rand.init(1234);
18 rng.fillBytes(data[0..]);13 rng.fillBytes(data[0..]);
std/math/acosh.zig-5
...@@ -55,11 +55,6 @@ fn acosh64(x: f64) -> f64 {...@@ -55,11 +55,6 @@ fn acosh64(x: f64) -> f64 {
55}55}
5656
57test "math.acosh" {57test "math.acosh" {
58 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
59 // TODO get this test passing
60 // https://github.com/zig-lang/zig/issues/537
61 return;
62 }
63 assert(acosh(f32(1.5)) == acosh32(1.5));58 assert(acosh(f32(1.5)) == acosh32(1.5));
64 assert(acosh(f64(1.5)) == acosh64(1.5));59 assert(acosh(f64(1.5)) == acosh64(1.5));
65}60}
std/math/cos.zig-5
...@@ -146,11 +146,6 @@ test "math.cos" {...@@ -146,11 +146,6 @@ test "math.cos" {
146}146}
147147
148test "math.cos32" {148test "math.cos32" {
149 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
150 // TODO get this test passing
151 // https://github.com/zig-lang/zig/issues/537
152 return;
153 }
154 const epsilon = 0.000001;149 const epsilon = 0.000001;
155150
156 assert(math.approxEq(f32, cos32(0.0), 1.0, epsilon));151 assert(math.approxEq(f32, cos32(0.0), 1.0, epsilon));
std/math/cosh.zig-5
...@@ -81,11 +81,6 @@ fn cosh64(x: f64) -> f64 {...@@ -81,11 +81,6 @@ fn cosh64(x: f64) -> f64 {
81}81}
8282
83test "math.cosh" {83test "math.cosh" {
84 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
85 // TODO get this test passing
86 // https://github.com/zig-lang/zig/issues/537
87 return;
88 }
89 assert(cosh(f32(1.5)) == cosh32(1.5));84 assert(cosh(f32(1.5)) == cosh32(1.5));
90 assert(cosh(f64(1.5)) == cosh64(1.5));85 assert(cosh(f64(1.5)) == cosh64(1.5));
91}86}
std/math/index.zig-15
...@@ -359,11 +359,6 @@ pub fn divTrunc(comptime T: type, numerator: T, denominator: T) -> %T {...@@ -359,11 +359,6 @@ pub fn divTrunc(comptime T: type, numerator: T, denominator: T) -> %T {
359}359}
360360
361test "math.divTrunc" {361test "math.divTrunc" {
362 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
363 // TODO get this test passing
364 // https://github.com/zig-lang/zig/issues/537
365 return;
366 }
367 testDivTrunc();362 testDivTrunc();
368 comptime testDivTrunc();363 comptime testDivTrunc();
369}364}
...@@ -389,11 +384,6 @@ pub fn divFloor(comptime T: type, numerator: T, denominator: T) -> %T {...@@ -389,11 +384,6 @@ pub fn divFloor(comptime T: type, numerator: T, denominator: T) -> %T {
389}384}
390385
391test "math.divFloor" {386test "math.divFloor" {
392 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
393 // TODO get this test passing
394 // https://github.com/zig-lang/zig/issues/537
395 return;
396 }
397 testDivFloor();387 testDivFloor();
398 comptime testDivFloor();388 comptime testDivFloor();
399}389}
...@@ -423,11 +413,6 @@ pub fn divExact(comptime T: type, numerator: T, denominator: T) -> %T {...@@ -423,11 +413,6 @@ pub fn divExact(comptime T: type, numerator: T, denominator: T) -> %T {
423}413}
424414
425test "math.divExact" {415test "math.divExact" {
426 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
427 // TODO get this test passing
428 // https://github.com/zig-lang/zig/issues/537
429 return;
430 }
431 testDivExact();416 testDivExact();
432 comptime testDivExact();417 comptime testDivExact();
433}418}
std/math/ln.zig-5
...@@ -147,11 +147,6 @@ pub fn ln_64(x_: f64) -> f64 {...@@ -147,11 +147,6 @@ pub fn ln_64(x_: f64) -> f64 {
147}147}
148148
149test "math.ln" {149test "math.ln" {
150 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
151 // TODO get this test passing
152 // https://github.com/zig-lang/zig/issues/537
153 return;
154 }
155 assert(ln(f32(0.2)) == ln_32(0.2));150 assert(ln(f32(0.2)) == ln_32(0.2));
156 assert(ln(f64(0.2)) == ln_64(0.2));151 assert(ln(f64(0.2)) == ln_64(0.2));
157}152}
std/math/log.zig-5
...@@ -56,11 +56,6 @@ test "math.log float" {...@@ -56,11 +56,6 @@ test "math.log float" {
56}56}
5757
58test "math.log float_special" {58test "math.log float_special" {
59 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
60 // TODO get this test passing
61 // https://github.com/zig-lang/zig/issues/537
62 return;
63 }
64 assert(log(f32, 2, 0.2301974) == math.log2(f32(0.2301974)));59 assert(log(f32, 2, 0.2301974) == math.log2(f32(0.2301974)));
65 assert(log(f32, 10, 0.2301974) == math.log10(f32(0.2301974)));60 assert(log(f32, 10, 0.2301974) == math.log10(f32(0.2301974)));
6661
std/math/log10.zig-5
...@@ -172,11 +172,6 @@ pub fn log10_64(x_: f64) -> f64 {...@@ -172,11 +172,6 @@ pub fn log10_64(x_: f64) -> f64 {
172}172}
173173
174test "math.log10" {174test "math.log10" {
175 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
176 // TODO get this test passing
177 // https://github.com/zig-lang/zig/issues/537
178 return;
179 }
180 assert(log10(f32(0.2)) == log10_32(0.2));175 assert(log10(f32(0.2)) == log10_32(0.2));
181 assert(log10(f64(0.2)) == log10_64(0.2));176 assert(log10(f64(0.2)) == log10_64(0.2));
182}177}
std/math/log2.zig-5
...@@ -170,11 +170,6 @@ pub fn log2_64(x_: f64) -> f64 {...@@ -170,11 +170,6 @@ pub fn log2_64(x_: f64) -> f64 {
170}170}
171171
172test "math.log2" {172test "math.log2" {
173 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
174 // TODO get this test passing
175 // https://github.com/zig-lang/zig/issues/537
176 return;
177 }
178 assert(log2(f32(0.2)) == log2_32(0.2));173 assert(log2(f32(0.2)) == log2_32(0.2));
179 assert(log2(f64(0.2)) == log2_64(0.2));174 assert(log2(f64(0.2)) == log2_64(0.2));
180}175}
std/math/pow.zig-6
...@@ -176,12 +176,6 @@ fn isOddInteger(x: f64) -> bool {...@@ -176,12 +176,6 @@ fn isOddInteger(x: f64) -> bool {
176}176}
177177
178test "math.pow" {178test "math.pow" {
179 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
180 // TODO get this test passing
181 // https://github.com/zig-lang/zig/issues/537
182 return;
183 }
184
185 const epsilon = 0.000001;179 const epsilon = 0.000001;
186180
187 assert(math.approxEq(f32, pow(f32, 0.0, 3.3), 0.0, epsilon));181 assert(math.approxEq(f32, pow(f32, 0.0, 3.3), 0.0, epsilon));
std/math/round.zig-5
...@@ -98,11 +98,6 @@ test "math.round" {...@@ -98,11 +98,6 @@ test "math.round" {
98}98}
9999
100test "math.round32" {100test "math.round32" {
101 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
102 // TODO get this test passing
103 // https://github.com/zig-lang/zig/issues/537
104 return;
105 }
106 assert(round32(1.3) == 1.0);101 assert(round32(1.3) == 1.0);
107 assert(round32(-1.3) == -1.0);102 assert(round32(-1.3) == -1.0);
108 assert(round32(0.2) == 0.0);103 assert(round32(0.2) == 0.0);
std/math/sin.zig-5
...@@ -150,11 +150,6 @@ test "math.sin" {...@@ -150,11 +150,6 @@ test "math.sin" {
150}150}
151151
152test "math.sin32" {152test "math.sin32" {
153 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
154 // TODO get this test passing
155 // https://github.com/zig-lang/zig/issues/537
156 return;
157 }
158 const epsilon = 0.000001;153 const epsilon = 0.000001;
159154
160 assert(math.approxEq(f32, sin32(0.0), 0.0, epsilon));155 assert(math.approxEq(f32, sin32(0.0), 0.0, epsilon));
std/math/sinh.zig-5
...@@ -88,11 +88,6 @@ fn sinh64(x: f64) -> f64 {...@@ -88,11 +88,6 @@ fn sinh64(x: f64) -> f64 {
88}88}
8989
90test "math.sinh" {90test "math.sinh" {
91 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
92 // TODO get this test passing
93 // https://github.com/zig-lang/zig/issues/537
94 return;
95 }
96 assert(sinh(f32(1.5)) == sinh32(1.5));91 assert(sinh(f32(1.5)) == sinh32(1.5));
97 assert(sinh(f64(1.5)) == sinh64(1.5));92 assert(sinh(f64(1.5)) == sinh64(1.5));
98}93}
std/math/tan.zig-5
...@@ -136,11 +136,6 @@ test "math.tan" {...@@ -136,11 +136,6 @@ test "math.tan" {
136}136}
137137
138test "math.tan32" {138test "math.tan32" {
139 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
140 // TODO get this test passing
141 // https://github.com/zig-lang/zig/issues/537
142 return;
143 }
144 const epsilon = 0.000001;139 const epsilon = 0.000001;
145140
146 assert(math.approxEq(f32, tan32(0.0), 0.0, epsilon));141 assert(math.approxEq(f32, tan32(0.0), 0.0, epsilon));
std/math/tanh.zig-5
...@@ -112,11 +112,6 @@ fn tanh64(x: f64) -> f64 {...@@ -112,11 +112,6 @@ fn tanh64(x: f64) -> f64 {
112}112}
113113
114test "math.tanh" {114test "math.tanh" {
115 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
116 // TODO get this test passing
117 // https://github.com/zig-lang/zig/issues/537
118 return;
119 }
120 assert(tanh(f32(1.5)) == tanh32(1.5));115 assert(tanh(f32(1.5)) == tanh32(1.5));
121 assert(tanh(f64(1.5)) == tanh64(1.5));116 assert(tanh(f64(1.5)) == tanh64(1.5));
122}117}
std/os/index.zig+2-9
...@@ -148,7 +148,7 @@ pub coldcc fn abort() -> noreturn {...@@ -148,7 +148,7 @@ pub coldcc fn abort() -> noreturn {
148}148}
149149
150/// Exits the program cleanly with the specified status code.150/// Exits the program cleanly with the specified status code.
151pub coldcc fn exit(status: i32) -> noreturn {151pub coldcc fn exit(status: u8) -> noreturn {
152 if (builtin.link_libc) {152 if (builtin.link_libc) {
153 c.exit(status);153 c.exit(status);
154 }154 }
...@@ -157,14 +157,7 @@ pub coldcc fn exit(status: i32) -> noreturn {...@@ -157,14 +157,7 @@ pub coldcc fn exit(status: i32) -> noreturn {
157 posix.exit(status);157 posix.exit(status);
158 },158 },
159 Os.windows => {159 Os.windows => {
160 // Map a possibly negative status code to a non-negative status for the systems default160 windows.ExitProcess(status);
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);
168 },161 },
169 else => @compileError("Unsupported OS"),162 else => @compileError("Unsupported OS"),
170 }163 }
std/rand.zig-20
...@@ -194,11 +194,6 @@ fn MersenneTwister(...@@ -194,11 +194,6 @@ fn MersenneTwister(
194}194}
195195
196test "rand float 32" {196test "rand float 32" {
197 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
198 // TODO get this test passing
199 // https://github.com/zig-lang/zig/issues/537
200 return;
201 }
202 var r = Rand.init(42);197 var r = Rand.init(42);
203 var i: usize = 0;198 var i: usize = 0;
204 while (i < 1000) : (i += 1) {199 while (i < 1000) : (i += 1) {
...@@ -209,11 +204,6 @@ test "rand float 32" {...@@ -209,11 +204,6 @@ test "rand float 32" {
209}204}
210205
211test "rand.MT19937_64" {206test "rand.MT19937_64" {
212 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
213 // TODO get this test passing
214 // https://github.com/zig-lang/zig/issues/537
215 return;
216 }
217 var rng = MT19937_64.init(rand_test.mt64_seed);207 var rng = MT19937_64.init(rand_test.mt64_seed);
218 for (rand_test.mt64_data) |value| {208 for (rand_test.mt64_data) |value| {
219 assert(value == rng.get());209 assert(value == rng.get());
...@@ -221,11 +211,6 @@ test "rand.MT19937_64" {...@@ -221,11 +211,6 @@ test "rand.MT19937_64" {
221}211}
222212
223test "rand.MT19937_32" {213test "rand.MT19937_32" {
224 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
225 // TODO get this test passing
226 // https://github.com/zig-lang/zig/issues/537
227 return;
228 }
229 var rng = MT19937_32.init(rand_test.mt32_seed);214 var rng = MT19937_32.init(rand_test.mt32_seed);
230 for (rand_test.mt32_data) |value| {215 for (rand_test.mt32_data) |value| {
231 assert(value == rng.get());216 assert(value == rng.get());
...@@ -233,11 +218,6 @@ test "rand.MT19937_32" {...@@ -233,11 +218,6 @@ test "rand.MT19937_32" {
233}218}
234219
235test "rand.Rand.range" {220test "rand.Rand.range" {
236 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
237 // TODO get this test passing
238 // https://github.com/zig-lang/zig/issues/537
239 return;
240 }
241 var r = Rand.init(42);221 var r = Rand.init(42);
242 testRange(&r, -4, 3);222 testRange(&r, -4, 3);
243 testRange(&r, -4, -1);223 testRange(&r, -4, -1);
std/sort.zig-20
...@@ -1020,11 +1020,6 @@ fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> bool {...@@ -1020,11 +1020,6 @@ fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> bool {
1020}1020}
10211021
1022test "std.sort" {1022test "std.sort" {
1023 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1024 // TODO get this test passing
1025 // https://github.com/zig-lang/zig/issues/537
1026 return;
1027 }
1028 const u8cases = [][]const []const u8 {1023 const u8cases = [][]const []const u8 {
1029 [][]const u8{"", ""},1024 [][]const u8{"", ""},
1030 [][]const u8{"a", "a"},1025 [][]const u8{"a", "a"},
...@@ -1061,11 +1056,6 @@ test "std.sort" {...@@ -1061,11 +1056,6 @@ test "std.sort" {
1061}1056}
10621057
1063test "std.sort descending" {1058test "std.sort descending" {
1064 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1065 // TODO get this test passing
1066 // https://github.com/zig-lang/zig/issues/537
1067 return;
1068 }
1069 const rev_cases = [][]const []const i32 {1059 const rev_cases = [][]const []const i32 {
1070 [][]const i32{[]i32{}, []i32{}},1060 [][]const i32{[]i32{}, []i32{}},
1071 [][]const i32{[]i32{1}, []i32{1}},1061 [][]const i32{[]i32{1}, []i32{1}},
...@@ -1085,11 +1075,6 @@ test "std.sort descending" {...@@ -1085,11 +1075,6 @@ test "std.sort descending" {
1085}1075}
10861076
1087test "another sort case" {1077test "another sort case" {
1088 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1089 // TODO get this test passing
1090 // https://github.com/zig-lang/zig/issues/537
1091 return;
1092 }
1093 var arr = []i32{ 5, 3, 1, 2, 4 };1078 var arr = []i32{ 5, 3, 1, 2, 4 };
1094 sort(i32, arr[0..], i32asc);1079 sort(i32, arr[0..], i32asc);
10951080
...@@ -1097,11 +1082,6 @@ test "another sort case" {...@@ -1097,11 +1082,6 @@ test "another sort case" {
1097}1082}
10981083
1099test "sort fuzz testing" {1084test "sort fuzz testing" {
1100 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1101 // TODO get this test passing
1102 // https://github.com/zig-lang/zig/issues/537
1103 return;
1104 }
1105 var rng = std.rand.Rand.init(0x12345678);1085 var rng = std.rand.Rand.init(0x12345678);
1106 const test_case_count = 10;1086 const test_case_count = 10;
1107 var i: usize = 0;1087 var i: usize = 0;
std/special/bootstrap.zig+35-10
...@@ -21,8 +21,7 @@ comptime {...@@ -21,8 +21,7 @@ comptime {
21}21}
2222
23extern fn zenMain() -> noreturn {23extern fn zenMain() -> noreturn {
24 root.main() catch std.os.posix.exit(1);24 std.os.posix.exit(callMain());
25 std.os.posix.exit(0);
26}25}
2726
28nakedcc fn _start() -> noreturn {27nakedcc fn _start() -> noreturn {
...@@ -43,29 +42,55 @@ nakedcc fn _start() -> noreturn {...@@ -43,29 +42,55 @@ nakedcc fn _start() -> noreturn {
43extern fn WinMainCRTStartup() -> noreturn {42extern fn WinMainCRTStartup() -> noreturn {
44 @setAlignStack(16);43 @setAlignStack(16);
4544
46 root.main() catch std.os.windows.ExitProcess(1);45 std.os.windows.ExitProcess(callMain());
47 std.os.windows.ExitProcess(0);
48}46}
4947
50fn posixCallMainAndExit() -> noreturn {48fn posixCallMainAndExit() -> noreturn {
51 const argc = *argc_ptr;49 const argc = *argc_ptr;
52 const argv = @ptrCast(&&u8, &argc_ptr[1]);50 const argv = @ptrCast(&&u8, &argc_ptr[1]);
53 const envp = @ptrCast(&?&u8, &argv[argc + 1]);51 const envp = @ptrCast(&?&u8, &argv[argc + 1]);
54 callMain(argc, argv, envp) catch std.os.posix.exit(1);52 std.os.posix.exit(callMainWithArgs(argc, argv, envp));
55 std.os.posix.exit(0);
56}53}
5754
58fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {55fn callMainWithArgs(argc: usize, argv: &&u8, envp: &?&u8) -> u8 {
59 std.os.ArgIteratorPosix.raw = argv[0..argc];56 std.os.ArgIteratorPosix.raw = argv[0..argc];
6057
61 var env_count: usize = 0;58 var env_count: usize = 0;
62 while (envp[env_count] != null) : (env_count += 1) {}59 while (envp[env_count] != null) : (env_count += 1) {}
63 std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count];60 std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count];
6461
65 return root.main();62 return callMain();
66}63}
6764
68extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {65extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {
69 callMain(usize(c_argc), c_argv, c_envp) catch return 1;66 return callMainWithArgs(usize(c_argc), c_argv, c_envp);
70 return 0;67}
68
69fn 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,7 +14,7 @@ pub fn main() -> %void {
14 var arg_it = os.args();14 var arg_it = os.args();
1515
16 // TODO use a more general purpose allocator here16 // 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 defer inc_allocator.deinit();18 defer inc_allocator.deinit();
1919
20 const allocator = &inc_allocator.allocator;20 const allocator = &inc_allocator.allocator;
...@@ -107,12 +107,12 @@ pub fn main() -> %void {...@@ -107,12 +107,12 @@ pub fn main() -> %void {
107 return usageAndErr(&builder, false, try stderr_stream);107 return usageAndErr(&builder, false, try stderr_stream);
108 }108 }
109 } else {109 } else {
110 targets.append(arg) catch unreachable;110 try targets.append(arg);
111 }111 }
112 }112 }
113113
114 builder.setInstallPrefix(prefix);114 builder.setInstallPrefix(prefix);
115 root.build(&builder);115 try root.build(&builder);
116116
117 if (builder.validateUserInputDidItFail())117 if (builder.validateUserInputDidItFail())
118 return usageAndErr(&builder, true, try stderr_stream);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,7 +129,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
129 // run the build script to collect the options129 // run the build script to collect the options
130 if (!already_ran_build) {130 if (!already_ran_build) {
131 builder.setInstallPrefix(null);131 builder.setInstallPrefix(null);
132 root.build(builder);132 try root.build(builder);
133 }133 }
134134
135 // This usage text has to be synchronized with src/main.cpp135 // 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,7 +5,7 @@ const builtin = @import("builtin");
55
6// Avoid dragging in the debug safety mechanisms into this .o file,6// Avoid dragging in the debug safety mechanisms into this .o file,
7// unless we're trying to test this file.7// unless we're trying to test this file.
8pub coldcc fn panic(msg: []const u8) -> noreturn {8pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
9 if (builtin.is_test) {9 if (builtin.is_test) {
10 @import("std").debug.panic("{}", msg);10 @import("std").debug.panic("{}", msg);
11 } else {11 } else {
std/special/compiler_rt/index.zig+1-1
...@@ -74,7 +74,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;...@@ -74,7 +74,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
7474
75// Avoid dragging in the debug safety mechanisms into this .o file,75// Avoid dragging in the debug safety mechanisms into this .o file,
76// unless we're trying to test this file.76// unless we're trying to test this file.
77pub coldcc fn panic(msg: []const u8) -> noreturn {77pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
78 if (is_test) {78 if (is_test) {
79 @import("std").debug.panic("{}", msg);79 @import("std").debug.panic("{}", msg);
80 } else {80 } else {
std/special/panic.zig+5-1
...@@ -4,14 +4,18 @@...@@ -4,14 +4,18 @@
4// have to be added in the compiler.4// have to be added in the compiler.
55
6const builtin = @import("builtin");6const builtin = @import("builtin");
7const std = @import("std");
78
8pub coldcc fn panic(msg: []const u8) -> noreturn {9pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
9 switch (builtin.os) {10 switch (builtin.os) {
10 // TODO: fix panic in zen.11 // TODO: fix panic in zen.
11 builtin.Os.freestanding, builtin.Os.zen => {12 builtin.Os.freestanding, builtin.Os.zen => {
12 while (true) {}13 while (true) {}
13 },14 },
14 else => {15 else => {
16 if (error_return_trace) |trace| {
17 @import("std").debug.panicWithTrace(trace, "{}", msg);
18 }
15 @import("std").debug.panic("{}", msg);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,10 +8,7 @@ pub fn main() -> %void {
8 for (test_fn_list) |test_fn, i| {8 for (test_fn_list) |test_fn, i| {
9 warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);9 warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);
1010
11 test_fn.func() catch |err| {11 try test_fn.func();
12 warn("{}\n", err);
13 return err;
14 };
1512
16 warn("OK\n");13 warn("OK\n");
17 }14 }
test/build_examples.zig+1
...@@ -16,4 +16,5 @@ pub fn addCases(cases: &tests.BuildExamplesContext) {...@@ -16,4 +16,5 @@ pub fn addCases(cases: &tests.BuildExamplesContext) {
16 cases.addBuildFile("test/standalone/issue_339/build.zig");16 cases.addBuildFile("test/standalone/issue_339/build.zig");
17 cases.addBuildFile("test/standalone/pkg_import/build.zig");17 cases.addBuildFile("test/standalone/pkg_import/build.zig");
18 cases.addBuildFile("test/standalone/use_alias/build.zig");18 cases.addBuildFile("test/standalone/use_alias/build.zig");
19 cases.addBuildFile("test/standalone/brace_expansion/build.zig");
19}20}
test/compile_errors.zig+9-9
...@@ -1,6 +1,15 @@...@@ -1,6 +1,15 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.CompileErrorContext) {3pub 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 cases.add("bad identifier in function with struct defined inside function which references local const",13 cases.add("bad identifier in function with struct defined inside function which references local const",
5 \\export fn entry() {14 \\export fn entry() {
6 \\ const BlockKind = u32;15 \\ const BlockKind = u32;
...@@ -1059,15 +1068,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1059,15 +1068,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1059 ,1068 ,
1060 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'");1069 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'");
10611070
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 cases.add("invalid pointer for var type",1071 cases.add("invalid pointer for var type",
1072 \\extern fn ext() -> usize;1072 \\extern fn ext() -> usize;
1073 \\var bytes: [ext()]u8 = undefined;1073 \\var bytes: [ext()]u8 = undefined;
test/debug_safety.zig+20-20
...@@ -2,7 +2,7 @@ const tests = @import("tests.zig");...@@ -2,7 +2,7 @@ const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.CompareOutputContext) {3pub fn addCases(cases: &tests.CompareOutputContext) {
4 cases.addDebugSafety("calling panic",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 \\ @import("std").os.exit(126);6 \\ @import("std").os.exit(126);
7 \\}7 \\}
8 \\pub fn main() -> %void {8 \\pub fn main() -> %void {
...@@ -11,7 +11,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -11,7 +11,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
11 );11 );
1212
13 cases.addDebugSafety("out of bounds slice access",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 \\ @import("std").os.exit(126);15 \\ @import("std").os.exit(126);
16 \\}16 \\}
17 \\pub fn main() -> %void {17 \\pub fn main() -> %void {
...@@ -25,7 +25,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -25,7 +25,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
25 );25 );
2626
27 cases.addDebugSafety("integer addition overflow",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 \\ @import("std").os.exit(126);29 \\ @import("std").os.exit(126);
30 \\}30 \\}
31 \\error Whatever;31 \\error Whatever;
...@@ -39,7 +39,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -39,7 +39,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
39 );39 );
4040
41 cases.addDebugSafety("integer subtraction overflow",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 \\ @import("std").os.exit(126);43 \\ @import("std").os.exit(126);
44 \\}44 \\}
45 \\error Whatever;45 \\error Whatever;
...@@ -53,7 +53,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -53,7 +53,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
53 );53 );
5454
55 cases.addDebugSafety("integer multiplication overflow",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 \\ @import("std").os.exit(126);57 \\ @import("std").os.exit(126);
58 \\}58 \\}
59 \\error Whatever;59 \\error Whatever;
...@@ -67,7 +67,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -67,7 +67,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
67 );67 );
6868
69 cases.addDebugSafety("integer negation overflow",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 \\ @import("std").os.exit(126);71 \\ @import("std").os.exit(126);
72 \\}72 \\}
73 \\error Whatever;73 \\error Whatever;
...@@ -81,7 +81,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -81,7 +81,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
81 );81 );
8282
83 cases.addDebugSafety("signed integer division overflow",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 \\ @import("std").os.exit(126);85 \\ @import("std").os.exit(126);
86 \\}86 \\}
87 \\error Whatever;87 \\error Whatever;
...@@ -95,7 +95,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -95,7 +95,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
95 );95 );
9696
97 cases.addDebugSafety("signed shift left overflow",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 \\ @import("std").os.exit(126);99 \\ @import("std").os.exit(126);
100 \\}100 \\}
101 \\error Whatever;101 \\error Whatever;
...@@ -109,7 +109,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -109,7 +109,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
109 );109 );
110110
111 cases.addDebugSafety("unsigned shift left overflow",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 \\ @import("std").os.exit(126);113 \\ @import("std").os.exit(126);
114 \\}114 \\}
115 \\error Whatever;115 \\error Whatever;
...@@ -123,7 +123,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -123,7 +123,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
123 );123 );
124124
125 cases.addDebugSafety("signed shift right overflow",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 \\ @import("std").os.exit(126);127 \\ @import("std").os.exit(126);
128 \\}128 \\}
129 \\error Whatever;129 \\error Whatever;
...@@ -137,7 +137,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -137,7 +137,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
137 );137 );
138138
139 cases.addDebugSafety("unsigned shift right overflow",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 \\ @import("std").os.exit(126);141 \\ @import("std").os.exit(126);
142 \\}142 \\}
143 \\error Whatever;143 \\error Whatever;
...@@ -151,7 +151,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -151,7 +151,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
151 );151 );
152152
153 cases.addDebugSafety("integer division by zero",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 \\ @import("std").os.exit(126);155 \\ @import("std").os.exit(126);
156 \\}156 \\}
157 \\error Whatever;157 \\error Whatever;
...@@ -164,7 +164,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -164,7 +164,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
164 );164 );
165165
166 cases.addDebugSafety("exact division failure",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 \\ @import("std").os.exit(126);168 \\ @import("std").os.exit(126);
169 \\}169 \\}
170 \\error Whatever;170 \\error Whatever;
...@@ -178,7 +178,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -178,7 +178,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
178 );178 );
179179
180 cases.addDebugSafety("cast []u8 to bigger slice of wrong size",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 \\ @import("std").os.exit(126);182 \\ @import("std").os.exit(126);
183 \\}183 \\}
184 \\error Whatever;184 \\error Whatever;
...@@ -192,7 +192,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -192,7 +192,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
192 );192 );
193193
194 cases.addDebugSafety("value does not fit in shortening cast",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 \\ @import("std").os.exit(126);196 \\ @import("std").os.exit(126);
197 \\}197 \\}
198 \\error Whatever;198 \\error Whatever;
...@@ -206,7 +206,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -206,7 +206,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
206 );206 );
207207
208 cases.addDebugSafety("signed integer not fitting in cast to unsigned integer",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 \\ @import("std").os.exit(126);210 \\ @import("std").os.exit(126);
211 \\}211 \\}
212 \\error Whatever;212 \\error Whatever;
...@@ -220,7 +220,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -220,7 +220,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
220 );220 );
221221
222 cases.addDebugSafety("unwrap error",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 \\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) {224 \\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) {
225 \\ @import("std").os.exit(126); // good225 \\ @import("std").os.exit(126); // good
226 \\ }226 \\ }
...@@ -236,7 +236,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -236,7 +236,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
236 );236 );
237237
238 cases.addDebugSafety("cast integer to error and no code matches",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 \\ @import("std").os.exit(126);240 \\ @import("std").os.exit(126);
241 \\}241 \\}
242 \\pub fn main() -> %void {242 \\pub fn main() -> %void {
...@@ -248,7 +248,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -248,7 +248,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
248 );248 );
249249
250 cases.addDebugSafety("@alignCast misaligned",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 \\ @import("std").os.exit(126);252 \\ @import("std").os.exit(126);
253 \\}253 \\}
254 \\error Wrong;254 \\error Wrong;
...@@ -265,7 +265,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -265,7 +265,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
265 );265 );
266266
267 cases.addDebugSafety("bad union field access",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 \\ @import("std").os.exit(126);269 \\ @import("std").os.exit(126);
270 \\}270 \\}
271 \\271 \\
test/standalone/brace_expansion/build.zig created+9
...@@ -0,0 +1,9 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: &Builder) -> %void {
4 const main = b.addTest("main.zig");
5 main.setBuildMode(b.standardReleaseOptions());
6
7 const test_step = b.step("test", "Test it");
8 test_step.dependOn(&main.step);
9}
test/standalone/brace_expansion/main.zig created+254
...@@ -0,0 +1,254 @@
1const std = @import("std");
2const io = std.io;
3const mem = std.mem;
4const debug = std.debug;
5const assert = debug.assert;
6const Buffer = std.Buffer;
7const ArrayList = std.ArrayList;
8
9error InvalidInput;
10error OutOfMem;
11
12const Token = union(enum) {
13 Word: []const u8,
14 OpenBrace,
15 CloseBrace,
16 Comma,
17 Eof,
18};
19
20var global_allocator: &mem.Allocator = undefined;
21
22fn tokenize(input:[] const u8) -> %ArrayList(Token) {
23 const State = enum {
24 Start,
25 Word,
26 };
27
28 var token_list = ArrayList(Token).init(global_allocator);
29 var tok_begin: usize = undefined;
30 var state = State.Start;
31
32 for (input) |b, i| {
33 switch (state) {
34 State.Start => switch (b) {
35 'a'...'z', 'A'...'Z' => {
36 state = State.Word;
37 tok_begin = i;
38 },
39 '{' => try token_list.append(Token.OpenBrace),
40 '}' => try token_list.append(Token.CloseBrace),
41 ',' => try token_list.append(Token.Comma),
42 else => return error.InvalidInput,
43 },
44 State.Word => switch (b) {
45 'a'...'z', 'A'...'Z' => {},
46 '{', '}', ',' => {
47 try token_list.append(Token { .Word = input[tok_begin..i] });
48 switch (b) {
49 '{' => try token_list.append(Token.OpenBrace),
50 '}' => try token_list.append(Token.CloseBrace),
51 ',' => try token_list.append(Token.Comma),
52 else => unreachable,
53 }
54 state = State.Start;
55 },
56 else => return error.InvalidInput,
57 },
58 }
59 }
60 switch (state) {
61 State.Start => {},
62 State.Word => try token_list.append(Token {.Word = input[tok_begin..] }),
63 }
64 try token_list.append(Token.Eof);
65 return token_list;
66}
67
68const Node = union(enum) {
69 Scalar: []const u8,
70 List: ArrayList(Node),
71 Combine: []Node,
72};
73
74fn parse(tokens: &const ArrayList(Token), token_index: &usize) -> %Node {
75 const first_token = tokens.items[*token_index];
76 *token_index += 1;
77
78 const result_node = switch (first_token) {
79 Token.Word => |word| Node { .Scalar = word },
80 Token.OpenBrace => blk: {
81 var list = ArrayList(Node).init(global_allocator);
82 while (true) {
83 try list.append(try parse(tokens, token_index));
84
85 const token = tokens.items[*token_index];
86 *token_index += 1;
87
88 switch (token) {
89 Token.CloseBrace => break,
90 Token.Comma => continue,
91 else => return error.InvalidInput,
92 }
93 }
94 break :blk Node { .List = list };
95 },
96 else => return error.InvalidInput,
97 };
98
99 switch (tokens.items[*token_index]) {
100 Token.Word, Token.OpenBrace => {
101 const pair = try global_allocator.alloc(Node, 2);
102 pair[0] = result_node;
103 pair[1] = try parse(tokens, token_index);
104 return Node { .Combine = pair };
105 },
106 else => return result_node,
107 }
108}
109
110fn expandString(input: []const u8, output: &Buffer) -> %void {
111 const tokens = try tokenize(input);
112 if (tokens.len == 1) {
113 return output.resize(0);
114 }
115
116 var token_index: usize = 0;
117 const root = try parse(tokens, &token_index);
118 const last_token = tokens.items[token_index];
119 switch (last_token) {
120 Token.Eof => {},
121 else => return error.InvalidInput,
122 }
123
124 var result_list = ArrayList(Buffer).init(global_allocator);
125 defer result_list.deinit();
126
127 try expandNode(root, &result_list);
128
129 try output.resize(0);
130 for (result_list.toSliceConst()) |buf, i| {
131 if (i != 0) {
132 try output.appendByte(' ');
133 }
134 try output.append(buf.toSliceConst());
135 }
136}
137
138const ListOfBuffer0 = ArrayList(Buffer); // TODO this is working around a compiler bug, fix and delete this
139
140fn expandNode(node: &const Node, output: &ListOfBuffer0) -> %void {
141 assert(output.len == 0);
142 switch (*node) {
143 Node.Scalar => |scalar| {
144 try output.append(try Buffer.init(global_allocator, scalar));
145 },
146 Node.Combine => |pair| {
147 const a_node = pair[0];
148 const b_node = pair[1];
149
150 var child_list_a = ArrayList(Buffer).init(global_allocator);
151 try expandNode(a_node, &child_list_a);
152
153 var child_list_b = ArrayList(Buffer).init(global_allocator);
154 try expandNode(b_node, &child_list_b);
155
156 for (child_list_a.toSliceConst()) |buf_a| {
157 for (child_list_b.toSliceConst()) |buf_b| {
158 var combined_buf = try Buffer.initFromBuffer(buf_a);
159 try combined_buf.append(buf_b.toSliceConst());
160 try output.append(combined_buf);
161 }
162 }
163 },
164 Node.List => |list| {
165 for (list.toSliceConst()) |child_node| {
166 var child_list = ArrayList(Buffer).init(global_allocator);
167 try expandNode(child_node, &child_list);
168
169 for (child_list.toSliceConst()) |buf| {
170 try output.append(buf);
171 }
172 }
173 },
174 }
175}
176
177pub fn main() -> %void {
178 var stdin_file = try io.getStdIn();
179 var stdout_file = try io.getStdOut();
180
181 var inc_allocator = try std.heap.IncrementingAllocator.init(2 * 1024 * 1024);
182 defer inc_allocator.deinit();
183
184 global_allocator = &inc_allocator.allocator;
185
186 var stdin_buf = try Buffer.initSize(global_allocator, 0);
187 defer stdin_buf.deinit();
188
189 var stdin_adapter = io.FileInStream.init(&stdin_file);
190 try stdin_adapter.stream.readAllBuffer(&stdin_buf, @maxValue(usize));
191
192 var result_buf = try Buffer.initSize(global_allocator, 0);
193 defer result_buf.deinit();
194
195 try expandString(stdin_buf.toSlice(), &result_buf);
196 try stdout_file.write(result_buf.toSliceConst());
197}
198
199test "invalid inputs" {
200 global_allocator = std.debug.global_allocator;
201
202 expectError("}ABC", error.InvalidInput);
203 expectError("{ABC", error.InvalidInput);
204 expectError("}{", error.InvalidInput);
205 expectError("{}", error.InvalidInput);
206 expectError("A,B,C", error.InvalidInput);
207 expectError("{A{B,C}", error.InvalidInput);
208 expectError("{A,}", error.InvalidInput);
209
210 expectError("\n", error.InvalidInput);
211}
212
213fn expectError(test_input: []const u8, expected_err: error) {
214 var output_buf = Buffer.initSize(global_allocator, 0) catch unreachable;
215 defer output_buf.deinit();
216
217 if (expandString("}ABC", &output_buf)) {
218 unreachable;
219 } else |err| {
220 assert(expected_err == err);
221 }
222}
223
224test "valid inputs" {
225 global_allocator = std.debug.global_allocator;
226
227 expectExpansion("{x,y,z}", "x y z");
228 expectExpansion("{A,B}{x,y}", "Ax Ay Bx By");
229 expectExpansion("{A,B{x,y}}", "A Bx By");
230
231 expectExpansion("{ABC}", "ABC");
232 expectExpansion("{A,B,C}", "A B C");
233 expectExpansion("ABC", "ABC");
234
235 expectExpansion("", "");
236 expectExpansion("{A,B}{C,{x,y}}{g,h}", "ACg ACh Axg Axh Ayg Ayh BCg BCh Bxg Bxh Byg Byh");
237 expectExpansion("{A,B}{C,C{x,y}}{g,h}", "ACg ACh ACxg ACxh ACyg ACyh BCg BCh BCxg BCxh BCyg BCyh");
238 expectExpansion("{A,B}a", "Aa Ba");
239 expectExpansion("{C,{x,y}}", "C x y");
240 expectExpansion("z{C,{x,y}}", "zC zx zy");
241 expectExpansion("a{b,c{d,e{f,g}}}", "ab acd acef aceg");
242 expectExpansion("a{x,y}b", "axb ayb");
243 expectExpansion("z{{a,b}}", "za zb");
244 expectExpansion("a{b}", "ab");
245}
246
247fn expectExpansion(test_input: []const u8, expected_result: []const u8) {
248 var result = Buffer.initSize(global_allocator, 0) catch unreachable;
249 defer result.deinit();
250
251 expandString(test_input, &result) catch unreachable;
252
253 assert(mem.eql(u8, result.toSlice(), expected_result));
254}
test/standalone/issue_339/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {3pub fn build(b: &Builder) -> %void {
4 const obj = b.addObject("test", "test.zig");4 const obj = b.addObject("test", "test.zig");
55
6 const test_step = b.step("test", "Test the program");6 const test_step = b.step("test", "Test the program");
test/standalone/issue_339/test.zig+2-1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1pub fn panic(msg: []const u8) -> noreturn { @breakpoint(); while (true) {} }1const StackTrace = @import("builtin").StackTrace;
2pub fn panic(msg: []const u8, stack_trace: ?&StackTrace) -> noreturn { @breakpoint(); while (true) {} }
23
3fn bar() -> %void {}4fn bar() -> %void {}
45
test/standalone/pkg_import/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {3pub fn build(b: &Builder) -> %void {
4 const exe = b.addExecutable("test", "test.zig");4 const exe = b.addExecutable("test", "test.zig");
5 exe.addPackagePath("my_pkg", "pkg.zig");5 exe.addPackagePath("my_pkg", "pkg.zig");
66
test/standalone/use_alias/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {3pub fn build(b: &Builder) -> %void {
4 b.addCIncludePath(".");4 b.addCIncludePath(".");
55
6 const main = b.addTest("main.zig");6 const main = b.addTest("main.zig");
test/tests.zig+2-7
...@@ -42,14 +42,10 @@ const test_targets = []TestTarget {...@@ -42,14 +42,10 @@ const test_targets = []TestTarget {
42 .arch = builtin.Arch.x86_64,42 .arch = builtin.Arch.x86_64,
43 .environ = builtin.Environ.msvc,43 .environ = builtin.Environ.msvc,
44 },44 },
45 TestTarget {
46 .os = builtin.Os.windows,
47 .arch = builtin.Arch.i386,
48 .environ = builtin.Environ.msvc,
49 },
50};45};
5146
52error TestFailed;47error TestFailed;
48error CompilationIncorrectlySucceeded;
5349
54const max_stdout_size = 1 * 1024 * 1024; // 1 MB50const max_stdout_size = 1 * 1024 * 1024; // 1 MB
5551
...@@ -607,8 +603,7 @@ pub const CompileErrorContext = struct {...@@ -607,8 +603,7 @@ pub const CompileErrorContext = struct {
607 switch (term) {603 switch (term) {
608 Term.Exited => |code| {604 Term.Exited => |code| {
609 if (code == 0) {605 if (code == 0) {
610 warn("Compilation incorrectly succeeded\n");606 return error.CompilationIncorrectlySucceeded;
611 return error.TestFailed;
612 }607 }
613 },608 },
614 else => {609 else => {