Skip to content

Commit

Permalink
v.gen.c: support inter-dependent function types (vlang#20638)
Browse files Browse the repository at this point in the history
  • Loading branch information
pierrec authored Jan 24, 2024
1 parent d750d1f commit a09bd7c
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 5 deletions.
63 changes: 58 additions & 5 deletions vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions vlib/v/gen/c/testdata/func_type_dependency.c.must_have
Original file line number Diff line number Diff line change
@@ -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*);
8 changes: 8 additions & 0 deletions vlib/v/gen/c/testdata/func_type_dependency.vv
Original file line number Diff line number Diff line change
@@ -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 ()

0 comments on commit a09bd7c

Please sign in to comment.