diff --git a/doc/langref.html.in b/doc/langref.html.in index 2476790105..94bc780959 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -142,6 +142,7 @@
  • @TagType
  • @EnumTagType
  • @errorName
  • +
  • @errorReturnTrace
  • @fence
  • @fieldParentPtr
  • @frameAddress
  • @@ -4412,6 +4413,13 @@ test.zig:6:2: error: found compile log statement or all calls have a compile-time known value for err, then no error name table will be generated.

    +

    @errorReturnTrace

    +
    @errorReturnTrace() -> ?&builtin.StackTrace
    +

    + If the binary is built with error return tracing, and this function is invoked in a + function that calls a function with an error or error union return type, returns a + stack trace object. Otherwise returns `null`. +

    @fence

    @fence(order: AtomicOrder)

    diff --git a/example/mix_o_files/build.zig b/example/mix_o_files/build.zig index 391af9924a..4bba69b091 100644 --- a/example/mix_o_files/build.zig +++ b/example/mix_o_files/build.zig @@ -1,6 +1,6 @@ const Builder = @import("std").build.Builder; -pub fn build(b: &Builder) { +pub fn build(b: &Builder) -> %void { const obj = b.addObject("base64", "base64.zig"); const exe = b.addCExecutable("test"); diff --git a/example/shared_library/build.zig b/example/shared_library/build.zig index 9b7f3793c6..147b54401c 100644 --- a/example/shared_library/build.zig +++ b/example/shared_library/build.zig @@ -1,6 +1,6 @@ const Builder = @import("std").build.Builder; -pub fn build(b: &Builder) { +pub fn build(b: &Builder) -> %void { const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0)); const exe = b.addCExecutable("test"); diff --git a/src/all_types.hpp b/src/all_types.hpp index 7a3f1a9b79..b401097647 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1274,6 +1274,7 @@ enum BuiltinFnId { BuiltinFnIdSetAlignStack, BuiltinFnIdArgType, BuiltinFnIdExport, + BuiltinFnIdErrorReturnTrace, }; struct BuiltinFnEntry { @@ -1499,6 +1500,7 @@ struct CodeGen { Buf triple_str; BuildMode build_mode; bool is_test_build; + bool have_err_ret_tracing; uint32_t target_os_index; uint32_t target_arch_index; uint32_t target_environ_index; @@ -1902,6 +1904,7 @@ enum IrInstructionId { IrInstructionIdSetAlignStack, IrInstructionIdArgType, IrInstructionIdExport, + IrInstructionIdErrorReturnTrace, }; struct IrInstruction { @@ -2723,6 +2726,10 @@ struct IrInstructionExport { IrInstruction *target; }; +struct IrInstructionErrorReturnTrace { + IrInstruction base; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index f7c0f832a2..8028ace289 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -925,8 +925,9 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { if (!skip_debug_info) { bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) && handle_is_ptr(fn_type_id->return_type); - bool prefix_arg_error_return_trace = fn_type_id->return_type->id == TypeTableEntryIdErrorUnion || - fn_type_id->return_type->id == TypeTableEntryIdPureError; + bool prefix_arg_error_return_trace = g->have_err_ret_tracing && + (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion || + fn_type_id->return_type->id == TypeTableEntryIdPureError); // +1 for maybe making the first argument the return value // +1 for maybe last argument the error return trace LLVMTypeRef *gen_param_types = allocate(2 + fn_type_id->param_count); @@ -2711,13 +2712,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { { if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) { g->main_fn = fn_table_entry; - TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); - TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; - if (actual_return_type != err_void) { - add_node_error(g, fn_proto->return_type, - buf_sprintf("expected return type of main to be '%%void', instead is '%s'", - buf_ptr(&actual_return_type->name))); - } } else if ((import->package == g->panic_package || g->have_pub_panic) && buf_eql_str(&fn_table_entry->symbol_name, "panic")) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 96c0879615..5113aa7275 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -404,7 +404,10 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) { zig_unreachable(); } -static uint32_t get_err_ret_trace_arg_index(FnTableEntry *fn_table_entry) { +static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_entry) { + if (!g->have_err_ret_tracing) { + return UINT32_MAX; + } TypeTableEntry *fn_type = fn_table_entry->type_entry; TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdPureError) { @@ -572,7 +575,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { } } - uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(fn_table_entry); + uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); if (err_ret_trace_arg_index != UINT32_MAX) { addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull"); } @@ -1415,31 +1418,33 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns LLVMValueRef value = ir_llvm_value(g, return_instruction->value); TypeTableEntry *return_type = return_instruction->value->value.type; - bool is_err_return = false; - if (return_type->id == TypeTableEntryIdErrorUnion) { - if (return_instruction->value->value.special == ConstValSpecialStatic) { - is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr; - } else if (return_instruction->value->value.special == ConstValSpecialRuntime) { - is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError; - // TODO: emit a branch to check if the return value is an error + if (g->have_err_ret_tracing) { + bool is_err_return = false; + if (return_type->id == TypeTableEntryIdErrorUnion) { + if (return_instruction->value->value.special == ConstValSpecialStatic) { + is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr; + } else if (return_instruction->value->value.special == ConstValSpecialRuntime) { + is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError; + // TODO: emit a branch to check if the return value is an error + } + } else if (return_type->id == TypeTableEntryIdPureError) { + is_err_return = true; } - } else if (return_type->id == TypeTableEntryIdPureError) { - is_err_return = true; - } - if (is_err_return) { - LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnError"); - LLVMValueRef block_address = LLVMBlockAddress(g->cur_fn_val, return_block); + if (is_err_return) { + LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnError"); + LLVMValueRef block_address = LLVMBlockAddress(g->cur_fn_val, return_block); - LLVMValueRef return_err_fn = get_return_err_fn(g); - LLVMValueRef args[] = { - g->cur_err_ret_trace_val, - block_address, - }; - LLVMBuildBr(g->builder, return_block); - LLVMPositionBuilderAtEnd(g->builder, return_block); - LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 2, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); - LLVMSetTailCall(call_instruction, true); + LLVMValueRef return_err_fn = get_return_err_fn(g); + LLVMValueRef args[] = { + g->cur_err_ret_trace_val, + block_address, + }; + LLVMBuildBr(g->builder, return_block); + LLVMPositionBuilderAtEnd(g->builder, return_block); + LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 2, + get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); + LLVMSetTailCall(call_instruction, true); + } } if (handle_is_ptr(return_type)) { 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 TypeTableEntry *src_return_type = fn_type_id->return_type; bool ret_has_bits = type_has_bits(src_return_type); bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type); - bool prefix_arg_err_ret_stack = src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdPureError; + bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdPureError); size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0); bool is_var_args = fn_type_id->is_var_args; LLVMValueRef *gen_param_values = allocate(actual_param_count); @@ -3031,6 +3036,16 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I return target_val; } +static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable, + IrInstructionErrorReturnTrace *instruction) +{ + TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); + if (g->cur_err_ret_trace_val == nullptr) { + return LLVMConstNull(ptr_to_stack_trace_type->type_ref); + } + return g->cur_err_ret_trace_val; +} + static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { switch (atomic_order) { case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered; @@ -3804,6 +3819,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction); case IrInstructionIdAlignCast: return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction); + case IrInstructionIdErrorReturnTrace: + return ir_render_error_return_trace(g, executable, (IrInstructionErrorReturnTrace *)instruction); } zig_unreachable(); } @@ -4653,10 +4670,10 @@ static void do_code_gen(CodeGen *g) { build_all_basic_blocks(g, fn_table_entry); clear_debug_source_node(g); - uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(fn_table_entry); + uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); if (err_ret_trace_arg_index != UINT32_MAX) { g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index); - } else if (fn_table_entry->calls_errorable_function) { + } else if (g->have_err_ret_tracing && fn_table_entry->calls_errorable_function) { // TODO call graph analysis to find out what this number needs to be for every function static const size_t stack_trace_ptr_count = 30; @@ -5251,6 +5268,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2); create_builtin_fn(g, BuiltinFnIdExport, "export", 3); + create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0); } static const char *bool_to_str(bool b) { @@ -5553,6 +5571,8 @@ static void init(CodeGen *g) { } } + g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease; + define_builtin_fns(g); define_builtin_compile_vars(g); } diff --git a/src/ir.cpp b/src/ir.cpp index 5dd608083f..d6844f32ba 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -572,6 +572,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArgType *) { return IrInstructionIdArgType; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace *) { + return IrInstructionIdErrorReturnTrace; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -2305,6 +2309,12 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s return &instruction->base; } +static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node) { + IrInstructionErrorReturnTrace *instruction = ir_build_instruction(irb, scope, source_node); + + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -3731,6 +3741,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value); } + case BuiltinFnIdErrorReturnTrace: + { + return ir_build_error_return_trace(irb, scope, node); + } } zig_unreachable(); } @@ -9568,6 +9582,24 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi return ira->codegen->builtin_types.entry_void; } +static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, + IrInstructionErrorReturnTrace *instruction) +{ + FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); + TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen); + TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type); + if (fn_entry == nullptr || !fn_entry->calls_errorable_function || !ira->codegen->have_err_ret_tracing) { + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); + out_val->data.x_maybe = nullptr; + return nullable_type; + } + + IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope, + instruction->base.source_node); + ir_link_new_instruction(new_instruction, &instruction->base); + return nullable_type; +} + static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i) { @@ -15324,6 +15356,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction); case IrInstructionIdExport: return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction); + case IrInstructionIdErrorReturnTrace: + return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction); } zig_unreachable(); } @@ -15507,6 +15541,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdOpaqueType: case IrInstructionIdArgType: case IrInstructionIdTagType: + case IrInstructionIdErrorReturnTrace: return false; case IrInstructionIdAsm: { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index f5aba2a45d..930d22f21a 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -996,6 +996,10 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) { } } +static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) { + fprintf(irp->f, "@errorReturnTrace()"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); @@ -1308,6 +1312,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdExport: ir_print_export(irp, (IrInstructionExport *)instruction); break; + case IrInstructionIdErrorReturnTrace: + ir_print_error_return_trace(irp, (IrInstructionErrorReturnTrace *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/std/build.zig b/std/build.zig index 6984715466..5d79b00c4f 100644 --- a/std/build.zig +++ b/std/build.zig @@ -247,11 +247,11 @@ pub const Builder = struct { defer wanted_steps.deinit(); if (step_names.len == 0) { - wanted_steps.append(&self.default_step) catch unreachable; + try wanted_steps.append(&self.default_step); } else { for (step_names) |step_name| { const s = try self.getTopLevelStepByName(step_name); - wanted_steps.append(s) catch unreachable; + try wanted_steps.append(s); } } diff --git a/std/debug/index.zig b/std/debug/index.zig index f7f6ffa323..5dc7b0dbfa 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -56,7 +56,7 @@ pub fn dumpCurrentStackTrace() { } /// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned. -pub fn dumpStackTrace(stack_trace: &builtin.StackTrace) { +pub fn dumpStackTrace(stack_trace: &const builtin.StackTrace) { const stderr = getStderrStream() catch return; const debug_info = openSelfDebugInfo(global_allocator) catch |err| { stderr.print("Unable to open debug info: {}\n", @errorName(err)) catch return; @@ -127,7 +127,7 @@ const RESET = "\x1b[0m"; error PathNotFound; error InvalidDebugInfo; -pub fn writeStackTrace(stack_trace: &builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator, +pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator, debug_info: &ElfStackTrace, tty_color: bool) -> %void { var frame_index: usize = undefined; @@ -167,6 +167,9 @@ pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocat } fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, address: usize) -> %void { + if (builtin.os == builtin.Os.windows) { + return error.UnsupportedDebugInfo; + } // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal // at compile time. I'll call it issue #313 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 return; }; const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name); - if (getLineNumberInfo(debug_info, compile_unit, usize(address) - 1)) |line_info| { + if (getLineNumberInfo(debug_info, compile_unit, address - 1)) |line_info| { defer line_info.deinit(); try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n", diff --git a/std/io.zig b/std/io.zig index c6fd5502a2..605553b0ea 100644 --- a/std/io.zig +++ b/std/io.zig @@ -224,7 +224,7 @@ pub const File = struct { }; } }, - else => @compileError("unsupported OS"), + else => @compileError("unsupported OS: " ++ @tagName(builtin.os)), } } diff --git a/std/os/index.zig b/std/os/index.zig index e338359522..fd8eb84ab4 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -148,7 +148,7 @@ pub coldcc fn abort() -> noreturn { } /// Exits the program cleanly with the specified status code. -pub coldcc fn exit(status: i32) -> noreturn { +pub coldcc fn exit(status: u8) -> noreturn { if (builtin.link_libc) { c.exit(status); } @@ -157,14 +157,7 @@ pub coldcc fn exit(status: i32) -> noreturn { posix.exit(status); }, Os.windows => { - // Map a possibly negative status code to a non-negative status for the systems default - // integer width. - const p_status = if (@sizeOf(c_uint) < @sizeOf(u32)) - @truncate(c_uint, @bitCast(u32, status)) - else - c_uint(@bitCast(u32, status)); - - windows.ExitProcess(p_status); + windows.ExitProcess(status); }, else => @compileError("Unsupported OS"), } diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 55d28a2d0e..77bb7316a9 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -21,8 +21,7 @@ comptime { } extern fn zenMain() -> noreturn { - root.main() catch std.os.posix.exit(1); - std.os.posix.exit(0); + std.os.posix.exit(callMain()); } nakedcc fn _start() -> noreturn { @@ -43,29 +42,55 @@ nakedcc fn _start() -> noreturn { extern fn WinMainCRTStartup() -> noreturn { @setAlignStack(16); - root.main() catch std.os.windows.ExitProcess(1); - std.os.windows.ExitProcess(0); + std.os.windows.ExitProcess(callMain()); } fn posixCallMainAndExit() -> noreturn { const argc = *argc_ptr; const argv = @ptrCast(&&u8, &argc_ptr[1]); const envp = @ptrCast(&?&u8, &argv[argc + 1]); - callMain(argc, argv, envp) catch std.os.posix.exit(1); - std.os.posix.exit(0); + std.os.posix.exit(callMainWithArgs(argc, argv, envp)); } -fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { +fn callMainWithArgs(argc: usize, argv: &&u8, envp: &?&u8) -> u8 { std.os.ArgIteratorPosix.raw = argv[0..argc]; var env_count: usize = 0; while (envp[env_count] != null) : (env_count += 1) {} std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count]; - return root.main(); + return callMain(); } extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { - callMain(usize(c_argc), c_argv, c_envp) catch return 1; - return 0; + return callMainWithArgs(usize(c_argc), c_argv, c_envp); +} + +fn callMain() -> u8 { + switch (@typeId(@typeOf(root.main).ReturnType)) { + builtin.TypeId.NoReturn => { + root.main(); + }, + builtin.TypeId.Void => { + root.main(); + return 0; + }, + builtin.TypeId.Int => { + if (@typeOf(root.main).ReturnType.bit_count != 8) { + @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"); + } + return root.main(); + }, + builtin.TypeId.ErrorUnion => { + root.main() catch |err| { + std.debug.warn("error: {}\n", @errorName(err)); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace); + } + return 1; + }; + return 0; + }, + else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"), + } } diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig index b293a1e64d..4722aff07a 100644 --- a/std/special/build_runner.zig +++ b/std/special/build_runner.zig @@ -14,7 +14,7 @@ pub fn main() -> %void { var arg_it = os.args(); // TODO use a more general purpose allocator here - var inc_allocator = std.heap.IncrementingAllocator.init(40 * 1024 * 1024) catch unreachable; + var inc_allocator = try std.heap.IncrementingAllocator.init(40 * 1024 * 1024); defer inc_allocator.deinit(); const allocator = &inc_allocator.allocator; @@ -107,12 +107,12 @@ pub fn main() -> %void { return usageAndErr(&builder, false, try stderr_stream); } } else { - targets.append(arg) catch unreachable; + try targets.append(arg); } } builder.setInstallPrefix(prefix); - root.build(&builder) catch unreachable; + try root.build(&builder); if (builder.validateUserInputDidItFail()) return usageAndErr(&builder, true, try stderr_stream); @@ -129,7 +129,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) // run the build script to collect the options if (!already_ran_build) { builder.setInstallPrefix(null); - root.build(builder) catch unreachable; + try root.build(builder); } // This usage text has to be synchronized with src/main.cpp diff --git a/std/special/test_runner.zig b/std/special/test_runner.zig index 027251c52c..c5c0bad40c 100644 --- a/std/special/test_runner.zig +++ b/std/special/test_runner.zig @@ -8,14 +8,7 @@ pub fn main() -> %void { for (test_fn_list) |test_fn, i| { warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name); - if (builtin.is_test) { - test_fn.func() catch unreachable; - } else { - test_fn.func() catch |err| { - warn("{}\n", err); - return err; - }; - } + try test_fn.func(); warn("OK\n"); } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 005fe55e41..6b2ea545ed 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,15 @@ const tests = @import("tests.zig"); pub fn addCases(cases: &tests.CompileErrorContext) { + cases.add("wrong return type for main", + \\pub fn main() -> f32 { } + , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"); + + cases.add("double ?? on main return value", + \\pub fn main() -> ??void { + \\} + , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"); + cases.add("bad identifier in function with struct defined inside function which references local const", \\export fn entry() { \\ const BlockKind = u32; @@ -1059,15 +1068,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { , ".tmp_source.zig:2:5: error: expected type 'void', found 'error'"); - cases.add("wrong return type for main", - \\pub fn main() { } - , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'"); - - cases.add("double ?? on main return value", - \\pub fn main() -> ??void { - \\} - , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'"); - cases.add("invalid pointer for var type", \\extern fn ext() -> usize; \\var bytes: [ext()]u8 = undefined; diff --git a/test/debug_safety.zig b/test/debug_safety.zig index fde5b061ee..b32ffb34f0 100644 --- a/test/debug_safety.zig +++ b/test/debug_safety.zig @@ -2,7 +2,7 @@ const tests = @import("tests.zig"); pub fn addCases(cases: &tests.CompareOutputContext) { cases.addDebugSafety("calling panic", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() -> %void { @@ -11,7 +11,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("out of bounds slice access", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() -> %void { @@ -25,7 +25,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("integer addition overflow", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -39,7 +39,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("integer subtraction overflow", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -53,7 +53,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("integer multiplication overflow", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -67,7 +67,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("integer negation overflow", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -81,7 +81,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("signed integer division overflow", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -95,7 +95,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("signed shift left overflow", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -109,7 +109,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("unsigned shift left overflow", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -123,7 +123,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("signed shift right overflow", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -137,7 +137,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("unsigned shift right overflow", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -151,7 +151,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("integer division by zero", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -164,7 +164,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("exact division failure", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -178,7 +178,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("cast []u8 to bigger slice of wrong size", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -192,7 +192,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("value does not fit in shortening cast", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -206,7 +206,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("signed integer not fitting in cast to unsigned integer", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Whatever; @@ -220,7 +220,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("unwrap error", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) { \\ @import("std").os.exit(126); // good \\ } @@ -236,7 +236,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("cast integer to error and no code matches", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\pub fn main() -> %void { @@ -248,7 +248,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("@alignCast misaligned", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\error Wrong; @@ -265,7 +265,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { ); cases.addDebugSafety("bad union field access", - \\pub fn panic(message: []const u8) -> noreturn { + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn { \\ @import("std").os.exit(126); \\} \\ diff --git a/test/standalone/issue_339/build.zig b/test/standalone/issue_339/build.zig index 50fa10c593..b7b288f7a1 100644 --- a/test/standalone/issue_339/build.zig +++ b/test/standalone/issue_339/build.zig @@ -1,6 +1,6 @@ const Builder = @import("std").build.Builder; -pub fn build(b: &Builder) { +pub fn build(b: &Builder) -> %void { const obj = b.addObject("test", "test.zig"); const test_step = b.step("test", "Test the program"); diff --git a/test/standalone/issue_339/test.zig b/test/standalone/issue_339/test.zig index e0d6c3f3e5..dd97ffa9b1 100644 --- a/test/standalone/issue_339/test.zig +++ b/test/standalone/issue_339/test.zig @@ -1,4 +1,5 @@ -pub fn panic(msg: []const u8) -> noreturn { @breakpoint(); while (true) {} } +const StackTrace = @import("builtin").StackTrace; +pub fn panic(msg: []const u8, stack_trace: ?&StackTrace) -> noreturn { @breakpoint(); while (true) {} } fn bar() -> %void {} diff --git a/test/standalone/pkg_import/build.zig b/test/standalone/pkg_import/build.zig index 044787dd4d..f40011d834 100644 --- a/test/standalone/pkg_import/build.zig +++ b/test/standalone/pkg_import/build.zig @@ -1,6 +1,6 @@ const Builder = @import("std").build.Builder; -pub fn build(b: &Builder) { +pub fn build(b: &Builder) -> %void { const exe = b.addExecutable("test", "test.zig"); exe.addPackagePath("my_pkg", "pkg.zig"); diff --git a/test/standalone/use_alias/build.zig b/test/standalone/use_alias/build.zig index 03398f1a41..beca6bc304 100644 --- a/test/standalone/use_alias/build.zig +++ b/test/standalone/use_alias/build.zig @@ -1,6 +1,6 @@ const Builder = @import("std").build.Builder; -pub fn build(b: &Builder) { +pub fn build(b: &Builder) -> %void { b.addCIncludePath("."); const main = b.addTest("main.zig"); diff --git a/test/tests.zig b/test/tests.zig index 20e1e94459..5fd995f034 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -50,6 +50,7 @@ const test_targets = []TestTarget { }; error TestFailed; +error CompilationIncorrectlySucceeded; const max_stdout_size = 1 * 1024 * 1024; // 1 MB @@ -607,8 +608,7 @@ pub const CompileErrorContext = struct { switch (term) { Term.Exited => |code| { if (code == 0) { - warn("Compilation incorrectly succeeded\n"); - return error.TestFailed; + return error.CompilationIncorrectlySucceeded; } }, else => {