| 1 | module builtin |
| 2 | |
| 3 | // panic_debug private function that V uses for panics, -cg/-g is passed |
| 4 | // recent versions of tcc print nicer backtraces automatically |
| 5 | // Note: the duplication here is because tcc_backtrace should be called directly |
| 6 | // inside the panic functions. |
| 7 | @[noreturn] |
| 8 | fn panic_debug(line_no int, file string, mod string, fn_name string, s string) { |
| 9 | // Note: the order here is important for a stabler test output |
| 10 | // module is less likely to change than function, etc... |
| 11 | // During edits, the line number will change most frequently, |
| 12 | // so it is last |
| 13 | $if freestanding { |
| 14 | bare_panic(s) |
| 15 | } $else { |
| 16 | // vfmt off |
| 17 | // Note: be carefull to not allocate here, avoid string interpolation |
| 18 | flush_stdout() |
| 19 | eprintln('================ V panic ================') |
| 20 | eprint(' module: '); eprintln(mod) |
| 21 | eprint(' function: '); eprint(fn_name); eprintln('()') |
| 22 | eprint(' message: '); eprintln(s) |
| 23 | eprint(' file: '); eprint(file); eprint(':'); |
| 24 | C.fprintf(C.stderr, c'%d\n', line_no) |
| 25 | eprint(' v hash: '); eprintln(vcurrent_hash()) |
| 26 | $if !vinix { |
| 27 | eprint(' pid: '); C.fprintf(C.stderr, c'%p\n', voidptr(v_getpid())) |
| 28 | eprint(' tid: '); C.fprintf(C.stderr, c'%p\n', voidptr(v_gettid())) |
| 29 | } |
| 30 | eprintln('=========================================') |
| 31 | flush_stdout() |
| 32 | // vfmt on |
| 33 | $if exit_after_panic_message ? { |
| 34 | C.exit(1) |
| 35 | } $else $if no_backtrace ? { |
| 36 | C.exit(1) |
| 37 | } $else { |
| 38 | $if tinyc { |
| 39 | $if panics_break_into_debugger ? { |
| 40 | break_if_debugger_attached() |
| 41 | } $else { |
| 42 | C.tcc_backtrace(c'Backtrace') |
| 43 | } |
| 44 | C.exit(1) |
| 45 | } |
| 46 | $if use_libbacktrace ? { |
| 47 | $if openbsd { |
| 48 | print_backtrace_skipping_top_frames(1) |
| 49 | } $else { |
| 50 | eprint_libbacktrace(1) |
| 51 | } |
| 52 | } $else { |
| 53 | print_backtrace_skipping_top_frames(1) |
| 54 | } |
| 55 | $if panics_break_into_debugger ? { |
| 56 | break_if_debugger_attached() |
| 57 | } |
| 58 | C.exit(1) |
| 59 | } |
| 60 | } |
| 61 | C.exit(1) |
| 62 | for {} |
| 63 | } |
| 64 | |
| 65 | // panic_option_not_set is called by V, when you use option error propagation in your main function. |
| 66 | // It ends the program with a panic. |
| 67 | @[noreturn] |
| 68 | pub fn panic_option_not_set(s string) { |
| 69 | panic('option not set (' + s + ')') |
| 70 | } |
| 71 | |
| 72 | // panic_result_not_set is called by V, when you use result error propagation in your main function |
| 73 | // It ends the program with a panic. |
| 74 | @[noreturn] |
| 75 | pub fn panic_result_not_set(s string) { |
| 76 | panic('result not set (' + s + ')') |
| 77 | } |
| 78 | |
| 79 | // panic prints a nice error message, then exits the process with exit code of 1. |
| 80 | // It also shows a backtrace on most platforms. |
| 81 | @[noreturn] |
| 82 | pub fn panic(s string) { |
| 83 | // Note: be careful to not use string interpolation here: |
| 84 | $if freestanding { |
| 85 | bare_panic(s) |
| 86 | } $else { |
| 87 | // vfmt off |
| 88 | flush_stdout() |
| 89 | eprint('V panic: ') |
| 90 | eprintln(s) |
| 91 | eprint(' v hash: ') |
| 92 | eprintln(vcurrent_hash()) |
| 93 | $if !vinix { |
| 94 | eprint(' pid: '); C.fprintf(C.stderr, c'%p\n', voidptr(v_getpid())) |
| 95 | eprint(' tid: '); C.fprintf(C.stderr, c'%p\n', voidptr(v_gettid())) |
| 96 | } |
| 97 | flush_stdout() |
| 98 | // vfmt on |
| 99 | $if exit_after_panic_message ? { |
| 100 | C.exit(1) |
| 101 | } $else $if no_backtrace ? { |
| 102 | C.exit(1) |
| 103 | } $else { |
| 104 | $if tinyc { |
| 105 | $if panics_break_into_debugger ? { |
| 106 | break_if_debugger_attached() |
| 107 | } $else { |
| 108 | C.tcc_backtrace(c'Backtrace') |
| 109 | } |
| 110 | C.exit(1) |
| 111 | } |
| 112 | $if use_libbacktrace ? { |
| 113 | $if openbsd { |
| 114 | print_backtrace_skipping_top_frames(1) |
| 115 | } $else { |
| 116 | eprint_libbacktrace(1) |
| 117 | } |
| 118 | } $else { |
| 119 | print_backtrace_skipping_top_frames(1) |
| 120 | } |
| 121 | $if panics_break_into_debugger ? { |
| 122 | break_if_debugger_attached() |
| 123 | } |
| 124 | C.exit(1) |
| 125 | } |
| 126 | } |
| 127 | C.exit(1) |
| 128 | for {} |
| 129 | } |
| 130 | |
| 131 | // return a C-API error message matching to `errnum` |
| 132 | pub fn c_error_number_str(errnum int) string { |
| 133 | mut err_msg := '' |
| 134 | $if freestanding { |
| 135 | err_msg = 'error ' + errnum.str() |
| 136 | } $else { |
| 137 | $if !vinix { |
| 138 | c_msg := C.strerror(errnum) |
| 139 | err_msg = string{ |
| 140 | str: &u8(c_msg) |
| 141 | len: int(unsafe { C.strlen(c_msg) }) |
| 142 | is_lit: 1 |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 | return err_msg |
| 147 | } |
| 148 | |
| 149 | // panic_n prints an error message, followed by the given number, then exits the process with exit code of 1. |
| 150 | @[noreturn] |
| 151 | pub fn panic_n(s string, number1 i64) { |
| 152 | panic(s + impl_i64_to_string(number1)) |
| 153 | } |
| 154 | |
| 155 | // panic_n2 prints an error message, followed by the given numbers, then exits the process with exit code of 1. |
| 156 | @[noreturn] |
| 157 | pub fn panic_n2(s string, number1 i64, number2 i64) { |
| 158 | panic(s + impl_i64_to_string(number1) + ', ' + impl_i64_to_string(number2)) |
| 159 | } |
| 160 | |
| 161 | // panic_n3 prints an error message, followed by the given numbers, then exits the process with exit code of 1. |
| 162 | @[noreturn] |
| 163 | fn panic_n3(s string, number1 i64, number2 i64, number3 i64) { |
| 164 | panic(s + impl_i64_to_string(number1) + ', ' + impl_i64_to_string(number2) + ', ' + |
| 165 | impl_i64_to_string(number3)) |
| 166 | } |
| 167 | |
| 168 | // panic with a C-API error message matching `errnum` |
| 169 | @[noreturn] |
| 170 | pub fn panic_error_number(basestr string, errnum int) { |
| 171 | panic(basestr + c_error_number_str(errnum)) |
| 172 | } |
| 173 | |