diff --git a/cl/_testcpp/template_class/in.h b/cl/_testcpp/template_class/in.h index e2b8f6ab..bf562385 100644 --- a/cl/_testcpp/template_class/in.h +++ b/cl/_testcpp/template_class/in.h @@ -19,6 +19,6 @@ class Bar { 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 + return val2; } }; diff --git a/cl/class.go b/cl/class.go index 1c9d85f8..87ccc4db 100644 --- a/cl/class.go +++ b/cl/class.go @@ -102,14 +102,14 @@ func newTemplateParams(ctx *pkgCtx, pkg *types.Package, cls clang.Cursor, feats func loadTemplateClass(ctx *pkgCtx, cls clang.Cursor, ns string, parent *scopeCtx) { origName := nameWithNS(clang.String(cls), ns) - if obj, ok := ctx.addTemplate(ctx, origName, cls, true); ok { + if obj, ok := ctx.addTemplateClass(ctx, origName, cls); ok { ctx.addCompileUnit(func(ctx *pkgCtx) { compileTemplateClass(ctx, obj, parent) }) } } -func compileTemplateClass(ctx *pkgCtx, obj *templateObj, parent *scopeCtx) { +func compileTemplateClass(ctx *pkgCtx, obj *templateClass, parent *scopeCtx) { origName := obj.name cls := obj.decl if debugCompileDecl { @@ -128,6 +128,9 @@ func compileTemplateClass(ctx *pkgCtx, obj *templateObj, parent *scopeCtx) { var clsName string var typDecl, ok = ctx.typdecls[origName] if !ok { + if cls.IsCursorDefinition() == 0 || cls.NumTemplateArguments() > 0 { + return + } clsName = ctx.typeName(origName, true) typDecl = newType(ctx, cls, clsName, tagClass) ctx.typdecls[origName] = typDecl @@ -233,7 +236,8 @@ func isPublic(decl clang.Cursor) bool { func loadClassMember(ctx *pkgCtx, pkg *types.Package, this *classCtx, clsName string, decl clang.Cursor) { switch decl.Kind { - case lc.Cursor_CXXMethod, lc.Cursor_Constructor, lc.Cursor_Destructor: + case lc.Cursor_CXXMethod, lc.Cursor_FunctionTemplate, + lc.Cursor_Constructor, lc.Cursor_Destructor, lc.Cursor_ConversionFunction: var name string switch decl.Kind { case lc.Cursor_Constructor: @@ -351,7 +355,7 @@ func loadClassMember(ctx *pkgCtx, pkg *types.Package, this *classCtx, clsName st } case lc.Cursor_TemplateTypeParameter, lc.Cursor_NonTypeTemplateParameter, - lc.Cursor_TemplateTemplateParameter: + lc.Cursor_TemplateTemplateParameter, lc.Cursor_TypeRef: // noop case lc.Cursor_UnexposedAttr: diff --git a/cl/ctx.go b/cl/ctx.go index fc351b7e..62080ca9 100644 --- a/cl/ctx.go +++ b/cl/ctx.go @@ -164,6 +164,10 @@ func (p *pkgCtx) panicf(decl clang.Cursor, format string, args ...any) { log.Panicf("%s: %s", pos, fmt.Sprintf(format, args...)) } +func (p *pkgCtx) logtf(typ lc.Type, format string, args ...any) { + p.logf(typ.Declaration(), format, args...) +} + const ( anonPrefix = "_llcppg_anon_" ) @@ -453,18 +457,16 @@ func contains(v string, names []string) bool { // ----------------------------------------------------------------------------- -type templateObj struct { +type templateClass struct { name string // go name decl clang.Cursor // AST object overloads *overloads - - isClass bool } -// order returns the order of the template object in the overloads list. +// order returns the order of the template class in the overloads list. // -1 means no order (only one overload, or not found). -func (p *templateObj) order() int { - items := p.overloads.tos +func (p *templateClass) order() int { + items := p.overloads.classes if len(items) > 1 { for i, obj := range items { if obj == p { @@ -498,8 +500,8 @@ func (p *funcObj) order() int { } type overloads struct { - fns []*funcObj - tos []*templateObj + fns []*funcObj + classes []*templateClass } func (p *overloads) reorder() { @@ -540,21 +542,20 @@ func (p *scopeCtx) lookupType(name string) (types.Type, bool) { return nil, false } -func (p *scopeCtx) addTemplate(_ *pkgCtx, name string, decl clang.Cursor, isClass bool) (*templateObj, bool) { +func (p *scopeCtx) addTemplateClass(_ *pkgCtx, name string, decl clang.Cursor) (*templateClass, bool) { if debugCompileDecl { - log.Println("==> addTemplate", name, "-", clang.DisplayName(decl)) + log.Println("==> addTemplateClass", name, "-", clang.DisplayName(decl)) } // TODO(xsw): check if the class is already added - obj := &templateObj{ - name: name, - decl: decl, - isClass: isClass, + obj := &templateClass{ + name: name, + decl: decl, } ovs, ok := p.overloads[name] if ok { - ovs.tos = append(ovs.tos, obj) + ovs.classes = append(ovs.classes, obj) } else { - ovs = &overloads{tos: []*templateObj{obj}} + ovs = &overloads{classes: []*templateClass{obj}} p.overloads[name] = ovs } obj.overloads = ovs diff --git a/cl/type.go b/cl/type.go index 2f53c784..5b6de45e 100644 --- a/cl/type.go +++ b/cl/type.go @@ -19,7 +19,6 @@ package cl import ( "go/token" "go/types" - "log" "strconv" "strings" @@ -64,7 +63,11 @@ const ( func toType(ctx *pkgCtx, pkg *types.Package, typ lc.Type, flags int, scope *scopeCtx) types.Type { var feats int - return toTypeEx(ctx, pkg, typ, flags, &feats, scope) + ret := toTypeEx(ctx, pkg, typ, flags, &feats, scope) + if feats&featIgnored != 0 { + panic("unsupported type - " + clang.String(typ)) + } + return ret } func toTypeEx(ctx *pkgCtx, pkg *types.Package, typ lc.Type, flags int, feats *int, scope *scopeCtx) types.Type { @@ -162,13 +165,15 @@ func toTypeEx(ctx *pkgCtx, pkg *types.Package, typ lc.Type, flags int, feats *in return t } case lc.Type_BlockPointer: - log.Println("==> toType: C blocks is unsupported, use void* as work around") + ctx.logtf(typ, "C blocks (closures) are unsupported, ignored") *feats |= featIgnored return types.Typ[types.UnsafePointer] default: - log.Println("==> toType: unknown Kind -", typ.Kind) + ctx.logtf(typ, "toType: unknown kind - %v", typ.Kind) } - panic("todo: toType " + clang.String(typ)) + ctx.logtf(typ, "unsupported type - %s", clang.String(typ)) + *feats |= featIgnored + return types.Typ[types.Invalid] } func toFuncType(ctx *pkgCtx, pkg *types.Package, fn lc.Type, feats *int) *types.Signature { diff --git a/tool/_testcpp/llvm-22.1.8-support/StringRef/out.go b/tool/_testcpp/llvm-22.1.8-support/StringRef/out.go new file mode 100644 index 00000000..be613888 --- /dev/null +++ b/tool/_testcpp/llvm-22.1.8-support/StringRef/out.go @@ -0,0 +1,291 @@ +package StringRef + +import ( + "github.com/goplus/lib/c" + _ "unsafe" +) + +const XGoPackage = true +const LLGoPackage = "link: -L$(llvm-config --libdir) -lLLVM; -lLLVM" + +type APInt struct { +} +type HashCode struct { +} + +// StringRef - Represent a constant reference to a string, i.e. a character +// array and a length, which need not be null terminated. +// +// This class does not own the string data, it is expected to be used in +// situations where the character data resides in some other buffer, whose +// lifetime extends past that of the StringRef. For this reason, it is not in +// general safe to store a StringRef. +type StringRef struct { + Data *c.Char + Length c.SizeT +} +type StringRefIterator = *c.Char +type StringRefConstStringRefIterator = *c.Char +type StringRefSizeType = c.SizeT +type StringRefValueType = c.Char + +// A wrapper around a string literal that serves as a proxy for constructing +// global tables of StringRefs with the length computed at compile time. +// In order to avoid the invocation of a global constructor, StringLiteral +// should *only* be used in a constexpr context, as such: +// +// constexpr StringLiteral S("test"); +type StringLiteral struct { + StringRef +} + +// Helper functions for StringRef::getAsInteger. +// +//go:linkname GetAsUnsignedInteger C._ZN4llvm20getAsUnsignedIntegerENS_9StringRefEjRy +func GetAsUnsignedInteger(Str StringRef, Radix c.Uint, Result *c.UlongLong) bool + +//go:linkname GetAsSignedInteger C._ZN4llvm18getAsSignedIntegerENS_9StringRefEjRx +func GetAsSignedInteger(Str StringRef, Radix c.Uint, Result *c.LongLong) bool + +//go:linkname GetAutoSenseRadix C._ZN4llvm17getAutoSenseRadixERNS_9StringRefE +func GetAutoSenseRadix(Str *StringRef) c.Uint + +//go:linkname ConsumeUnsignedInteger C._ZN4llvm22consumeUnsignedIntegerERNS_9StringRefEjRy +func ConsumeUnsignedInteger(Str *StringRef, Radix c.Uint, Result *c.UlongLong) bool + +//go:linkname ConsumeSignedInteger C._ZN4llvm20consumeSignedIntegerERNS_9StringRefEjRx +func ConsumeSignedInteger(Str *StringRef, Radix c.Uint, Result *c.LongLong) bool + +//go:linkname StringRefNpos C._ZN4llvm9StringRef4nposE +var StringRefNpos c.SizeT + +// Compare two strings, ignoring case. +// +// llgo:link (*StringRef).CompareInsensitive C._ZNK4llvm9StringRef19compare_insensitiveES0_ +func (this *StringRef) CompareInsensitive(RHS StringRef) c.Int { + return 0 +} + +// compare_numeric - Compare two strings, treating sequences of digits as +// numbers. +// +// llgo:link (*StringRef).CompareNumeric C._ZNK4llvm9StringRef15compare_numericES0_ +func (this *StringRef) CompareNumeric(RHS StringRef) c.Int { + return 0 +} + +// Determine the edit distance between this string and another +// string. +// +// \param Other the string to compare this string against. +// +// \param AllowReplacements whether to allow character +// replacements (change one character into another) as a single +// operation, rather than as two operations (an insertion and a +// removal). +// +// \param MaxEditDistance If non-zero, the maximum edit distance that +// this routine is allowed to compute. If the edit distance will exceed +// that maximum, returns \c MaxEditDistance+1. +// +// \returns the minimum number of character insertions, removals, +// or (if \p AllowReplacements is \c true) replacements needed to +// transform one of the given strings into the other. If zero, +// the strings are identical. +// +// llgo:link (*StringRef).EditDistance C._ZNK4llvm9StringRef13edit_distanceES0_bj +func (this *StringRef) EditDistance(Other StringRef, AllowReplacements bool, MaxEditDistance c.Uint) c.Uint { + return 0 +} + +// llgo:link (*StringRef).EditDistanceInsensitive C._ZNK4llvm9StringRef25edit_distance_insensitiveES0_bj +func (this *StringRef) EditDistanceInsensitive(Other StringRef, AllowReplacements bool, MaxEditDistance c.Uint) c.Uint { + return 0 +} + +// Check if this string starts with the given \p Prefix, ignoring case. +// +// llgo:link (*StringRef).StartsWithInsensitive C._ZNK4llvm9StringRef23starts_with_insensitiveES0_ +func (this *StringRef) StartsWithInsensitive(Prefix StringRef) bool { + return false +} + +// Check if this string ends with the given \p Suffix, ignoring case. +// +// llgo:link (*StringRef).EndsWithInsensitive C._ZNK4llvm9StringRef21ends_with_insensitiveES0_ +func (this *StringRef) EndsWithInsensitive(Suffix StringRef) bool { + return false +} + +// Search for the first character \p C in the string, ignoring case. +// +// \returns The index of the first occurrence of \p C, or npos if not +// found. +// +// llgo:link (*StringRef).FindInsensitive__0 C._ZNK4llvm9StringRef16find_insensitiveEcm +func (this *StringRef) FindInsensitive__0(C c.Char, From c.SizeT) c.SizeT { + return 0 +} + +// Search for the first string \p Str in the string. +// +// \returns The index of the first occurrence of \p Str, or npos if not +// found. +// +// llgo:link (*StringRef).Find__1 C._ZNK4llvm9StringRef4findES0_m +func (this *StringRef) Find__1(Str StringRef, From c.SizeT) c.SizeT { + return 0 +} + +// Search for the first string \p Str in the string, ignoring case. +// +// \returns The index of the first occurrence of \p Str, or npos if not +// found. +// +// llgo:link (*StringRef).FindInsensitive__1 C._ZNK4llvm9StringRef16find_insensitiveES0_m +func (this *StringRef) FindInsensitive__1(Str StringRef, From c.SizeT) c.SizeT { + return 0 +} + +// Search for the last character \p C in the string, ignoring case. +// +// \returns The index of the last occurrence of \p C, or npos if not +// found. +// +// llgo:link (*StringRef).RfindInsensitive__1 C._ZNK4llvm9StringRef17rfind_insensitiveEcm +func (this *StringRef) RfindInsensitive__1(C c.Char, From c.SizeT) c.SizeT { + return 0 +} + +// Search for the last string \p Str in the string. +// +// \returns The index of the last occurrence of \p Str, or npos if not +// found. +// +// llgo:link (*StringRef).Rfind__0 C._ZNK4llvm9StringRef5rfindES0_ +func (this *StringRef) Rfind__0(Str StringRef) c.SizeT { + return 0 +} + +// Search for the last string \p Str in the string, ignoring case. +// +// \returns The index of the last occurrence of \p Str, or npos if not +// found. +// +// llgo:link (*StringRef).RfindInsensitive__0 C._ZNK4llvm9StringRef17rfind_insensitiveES0_ +func (this *StringRef) RfindInsensitive__0(Str StringRef) c.SizeT { + return 0 +} + +// Find the first character in the string that is in \p Chars, or npos if +// not found. +// +// Complexity: O(size() + Chars.size()) +// +// llgo:link (*StringRef).FindFirstOf__1 C._ZNK4llvm9StringRef13find_first_ofES0_m +func (this *StringRef) FindFirstOf__1(Chars StringRef, From c.SizeT) c.SizeT { + return 0 +} + +// Find the first character in the string that is not \p C or npos if not +// found. +// +// llgo:link (*StringRef).FindFirstNotOf__0 C._ZNK4llvm9StringRef17find_first_not_ofEcm +func (this *StringRef) FindFirstNotOf__0(C c.Char, From c.SizeT) c.SizeT { + return 0 +} + +// Find the first character in the string that is not in the string +// \p Chars, or npos if not found. +// +// Complexity: O(size() + Chars.size()) +// +// llgo:link (*StringRef).FindFirstNotOf__1 C._ZNK4llvm9StringRef17find_first_not_ofES0_m +func (this *StringRef) FindFirstNotOf__1(Chars StringRef, From c.SizeT) c.SizeT { + return 0 +} + +// Find the last character in the string that is in \p C, or npos if not +// found. +// +// Complexity: O(size() + Chars.size()) +// +// llgo:link (*StringRef).FindLastOf__1 C._ZNK4llvm9StringRef12find_last_ofES0_m +func (this *StringRef) FindLastOf__1(Chars StringRef, From c.SizeT) c.SizeT { + return 0 +} + +// Find the last character in the string that is not \p C, or npos if not +// found. +// +// llgo:link (*StringRef).FindLastNotOf__0 C._ZNK4llvm9StringRef16find_last_not_ofEcm +func (this *StringRef) FindLastNotOf__0(C c.Char, From c.SizeT) c.SizeT { + return 0 +} + +// Find the last character in the string that is not in \p Chars, or +// npos if not found. +// +// Complexity: O(size() + Chars.size()) +// +// llgo:link (*StringRef).FindLastNotOf__1 C._ZNK4llvm9StringRef16find_last_not_ofES0_m +func (this *StringRef) FindLastNotOf__1(Chars StringRef, From c.SizeT) c.SizeT { + return 0 +} + +// Return the number of non-overlapped occurrences of \p Str in +// the string. +// +// llgo:link (*StringRef).Count__1 C._ZNK4llvm9StringRef5countES0_ +func (this *StringRef) Count__1(Str StringRef) c.SizeT { + return 0 +} + +// Parse the current string as an integer of the specified \p Radix, or of +// an autosensed radix if the \p Radix given is 0. The current value in +// \p Result is discarded, and the storage is changed to be wide enough to +// store the parsed integer. +// +// \returns true if the string does not solely consist of a valid +// non-empty number in the appropriate base. +// +// APInt::fromString is superficially similar but assumes the +// string is well-formed in the given radix. +// +// llgo:link (*StringRef).GetAsInteger__1 C._ZNK4llvm9StringRef12getAsIntegerEjRNS_5APIntE +func (this *StringRef) GetAsInteger__1(Radix c.Uint, Result *APInt) bool { + return false +} + +// Parse the current string as an integer of the specified \p Radix. If +// \p Radix is specified as zero, this does radix autosensing using +// extended C rules: 0 is octal, 0x is hex, 0b is binary. +// +// If the string does not begin with a number of the specified radix, +// this returns true to signify the error. The string is considered +// erroneous if empty. +// The portion of the string representing the discovered numeric value +// is removed from the beginning of the string. +// +// llgo:link (*StringRef).ConsumeInteger__1 C._ZN4llvm9StringRef14consumeIntegerEjRNS_5APIntE +func (this *StringRef) ConsumeInteger__1(Radix c.Uint, Result *APInt) bool { + return false +} + +// Parse the current string as an IEEE double-precision floating +// point value. The string must be a well-formed double. +// +// If \p AllowInexact is false, the function will fail if the string +// cannot be represented exactly. Otherwise, the function only fails +// in case of an overflow or underflow, or an invalid floating point +// representation. +// +// llgo:link (*StringRef).GetAsDouble C._ZNK4llvm9StringRef11getAsDoubleERdb +func (this *StringRef) GetAsDouble(Result *c.Double, AllowInexact bool) bool { + return false +} + +// Compute a hash_code for a StringRef. +// +//go:linkname HashValue C._ZN4llvm10hash_valueENS_9StringRefE +func HashValue(S StringRef) HashCode diff --git a/tool/gen_test.go b/tool/gen_test.go index 88cd0d94..783fe365 100644 --- a/tool/gen_test.go +++ b/tool/gen_test.go @@ -70,7 +70,8 @@ func testGenGo(t *testing.T, pkg *gogen.Package, dir, fname string, exp any) { func testSingleFile(t *testing.T, idx clang.Index, pkgDir, headerDir, headerFile string, conf *tool.Config) { myPkgName := headerFile[len(headerDir) : len(headerFile)-2] - if myPkgName == "Index" || myPkgName == "DenseMapInfo" && runtime.GOOS != "darwin" { + if (myPkgName == "Index" || myPkgName == "DenseMapInfo" || myPkgName == "StringRef") && + runtime.GOOS != "darwin" { log.Println("==> only test Index on macOS") return } @@ -288,6 +289,6 @@ func TestLLVM_DenseMapInfo(t *testing.T) { testFromDir(t, "DenseMapInfo", "./_testcpp", true, "adt") } -func _TestLLVM_String(t *testing.T) { +func TestLLVM_String(t *testing.T) { testFromDir(t, "StringRef", "./_testcpp", true, "adt") }