diff --git a/cl/_testcpp/template_class/in.h b/cl/_testcpp/template_class/in.h index 77b1cc05..e2b8f6ab 100644 --- a/cl/_testcpp/template_class/in.h +++ b/cl/_testcpp/template_class/in.h @@ -1,11 +1,24 @@ template -class Foo { -private: +struct Foo { T value; -public: Foo(T val) : value(val) {} ~Foo() {} void g(T val) {} }; + +template +class Bar { +private: + T1 v1; + T2 v2; + int v3; + +public: + Bar(T1 val1, T2 val2, int val3) : v1(val1), v2(val2), v3(val3) {} + virtual ~Bar() {} + virtual T2 g(T1 val1, T2 val2, int val3) { + return val2 + } +}; diff --git a/cl/_testcpp/template_class/out.go b/cl/_testcpp/template_class/out.go index f06c291d..a64546a5 100644 --- a/cl/_testcpp/template_class/out.go +++ b/cl/_testcpp/template_class/out.go @@ -1,5 +1,27 @@ package foo +import ( + "github.com/goplus/lib/c" + "unsafe" +) + type Foo[T any] struct { - value T + Value T +} +type Bar[T1 any, T2 any] struct { + _xgo_vptr unsafe.Pointer + v1 T1 + v2 T2 + v3 c.Int +} + +// llgo:type C +type _xgo_vtable_Bar[T1 any, T2 any] struct { + XGo_dtor func(this *Bar) + XGo_dtor_deleting func(this *Bar) + G func(this *Bar, val1 T1, val2 T2, val3 c.Int) T2 +} + +func (p *Bar[T1, T2]) XGo_vptr() *_xgo_vtable_Bar[T1, T2] { + return (*_xgo_vtable_Bar[T1, T2])(p._xgo_vptr) } diff --git a/cl/vtable.go b/cl/vtable.go index c382103d..9bd7ec09 100644 --- a/cl/vtable.go +++ b/cl/vtable.go @@ -89,14 +89,14 @@ func vtableSlotOf(ctx *pkgCtx, m clang.Cursor, named bool) vtableSlot { // polymorphic class. ownsVptr reports whether the class declares its own vptr // field (no primary base); when false the class shares its primary base's vptr, // which sits at offset 0. -func genVtable(ctx *pkgCtx, scope *classCtx, ownsVptr bool) { - slots := vtableSlots(ctx, scope, scope.decl) +func genVtable(ctx *pkgCtx, this *classCtx, ownsVptr bool) { + slots := vtableSlots(ctx, this, this.decl) if len(slots) == 0 { return } pkg := ctx.pkg pkgTypes := pkg.Types - clsNamed := scope.typNamed + clsNamed := this.typNamed clsName := clsNamed.Obj().Name() recvPtr := types.NewPointer(clsNamed) @@ -111,12 +111,12 @@ func genVtable(ctx *pkgCtx, scope *classCtx, ownsVptr bool) { var fldName string if slot.named { fldName = slot.name - fldType = vtableSlotFunc(ctx, pkgTypes, recvPtr, slot.decl) + fldType = vtableSlotFunc(ctx, pkgTypes, recvPtr, slot.decl, this.scope()) } else { fldName = placeholderSlotName(i) fldType = types.Typ[types.UnsafePointer] } - fields = append(fields, types.NewField(goNodePos(ctx, scope.decl), pkgTypes, fldName, fldType, false)) + fields = append(fields, types.NewField(goNodePos(ctx, this.decl), pkgTypes, fldName, fldType, false)) } vtStruct := types.NewStruct(fields, nil) @@ -126,13 +126,46 @@ func genVtable(ctx *pkgCtx, scope *classCtx, ownsVptr bool) { // method blocks. vtDecl := pkg.NewTypeDefs().SetComments(&ast.CommentGroup{ List: []*ast.Comment{{Text: "\n// llgo:type C"}}, - }).NewType(vtableName(clsName), goNode(ctx, scope.decl)) - vtNamed := vtDecl.InitType(pkg, vtStruct) - vtPtr := types.NewPointer(vtNamed) + }).NewType(vtableName(clsName), goNode(ctx, this.decl)) + var targs = this.tparams + var tparams []*types.TypeParam + var vtRecv types.Type + var hasTarg = len(targs) > 0 + if hasTarg { + tparams = cloneTypeParams(targs) + } + vtNamed := vtDecl.InitType(pkg, vtStruct, tparams...) + if hasTarg { + vtRecv, _ = types.Instantiate(nil, vtNamed, cloneTypes(targs), false) + } else { + vtRecv = vtNamed + } + vtPtr := types.NewPointer(vtRecv) genVptrAccessor(ctx, recvPtr, vtPtr, ownsVptr) } +func cloneTypes(tparams []*types.TypeParam) []types.Type { + ret := make([]types.Type, len(tparams)) + for i, tp := range tparams { + ret[i] = tp + } + return ret +} + +func cloneTypeParams(tparams []*types.TypeParam) []*types.TypeParam { + ret := make([]*types.TypeParam, len(tparams)) + for i, tp := range tparams { + obj := cloneTypeName(tp.Obj()) + ret[i] = types.NewTypeParam(obj, tp.Constraint()) + } + return ret +} + +func cloneTypeName(obj *types.TypeName) *types.TypeName { + return types.NewTypeName(obj.Pos(), obj.Pkg(), obj.Name(), obj.Type()) +} + // genVptrAccessor emits "func (p *X) XGo_vptr() *_xgo_vtable_X". // // When the class owns its vptr the body is: @@ -174,16 +207,16 @@ func genVptrAccessor(ctx *pkgCtx, recvPtr, vtPtr types.Type, ownsVptr bool) { // vtableSlotFunc builds the function-pointer type of a named vtable slot: // func(this *X, ) , mirroring the method signature but with the // receiver turned into an explicit leading "this" parameter. -func vtableSlotFunc(ctx *pkgCtx, pkg *types.Package, recvPtr types.Type, fn clang.Cursor) types.Type { +func vtableSlotFunc(ctx *pkgCtx, pkg *types.Package, recvPtr types.Type, fn clang.Cursor, scope *scopeCtx) types.Type { this := types.NewParam(0, pkg, "this", recvPtr) feats := 0 - rest, variadic := newParams(ctx, pkg, fn, &feats, nil) + rest, variadic := newParams(ctx, pkg, fn, &feats, scope) params := make([]*types.Var, 0, 1+len(rest)) params = append(params, this) for _, param := range rest { params = append(params, param) } - results := toFuncResults(ctx, pkg, fn.ResultType(), &feats, nil) + results := toFuncResults(ctx, pkg, fn.ResultType(), &feats, scope) sig := types.NewSignatureType(nil, nil, nil, types.NewTuple(params...), results, variadic) return sig }