cgen: panic with error message when `go` command fails (#10943)
parent
a09324faa9
commit
55c5b9ce7b
|
@ -3,6 +3,7 @@ module builtin
|
||||||
type FnExitCb = fn ()
|
type FnExitCb = fn ()
|
||||||
|
|
||||||
fn C.atexit(f FnExitCb) int
|
fn C.atexit(f FnExitCb) int
|
||||||
|
fn C.strerror(int) &char
|
||||||
|
|
||||||
[noreturn]
|
[noreturn]
|
||||||
fn vhalt() {
|
fn vhalt() {
|
||||||
|
@ -100,6 +101,28 @@ pub fn panic(s string) {
|
||||||
vhalt()
|
vhalt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return a C-API error message matching to `errnum`
|
||||||
|
pub fn c_error_number_str(errnum int) string {
|
||||||
|
mut err_msg := ''
|
||||||
|
$if freestanding {
|
||||||
|
err_msg = 'error $errnum'
|
||||||
|
} $else {
|
||||||
|
c_msg := C.strerror(errnum)
|
||||||
|
err_msg = string{
|
||||||
|
str: &byte(c_msg)
|
||||||
|
len: unsafe { C.strlen(c_msg) }
|
||||||
|
is_lit: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err_msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// panic with a C-API error message matching `errnum`
|
||||||
|
[noreturn]
|
||||||
|
pub fn panic_error_number(basestr string, errnum int) {
|
||||||
|
panic(basestr + c_error_number_str(errnum))
|
||||||
|
}
|
||||||
|
|
||||||
// eprintln prints a message with a line end, to stderr. Both stderr and stdout are flushed.
|
// eprintln prints a message with a line end, to stderr. Both stderr and stdout are flushed.
|
||||||
pub fn eprintln(s string) {
|
pub fn eprintln(s string) {
|
||||||
if s.str == 0 {
|
if s.str == 0 {
|
||||||
|
|
|
@ -134,3 +134,11 @@ fn break_if_debugger_attached() {
|
||||||
_ = ptr
|
_ = ptr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These functions are Windows specific - provide dummys for *nix
|
||||||
|
pub fn winapi_lasterr_str() string {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
[noreturn]
|
||||||
|
pub fn panic_lasterr() {}
|
||||||
|
|
|
@ -54,6 +54,8 @@ fn C.SymFromAddr(h_process voidptr, address u64, p_displacement voidptr, p_symbo
|
||||||
|
|
||||||
fn C.SymGetLineFromAddr64(h_process voidptr, address u64, p_displacement voidptr, p_line &Line64) int
|
fn C.SymGetLineFromAddr64(h_process voidptr, address u64, p_displacement voidptr, p_line &Line64) int
|
||||||
|
|
||||||
|
fn C.FormatMessage(dwFlags u32, lpSource voidptr, dwMessageId u32, dwLanguageId u32, lpBuffer &voidptr, nSize u32, Arguments voidptr) u32
|
||||||
|
|
||||||
// Ref - https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symsetoptions
|
// Ref - https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symsetoptions
|
||||||
const (
|
const (
|
||||||
symopt_undname = 0x00000002
|
symopt_undname = 0x00000002
|
||||||
|
@ -277,3 +279,26 @@ fn break_if_debugger_attached() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return an error message generated from WinAPI's `LastError`
|
||||||
|
pub fn winapi_lasterr_str() string {
|
||||||
|
mut msgbuf := &byte(0)
|
||||||
|
err_msg_id := C.GetLastError()
|
||||||
|
res := C.FormatMessage(C.FORMAT_MESSAGE_ALLOCATE_BUFFER | C.FORMAT_MESSAGE_FROM_SYSTEM,
|
||||||
|
C.NULL, err_msg_id, 0, &msgbuf, 0, C.NULL)
|
||||||
|
err_msg := if res == 0 {
|
||||||
|
'unknown error $err_msg_id'
|
||||||
|
} else {
|
||||||
|
string{
|
||||||
|
str: msgbuf
|
||||||
|
len: int(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err_msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// panic with an error message generated from WinAPI's `LastError`
|
||||||
|
[noreturn]
|
||||||
|
pub fn panic_lasterr(base string) {
|
||||||
|
panic(base + winapi_lasterr_str())
|
||||||
|
}
|
||||||
|
|
|
@ -6597,7 +6597,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
}
|
}
|
||||||
c.skip_flags = cur_skip_flags
|
c.skip_flags = cur_skip_flags
|
||||||
if c.fn_level == 0 && c.pref.output_cross_c && c.ct_cond_stack.len > 0 {
|
if c.fn_level == 0 && c.pref.output_cross_c && c.ct_cond_stack.len > 0 {
|
||||||
c.ct_cond_stack.pop()
|
c.ct_cond_stack.delete_last()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// smartcast sumtypes and interfaces when using `is`
|
// smartcast sumtypes and interfaces when using `is`
|
||||||
|
|
|
@ -6087,6 +6087,7 @@ fn (mut g Gen) go_expr(node ast.GoExpr) {
|
||||||
'thread_$tmp'
|
'thread_$tmp'
|
||||||
}
|
}
|
||||||
g.writeln('HANDLE $simple_handle = CreateThread(0,0, (LPTHREAD_START_ROUTINE)$wrapper_fn_name, $arg_tmp_var, 0,0);')
|
g.writeln('HANDLE $simple_handle = CreateThread(0,0, (LPTHREAD_START_ROUTINE)$wrapper_fn_name, $arg_tmp_var, 0,0);')
|
||||||
|
g.writeln('if (!$simple_handle) panic_lasterr(tos3("`go ${name}()`: "));')
|
||||||
if node.is_expr && node.call_expr.return_type != ast.void_type {
|
if node.is_expr && node.call_expr.return_type != ast.void_type {
|
||||||
g.writeln('$gohandle_name thread_$tmp = {')
|
g.writeln('$gohandle_name thread_$tmp = {')
|
||||||
g.writeln('\t.ret_ptr = $arg_tmp_var->ret_ptr,')
|
g.writeln('\t.ret_ptr = $arg_tmp_var->ret_ptr,')
|
||||||
|
@ -6098,7 +6099,8 @@ fn (mut g Gen) go_expr(node ast.GoExpr) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g.writeln('pthread_t thread_$tmp;')
|
g.writeln('pthread_t thread_$tmp;')
|
||||||
g.writeln('pthread_create(&thread_$tmp, NULL, (void*)$wrapper_fn_name, $arg_tmp_var);')
|
g.writeln('int ${tmp}_thr_res = pthread_create(&thread_$tmp, NULL, (void*)$wrapper_fn_name, $arg_tmp_var);')
|
||||||
|
g.writeln('if (${tmp}_thr_res) panic_error_number(tos3("`go ${name}()`: "), ${tmp}_thr_res);')
|
||||||
if !node.is_expr {
|
if !node.is_expr {
|
||||||
g.writeln('pthread_detach(thread_$tmp);')
|
g.writeln('pthread_detach(thread_$tmp);')
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,6 +280,7 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
||||||
files: ast_files
|
files: ast_files
|
||||||
all_fns: all_fns
|
all_fns: all_fns
|
||||||
all_consts: all_consts
|
all_consts: all_consts
|
||||||
|
pref: pref
|
||||||
}
|
}
|
||||||
// println( all_fns.keys() )
|
// println( all_fns.keys() )
|
||||||
walker.mark_exported_fns()
|
walker.mark_exported_fns()
|
||||||
|
|
|
@ -5,6 +5,7 @@ module markused
|
||||||
// Walk the entire program starting at fn main and marks used (called) functions.
|
// Walk the entire program starting at fn main and marks used (called) functions.
|
||||||
// Unused functions can be safely skipped by the backends to save CPU time and space.
|
// Unused functions can be safely skipped by the backends to save CPU time and space.
|
||||||
import v.ast
|
import v.ast
|
||||||
|
import v.pref
|
||||||
|
|
||||||
pub struct Walker {
|
pub struct Walker {
|
||||||
pub mut:
|
pub mut:
|
||||||
|
@ -12,6 +13,7 @@ pub mut:
|
||||||
used_fns map[string]bool // used_fns['println'] == true
|
used_fns map[string]bool // used_fns['println'] == true
|
||||||
used_consts map[string]bool // used_consts['os.args'] == true
|
used_consts map[string]bool // used_consts['os.args'] == true
|
||||||
n_asserts int
|
n_asserts int
|
||||||
|
pref &pref.Preferences
|
||||||
mut:
|
mut:
|
||||||
files []&ast.File
|
files []&ast.File
|
||||||
all_fns map[string]ast.FnDecl
|
all_fns map[string]ast.FnDecl
|
||||||
|
@ -213,6 +215,13 @@ fn (mut w Walker) expr(node ast.Expr) {
|
||||||
}
|
}
|
||||||
ast.GoExpr {
|
ast.GoExpr {
|
||||||
w.expr(node.call_expr)
|
w.expr(node.call_expr)
|
||||||
|
if w.pref.os == .windows {
|
||||||
|
w.fn_by_name('panic_lasterr')
|
||||||
|
w.fn_by_name('winapi_lasterr_str')
|
||||||
|
} else {
|
||||||
|
w.fn_by_name('c_error_number_str')
|
||||||
|
w.fn_by_name('panic_error_number')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ast.IndexExpr {
|
ast.IndexExpr {
|
||||||
w.expr(node.left)
|
w.expr(node.left)
|
||||||
|
|
Loading…
Reference in New Issue