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