diff --git a/cmd/genbindings/emitcabi.go b/cmd/genbindings/emitcabi.go index 392c8142..3af268dc 100644 --- a/cmd/genbindings/emitcabi.go +++ b/cmd/genbindings/emitcabi.go @@ -718,9 +718,9 @@ extern "C" { } for _, m := range c.VirtualMethods() { - ret.WriteString(fmt.Sprintf("void %s_override_virtual_%s(%s* self, intptr_t slot);\n", methodPrefixName, m.SafeMethodName(), methodPrefixName)) + ret.WriteString(fmt.Sprintf("void %s_override_virtual_%s(%s* self, intptr_t slot);\n", methodPrefixName, m.SafeMethodName(), "void" /*methodPrefixName*/)) - ret.WriteString(fmt.Sprintf("%s %s_virtualbase_%s(%s);\n", m.ReturnType.RenderTypeCabi(), methodPrefixName, m.SafeMethodName(), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+methodPrefixName+"*"))) + ret.WriteString(fmt.Sprintf("%s %s_virtualbase_%s(%s);\n", m.ReturnType.RenderTypeCabi(), methodPrefixName, m.SafeMethodName(), emitParametersCabi(m, ifv(m.IsConst, "const ", "")+"void" /*methodPrefixName*/ +"*"))) } // delete @@ -786,18 +786,27 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) { ret.WriteString("class " + overriddenClassName + " : public virtual " + cppClassName + " {\n" + "public:\n" + - "\tusing " + fullyQualifiedConstructor(cppClassName) + ";\n" + // inherit constructors "\n", ) + for _, ctor := range c.Ctors { + ret.WriteString("\t" + overriddenClassName + "(" + emitParametersCpp(ctor) + "): " + cppClassName + "(" + emitParameterNames(ctor) + ") {};\n") + } + ret.WriteString("\n") + if !c.CanDelete { ret.WriteString( "private:\n" + - "\t~" + overriddenClassName + "();\n" + // = delete;\n" + + "\tvirtual ~" + overriddenClassName + "();\n" + // = delete;\n" + "\n" + "public:\n" + "\n", ) + } else { + ret.WriteString( + "\tvirtual ~" + overriddenClassName + "() = default;\n" + + "\n", + ) } for _, m := range virtualMethods { @@ -834,7 +843,7 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) { ret.WriteString( "\t// Subclass to allow providing a Go implementation\n" + - "\t" + m.ReturnType.RenderTypeQtCpp() + " " + m.CppCallTarget() + "(" + emitParametersCpp(m) + ") " + ifv(m.IsConst, "const ", "") + "override {\n" + + "\tvirtual " + m.ReturnType.RenderTypeQtCpp() + " " + m.CppCallTarget() + "(" + emitParametersCpp(m) + ") " + ifv(m.IsConst, "const ", "") + "override {\n" + "\t\tif (handle__" + m.SafeMethodName() + " == 0) {\n", ) if m.IsPureVirtual { @@ -845,6 +854,10 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) { } } else { ret.WriteString("\t\t\t" + maybeReturn + methodPrefixName + "::" + m.CppCallTarget() + "(" + emitParameterNames(m) + ");\n") + + if m.ReturnType.Void() { + ret.WriteString("\t\t\treturn;\n") + } } ret.WriteString( "\t\t}\n" + @@ -874,12 +887,6 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) { } vbpreamble, vbforwarding := emitParametersCABI2CppForwarding(m.Parameters, "\t\t") - // To call the super/parent's version of this method, normally - // we use the scope operator (Base::Foo()), but that only works - // inside the actual overridden method itself - // Use a reinterpret_cast<> instead - - // vbCallTarget := "reinterpret_cast<" + ifv(m.IsConst, "const ", "") + c.ClassName + "*>(this)->" + m.CppCallTarget() + "(" + vbforwarding + ")" vbCallTarget := methodPrefixName + "::" + m.CppCallTarget() + "(" + vbforwarding + ")" ret.WriteString( @@ -904,18 +911,6 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) { for i, ctor := range c.Ctors { - if len(virtualMethods) > 0 && - len(ctor.Parameters) == 1 && - ctor.Parameters[0].ParameterType == c.ClassName && - (ctor.Parameters[0].Pointer || ctor.Parameters[0].ByRef) { - // This is a copy-constructor for the base class - // We can't just call it on the derived class, that doesn't work: - // ""an inherited constructor is not a candidate for initialization from an expression of the same or derived type"" - // @ref https://stackoverflow.com/q/57926023 - // FIXME need to block this in the header and in Go as well - continue - } - preamble, forwarding := emitParametersCABI2CppForwarding(ctor.Parameters, "\t") if ctor.LinuxOnly { @@ -1063,8 +1058,8 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) { // (Never use a const self*) ret.WriteString( - `void ` + methodPrefixName + `_override_virtual_` + m.SafeMethodName() + `(` + methodPrefixName + `* self, intptr_t slot) {` + "\n" + - "\tdynamic_cast<" + cppClassName + "*>(self)->handle__" + m.SafeMethodName() + " = slot;\n" + + `void ` + methodPrefixName + `_override_virtual_` + m.SafeMethodName() + `(void* self, intptr_t slot) {` + "\n" + + "\t( (" + cppClassName + "*)(self) )->handle__" + m.SafeMethodName() + " = slot;\n" + "}\n" + "\n", ) @@ -1088,10 +1083,10 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) { // callTarget is an rvalue representing the full C++ function call. // These are never static - callTarget := "dynamic_cast<" + ifv(m.IsConst, "const ", "") + cppClassName + "*>(self)->virtualbase_" + m.SafeMethodName() + "(" + strings.Join(parameterNames, `, `) + ")" + callTarget := "( (" + ifv(m.IsConst, "const ", "") + cppClassName + "*)(self) )->virtualbase_" + m.SafeMethodName() + "(" + strings.Join(parameterNames, `, `) + ")" ret.WriteString( - m.ReturnType.RenderTypeCabi() + " " + methodPrefixName + "_virtualbase_" + m.SafeMethodName() + "(" + emitParametersCabi(m, ifv(m.IsConst, "const ", "")+methodPrefixName+"*") + ") {\n" + + m.ReturnType.RenderTypeCabi() + " " + methodPrefixName + "_virtualbase_" + m.SafeMethodName() + "(" + emitParametersCabi(m, ifv(m.IsConst, "const ", "")+"void*") + ") {\n" + "\t" + ifv(m.ReturnType.Void(), "", "return ") + callTarget + ";\n" + "}\n" + "\n", diff --git a/cmd/genbindings/emitgo.go b/cmd/genbindings/emitgo.go index 43aa0737..ff67fe94 100644 --- a/cmd/genbindings/emitgo.go +++ b/cmd/genbindings/emitgo.go @@ -806,6 +806,11 @@ import "C" } for _, m := range c.Methods { + + if m.IsProtected { + continue // Don't add a direct call for it + } + preamble, forwarding := gfs.emitParametersGo2CABIForwarding(m) returnTypeDecl := m.ReturnType.RenderTypeGo(&gfs) @@ -910,7 +915,7 @@ import "C" } ret.WriteString(`func (this *` + goClassName + `) On` + m.SafeMethodName() + `(slot ` + goCbType + `) { - C.` + goClassName + `_override_virtual_` + m.SafeMethodName() + `(this.h, C.intptr_t(cgo.NewHandle(slot)) ) + C.` + goClassName + `_override_virtual_` + m.SafeMethodName() + `(unsafe.Pointer(this.h), C.intptr_t(cgo.NewHandle(slot)) ) } //export miqt_exec_callback_` + goClassName + `_` + m.SafeMethodName() + ` diff --git a/cmd/genbindings/intermediate.go b/cmd/genbindings/intermediate.go index d2bcd08a..eff54906 100644 --- a/cmd/genbindings/intermediate.go +++ b/cmd/genbindings/intermediate.go @@ -394,6 +394,28 @@ func (c *CppClass) VirtualMethods() []CppMethod { var retNames = make(map[string]struct{}, 0) // if name is present, a child class found it first var block = slice_to_set(c.PrivateMethods) + if len(c.Ctors) == 0 { + // This class can't be constructed + // Therefore there's no way to get a derived version of it for subclassing + // (Unless we add custom constructors, but that seems like there would be + // no in-Qt use for such a thing) + // Pretend that this class is non-virtual + return nil + } + + // FIXME Allowing the subclassing of QAccessibleWidget compiles fine, + // but, always gives a linker error: + // + // /usr/lib/go-1.19/pkg/tool/linux_amd64/link: running g++ failed: exit status 1 + // /usr/bin/ld: /tmp/go-link-1745036494/000362.o: in function `MiqtVirtualQAccessibleWidget::MiqtVirtualQAccessibleWidget(QWidget*)': + // undefined reference to `vtable for MiqtVirtualQAccessibleWidget' + // + // An undefined vtable usually indicates that the virtual class is missing + // definitions for some virtual methods, but AFAICT we have complete coverage. + if c.ClassName == "QAccessibleWidget" { + return nil + } + for _, m := range c.Methods { if !m.IsVirtual { continue