v / vlib / builtin / panicing.c.v
186 lines · 177 sloc · 5.06 KB · 81a5657604ec6da99c25e26546870c6888d6fdde
Raw
1module 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]
8fn 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]
76pub 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]
83pub 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]
90pub 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`
146pub 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]
165pub 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]
171pub 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]
177fn 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]
184pub fn panic_error_number(basestr string, errnum int) {
185 panic(basestr + c_error_number_str(errnum))
186}
187