checker, cgen: c2v variadic fixes

master
Alexander Medvednikov 2022-06-02 09:35:05 +03:00
parent 10fb16e00b
commit 8b0e843cb8
2 changed files with 46 additions and 30 deletions

View File

@ -213,8 +213,8 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
} }
} }
} }
if (c.pref.translated || c.file.is_translated) && node.is_variadic //&& node.params.len == 1 && param.typ.is_ptr() {
&& node.params.len == 1 && param.typ.is_ptr() { if (c.pref.translated || c.file.is_translated) && node.is_variadic && param.typ.is_ptr() {
// TODO c2v hack to fix `(const char *s, ...)` // TODO c2v hack to fix `(const char *s, ...)`
param.typ = ast.int_type.ref() param.typ = ast.int_type.ref()
} }

View File

@ -533,33 +533,37 @@ fn (mut g Gen) write_defer_stmts_when_needed() {
} }
fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic bool) ([]string, []string, []bool) { fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic bool) ([]string, []string, []bool) {
mut fargs := []string{} mut fparams := []string{}
mut fargtypes := []string{} mut fparamtypes := []string{}
mut heap_promoted := []bool{} mut heap_promoted := []bool{}
if params.len == 0 { if params.len == 0 {
// in C, `()` is untyped, unlike `(void)` // in C, `()` is untyped, unlike `(void)`
g.write('void') g.write('void')
} }
for i, arg in params { for i, param in params {
mut caname := if arg.name == '_' { g.new_tmp_declaration_name() } else { c_name(arg.name) } mut caname := if param.name == '_' {
typ := g.unwrap_generic(arg.typ) g.new_tmp_declaration_name()
arg_type_sym := g.table.sym(typ) } else {
mut arg_type_name := g.typ(typ) // util.no_dots(arg_type_sym.name) c_name(param.name)
if arg_type_sym.kind == .function { }
info := arg_type_sym.info as ast.FnType typ := g.unwrap_generic(param.typ)
param_type_sym := g.table.sym(typ)
mut param_type_name := g.typ(typ) // util.no_dots(param_type_sym.name)
if param_type_sym.kind == .function {
info := param_type_sym.info as ast.FnType
func := info.func func := info.func
g.write('${g.typ(func.return_type)} (*$caname)(') g.write('${g.typ(func.return_type)} (*$caname)(')
g.definitions.write_string('${g.typ(func.return_type)} (*$caname)(') g.definitions.write_string('${g.typ(func.return_type)} (*$caname)(')
g.fn_decl_params(func.params, voidptr(0), func.is_variadic) g.fn_decl_params(func.params, voidptr(0), func.is_variadic)
g.write(')') g.write(')')
g.definitions.write_string(')') g.definitions.write_string(')')
fargs << caname fparams << caname
fargtypes << arg_type_name fparamtypes << param_type_name
} else { } else {
mut heap_prom := false mut heap_prom := false
if scope != voidptr(0) { if scope != voidptr(0) {
if arg.name != '_' { if param.name != '_' {
if v := scope.find_var(arg.name) { if v := scope.find_var(param.name) {
if !v.is_stack_obj && v.is_auto_heap { if !v.is_stack_obj && v.is_auto_heap {
heap_prom = true heap_prom = true
} }
@ -567,17 +571,17 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic
} }
} }
var_name_prefix := if heap_prom { '_v_toheap_' } else { '' } var_name_prefix := if heap_prom { '_v_toheap_' } else { '' }
const_prefix := if arg.typ.is_any_kind_of_pointer() && !arg.is_mut const_prefix := if param.typ.is_any_kind_of_pointer() && !param.is_mut
&& arg.name.starts_with('const_') { && param.name.starts_with('const_') {
'const ' 'const '
} else { } else {
'' ''
} }
s := '$const_prefix$arg_type_name $var_name_prefix$caname' s := '$const_prefix$param_type_name $var_name_prefix$caname'
g.write(s) g.write(s)
g.definitions.write_string(s) g.definitions.write_string(s)
fargs << caname fparams << caname
fargtypes << arg_type_name fparamtypes << param_type_name
heap_promoted << heap_prom heap_promoted << heap_prom
} }
if i < params.len - 1 { if i < params.len - 1 {
@ -586,10 +590,10 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic
} }
} }
if g.pref.translated && is_variadic { if g.pref.translated && is_variadic {
g.write(', ...') g.write(', ... ')
g.definitions.write_string(', ...') g.definitions.write_string(', ... ')
} }
return fargs, fargtypes, heap_promoted return fparams, fparamtypes, heap_promoted
} }
fn (mut g Gen) get_anon_fn_type_name(mut node ast.AnonFn, var_name string) string { fn (mut g Gen) get_anon_fn_type_name(mut node ast.AnonFn, var_name string) string {
@ -1660,6 +1664,17 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
g.expr(args[args.len - 1].expr) g.expr(args[args.len - 1].expr)
} else { } else {
if variadic_count > 0 { if variadic_count > 0 {
if g.pref.translated || g.file.is_translated {
// Handle passing e.g. C string literals to `...` C varargs:
// void DEH_snprintf(char *buffer, size_t len, const char *fmt, ...)
// deh_snprintf(buffer, 9, c'STCFN%.3d', j++)
for j in arg_nr .. args.len {
g.expr(args[j].expr)
if j < args.len - 1 {
g.write(', ')
}
}
} else {
noscan := g.check_noscan(arr_info.elem_type) noscan := g.check_noscan(arr_info.elem_type)
g.write('new_array_from_c_array${noscan}($variadic_count, $variadic_count, sizeof($elem_type), _MOV(($elem_type[$variadic_count]){') g.write('new_array_from_c_array${noscan}($variadic_count, $variadic_count, sizeof($elem_type), _MOV(($elem_type[$variadic_count]){')
for j in arg_nr .. args.len { for j in arg_nr .. args.len {
@ -1669,6 +1684,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
} }
} }
g.write('}))') g.write('}))')
}
} else { } else {
g.write('__new_array(0, 0, sizeof($elem_type))') g.write('__new_array(0, 0, sizeof($elem_type))')
} }