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.
5454
5555| | freestanding | linux | macosx | windows | other |
5656|-------------|--------------|---------|---------|---------|---------|
57|i386 | OK | planned | OK | OK | planned |
57|i386 | OK | planned | OK | planned | planned |
5858|x86_64 | OK | OK | OK | OK | planned |
5959|arm | OK | planned | planned | N/A | planned |
6060|aarch64 | OK | planned | planned | planned | planned |
build.zig+6-6
......@@ -10,7 +10,7 @@ const ArrayList = std.ArrayList;
1010const Buffer = std.Buffer;
1111const io = std.io;
1212
13pub fn build(b: &Builder) {
13pub fn build(b: &Builder) -> %void {
1414 const mode = b.standardReleaseOptions();
1515
1616 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
......@@ -36,7 +36,7 @@ pub fn build(b: &Builder) {
3636 const test_step = b.step("test", "Run all the tests");
3737
3838 // 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"});
4040 var index: usize = 0;
4141 const cmake_binary_dir = nextValue(&index, build_info);
4242 const cxx_compiler = nextValue(&index, build_info);
......@@ -68,7 +68,7 @@ pub fn build(b: &Builder) {
6868 dependOnLib(exe, llvm);
6969
7070 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"});
7272 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();
7373 exe.addObjectFile(libstdcxx_path);
7474
......@@ -155,9 +155,9 @@ const LibraryDep = struct {
155155};
156156
157157fn findLLVM(b: &Builder, llvm_config_exe: []const u8) -> %LibraryDep {
158 const libs_output = b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
159 const includes_output = b.exec([][]const u8{llvm_config_exe, "--includedir"});
160 const libdir_output = b.exec([][]const u8{llvm_config_exe, "--libdir"});
158 const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
159 const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"});
160 const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"});
161161
162162 var result = LibraryDep {
163163 .libs = ArrayList([]const u8).init(b.allocator),
doc/langref.html.in+8
......@@ -142,6 +142,7 @@
142142 <li><a href="#builtin-TagType">@TagType</a></li>
143143 <li><a href="#builtin-EnumTagType">@EnumTagType</a></li>
144144 <li><a href="#builtin-errorName">@errorName</a></li>
145 <li><a href="#builtin-errorReturnTrace">@errorReturnTrace</a></li>
145146 <li><a href="#builtin-fence">@fence</a></li>
146147 <li><a href="#builtin-fieldParentPtr">@fieldParentPtr</a></li>
147148 <li><a href="#builtin-frameAddress">@frameAddress</a></li>
......@@ -4412,6 +4413,13 @@ test.zig:6:2: error: found compile log statement
44124413 or all calls have a compile-time known value for <code>err</code>, then no
44134414 error name table will be generated.
44144415 </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>
44154423 <h3 id="builtin-fence">@fence</h3>
44164424 <pre><code class="zig">@fence(order: AtomicOrder)</code></pre>
44174425 <p>
example/mix_o_files/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {
3pub fn build(b: &Builder) -> %void {
44 const obj = b.addObject("base64", "base64.zig");
55
66 const exe = b.addCExecutable("test");
example/shared_library/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {
3pub fn build(b: &Builder) -> %void {
44 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
55
66 const exe = b.addCExecutable("test");
src-self-hosted/parser.zig-6
......@@ -1146,12 +1146,6 @@ fn testCanonical(source: []const u8) {
11461146}
11471147
11481148test "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
11551149 testCanonical(
11561150 \\extern fn puts(s: &const u8) -> c_int;
11571151 \\
src/all_types.hpp+13
......@@ -1205,6 +1205,7 @@ struct FnTableEntry {
12051205 uint32_t alignstack_value;
12061206
12071207 ZigList<FnExport> export_list;
1208 bool calls_errorable_function;
12081209};
12091210
12101211uint32_t fn_table_entry_hash(FnTableEntry*);
......@@ -1273,6 +1274,7 @@ enum BuiltinFnId {
12731274 BuiltinFnIdSetAlignStack,
12741275 BuiltinFnIdArgType,
12751276 BuiltinFnIdExport,
1277 BuiltinFnIdErrorReturnTrace,
12761278};
12771279
12781280struct BuiltinFnEntry {
......@@ -1498,6 +1500,7 @@ struct CodeGen {
14981500 Buf triple_str;
14991501 BuildMode build_mode;
15001502 bool is_test_build;
1503 bool have_err_ret_tracing;
15011504 uint32_t target_os_index;
15021505 uint32_t target_arch_index;
15031506 uint32_t target_environ_index;
......@@ -1530,6 +1533,7 @@ struct CodeGen {
15301533 FnTableEntry *panic_fn;
15311534 LLVMValueRef cur_ret_ptr;
15321535 LLVMValueRef cur_fn_val;
1536 LLVMValueRef cur_err_ret_trace_val;
15331537 bool c_want_stdint;
15341538 bool c_want_stdbool;
15351539 AstNode *root_export_decl;
......@@ -1572,6 +1576,8 @@ struct CodeGen {
15721576 size_t largest_err_name_len;
15731577 LLVMValueRef safety_crash_err_fn;
15741578
1579 LLVMValueRef return_err_fn;
1580
15751581 IrInstruction *invalid_instruction;
15761582 ConstExprValue const_void_val;
15771583
......@@ -1595,6 +1601,8 @@ struct CodeGen {
15951601 ZigList<AstNode *> tld_ref_source_node_stack;
15961602
15971603 TypeTableEntry *align_amt_type;
1604 TypeTableEntry *stack_trace_type;
1605 TypeTableEntry *ptr_to_stack_trace_type;
15981606};
15991607
16001608enum VarLinkage {
......@@ -1896,6 +1904,7 @@ enum IrInstructionId {
18961904 IrInstructionIdSetAlignStack,
18971905 IrInstructionIdArgType,
18981906 IrInstructionIdExport,
1907 IrInstructionIdErrorReturnTrace,
18991908};
19001909
19011910struct IrInstruction {
......@@ -2717,6 +2726,10 @@ struct IrInstructionExport {
27172726 IrInstruction *target;
27182727};
27192728
2729struct IrInstructionErrorReturnTrace {
2730 IrInstruction base;
2731};
2732
27202733static const size_t slice_ptr_index = 0;
27212734static 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) {
869869 zig_unreachable();
870870}
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
872882TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
873883 auto table_entry = g->fn_type_table.maybe_get(fn_type_id);
874884 if (table_entry) {
......@@ -915,10 +925,16 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
915925 if (!skip_debug_info) {
916926 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&
917927 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);
918931 // +1 for maybe making the first argument the return value
919 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count);
920 // +1 because 0 is the return type and +1 for maybe making first arg ret val
921 ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(2 + fn_type_id->param_count);
932 // +1 for maybe last argument the error return trace
933 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(2 + fn_type_id->param_count);
934 // +1 because 0 is the return type and
935 // +1 for maybe making first arg ret val and
936 // +1 for maybe last argument the error return trace
937 ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(3 + fn_type_id->param_count);
922938 param_di_types[0] = fn_type_id->return_type->di_type;
923939 size_t gen_param_index = 0;
924940 TypeTableEntry *gen_return_type;
......@@ -936,6 +952,14 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
936952 }
937953 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
939963 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
940964 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
941965 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
11681192 }
11691193
11701194 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 }
11711198 if (fn_type_id.cc != CallingConventionUnspecified) {
11721199 type_ensure_zero_bits_known(g, type_entry);
11731200 if (!type_has_bits(type_entry)) {
......@@ -2204,6 +2231,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
22042231 // is a pointer to this very struct, or a function pointer with parameters that
22052232 // reference such a type.
22062233 union_type->data.unionation.zero_bits_known = true;
2234 union_type->data.unionation.zero_bits_loop_flag = false;
22072235 if (union_type->data.unionation.abi_alignment == 0) {
22082236 if (union_type->data.unionation.layout == ContainerLayoutPacked) {
22092237 union_type->data.unionation.abi_alignment = 1;
......@@ -2558,7 +2586,7 @@ static bool scope_is_root_decls(Scope *scope) {
25582586
25592587static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, TypeTableEntry *fn_type) {
25602588 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'",
25622590 buf_ptr(&fn_type->name)));
25632591}
25642592
......@@ -2567,7 +2595,7 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
25672595 assert(proto_node->type == NodeTypeFnProto);
25682596 TypeTableEntry *fn_type = panic_fn->type_entry;
25692597 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) {
25712599 return wrong_panic_prototype(g, proto_node, fn_type);
25722600 }
25732601 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) {
25762604 return wrong_panic_prototype(g, proto_node, fn_type);
25772605 }
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
25792612 TypeTableEntry *actual_return_type = fn_type_id->return_type;
25802613 if (actual_return_type != g->builtin_types.entry_unreachable) {
25812614 return wrong_panic_prototype(g, proto_node, fn_type);
......@@ -2680,13 +2713,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
26802713 {
26812714 if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {
26822715 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 }
26902716 } else if ((import->package == g->panic_package || g->have_pub_panic) &&
26912717 buf_eql_str(&fn_table_entry->symbol_name, "panic"))
26922718 {
......@@ -5527,3 +5553,13 @@ bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) {
55275553 return a == b;
55285554}
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);
185185Buf *const_value_to_buffer(ConstExprValue *const_val);
186186void 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
188193#endif
src/codegen.cpp+231-16
......@@ -404,6 +404,19 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
404404 zig_unreachable();
405405}
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
407420static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
408421 if (fn_table_entry->llvm_value)
409422 return fn_table_entry->llvm_value;
......@@ -483,7 +496,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
483496 LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true);
484497 }
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) {
487501 addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn");
488502 }
489503
......@@ -520,13 +534,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
520534 // use the ABI alignment, which is fine.
521535 }
522536
523 if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {
537 if (!type_has_bits(return_type)) {
524538 // nothing to do
525 } else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer ||
526 fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdFn)
527 {
539 } else if (return_type->id == TypeTableEntryIdPointer || return_type->id == TypeTableEntryIdFn) {
528540 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) &&
530542 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
531543 {
532544 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
......@@ -563,6 +575,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
563575 }
564576 }
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
566583 return fn_table_entry->llvm_value;
567584}
568585
......@@ -864,16 +881,25 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
864881 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));
865882}
866883
867static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {
884static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {
868885 assert(g->panic_fn != nullptr);
869886 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
870887 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);
872898 LLVMBuildUnreachable(g->builder);
873899}
874900
875901static 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);
877903}
878904
879905static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
......@@ -895,6 +921,87 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
895921 return g->memcpy_fn_val;
896922}
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
8981005static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
8991006 if (g->safety_crash_err_fn != nullptr)
9001007 return g->safety_crash_err_fn;
......@@ -953,7 +1060,11 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
9531060 LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_array, offset_ptr_indices, 2);
9541061
9551062 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);
9571068 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
9581069 addLLVMFnAttr(fn_val, "noreturn");
9591070 addLLVMFnAttr(fn_val, "cold");
......@@ -975,7 +1086,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
9751086 LLVMPositionBuilderAtEnd(g->builder, entry_block);
9761087 ZigLLVMClearCurrentDebugLocation(g->builder);
9771088
978 LLVMValueRef err_val = LLVMGetParam(fn_val, 0);
1089 LLVMValueRef err_val = LLVMGetParam(fn_val, 1);
9791090
9801091 LLVMValueRef err_table_indices[] = {
9811092 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
......@@ -1005,7 +1116,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
10051116 LLVMValueRef global_slice_len_field_ptr = LLVMBuildStructGEP(g->builder, global_slice, slice_len_index, "");
10061117 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
10101121 LLVMPositionBuilderAtEnd(g->builder, prev_block);
10111122 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
......@@ -1016,8 +1127,18 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
10161127
10171128static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
10181129 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),
10201140 ZigLLVM_FnInlineAuto, "");
1141 LLVMSetTailCall(call_instruction, true);
10211142 LLVMBuildUnreachable(g->builder);
10221143}
10231144
......@@ -1296,6 +1417,35 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
12961417static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
12971418 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
12981419 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 }
12991449 if (handle_is_ptr(return_type)) {
13001450 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
13011451 assert(g->cur_ret_ptr);
......@@ -2330,7 +2480,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
23302480 TypeTableEntry *src_return_type = fn_type_id->return_type;
23312481 bool ret_has_bits = type_has_bits(src_return_type);
23322482 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);
23342485 bool is_var_args = fn_type_id->is_var_args;
23352486 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
23362487 size_t gen_param_index = 0;
......@@ -2338,6 +2489,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
23382489 gen_param_values[gen_param_index] = instruction->tmp_ptr;
23392490 gen_param_index += 1;
23402491 }
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 }
23412496 for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
23422497 IrInstruction *param_instruction = instruction->args[call_i];
23432498 TypeTableEntry *param_type = param_instruction->value.type;
......@@ -2881,6 +3036,16 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
28813036 return target_val;
28823037}
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
28843049static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
28853050 switch (atomic_order) {
28863051 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
......@@ -3474,7 +3639,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
34743639}
34753640
34763641static 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);
34783643 return nullptr;
34793644}
34803645
......@@ -3654,6 +3819,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
36543819 return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction);
36553820 case IrInstructionIdAlignCast:
36563821 return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);
3822 case IrInstructionIdErrorReturnTrace:
3823 return ir_render_error_return_trace(g, executable, (IrInstructionErrorReturnTrace *)instruction);
36573824 }
36583825 zig_unreachable();
36593826}
......@@ -4493,7 +4660,8 @@ static void do_code_gen(CodeGen *g) {
44934660 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
44944661 g->cur_fn = fn_table_entry;
44954662 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)) {
44974665 g->cur_ret_ptr = LLVMGetParam(fn, 0);
44984666 } else {
44994667 g->cur_ret_ptr = nullptr;
......@@ -4502,6 +4670,42 @@ static void do_code_gen(CodeGen *g) {
45024670 build_all_basic_blocks(g, fn_table_entry);
45034671 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
45054709 // allocate temporary stack data
45064710 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {
45074711 IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);
......@@ -5064,6 +5268,7 @@ static void define_builtin_fns(CodeGen *g) {
50645268 create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);
50655269 create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2);
50665270 create_builtin_fn(g, BuiltinFnIdExport, "export", 3);
5271 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
50675272}
50685273
50695274static const char *bool_to_str(bool b) {
......@@ -5088,6 +5293,12 @@ static void define_builtin_compile_vars(CodeGen *g) {
50885293 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
50895294 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
50915302 const char *cur_os = nullptr;
50925303 {
50935304 buf_appendf(contents, "pub const Os = enum {\n");
......@@ -5233,6 +5444,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
52335444 buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
52345445 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
52355446 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
52375449 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) {
52515463 g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
52525464 g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
52535465 g->compile_var_import = add_source_file(g, g->compile_var_package, abs_full_path, contents);
5466 scan_import(g, g->compile_var_import);
52545467}
52555468
52565469static void init(CodeGen *g) {
......@@ -5359,6 +5572,8 @@ static void init(CodeGen *g) {
53595572 }
53605573 }
53615574
5575 g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease;
5576
53625577 define_builtin_fns(g);
53635578 define_builtin_compile_vars(g);
53645579}
src/ir.cpp+49-12
......@@ -572,6 +572,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArgType *) {
572572 return IrInstructionIdArgType;
573573}
574574
575static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace *) {
576 return IrInstructionIdErrorReturnTrace;
577}
578
575579template<typename T>
576580static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
577581 T *special_instruction = allocate<T>(1);
......@@ -2305,6 +2309,12 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s
23052309 return &instruction->base;
23062310}
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
23082318static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
23092319 results[ReturnKindUnconditional] = 0;
23102320 results[ReturnKindError] = 0;
......@@ -3731,6 +3741,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37313741
37323742 return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value);
37333743 }
3744 case BuiltinFnIdErrorReturnTrace:
3745 {
3746 return ir_build_error_return_trace(irb, scope, node);
3747 }
37343748 }
37353749 zig_unreachable();
37363750}
......@@ -8230,16 +8244,6 @@ static bool ir_resolve_comptime(IrAnalyze *ira, IrInstruction *value, bool *out)
82308244 return ir_resolve_bool(ira, value, out);
82318245}
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
82438247static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) {
82448248 if (type_is_invalid(value->value.type))
82458249 return false;
......@@ -9578,6 +9582,24 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
95789582 return ira->codegen->builtin_types.entry_void;
95799583}
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
95819603static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
95829604 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
95839605{
......@@ -9836,7 +9858,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
98369858
98379859 if (fn_proto_node->data.fn_proto.is_var_args) {
98389860 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"));
98409862 return ira->codegen->builtin_types.entry_invalid;
98419863 }
98429864
......@@ -10053,9 +10075,21 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1005310075 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
1005410076 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
1005610082 return ir_finish_anal(ira, return_type);
1005710083 }
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
1005910093 IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
1006010094 size_t next_arg_index = 0;
1006110095 if (first_arg_ptr) {
......@@ -13977,7 +14011,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
1397714011 return ira->codegen->builtin_types.entry_invalid;
1397814012 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);
1398114015 if (type_is_invalid(type_entry))
1398214016 return ira->codegen->builtin_types.entry_invalid;
1398314017
......@@ -15322,6 +15356,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1532215356 return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction);
1532315357 case IrInstructionIdExport:
1532415358 return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction);
15359 case IrInstructionIdErrorReturnTrace:
15360 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);
1532515361 }
1532615362 zig_unreachable();
1532715363}
......@@ -15505,6 +15541,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1550515541 case IrInstructionIdOpaqueType:
1550615542 case IrInstructionIdArgType:
1550715543 case IrInstructionIdTagType:
15544 case IrInstructionIdErrorReturnTrace:
1550815545 return false;
1550915546 case IrInstructionIdAsm:
1551015547 {
src/ir_print.cpp+7
......@@ -996,6 +996,10 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {
996996 }
997997}
998998
999static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {
1000 fprintf(irp->f, "@errorReturnTrace()");
1001}
1002
9991003
10001004static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
10011005 ir_print_prefix(irp, instruction);
......@@ -1308,6 +1312,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
13081312 case IrInstructionIdExport:
13091313 ir_print_export(irp, (IrInstructionExport *)instruction);
13101314 break;
1315 case IrInstructionIdErrorReturnTrace:
1316 ir_print_error_return_trace(irp, (IrInstructionErrorReturnTrace *)instruction);
1317 break;
13111318 }
13121319 fprintf(irp->f, "\n");
13131320}
std/build.zig+4-6
......@@ -247,11 +247,11 @@ pub const Builder = struct {
247247 defer wanted_steps.deinit();
248248
249249 if (step_names.len == 0) {
250 wanted_steps.append(&self.default_step) catch unreachable;
250 try wanted_steps.append(&self.default_step);
251251 } else {
252252 for (step_names) |step_name| {
253253 const s = try self.getTopLevelStepByName(step_name);
254 wanted_steps.append(s) catch unreachable;
254 try wanted_steps.append(s);
255255 }
256256 }
257257
......@@ -721,11 +721,9 @@ pub const Builder = struct {
721721 return error.FileNotFound;
722722 }
723723
724 pub fn exec(self: &Builder, argv: []const []const u8) -> []u8 {
724 pub fn exec(self: &Builder, argv: []const []const u8) -> %[]u8 {
725725 const max_output_size = 100 * 1024;
726 const result = os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size) catch |err| {
727 std.debug.panic("Unable to spawn {}: {}", argv[0], @errorName(err));
728 };
726 const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size);
729727 switch (result.term) {
730728 os.ChildProcess.Term.Exited => |code| {
731729 if (code != 0) {
std/crypto/sha2.zig-40
......@@ -267,22 +267,12 @@ fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
267267};}
268268
269269test "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
275270 htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "");
276271 htest.assertEqualHash(Sha224, "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc");
277272 htest.assertEqualHash(Sha224, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
278273}
279274
280275test "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
286276 var h = Sha224.init();
287277 var out: [28]u8 = undefined;
288278
......@@ -303,22 +293,12 @@ test "sha224 streaming" {
303293}
304294
305295test "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
311296 htest.assertEqualHash(Sha256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "");
312297 htest.assertEqualHash(Sha256, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc");
313298 htest.assertEqualHash(Sha256, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
314299}
315300
316301test "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
322302 var h = Sha256.init();
323303 var out: [32]u8 = undefined;
324304
......@@ -622,11 +602,6 @@ fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
622602};}
623603
624604test "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
630605 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
631606 htest.assertEqualHash(Sha384, h1, "");
632607
......@@ -638,11 +613,6 @@ test "sha384 single" {
638613}
639614
640615test "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
646616 var h = Sha384.init();
647617 var out: [48]u8 = undefined;
648618
......@@ -666,11 +636,6 @@ test "sha384 streaming" {
666636}
667637
668638test "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
674639 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
675640 htest.assertEqualHash(Sha512, h1, "");
676641
......@@ -682,11 +647,6 @@ test "sha512 single" {
682647}
683648
684649test "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
690650 var h = Sha512.init();
691651 var out: [64]u8 = undefined;
692652
std/debug/index.zig+149-63
......@@ -13,6 +13,10 @@ pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
1313error MissingDebugInfo;
1414error InvalidDebugInfo;
1515error UnsupportedDebugInfo;
16error UnknownObjectFormat;
17error TodoSupportCoffDebugInfo;
18error TodoSupportMachoDebugInfo;
19error TodoSupportCOFFDebugInfo;
1620
1721
1822/// Tries to write to stderr, unbuffered, and ignores any error returned.
......@@ -37,10 +41,43 @@ fn getStderrStream() -> %&io.OutStream {
3741 }
3842}
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
4069/// 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) {
4271 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 };
4481}
4582
4683/// This function invokes undefined behavior when `ok` is `false`.
......@@ -88,7 +125,21 @@ pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
88125
89126 const stderr = getStderrStream() catch os.abort();
90127 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
93144 os.abort();
94145}
......@@ -101,12 +152,91 @@ const RESET = "\x1b[0m";
101152error PathNotFound;
102153error InvalidDebugInfo;
103154
104pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,
105 ignore_frame_count: usize) -> %void
155pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator,
156 debug_info: &ElfStackTrace, tty_color: bool) -> %void
106157{
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 {
107236 switch (builtin.object_format) {
108237 builtin.ObjectFormat.elf => {
109 var stack_trace = ElfStackTrace {
238 const st = try allocator.create(ElfStackTrace);
239 *st = ElfStackTrace {
110240 .self_exe_file = undefined,
111241 .elf = undefined,
112242 .debug_info = undefined,
......@@ -117,12 +247,11 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
117247 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
118248 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
119249 };
120 const st = &stack_trace;
121250 st.self_exe_file = try os.openSelfExe();
122 defer st.self_exe_file.close();
251 %defer st.self_exe_file.close();
123252
124253 try st.elf.openFile(allocator, &st.self_exe_file);
125 defer st.elf.close();
254 %defer st.elf.close();
126255
127256 st.debug_info = (try st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
128257 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
130259 st.debug_line = (try st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
131260 st.debug_ranges = (try st.elf.findSection(".debug_ranges"));
132261 try scanAllCompileUnits(st);
133
134 var ignored_count: usize = 0;
135
136 var fp = @ptrToInt(@frameAddress());
137 while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
138 if (ignored_count < ignore_frame_count) {
139 ignored_count += 1;
140 continue;
141 }
142
143 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
144
145 // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
146 // at compile time. I'll call it issue #313
147 const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
148
149 const compile_unit = findCompileUnit(st, return_address) catch {
150 try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
151 return_address);
152 continue;
153 };
154 const compile_unit_name = try compile_unit.die.getAttrString(st, DW.AT_name);
155 if (getLineNumberInfo(st, compile_unit, usize(return_address) - 1)) |line_info| {
156 defer line_info.deinit();
157 try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
158 DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
159 line_info.file_name, line_info.line, line_info.column,
160 return_address, compile_unit_name);
161 if (printLineFromFile(st.allocator(), out_stream, line_info)) {
162 if (line_info.column == 0) {
163 try out_stream.write("\n");
164 } else {
165 {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
166 try out_stream.writeByte(' ');
167 }}
168 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
169 }
170 } else |err| switch (err) {
171 error.EndOfFile, error.PathNotFound => {},
172 else => return err,
173 }
174 } else |err| switch (err) {
175 error.MissingDebugInfo, error.InvalidDebugInfo => {
176 try out_stream.print(ptr_hex ++ " in ??? ({})\n",
177 return_address, compile_unit_name);
178 },
179 else => return err,
180 }
181 }
262 return st;
182263 },
183264 builtin.ObjectFormat.coff => {
184 try out_stream.write("(stack trace unavailable for COFF object format)\n");
265 return error.TodoSupportCoffDebugInfo;
185266 },
186267 builtin.ObjectFormat.macho => {
187 try out_stream.write("(stack trace unavailable for Mach-O object format)\n");
268 return error.TodoSupportMachoDebugInfo;
188269 },
189270 builtin.ObjectFormat.wasm => {
190 try out_stream.write("(stack trace unavailable for WASM object format)\n");
271 return error.TodoSupportCOFFDebugInfo;
191272 },
192273 builtin.ObjectFormat.unknown => {
193 try out_stream.write("(stack trace unavailable for unknown object format)\n");
274 return error.UnknownObjectFormat;
194275 },
195276 }
196277}
......@@ -228,7 +309,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_
228309 }
229310}
230311
231const ElfStackTrace = struct {
312pub const ElfStackTrace = struct {
232313 self_exe_file: io.File,
233314 elf: elf.Elf,
234315 debug_info: &elf.SectionHeader,
......@@ -248,6 +329,11 @@ const ElfStackTrace = struct {
248329 const in_stream = &in_file_stream.stream;
249330 return readStringRaw(self.allocator(), in_stream);
250331 }
332
333 pub fn close(self: &ElfStackTrace) {
334 self.self_exe_file.close();
335 self.elf.close();
336 }
251337};
252338
253339const PcRange = struct {
std/io.zig+1-1
......@@ -224,7 +224,7 @@ pub const File = struct {
224224 };
225225 }
226226 },
227 else => @compileError("unsupported OS"),
227 else => @compileError("unsupported OS: " ++ @tagName(builtin.os)),
228228 }
229229 }
230230
std/io_test.zig-5
......@@ -8,11 +8,6 @@ const os = std.os;
88const builtin = @import("builtin");
99
1010test "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 }
1611 var data: [1024]u8 = undefined;
1712 var rng = Rand.init(1234);
1813 rng.fillBytes(data[0..]);
std/math/acosh.zig-5
......@@ -55,11 +55,6 @@ fn acosh64(x: f64) -> f64 {
5555}
5656
5757test "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 }
6358 assert(acosh(f32(1.5)) == acosh32(1.5));
6459 assert(acosh(f64(1.5)) == acosh64(1.5));
6560}
std/math/cos.zig-5
......@@ -146,11 +146,6 @@ test "math.cos" {
146146}
147147
148148test "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 }
154149 const epsilon = 0.000001;
155150
156151 assert(math.approxEq(f32, cos32(0.0), 1.0, epsilon));
std/math/cosh.zig-5
......@@ -81,11 +81,6 @@ fn cosh64(x: f64) -> f64 {
8181}
8282
8383test "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 }
8984 assert(cosh(f32(1.5)) == cosh32(1.5));
9085 assert(cosh(f64(1.5)) == cosh64(1.5));
9186}
std/math/index.zig-15
......@@ -359,11 +359,6 @@ pub fn divTrunc(comptime T: type, numerator: T, denominator: T) -> %T {
359359}
360360
361361test "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 }
367362 testDivTrunc();
368363 comptime testDivTrunc();
369364}
......@@ -389,11 +384,6 @@ pub fn divFloor(comptime T: type, numerator: T, denominator: T) -> %T {
389384}
390385
391386test "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 }
397387 testDivFloor();
398388 comptime testDivFloor();
399389}
......@@ -423,11 +413,6 @@ pub fn divExact(comptime T: type, numerator: T, denominator: T) -> %T {
423413}
424414
425415test "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 }
431416 testDivExact();
432417 comptime testDivExact();
433418}
std/math/ln.zig-5
......@@ -147,11 +147,6 @@ pub fn ln_64(x_: f64) -> f64 {
147147}
148148
149149test "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 }
155150 assert(ln(f32(0.2)) == ln_32(0.2));
156151 assert(ln(f64(0.2)) == ln_64(0.2));
157152}
std/math/log.zig-5
......@@ -56,11 +56,6 @@ test "math.log float" {
5656}
5757
5858test "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 }
6459 assert(log(f32, 2, 0.2301974) == math.log2(f32(0.2301974)));
6560 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 {
172172}
173173
174174test "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 }
180175 assert(log10(f32(0.2)) == log10_32(0.2));
181176 assert(log10(f64(0.2)) == log10_64(0.2));
182177}
std/math/log2.zig-5
......@@ -170,11 +170,6 @@ pub fn log2_64(x_: f64) -> f64 {
170170}
171171
172172test "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 }
178173 assert(log2(f32(0.2)) == log2_32(0.2));
179174 assert(log2(f64(0.2)) == log2_64(0.2));
180175}
std/math/pow.zig-6
......@@ -176,12 +176,6 @@ fn isOddInteger(x: f64) -> bool {
176176}
177177
178178test "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
185179 const epsilon = 0.000001;
186180
187181 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" {
9898}
9999
100100test "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 }
106101 assert(round32(1.3) == 1.0);
107102 assert(round32(-1.3) == -1.0);
108103 assert(round32(0.2) == 0.0);
std/math/sin.zig-5
......@@ -150,11 +150,6 @@ test "math.sin" {
150150}
151151
152152test "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 }
158153 const epsilon = 0.000001;
159154
160155 assert(math.approxEq(f32, sin32(0.0), 0.0, epsilon));
std/math/sinh.zig-5
......@@ -88,11 +88,6 @@ fn sinh64(x: f64) -> f64 {
8888}
8989
9090test "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 }
9691 assert(sinh(f32(1.5)) == sinh32(1.5));
9792 assert(sinh(f64(1.5)) == sinh64(1.5));
9893}
std/math/tan.zig-5
......@@ -136,11 +136,6 @@ test "math.tan" {
136136}
137137
138138test "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 }
144139 const epsilon = 0.000001;
145140
146141 assert(math.approxEq(f32, tan32(0.0), 0.0, epsilon));
std/math/tanh.zig-5
......@@ -112,11 +112,6 @@ fn tanh64(x: f64) -> f64 {
112112}
113113
114114test "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 }
120115 assert(tanh(f32(1.5)) == tanh32(1.5));
121116 assert(tanh(f64(1.5)) == tanh64(1.5));
122117}
std/os/index.zig+2-9
......@@ -148,7 +148,7 @@ pub coldcc fn abort() -> noreturn {
148148}
149149
150150/// Exits the program cleanly with the specified status code.
151pub coldcc fn exit(status: i32) -> noreturn {
151pub coldcc fn exit(status: u8) -> noreturn {
152152 if (builtin.link_libc) {
153153 c.exit(status);
154154 }
......@@ -157,14 +157,7 @@ pub coldcc fn exit(status: i32) -> noreturn {
157157 posix.exit(status);
158158 },
159159 Os.windows => {
160 // Map a possibly negative status code to a non-negative status for the systems default
161 // integer width.
162 const p_status = if (@sizeOf(c_uint) < @sizeOf(u32))
163 @truncate(c_uint, @bitCast(u32, status))
164 else
165 c_uint(@bitCast(u32, status));
166
167 windows.ExitProcess(p_status);
160 windows.ExitProcess(status);
168161 },
169162 else => @compileError("Unsupported OS"),
170163 }
std/rand.zig-20
......@@ -194,11 +194,6 @@ fn MersenneTwister(
194194}
195195
196196test "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 }
202197 var r = Rand.init(42);
203198 var i: usize = 0;
204199 while (i < 1000) : (i += 1) {
......@@ -209,11 +204,6 @@ test "rand float 32" {
209204}
210205
211206test "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 }
217207 var rng = MT19937_64.init(rand_test.mt64_seed);
218208 for (rand_test.mt64_data) |value| {
219209 assert(value == rng.get());
......@@ -221,11 +211,6 @@ test "rand.MT19937_64" {
221211}
222212
223213test "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 }
229214 var rng = MT19937_32.init(rand_test.mt32_seed);
230215 for (rand_test.mt32_data) |value| {
231216 assert(value == rng.get());
......@@ -233,11 +218,6 @@ test "rand.MT19937_32" {
233218}
234219
235220test "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 }
241221 var r = Rand.init(42);
242222 testRange(&r, -4, 3);
243223 testRange(&r, -4, -1);
std/sort.zig-20
......@@ -1020,11 +1020,6 @@ fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> bool {
10201020}
10211021
10221022test "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 }
10281023 const u8cases = [][]const []const u8 {
10291024 [][]const u8{"", ""},
10301025 [][]const u8{"a", "a"},
......@@ -1061,11 +1056,6 @@ test "std.sort" {
10611056}
10621057
10631058test "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 }
10691059 const rev_cases = [][]const []const i32 {
10701060 [][]const i32{[]i32{}, []i32{}},
10711061 [][]const i32{[]i32{1}, []i32{1}},
......@@ -1085,11 +1075,6 @@ test "std.sort descending" {
10851075}
10861076
10871077test "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 }
10931078 var arr = []i32{ 5, 3, 1, 2, 4 };
10941079 sort(i32, arr[0..], i32asc);
10951080
......@@ -1097,11 +1082,6 @@ test "another sort case" {
10971082}
10981083
10991084test "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 }
11051085 var rng = std.rand.Rand.init(0x12345678);
11061086 const test_case_count = 10;
11071087 var i: usize = 0;
std/special/bootstrap.zig+35-10
......@@ -21,8 +21,7 @@ comptime {
2121}
2222
2323extern fn zenMain() -> noreturn {
24 root.main() catch std.os.posix.exit(1);
25 std.os.posix.exit(0);
24 std.os.posix.exit(callMain());
2625}
2726
2827nakedcc fn _start() -> noreturn {
......@@ -43,29 +42,55 @@ nakedcc fn _start() -> noreturn {
4342extern fn WinMainCRTStartup() -> noreturn {
4443 @setAlignStack(16);
4544
46 root.main() catch std.os.windows.ExitProcess(1);
47 std.os.windows.ExitProcess(0);
45 std.os.windows.ExitProcess(callMain());
4846}
4947
5048fn posixCallMainAndExit() -> noreturn {
5149 const argc = *argc_ptr;
5250 const argv = @ptrCast(&&u8, &argc_ptr[1]);
5351 const envp = @ptrCast(&?&u8, &argv[argc + 1]);
54 callMain(argc, argv, envp) catch std.os.posix.exit(1);
55 std.os.posix.exit(0);
52 std.os.posix.exit(callMainWithArgs(argc, argv, envp));
5653}
5754
58fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {
55fn callMainWithArgs(argc: usize, argv: &&u8, envp: &?&u8) -> u8 {
5956 std.os.ArgIteratorPosix.raw = argv[0..argc];
6057
6158 var env_count: usize = 0;
6259 while (envp[env_count] != null) : (env_count += 1) {}
6360 std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count];
6461
65 return root.main();
62 return callMain();
6663}
6764
6865extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {
69 callMain(usize(c_argc), c_argv, c_envp) catch return 1;
70 return 0;
66 return callMainWithArgs(usize(c_argc), c_argv, c_envp);
67}
68
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 }
7196}
std/special/build_runner.zig+4-4
......@@ -14,7 +14,7 @@ pub fn main() -> %void {
1414 var arg_it = os.args();
1515
1616 // 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);
1818 defer inc_allocator.deinit();
1919
2020 const allocator = &inc_allocator.allocator;
......@@ -107,12 +107,12 @@ pub fn main() -> %void {
107107 return usageAndErr(&builder, false, try stderr_stream);
108108 }
109109 } else {
110 targets.append(arg) catch unreachable;
110 try targets.append(arg);
111111 }
112112 }
113113
114114 builder.setInstallPrefix(prefix);
115 root.build(&builder);
115 try root.build(&builder);
116116
117117 if (builder.validateUserInputDidItFail())
118118 return usageAndErr(&builder, true, try stderr_stream);
......@@ -129,7 +129,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
129129 // run the build script to collect the options
130130 if (!already_ran_build) {
131131 builder.setInstallPrefix(null);
132 root.build(builder);
132 try root.build(builder);
133133 }
134134
135135 // 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");
55
66// Avoid dragging in the debug safety mechanisms into this .o file,
77// 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 {
99 if (builtin.is_test) {
1010 @import("std").debug.panic("{}", msg);
1111 } else {
std/special/compiler_rt/index.zig+1-1
......@@ -74,7 +74,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
7474
7575// Avoid dragging in the debug safety mechanisms into this .o file,
7676// 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 {
7878 if (is_test) {
7979 @import("std").debug.panic("{}", msg);
8080 } else {
std/special/panic.zig+5-1
......@@ -4,14 +4,18 @@
44// have to be added in the compiler.
55
66const 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 {
910 switch (builtin.os) {
1011 // TODO: fix panic in zen.
1112 builtin.Os.freestanding, builtin.Os.zen => {
1213 while (true) {}
1314 },
1415 else => {
16 if (error_return_trace) |trace| {
17 @import("std").debug.panicWithTrace(trace, "{}", msg);
18 }
1519 @import("std").debug.panic("{}", msg);
1620 },
1721 }
std/special/test_runner.zig+1-4
......@@ -8,10 +8,7 @@ pub fn main() -> %void {
88 for (test_fn_list) |test_fn, i| {
99 warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);
1010
11 test_fn.func() catch |err| {
12 warn("{}\n", err);
13 return err;
14 };
11 try test_fn.func();
1512
1613 warn("OK\n");
1714 }
test/build_examples.zig+1
......@@ -16,4 +16,5 @@ pub fn addCases(cases: &tests.BuildExamplesContext) {
1616 cases.addBuildFile("test/standalone/issue_339/build.zig");
1717 cases.addBuildFile("test/standalone/pkg_import/build.zig");
1818 cases.addBuildFile("test/standalone/use_alias/build.zig");
19 cases.addBuildFile("test/standalone/brace_expansion/build.zig");
1920}
test/compile_errors.zig+9-9
......@@ -1,6 +1,15 @@
11const tests = @import("tests.zig");
22
33pub 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
413 cases.add("bad identifier in function with struct defined inside function which references local const",
514 \\export fn entry() {
615 \\ const BlockKind = u32;
......@@ -1059,15 +1068,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
10591068 ,
10601069 ".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
10711071 cases.add("invalid pointer for var type",
10721072 \\extern fn ext() -> usize;
10731073 \\var bytes: [ext()]u8 = undefined;
test/debug_safety.zig+20-20
......@@ -2,7 +2,7 @@ const tests = @import("tests.zig");
22
33pub fn addCases(cases: &tests.CompareOutputContext) {
44 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 {
66 \\ @import("std").os.exit(126);
77 \\}
88 \\pub fn main() -> %void {
......@@ -11,7 +11,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
1111 );
1212
1313 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 {
1515 \\ @import("std").os.exit(126);
1616 \\}
1717 \\pub fn main() -> %void {
......@@ -25,7 +25,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
2525 );
2626
2727 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 {
2929 \\ @import("std").os.exit(126);
3030 \\}
3131 \\error Whatever;
......@@ -39,7 +39,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
3939 );
4040
4141 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 {
4343 \\ @import("std").os.exit(126);
4444 \\}
4545 \\error Whatever;
......@@ -53,7 +53,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
5353 );
5454
5555 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 {
5757 \\ @import("std").os.exit(126);
5858 \\}
5959 \\error Whatever;
......@@ -67,7 +67,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
6767 );
6868
6969 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 {
7171 \\ @import("std").os.exit(126);
7272 \\}
7373 \\error Whatever;
......@@ -81,7 +81,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
8181 );
8282
8383 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 {
8585 \\ @import("std").os.exit(126);
8686 \\}
8787 \\error Whatever;
......@@ -95,7 +95,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
9595 );
9696
9797 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 {
9999 \\ @import("std").os.exit(126);
100100 \\}
101101 \\error Whatever;
......@@ -109,7 +109,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
109109 );
110110
111111 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 {
113113 \\ @import("std").os.exit(126);
114114 \\}
115115 \\error Whatever;
......@@ -123,7 +123,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
123123 );
124124
125125 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 {
127127 \\ @import("std").os.exit(126);
128128 \\}
129129 \\error Whatever;
......@@ -137,7 +137,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
137137 );
138138
139139 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 {
141141 \\ @import("std").os.exit(126);
142142 \\}
143143 \\error Whatever;
......@@ -151,7 +151,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
151151 );
152152
153153 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 {
155155 \\ @import("std").os.exit(126);
156156 \\}
157157 \\error Whatever;
......@@ -164,7 +164,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
164164 );
165165
166166 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 {
168168 \\ @import("std").os.exit(126);
169169 \\}
170170 \\error Whatever;
......@@ -178,7 +178,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
178178 );
179179
180180 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 {
182182 \\ @import("std").os.exit(126);
183183 \\}
184184 \\error Whatever;
......@@ -192,7 +192,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
192192 );
193193
194194 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 {
196196 \\ @import("std").os.exit(126);
197197 \\}
198198 \\error Whatever;
......@@ -206,7 +206,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
206206 );
207207
208208 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 {
210210 \\ @import("std").os.exit(126);
211211 \\}
212212 \\error Whatever;
......@@ -220,7 +220,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
220220 );
221221
222222 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 {
224224 \\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) {
225225 \\ @import("std").os.exit(126); // good
226226 \\ }
......@@ -236,7 +236,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
236236 );
237237
238238 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 {
240240 \\ @import("std").os.exit(126);
241241 \\}
242242 \\pub fn main() -> %void {
......@@ -248,7 +248,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
248248 );
249249
250250 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 {
252252 \\ @import("std").os.exit(126);
253253 \\}
254254 \\error Wrong;
......@@ -265,7 +265,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
265265 );
266266
267267 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 {
269269 \\ @import("std").os.exit(126);
270270 \\}
271271 \\
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 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {
3pub fn build(b: &Builder) -> %void {
44 const obj = b.addObject("test", "test.zig");
55
66 const test_step = b.step("test", "Test the program");
test/standalone/issue_339/test.zig+2-1
......@@ -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
34fn bar() -> %void {}
45
test/standalone/pkg_import/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {
3pub fn build(b: &Builder) -> %void {
44 const exe = b.addExecutable("test", "test.zig");
55 exe.addPackagePath("my_pkg", "pkg.zig");
66
test/standalone/use_alias/build.zig+1-1
......@@ -1,6 +1,6 @@
11const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {
3pub fn build(b: &Builder) -> %void {
44 b.addCIncludePath(".");
55
66 const main = b.addTest("main.zig");
test/tests.zig+2-7
......@@ -42,14 +42,10 @@ const test_targets = []TestTarget {
4242 .arch = builtin.Arch.x86_64,
4343 .environ = builtin.Environ.msvc,
4444 },
45 TestTarget {
46 .os = builtin.Os.windows,
47 .arch = builtin.Arch.i386,
48 .environ = builtin.Environ.msvc,
49 },
5045};
5146
5247error TestFailed;
48error CompilationIncorrectlySucceeded;
5349
5450const max_stdout_size = 1 * 1024 * 1024; // 1 MB
5551
......@@ -607,8 +603,7 @@ pub const CompileErrorContext = struct {
607603 switch (term) {
608604 Term.Exited => |code| {
609605 if (code == 0) {
610 warn("Compilation incorrectly succeeded\n");
611 return error.TestFailed;
606 return error.CompilationIncorrectlySucceeded;
612607 }
613608 },
614609 else => {