diff --git a/.github/workflows/llgo.yml b/.github/workflows/llgo.yml index 926cb25e..fb4aaccd 100644 --- a/.github/workflows/llgo.yml +++ b/.github/workflows/llgo.yml @@ -24,7 +24,7 @@ jobs: - macos-latest - ubuntu-latest llvm: [22] - llgo: [v1.0.2] + llgo: [v1.0.3] go: [1.27] fail-fast: false runs-on: ${{matrix.os}} diff --git a/cl/_testcpp/class_with_ns/in.h b/cl/_testcpp/class_with_ns/in.h new file mode 100644 index 00000000..d2265a45 --- /dev/null +++ b/cl/_testcpp/class_with_ns/in.h @@ -0,0 +1,13 @@ +namespace bar { + class base + { + public: + ~base(); + }; + + class derived + { + private: + base b; + }; +} diff --git a/cl/_testcpp/class_with_ns/out.go b/cl/_testcpp/class_with_ns/out.go new file mode 100644 index 00000000..4613680d --- /dev/null +++ b/cl/_testcpp/class_with_ns/out.go @@ -0,0 +1,11 @@ +package foo + +type Bar_base struct { +} +type Bar_derived struct { + b Bar_base +} + +// llgo:link (*Bar_base).XGo_Dtor C._ZN3bar4baseD1Ev +func (this *Bar_base) XGo_Dtor() { +} diff --git a/cl/_testcpp/ctor_dtor/out.go b/cl/_testcpp/ctor_dtor/out.go index 2c095389..271bd5f2 100644 --- a/cl/_testcpp/ctor_dtor/out.go +++ b/cl/_testcpp/ctor_dtor/out.go @@ -10,14 +10,13 @@ const ( type Base struct { } +type Bar struct { +} // llgo:link (*Base).XGo_Dtor C._ZN4baseD1Ev func (this *Base) XGo_Dtor() { } -type Bar struct { -} - // llgo:link (*Bar).XGo_Ctor__1 C._ZN3barC1Ei func (this *Bar) XGo_Ctor__1(a c.Int) { } diff --git a/cl/_testcpp/namespace/out.go b/cl/_testcpp/namespace/out.go index 02ecf355..9f59a3ac 100644 --- a/cl/_testcpp/namespace/out.go +++ b/cl/_testcpp/namespace/out.go @@ -7,17 +7,16 @@ import ( const XGoPackage = true +type Bar_base struct { +} +type Bar_boolean = c.Char + //go:linkname Bar_detail_f__1 C._ZN3bar6detail1fEi func Bar_detail_f__1(a c.Int) c.Uint //go:linkname Bar_detail_f__0 C._ZN3bar6detail1fEv func Bar_detail_f__0() -type Bar_base struct { -} - // llgo:link (*Bar_base).XGo_Dtor C._ZN3bar4baseD1Ev func (this *Bar_base) XGo_Dtor() { } - -type Bar_boolean = c.Char diff --git a/cl/class.go b/cl/class.go index 5d718f9c..f8f75a29 100644 --- a/cl/class.go +++ b/cl/class.go @@ -42,22 +42,8 @@ type classCtx struct { inPublic bool } -func compileClass(ctx *pkgCtx, scope *classCtx, cls clang.Cursor, ns string) { - origName := ns + clang.String(cls) - if debugCompileDecl { - log.Println("class", origName) - } - pkg := ctx.pkg - pkgTypes := pkg.Types - clsName, rewritten := ctx.getPubName(origName, -1) - typDecl := pkg.NewTypeDefs().NewType(clsName, goNode(ctx, cls)) - typStruc := types.NewStruct(scope.fields, nil) - typNamed := typDecl.InitType(pkg, typStruc) - if rewritten { - substObj(pkgTypes, pkgTypes.Scope(), origName, typNamed.Obj()) - } +func compileClass(ctx *pkgCtx, scope *classCtx) { scope.reorder() - scope.typNamed = typNamed for _, method := range scope.publicMethods { obj := method.obj if decl := method.outsideDecl; decl.Kind != 0 { @@ -71,8 +57,20 @@ func compileClass(ctx *pkgCtx, scope *classCtx, cls clang.Cursor, ns string) { func loadClass(ctx *pkgCtx, cls clang.Cursor, ns string, defaultInPublic bool) { pkg := ctx.pkg pkgTypes := pkg.Types + origName := ns + clang.String(cls) + if debugCompileDecl { + log.Println("class", origName) + } + clsName, rewritten := ctx.getPubName(origName, -1) + typDecl := pkg.NewTypeDefs().NewType(clsName, goNode(ctx, cls)) + typNamed := typDecl.Type() + if rewritten { + substObj(pkgTypes, pkgTypes.Scope(), origName, typNamed.Obj()) + } + ctx.types[clang.String(cls.Type())] = typNamed scope := &classCtx{ decl: cls, + typNamed: typNamed, overloads: make(map[string]*overloads), inPublic: defaultInPublic, } @@ -80,8 +78,10 @@ func loadClass(ctx *pkgCtx, cls clang.Cursor, ns string, defaultInPublic bool) { loadClassMember(ctx, pkgTypes, scope, decl) return clang.Continue }) + typStruc := types.NewStruct(scope.fields, nil) + typDecl.InitType(pkg, typStruc) ctx.compiles = append(ctx.compiles, func(ctx *pkgCtx) { - compileClass(ctx, scope, cls, ns) + compileClass(ctx, scope) }) } diff --git a/cl/compile.go b/cl/compile.go index f9d836e4..48d62d4f 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -130,10 +130,10 @@ func NewPackage(pkgPath, pkgName string, conf *Config, tu clang.TranslationUnit, nameLookup = defaultNameLookup } ctx := &pkgCtx{ - pkg: pkg, cb: pkg.CB(), llgo: llgo, fset: pkg.Fset, tu: tu, - c: c, lang: conf.Language, cflags: conf.CFlags, - wrapFileHeader: conf.WrapFileHeader, nameLookup: nameLookup, + pkg: pkg, cb: pkg.CB(), llgo: llgo, fset: pkg.Fset, tu: tu, c: c, lang: conf.Language, + cflags: conf.CFlags, wrapFileHeader: conf.WrapFileHeader, nameLookup: nameLookup, methods: make(map[string]*classMethod), macroVals: make(map[string]any), + types: make(map[string]types.Type), } ctx.initFiles(files) loadFiles(ctx) @@ -209,44 +209,41 @@ func loadMacro(ctx *pkgCtx, decl clang.Cursor) { if decl.IsMacroFunctionLike() != 0 { return } - ctx.compiles = append(ctx.compiles, func(ctx *pkgCtx) { - origName := clang.String(decl) - tokens, dispose := ctx.tu.Tokenize(decl.Extent()) - defer dispose() - if debugCompileDecl { - log.Println("macro", origName, "-", len(tokens), "tokens") - } - if len(tokens) > 1 { - if v, ok := evalConstExpr(ctx, tokens[1:]); ok { - pkg := ctx.pkg - pkgTypes := pkg.Types - ctx.macroVals[origName] = v - name, _ := ctx.getPubName(origName, -1) - pkg.NewConstDefs(pkgTypes.Scope()).New(func(cb *gogen.CodeBuilder) int { - cb.Val(v) - return 1 - }, 0, token.NoPos, nil, name) - } + origName := clang.String(decl) + tokens, dispose := ctx.tu.Tokenize(decl.Extent()) + defer dispose() + if debugCompileDecl { + log.Println("macro", origName, "-", len(tokens), "tokens") + } + if len(tokens) > 1 { + if v, ok := evalConstExpr(ctx, tokens[1:]); ok { + pkg := ctx.pkg + pkgTypes := pkg.Types + ctx.macroVals[origName] = v + name, _ := ctx.getPubName(origName, -1) + pkg.NewConstDefs(pkgTypes.Scope()).New(func(cb *gogen.CodeBuilder) int { + cb.Val(v) + return 1 + }, 0, token.NoPos, nil, name) } - }) + } } func loadTypedef(ctx *pkgCtx, decl clang.Cursor, ns string) { - ctx.compiles = append(ctx.compiles, func(ctx *pkgCtx) { - origName := ns + clang.String(decl) - pkg := ctx.pkg - pkgTypes := pkg.Types - underlying := decl.TypedefDeclUnderlyingType() - if debugCompileDecl { - log.Println("typedef", origName, "-", clang.String(underlying)) - } - tunder := toType(ctx, pkgTypes, underlying, flagIsTypedef) - name, rewritten := ctx.getPubName(origName, -1) - t := pkg.NewTypeDefs().AliasType(name, tunder) - if rewritten { - pkgTypes.Scope().Insert(types.NewTypeName(token.NoPos, pkgTypes, origName, t)) - } - }) + pkg := ctx.pkg + pkgTypes := pkg.Types + origName := ns + clang.String(decl) + underlying := decl.TypedefDeclUnderlyingType() + if debugCompileDecl { + log.Println("typedef", origName, "-", clang.String(underlying)) + } + tunder := toType(ctx, pkgTypes, underlying, flagIsTypedef) + name, rewritten := ctx.getPubName(origName, -1) + t := pkg.NewTypeDefs().AliasType(name, tunder) + if rewritten { + pkgTypes.Scope().Insert(types.NewTypeName(token.NoPos, pkgTypes, origName, t)) + } + ctx.types[clang.String(decl.Type())] = t } // ----------------------------------------------------------------------------- diff --git a/cl/ctx.go b/cl/ctx.go index 99b9c78d..c8ae699a 100644 --- a/cl/ctx.go +++ b/cl/ctx.go @@ -19,6 +19,7 @@ package cl import ( "go/ast" "go/token" + "go/types" "log" "sort" "strconv" @@ -109,6 +110,7 @@ type pkgCtx struct { macroVals map[string]any // macroName => value methods map[string]*classMethod // manglingName => class + types map[string]types.Type // c/c++ fullName => types.Type compiles []compileFunc diff --git a/cl/type_and_var.go b/cl/type_and_var.go index 69189fc9..1065fd92 100644 --- a/cl/type_and_var.go +++ b/cl/type_and_var.go @@ -74,6 +74,17 @@ func toType(ctx *pkgCtx, pkg *types.Package, typ lc.Type, flags int) types.Type return newPointer(pointee) case lc.TypeVoid: return tyVoid + case lc.TypeRecord: + cName := fullTypeName(typ) + log.Println("==> fullTypeName:", cName) + if t, ok := ctx.types[cName]; ok { + return t + } + case lc.TypeElaborated: + cName := clang.String(typ.NamedType()) + if t, ok := ctx.types[cName]; ok { + return t + } case lc.TypeFunctionProto: return toFuncType(ctx, pkg, typ) default: @@ -82,6 +93,20 @@ func toType(ctx *pkgCtx, pkg *types.Package, typ lc.Type, flags int) types.Type panic("todo: toType " + clang.String(typ)) } +func fullTypeName(typ lc.Type) string { + decl := typ.TypeDeclaration() + name := clang.String(decl) + for { + parent := decl.SemanticParent() + if kind := parent.Kind; kind != lc.CursorNamespace && kind != lc.CursorLastDecl { + break + } + name = clang.String(parent) + "::" + name + decl = parent + } + return name +} + func toFuncType(ctx *pkgCtx, pkg *types.Package, fn lc.Type) *types.Signature { params, variadic := toFuncParams(ctx, pkg, fn) results := toFuncResults(ctx, pkg, fn.ResultType()) diff --git a/cmd/llcppdump/cppdump.go b/cmd/llcppdump/cppdump.go index be44812c..a2ae1d1c 100644 --- a/cmd/llcppdump/cppdump.go +++ b/cmd/llcppdump/cppdump.go @@ -40,7 +40,7 @@ func dump(node clang.Cursor, ns, presumedFile string) { return clang.Continue } name := ns + clang.String(cur) - log.Println("==>", kind, clang.String(kind), name) + log.Println("==>", kind, clang.String(kind), name, typeOf(cur.Type())) switch kind { case lc.CursorFunctionDecl, lc.CursorCXXMethod, lc.CursorConstructor, lc.CursorDestructor: case lc.CursorClassDecl, lc.CursorNamespace: @@ -50,6 +50,15 @@ func dump(node clang.Cursor, ns, presumedFile string) { }) } +func typeOf(t lc.Type) string { + switch t.Kind { + case lc.TypeElaborated: + return typeOf(t.NamedType()) + default: + return clang.String(t) + } +} + func main() { if len(os.Args) < 2 { fmt.Println("usage: llcppdump []")