diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 726c117867274c..a59017596b2136 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1515,11 +1515,7 @@ static inline void __${sym.cname}_pushval(${sym.cname} ch, ${push_arg} val) { g.write_alias_typesymbol_declaration(sym) } } - for sym in g.table.type_symbols { - if sym.kind == .function && sym.name !in c.builtins { - g.write_fn_typesymbol_declaration(sym) - } - } + g.write_sorted_fn_typesymbol_declaration() // Generating interfaces after all the common types have been defined // to prevent generating interface struct before definition of field types for sym in g.table.type_symbols { @@ -6382,6 +6378,63 @@ fn (mut g Gen) sort_globals_consts() { } } +// sort functions by dependent arguments and return value +// As functions may depend on one another, make sure they are +// defined in the correct order: add non dependent ones first. +fn (mut g Gen) write_sorted_fn_typesymbol_declaration() { + util.timing_start(@METHOD) + defer { + util.timing_measure(@METHOD) + } + mut syms := []&ast.TypeSymbol{} // functions to be defined + for sym in g.table.type_symbols { + if sym.kind == .function && sym.name !in c.builtins { + syms << sym + } + } + mut pending := []&ast.TypeSymbol{} // functions with a dependency + for { + // Add non dependent functions or functions which + // dependency has been added. + next: for sym in syms { + info := sym.info as ast.FnType + func := info.func + return_sym := g.table.sym(func.return_type) + if return_sym in syms { + pending << sym + continue + } + for param in func.params { + param_sym := g.table.sym(param.typ) + if param_sym in syms { + pending << sym + continue next + } + } + g.write_fn_typesymbol_declaration(sym) + } + if pending.len == 0 { + // All functions were added. + break + } + if syms.len == pending.len { + // Could not add any function: there is a circular + // dependency. + mut deps := []string{} + for sym in pending { + deps << sym.name + } + verror( + 'cgen.write_sorted_fn_typesymbol_declaration(): the following functions form a dependency cycle:\n' + + deps.join(',')) + } + unsafe { + // Swap the to-be-processed and the dependent functions. + syms, pending = pending, syms[..0] + } + } +} + // sort structs by dependent fields fn (mut g Gen) sort_structs(typesa []&ast.TypeSymbol) []&ast.TypeSymbol { util.timing_start(@METHOD) diff --git a/vlib/v/gen/c/testdata/func_type_dependency.c.must_have b/vlib/v/gen/c/testdata/func_type_dependency.c.must_have new file mode 100644 index 00000000000000..1f6571766e14c7 --- /dev/null +++ b/vlib/v/gen/c/testdata/func_type_dependency.c.must_have @@ -0,0 +1,4 @@ +typedef void (*gdi__Function_ptr)(); +typedef void (*gdi__Function_ptr2)(); +typedef gdi__Function_ptr* (*gdi__Get_proc_address)(i8*); +typedef void (*gdi__Set_proc_address)(gdi__Function_ptr2*); \ No newline at end of file diff --git a/vlib/v/gen/c/testdata/func_type_dependency.vv b/vlib/v/gen/c/testdata/func_type_dependency.vv new file mode 100644 index 00000000000000..07d4ccc9b854b1 --- /dev/null +++ b/vlib/v/gen/c/testdata/func_type_dependency.vv @@ -0,0 +1,8 @@ +// vtest vflags: -shared +module gdi + +pub type Get_proc_address = fn(&i8) &Function_ptr +pub type Set_proc_address = fn(&Function_ptr2) + +pub type Function_ptr = fn () +pub type Function_ptr2 = fn ()