Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cl/_testmockc/type/in.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
int sort(void* a, void* b, int elementSize, int count, int (*cmp)(const void*, const void*));

void g(void);
12 changes: 12 additions & 0 deletions cl/_testmockc/type/out.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package foo

import (
"github.com/goplus/lib/c"
"unsafe"
)

//go:linkname Sort C.sort
func Sort(a unsafe.Pointer, b unsafe.Pointer, elementSize c.Int, count c.Int, cmp func(_llcppg_param1 unsafe.Pointer, _llcppg_param2 unsafe.Pointer) c.Int) c.Int

//go:linkname G C.g
func G()
8 changes: 2 additions & 6 deletions cl/blockctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,9 @@ func (p *blockCtx) initFile(file Source) {
p.file.SetLinesForContent(src)
}

func (p *blockCtx) getPubName(pfnName *string) (rewritten bool) {
fnName := *pfnName
pubName := cPubName(fnName)
func (p *blockCtx) getPubName(fnName string) (pubName string, rewritten bool) {
pubName = cPubName(fnName)
rewritten = fnName != pubName
if rewritten {
*pfnName = pubName
}
return
}

Expand Down
55 changes: 24 additions & 31 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,31 +172,16 @@ func compileFunc(ctx *blockCtx, fn clang.Cursor) {
return
}

fnName := clang.String(fn)
origName := clang.String(fn)
if debugCompileDecl {
log.Println("func", fnName, "-", clang.String(fn.Type()))
}
origName := fnName
rewritten := ctx.getPubName(&fnName)
n := fn.NumArguments()
var params []*types.Var
var results *types.Tuple
for i := range n {
item := fn.Argument(c.Uint(i))
param := newParam(ctx, item, i)
params = append(params, param)
}
variadic := fn.IsVariadic() != 0
if variadic {
params = append(params, newVariadicParam(ctx))
log.Println("func", origName, "-", clang.String(fn.Type()))
}
pkg := ctx.pkg
retType := fn.ResultType()
if retType.Kind != lc.TypeVoid {
tyRet := toType(ctx, retType, flagRetType)
results = types.NewTuple(pkg.NewParam(token.NoPos, "", tyRet, false))
}
sig := types.NewSignatureType(nil, nil, nil, types.NewTuple(params...), results, variadic)
pkgTypes := pkg.Types
fnName, rewritten := ctx.getPubName(origName)
params, variadic := newParams(ctx, pkgTypes, fn)
results := toFuncResults(ctx, pkgTypes, fn.ResultType())
sig := types.NewSignatureType(nil, nil, nil, params, results, variadic)
f, err := pkg.NewFuncWith(goNodePos(ctx, fn), fnName, sig, nil)
if err != nil {
log.Panicln("compileFunc:", fnName, err)
Expand All @@ -213,27 +198,35 @@ func compileFunc(ctx *blockCtx, fn clang.Cursor) {
}
}

var (
tyValist types.Type = types.NewSlice(gogen.TyAny)
)

func newVariadicParam(ctx *blockCtx) *types.Var {
return types.NewParam(token.NoPos, ctx.pkg.Types, "__llgo_va_list", tyValist)
func newParams(ctx *blockCtx, pkg *types.Package, fn clang.Cursor) (ret *types.Tuple, variadic bool) {
n := fn.NumArguments()
var params []*types.Var
for i := range n {
item := fn.Argument(c.Uint(i))
param := newParam(ctx, pkg, item, i)
params = append(params, param)
}
variadic = fn.IsVariadic() != 0
if variadic {
params = append(params, newVariadicParam(pkg))
}
ret = types.NewTuple(params...)
return
}

func newParam(ctx *blockCtx, decl clang.Cursor, i c.Int) *types.Var {
func newParam(ctx *blockCtx, pkg *types.Package, decl clang.Cursor, i c.Int) *types.Var {
declName := clang.String(decl)
declTyp := decl.Type()
if debugCompileDecl {
log.Println(" => param", declName, "-", clang.String(declTyp))
}
typ := toType(ctx, declTyp, flagIsParam)
typ := toType(ctx, pkg, declTyp, flagIsParam)
if declName != "" {
avoidKeyword(&declName)
} else {
declName = "_llcppg_param" + strconv.Itoa(int(i)+1)
}
return types.NewParam(goNodePos(ctx, decl), ctx.pkg.Types, declName, typ)
return types.NewParam(goNodePos(ctx, decl), pkg, declName, typ)
}

// -----------------------------------------------------------------------------
51 changes: 49 additions & 2 deletions cl/type_and_var.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import (
"go/token"
"go/types"
"log"
"strconv"

"github.com/goplus/gogen"
"github.com/goplus/lib/c"
"github.com/goplus/llcppg/clang"
lc "github.com/goplus/llcppg/lib/clang"
)
Expand Down Expand Up @@ -60,7 +62,7 @@ func newPointer(typ types.Type) types.Type {
return types.NewPointer(typ)
}

func toType(ctx *blockCtx, typ lc.Type, flags int) types.Type {
func toType(ctx *blockCtx, pkg *types.Package, typ lc.Type, flags int) types.Type {
switch typ.Kind {
case lc.TypeCharS:
return ctx.c.Ref("Char").Type()
Expand All @@ -69,14 +71,59 @@ func toType(ctx *blockCtx, typ lc.Type, flags int) types.Type {
case lc.TypeUInt:
return ctx.c.Ref("Uint").Type()
case lc.TypePointer:
pointee := toType(ctx, typ.PointeeType(), flags)
elem := typ.PointeeType()
if elem.Kind == lc.TypeFunctionProto {
return toFuncType(ctx, pkg, elem)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pointer branch forwards flags recursively (line 78), but the function-proto branch drops flags when calling toFuncType, and toFuncParams then hardcodes flagIsParam. Harmless today since flags is unused in the reachable branches, but the asymmetry could surprise if downstream logic ever keys off flagRetType/flagIsStructField inside a function pointer.

}
pointee := toType(ctx, pkg, elem, flags)
return newPointer(pointee)
case lc.TypeVoid:
return tyVoid
default:
log.Println("==> toType: unknown Kind -", typ.Kind)
}
panic("todo: toType " + clang.String(typ))
}

func toFuncType(ctx *blockCtx, pkg *types.Package, fn lc.Type) *types.Signature {
params, variadic := toFuncParams(ctx, pkg, fn)
results := toFuncResults(ctx, pkg, fn.ResultType())
return types.NewSignatureType(nil, nil, nil, params, results, variadic)
}

func toFuncParams(ctx *blockCtx, pkg *types.Package, fn lc.Type) (ret *types.Tuple, variadic bool) {
n := fn.NumArgTypes()
var params []*types.Var
for i := range n {
item := fn.ArgType(c.Uint(i))
tyParam := toType(ctx, pkg, item, flagIsParam)
nameParam := "_llcppg_param" + strconv.Itoa(int(i)+1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toFuncParams unconditionally names each parameter _llcppg_param<N> and never consults the declared C argument name or applies avoidKeyword. This diverges from newParam (cl/compile.go:217-230), which adopts the real C name when present. For a function-pointer prototype that carries argument names (e.g. int (*cmp)(const void* lhs, const void* rhs)), those names are silently dropped. If dropping them is intentional (proto types often have none), a short comment would help; otherwise consider sharing naming logic with newParam.

params = append(params, types.NewParam(token.NoPos, pkg, nameParam, tyParam))
}
variadic = fn.IsFunctionTypeVariadic() != 0
if variadic {
params = append(params, newVariadicParam(pkg))
}
ret = types.NewTuple(params...)
return
}

var (
tyValist types.Type = types.NewSlice(gogen.TyAny)
)

func newVariadicParam(pkg *types.Package) *types.Var {
return types.NewParam(token.NoPos, pkg, "__llgo_va_list", tyValist)
}

func toFuncResults(ctx *blockCtx, pkg *types.Package, retType lc.Type) (results *types.Tuple) {
if retType.Kind != lc.TypeVoid {
tyRet := toType(ctx, pkg, retType, flagRetType)
results = types.NewTuple(types.NewParam(token.NoPos, pkg, "", tyRet))
}
return
}

// -----------------------------------------------------------------------------

func substObj(pkg *types.Package, scope *types.Scope, origName string, real types.Object) {
Expand Down
Loading