authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-15 00:01:02-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-15 00:01:02-05:00
log7b57454cc11371b71097967656e19f0a1736d733
tree4eff514fcb0a0c1f95ac253624c4f705fe95b03e
parentd973b40884be1c7874805c81981cac7edca5605b

clean up error return tracing

* error return tracing is disabled in release-fast mode * add @errorReturnTrace * zig build API changes build return type from `void` to `%void` * allow `void`, `noreturn`, and `u8` from main. closes #535

22 files changed, 198 insertions(+), 112 deletions(-)

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/all_types.hpp+7
......@@ -1274,6 +1274,7 @@ enum BuiltinFnId {
12741274 BuiltinFnIdSetAlignStack,
12751275 BuiltinFnIdArgType,
12761276 BuiltinFnIdExport,
1277 BuiltinFnIdErrorReturnTrace,
12771278};
12781279
12791280struct BuiltinFnEntry {
......@@ -1499,6 +1500,7 @@ struct CodeGen {
14991500 Buf triple_str;
15001501 BuildMode build_mode;
15011502 bool is_test_build;
1503 bool have_err_ret_tracing;
15021504 uint32_t target_os_index;
15031505 uint32_t target_arch_index;
15041506 uint32_t target_environ_index;
......@@ -1902,6 +1904,7 @@ enum IrInstructionId {
19021904 IrInstructionIdSetAlignStack,
19031905 IrInstructionIdArgType,
19041906 IrInstructionIdExport,
1907 IrInstructionIdErrorReturnTrace,
19051908};
19061909
19071910struct IrInstruction {
......@@ -2723,6 +2726,10 @@ struct IrInstructionExport {
27232726 IrInstruction *target;
27242727};
27252728
2729struct IrInstructionErrorReturnTrace {
2730 IrInstruction base;
2731};
2732
27262733static const size_t slice_ptr_index = 0;
27272734static const size_t slice_len_index = 1;
27282735
src/analyze.cpp+3-9
......@@ -925,8 +925,9 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
925925 if (!skip_debug_info) {
926926 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&
927927 handle_is_ptr(fn_type_id->return_type);
928 bool prefix_arg_error_return_trace = fn_type_id->return_type->id == TypeTableEntryIdErrorUnion ||
929 fn_type_id->return_type->id == TypeTableEntryIdPureError;
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);
930931 // +1 for maybe making the first argument the return value
931932 // +1 for maybe last argument the error return trace
932933 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(2 + fn_type_id->param_count);
......@@ -2711,13 +2712,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
27112712 {
27122713 if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {
27132714 g->main_fn = fn_table_entry;
2714 TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);
2715 TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
2716 if (actual_return_type != err_void) {
2717 add_node_error(g, fn_proto->return_type,
2718 buf_sprintf("expected return type of main to be '%%void', instead is '%s'",
2719 buf_ptr(&actual_return_type->name)));
2720 }
27212715 } else if ((import->package == g->panic_package || g->have_pub_panic) &&
27222716 buf_eql_str(&fn_table_entry->symbol_name, "panic"))
27232717 {
src/codegen.cpp+49-29
......@@ -404,7 +404,10 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
404404 zig_unreachable();
405405}
406406
407static uint32_t get_err_ret_trace_arg_index(FnTableEntry *fn_table_entry) {
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 }
408411 TypeTableEntry *fn_type = fn_table_entry->type_entry;
409412 TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
410413 if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdPureError) {
......@@ -572,7 +575,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
572575 }
573576 }
574577
575 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(fn_table_entry);
578 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
576579 if (err_ret_trace_arg_index != UINT32_MAX) {
577580 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");
578581 }
......@@ -1415,31 +1418,33 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
14151418 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
14161419 TypeTableEntry *return_type = return_instruction->value->value.type;
14171420
1418 bool is_err_return = false;
1419 if (return_type->id == TypeTableEntryIdErrorUnion) {
1420 if (return_instruction->value->value.special == ConstValSpecialStatic) {
1421 is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr;
1422 } else if (return_instruction->value->value.special == ConstValSpecialRuntime) {
1423 is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError;
1424 // TODO: emit a branch to check if the return value is an error
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);
14251447 }
1426 } else if (return_type->id == TypeTableEntryIdPureError) {
1427 is_err_return = true;
1428 }
1429 if (is_err_return) {
1430 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnError");
1431 LLVMValueRef block_address = LLVMBlockAddress(g->cur_fn_val, return_block);
1432
1433 LLVMValueRef return_err_fn = get_return_err_fn(g);
1434 LLVMValueRef args[] = {
1435 g->cur_err_ret_trace_val,
1436 block_address,
1437 };
1438 LLVMBuildBr(g->builder, return_block);
1439 LLVMPositionBuilderAtEnd(g->builder, return_block);
1440 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 2,
1441 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1442 LLVMSetTailCall(call_instruction, true);
14431448 }
14441449 if (handle_is_ptr(return_type)) {
14451450 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
......@@ -2475,7 +2480,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
24752480 TypeTableEntry *src_return_type = fn_type_id->return_type;
24762481 bool ret_has_bits = type_has_bits(src_return_type);
24772482 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);
2478 bool prefix_arg_err_ret_stack = src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdPureError;
2483 bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdPureError);
24792484 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0);
24802485 bool is_var_args = fn_type_id->is_var_args;
24812486 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
......@@ -3031,6 +3036,16 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
30313036 return target_val;
30323037}
30333038
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
30343049static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
30353050 switch (atomic_order) {
30363051 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
......@@ -3804,6 +3819,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
38043819 return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction);
38053820 case IrInstructionIdAlignCast:
38063821 return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);
3822 case IrInstructionIdErrorReturnTrace:
3823 return ir_render_error_return_trace(g, executable, (IrInstructionErrorReturnTrace *)instruction);
38073824 }
38083825 zig_unreachable();
38093826}
......@@ -4653,10 +4670,10 @@ static void do_code_gen(CodeGen *g) {
46534670 build_all_basic_blocks(g, fn_table_entry);
46544671 clear_debug_source_node(g);
46554672
4656 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(fn_table_entry);
4673 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
46574674 if (err_ret_trace_arg_index != UINT32_MAX) {
46584675 g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index);
4659 } else if (fn_table_entry->calls_errorable_function) {
4676 } else if (g->have_err_ret_tracing && fn_table_entry->calls_errorable_function) {
46604677 // TODO call graph analysis to find out what this number needs to be for every function
46614678 static const size_t stack_trace_ptr_count = 30;
46624679
......@@ -5251,6 +5268,7 @@ static void define_builtin_fns(CodeGen *g) {
52515268 create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);
52525269 create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2);
52535270 create_builtin_fn(g, BuiltinFnIdExport, "export", 3);
5271 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
52545272}
52555273
52565274static const char *bool_to_str(bool b) {
......@@ -5553,6 +5571,8 @@ static void init(CodeGen *g) {
55535571 }
55545572 }
55555573
5574 g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease;
5575
55565576 define_builtin_fns(g);
55575577 define_builtin_compile_vars(g);
55585578}
src/ir.cpp+35
......@@ -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}
......@@ -9568,6 +9582,24 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
95689582 return ira->codegen->builtin_types.entry_void;
95699583}
95709584
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
95719603static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
95729604 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
95739605{
......@@ -15324,6 +15356,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1532415356 return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction);
1532515357 case IrInstructionIdExport:
1532615358 return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction);
15359 case IrInstructionIdErrorReturnTrace:
15360 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);
1532715361 }
1532815362 zig_unreachable();
1532915363}
......@@ -15507,6 +15541,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1550715541 case IrInstructionIdOpaqueType:
1550815542 case IrInstructionIdArgType:
1550915543 case IrInstructionIdTagType:
15544 case IrInstructionIdErrorReturnTrace:
1551015545 return false;
1551115546 case IrInstructionIdAsm:
1551215547 {
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+2-2
......@@ -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
std/debug/index.zig+6-3
......@@ -56,7 +56,7 @@ pub fn dumpCurrentStackTrace() {
5656}
5757
5858/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
59pub fn dumpStackTrace(stack_trace: &builtin.StackTrace) {
59pub fn dumpStackTrace(stack_trace: &const builtin.StackTrace) {
6060 const stderr = getStderrStream() catch return;
6161 const debug_info = openSelfDebugInfo(global_allocator) catch |err| {
6262 stderr.print("Unable to open debug info: {}\n", @errorName(err)) catch return;
......@@ -127,7 +127,7 @@ const RESET = "\x1b[0m";
127127error PathNotFound;
128128error InvalidDebugInfo;
129129
130pub fn writeStackTrace(stack_trace: &builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator,
130pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator,
131131 debug_info: &ElfStackTrace, tty_color: bool) -> %void
132132{
133133 var frame_index: usize = undefined;
......@@ -167,6 +167,9 @@ pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocat
167167}
168168
169169fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, address: usize) -> %void {
170 if (builtin.os == builtin.Os.windows) {
171 return error.UnsupportedDebugInfo;
172 }
170173 // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
171174 // at compile time. I'll call it issue #313
172175 const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
......@@ -177,7 +180,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a
177180 return;
178181 };
179182 const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
180 if (getLineNumberInfo(debug_info, compile_unit, usize(address) - 1)) |line_info| {
183 if (getLineNumberInfo(debug_info, compile_unit, address - 1)) |line_info| {
181184 defer line_info.deinit();
182185 try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
183186 DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
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/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/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) catch unreachable;
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) catch unreachable;
132 try root.build(builder);
133133 }
134134
135135 // This usage text has to be synchronized with src/main.cpp
std/special/test_runner.zig+1-8
......@@ -8,14 +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 if (builtin.is_test) {
12 test_fn.func() catch unreachable;
13 } else {
14 test_fn.func() catch |err| {
15 warn("{}\n", err);
16 return err;
17 };
18 }
11 try test_fn.func();
1912
2013 warn("OK\n");
2114 }
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/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-2
......@@ -50,6 +50,7 @@ const test_targets = []TestTarget {
5050};
5151
5252error TestFailed;
53error CompilationIncorrectlySucceeded;
5354
5455const max_stdout_size = 1 * 1024 * 1024; // 1 MB
5556
......@@ -607,8 +608,7 @@ pub const CompileErrorContext = struct {
607608 switch (term) {
608609 Term.Exited => |code| {
609610 if (code == 0) {
610 warn("Compilation incorrectly succeeded\n");
611 return error.TestFailed;
611 return error.CompilationIncorrectlySucceeded;
612612 }
613613 },
614614 else => {