diff options
Diffstat (limited to 'sources')
15 files changed, 247 insertions, 92 deletions
diff --git a/sources/pyside6/libpyside/pysideproperty.cpp b/sources/pyside6/libpyside/pysideproperty.cpp index ff3c7cc9b..0207a7320 100644 --- a/sources/pyside6/libpyside/pysideproperty.cpp +++ b/sources/pyside6/libpyside/pysideproperty.cpp @@ -319,6 +319,9 @@ static int qpropertyTpInit(PyObject *self, PyObject *args, PyObject *kwds) { auto *pData = propertyPrivate(self); + if (!pData->typeName().isEmpty()) // Cloned copy, already initialized + return 0; + static const char *kwlist[] = {"type", "fget", "fset", "freset", "fdel", "doc", "notify", "designable", "scriptable", "stored", "user", "constant", "final", dataCapsuleKeyName, nullptr}; @@ -402,80 +405,73 @@ static void qpropertyDeAlloc(PyObject *self) } // Create a copy of the property to prevent the @property.setter from modifying -// the property in place and avoid strange side effects in derived classes -// (cf https://bugs.python.org/issue1620). -static PyObject * -_property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *reset, PyObject *del) +// the property in place and avoid strange side effects when modifying the +// property in derived classes (cf https://bugs.python.org/issue1620, +// pysidetest/property_python_test.py). +static PyObject *copyProperty(PyObject *old) { - auto *pData = propertyPrivate(old); - AutoDecRef type(PyObject_Type(old)); - QByteArray doc{}; - if (type.isNull()) - return nullptr; - - if (get == nullptr || get == Py_None) { - Py_XDECREF(get); - get = pData->fget ? pData->fget : Py_None; - } - if (set == nullptr || set == Py_None) { - Py_XDECREF(set); - set = pData->fset ? pData->fset : Py_None; - } - if (reset == nullptr || reset == Py_None) { - Py_XDECREF(reset); - reset = pData->freset ? pData->freset : Py_None; - } - if (del == nullptr || del == Py_None) { - Py_XDECREF(del); - del = pData->fdel ? pData->fdel : Py_None; - } - // make _init use __doc__ from getter - if ((pData->getter_doc && get != Py_None) || pData->doc().isEmpty()) - doc.clear(); - else - doc = pData->doc(); - - auto *notify = pData->notify() ? pData->notify() : Py_None; - - const auto flags = pData->flags(); - PyObject *obNew = - PyObject_CallFunction(type, "OOOOOsO" "bbb" "bbb", - pData->pyTypeObject(), get, set, reset, del, doc.data(), notify, - flags.testFlag(PySide::Property::PropertyFlag::Designable), - flags.testFlag(PySide::Property::PropertyFlag::Scriptable), - flags.testFlag(PySide::Property::PropertyFlag::Stored), - flags.testFlag(PySide::Property::PropertyFlag::User), - flags.testFlag(PySide::Property::PropertyFlag::Constant), - flags.testFlag(PySide::Property::PropertyFlag::Final)); - - return obNew; + Shiboken::AutoDecRef kwds(PyDict_New()); + addDataCapsuleToKwArgs(kwds, propertyPrivate(old)->clone()); + Shiboken::AutoDecRef args(PyTuple_New(0)); + return PyObject_Call(type.object(), args.object(), kwds.object()); } static PyObject *qPropertyGetter(PyObject *self, PyObject *getter) { - return _property_copy(self, getter, nullptr, nullptr, nullptr); + PyObject *result = copyProperty(self); + if (result != nullptr) { + auto *data = propertyPrivate(result); + auto *old = std::exchange(data->fget, getter); + Py_XINCREF(data->fget); + Py_XDECREF(old); + data->setFlag(PySide::Property::PropertyFlag::Readable); + } + return result; } static PyObject *qPropertySetter(PyObject *self, PyObject *setter) { - return _property_copy(self, nullptr, setter, nullptr, nullptr); + PyObject *result = copyProperty(self); + if (result != nullptr) { + auto *data = propertyPrivate(result); + auto *old = std::exchange(data->fset, setter); + Py_XINCREF(data->fset); + Py_XDECREF(old); + data->setFlag(PySide::Property::PropertyFlag::Writable); + } + return result; } static PyObject *qPropertyResetter(PyObject *self, PyObject *resetter) { - return _property_copy(self, nullptr, nullptr, resetter, nullptr); + PyObject *result = copyProperty(self); + if (result != nullptr) { + auto *data = propertyPrivate(result); + auto *old = std::exchange(data->freset, resetter); + Py_XINCREF(data->freset); + Py_XDECREF(old); + data->setFlag(PySide::Property::PropertyFlag::Resettable); + } + return result; } static PyObject *qPropertyDeleter(PyObject *self, PyObject *deleter) { - return _property_copy(self, nullptr, nullptr, nullptr, deleter); + PyObject *result = copyProperty(self); + if (result != nullptr) { + auto *data = propertyPrivate(result); + auto *old = std::exchange(data->fdel, deleter); + Py_XINCREF(data->fdel); + Py_XDECREF(old); + } + return result; } static PyObject *qPropertyCall(PyObject *self, PyObject *args, PyObject * /* kw */) { PyObject *getter = PyTuple_GetItem(args, 0); - return _property_copy(self, getter, nullptr, nullptr, nullptr); + return qPropertyGetter(self, getter); } // PYSIDE-1019: Provide the same getters as Pythons `PyProperty`. diff --git a/sources/shiboken6/tests/libsample/spaceship.cpp b/sources/shiboken6/tests/libsample/spaceship.cpp index b30f2f30f..c883f7c2f 100644 --- a/sources/shiboken6/tests/libsample/spaceship.cpp +++ b/sources/shiboken6/tests/libsample/spaceship.cpp @@ -8,6 +8,13 @@ SpaceshipComparisonTester::SpaceshipComparisonTester(int v) noexcept { } +#if __cplusplus >= 202002 || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002) +std::strong_ordering SpaceshipComparisonTester::operator<=>(int rhs) const +{ + return m_value <=> rhs; +} +#endif // C++ 20 + FreeSpaceshipComparisonTester::FreeSpaceshipComparisonTester(int v) noexcept : m_value(v) { @@ -25,3 +32,18 @@ std::strong_ordering operator<=>(FreeSpaceshipComparisonTester lhs, return lhs.value() <=> rhs.value(); } #endif // C++ 20 + +NonEqualityComparisonTester::NonEqualityComparisonTester(int v) noexcept + : m_value(v) +{ +} + +int NonEqualityComparisonTester::value() const +{ + return m_value; +} + +bool NonEqualityComparisonTester::operator==(NonEqualityComparisonTester rhs) const +{ + return m_value == rhs.m_value; +} diff --git a/sources/shiboken6/tests/libsample/spaceship.h b/sources/shiboken6/tests/libsample/spaceship.h index 0d0854fe6..26f636009 100644 --- a/sources/shiboken6/tests/libsample/spaceship.h +++ b/sources/shiboken6/tests/libsample/spaceship.h @@ -17,6 +17,7 @@ public: #if __cplusplus >= 202002 || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002) auto operator<=>(const SpaceshipComparisonTester &rhs) const = default; + std::strong_ordering operator<=>(int rhs) const; enum Enabled { HasSpaceshipOperator = 1 }; #else @@ -44,4 +45,18 @@ LIBSAMPLE_API std::strong_ordering operator<=>(FreeSpaceshipComparisonTester lhs FreeSpaceshipComparisonTester rhs); #endif // C++ 20 + +class LIBSAMPLE_API NonEqualityComparisonTester +{ +public: + explicit NonEqualityComparisonTester(int v) noexcept; + + int value() const; + + bool operator==(NonEqualityComparisonTester rhs) const; + +private: + int m_value; +}; + #endif // SPACESHIP_H diff --git a/sources/shiboken6/tests/samplebinding/CMakeLists.txt b/sources/shiboken6/tests/samplebinding/CMakeLists.txt index c9e4f601f..01f51fc2d 100644 --- a/sources/shiboken6/tests/samplebinding/CMakeLists.txt +++ b/sources/shiboken6/tests/samplebinding/CMakeLists.txt @@ -64,6 +64,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/moveonly_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/moveonlyhandler_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/noimplicitconversion_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/nondefaultctor_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/nonequalitycomparisontester_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/objectmodel_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/objecttype_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypebyvalue_wrapper.cpp diff --git a/sources/shiboken6/tests/samplebinding/spaceship_test.py b/sources/shiboken6/tests/samplebinding/spaceship_test.py index 92d65d4ee..95d2506ce 100644 --- a/sources/shiboken6/tests/samplebinding/spaceship_test.py +++ b/sources/shiboken6/tests/samplebinding/spaceship_test.py @@ -14,7 +14,8 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) from shiboken_paths import init_paths init_paths() -from sample import FreeSpaceshipComparisonTester, SpaceshipComparisonTester +from sample import (FreeSpaceshipComparisonTester, SpaceshipComparisonTester, + NonEqualityComparisonTester) class SpaceshipTest(unittest.TestCase): @@ -31,6 +32,12 @@ class SpaceshipTest(unittest.TestCase): self.assertFalse(t1 > t2) @unittest.skipUnless(SpaceshipComparisonTester.Enabled.HasSpaceshipOperator, "< C++ 20") + def testNonHomogeneousSpaceshipOperator(self): + t = SpaceshipComparisonTester(42) + self.assertTrue(t < 43) + self.assertTrue(t > 41) + + @unittest.skipUnless(SpaceshipComparisonTester.Enabled.HasSpaceshipOperator, "< C++ 20") def testFreeSpaceshipOperator(self): """Test a free operator<=>(). It does not provide equality as it is not defaulted.""" @@ -39,6 +46,15 @@ class SpaceshipTest(unittest.TestCase): self.assertTrue(t1 < t2) self.assertFalse(t1 > t2) + @unittest.skipUnless(SpaceshipComparisonTester.Enabled.HasSpaceshipOperator, "< C++ 20") + def testNonEqualSynthetization(self): + ne_a = NonEqualityComparisonTester(1) + ne_b = NonEqualityComparisonTester(1) + self.assertTrue(ne_a == ne_b) + # Verify that different instances with same value are not reported as "not equal", + # (fooling the FallbackRichCompare() function which is generated for missing operators). + self.assertFalse(ne_a != ne_b) + if __name__ == '__main__': unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml index fed84ba0d..05798a6ce 100644 --- a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml @@ -160,6 +160,7 @@ <enum-type name="Enabled"/> </value-type> <value-type name="FreeSpaceshipComparisonTester"/> + <value-type name="NonEqualityComparisonTester"/> <primitive-type name="PStr"> <include file-name="str.h" location="global"/> diff --git a/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp index 2413cc1ad..bf8d3246c 100644 --- a/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp @@ -278,8 +278,35 @@ void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelI } } +// Find "operator!=" matching an "operator==" in a scope. +static bool hasOperatorNotEqual(const ScopeModelItem &scopeItem, const FunctionModelItem &operatorEqual) +{ + auto pred = [&operatorEqual](const FunctionModelItem &f) { + return f->isOperatorNotEqual() && operatorEqual->hasEquivalentArguments(*f); + }; + return std::any_of(scopeItem->functions().cbegin(), scopeItem->functions().cend(), pred); +} + +static ComparisonOperators synthesizedSpaceshipComparison(const AbstractMetaClassCPtr ¤tClass, + const FunctionModelItem &item) +{ + const auto te = currentClass->typeEntry(); + // operator "<", ">" not for non-pair type containers + if (te->isContainer()) { + auto cTe = std::static_pointer_cast<const ContainerTypeEntry>(te); + if (cTe->containerKind() != ContainerTypeEntry::PairContainer) + return ComparisonOperatorType::EqualityMask; + } + + // An == operator function is declared implicitly for each operator<=> + // defined as defaulted. + return item->attributes().testFlag(FunctionAttribute::Defaulted) + ? ComparisonOperatorType::AllMask : ComparisonOperatorType::OrderingMask; +} + // Traverse free operator functions (global/namespace) void AbstractMetaBuilderPrivate::traverseFreeOperatorFunction(const FunctionModelItem &item, + const ScopeModelItem &scope, const AbstractMetaClassPtr ¤tClass) { Q_ASSERT(!currentClass || currentClass->isNamespace()); @@ -315,12 +342,6 @@ void AbstractMetaBuilderPrivate::traverseFreeOperatorFunction(const FunctionMode return; } - if (item->isSpaceshipOperator() && !item->isDeleted()) { - AbstractMetaClass::addSynthesizedComparisonOperators(baseoperandClass, - InternalFunctionFlag::OperatorCpp20Spaceship); - return; - } - // Do not synthesize reverse comparison operators. CPython swaps the // arguments for them by itself in Py_tp_richcompare. const bool reverseOperator = !firstArgumentIsSelf && !unaryOperator; @@ -359,6 +380,27 @@ void AbstractMetaBuilderPrivate::traverseFreeOperatorFunction(const FunctionMode if (metaFunction->isComparisonOperator()) metaFunction->setConstant(true); metaFunction->setAccess(Access::Public); + if (item->isSpaceshipOperator()) { + // For spaceship, the traverse mechanism is only used to handle rejections + // and get the argument type. + const auto ops = synthesizedSpaceshipComparison(baseoperandClass, item); + flags.setFlag(InternalFunctionFlag::OperatorCpp20Spaceship); + AbstractMetaClass::addSynthesizedComparisonOperators(baseoperandClass, + metaFunction->arguments(), + ops, flags); + return; + } + + // C++20: Synthesize "!=" from "==" + if (clang::emulatedCompilerLanguageLevel() >= LanguageLevel::Cpp20 + && item->isOperatorEqual() + && !item->hasPointerArguments() && !hasOperatorNotEqual(scope, item)) { + AbstractMetaClass::addSynthesizedComparisonOperators( + baseoperandClass, metaFunction->arguments(), + ComparisonOperatorType::OperatorNotEqual, + flags | InternalFunctionFlag::OperatorCpp20NonEquality); + } + AbstractMetaClass::addFunction(baseoperandClass, metaFunction); ReportHandler::addGeneralMessage(msgSynthesizedFunction(metaFunction, item)); if (!metaFunction->arguments().isEmpty()) { @@ -676,11 +718,11 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom, case CodeModel::ArithmeticOperator: case CodeModel::BitwiseOperator: case CodeModel::LogicalOperator: - traverseFreeOperatorFunction(func, {}); + traverseFreeOperatorFunction(func, dom, {}); break; case CodeModel::ShiftOperator: if (!traverseStreamOperator(func, {})) - traverseFreeOperatorFunction(func, {}); + traverseFreeOperatorFunction(func, dom, {}); default: break; } @@ -1465,7 +1507,7 @@ void AbstractMetaBuilderPrivate::traverseNameSpaceFunctions(const ScopeModelItem functions.reserve(scopeFunctionList.size()); for (const FunctionModelItem &function : scopeFunctionList) { if (function->isOperator()) { - traverseFreeOperatorFunction(function, currentClass); + traverseFreeOperatorFunction(function, scopeItem, currentClass); } else if (auto metaFunction = traverseFunction(function, currentClass)) { metaFunction->setCppAttribute(FunctionAttribute::Static); functions.append(metaFunction); @@ -1548,8 +1590,27 @@ void AbstractMetaBuilderPrivate::traverseClassFunction(const ScopeModelItem& sco const AbstractMetaFunctionPtr &metaFunction, const AbstractMetaClassPtr &metaClass) const { - Q_UNUSED(scopeItem) - Q_UNUSED(function) + if (function->isSpaceshipOperator()) { + // For spaceship, the traverse mechanism is only used to handle rejections + // and get the argument type. + if (!function->isDeleted()) { + const auto ops = synthesizedSpaceshipComparison(metaClass, function); + AbstractMetaClass::addSynthesizedComparisonOperators(metaClass, + metaFunction->arguments(), + ops, InternalFunctionFlag::OperatorCpp20Spaceship); + } + return; + } + + // C++20: Synthesize "!=" from "==" + if (clang::emulatedCompilerLanguageLevel() >= LanguageLevel::Cpp20 + && function->isOperatorEqual() && !hasOperatorNotEqual(scopeItem, function)) { + AbstractMetaClass::addSynthesizedComparisonOperators( + metaClass, metaFunction->arguments(), + ComparisonOperatorType::OperatorNotEqual, + InternalFunctionFlag::OperatorCpp20NonEquality); + } + traverseClassFunction(metaFunction, metaClass); } @@ -1559,10 +1620,7 @@ void AbstractMetaBuilderPrivate::traverseClassFunctions(const ScopeModelItem& sc Q_ASSERT(metaClass); AbstractMetaClass::Attributes constructorAttributes; for (const FunctionModelItem &function : scopeItem->functions()) { - if (function->isSpaceshipOperator() && !function->isDeleted()) { - AbstractMetaClass::addSynthesizedComparisonOperators(metaClass, - InternalFunctionFlag::OperatorCpp20Spaceship); - } else if (auto metaFunction = traverseFunction(function, metaClass)) { + if (auto metaFunction = traverseFunction(function, metaClass)) { traverseClassFunction(scopeItem, function, metaFunction, metaClass); } else if (!function->isDeleted() && function->functionType() == CodeModel::Constructor) { // traverseFunction() failed: mark rejected constructors diff --git a/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder_p.h index b503f4b33..0890eb752 100644 --- a/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder_p.h +++ b/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder_p.h @@ -116,7 +116,7 @@ public: void traverseFields(const ScopeModelItem &item, const AbstractMetaClassPtr &parent); bool traverseStreamOperator(const FunctionModelItem &functionItem, const AbstractMetaClassPtr ¤tClass); - void traverseFreeOperatorFunction(const FunctionModelItem &item, + void traverseFreeOperatorFunction(const FunctionModelItem &item, const ScopeModelItem &scope, const AbstractMetaClassPtr ¤tClass); AbstractMetaFunctionPtr traverseAddedFunctionHelper(const AddedFunctionPtr &addedFunc, diff --git a/sources/shiboken6_generator/ApiExtractor/abstractmetalang.cpp b/sources/shiboken6_generator/ApiExtractor/abstractmetalang.cpp index 837ce0d1a..14ed79644 100644 --- a/sources/shiboken6_generator/ApiExtractor/abstractmetalang.cpp +++ b/sources/shiboken6_generator/ApiExtractor/abstractmetalang.cpp @@ -920,35 +920,30 @@ static AbstractMetaType boolType() return result; } -// Helper to synthesize comparison operators from a spaceship operator. Since -// shiboken also generates code for comparing to different types, this fits -// better than of handling it in the generator code. +// Helper to synthesize comparison operators from a spaceship operator and equality operators. +// Since shiboken also generates code for comparing to different types, this fits +// better than handling it in the generator code. void AbstractMetaClass::addSynthesizedComparisonOperators(const AbstractMetaClassPtr &c, + const AbstractMetaArgumentList &arguments, + ComparisonOperators ops, InternalFunctionFlags flags) { static const auto returnType = boolType(); - AbstractMetaType selfType(c->typeEntry()); - selfType.setConstant(true); - selfType.setReferenceType(LValueReference); - selfType.decideUsagePattern(); - AbstractMetaArgument selfArgument; - selfArgument.setType(selfType); - selfArgument.setName(u"rhs"_s); - AbstractMetaArgumentList arguments(1, selfArgument); - - static const char *operators[] - = {"operator==", "operator!=", "operator<", "operator<=", "operator>", "operator>="}; - for (const auto *op : operators) { - auto *f = AbstractMetaClassPrivate::createFunction(QLatin1StringView(op), - AbstractMetaFunction::ComparisonOperator, - Access::Public, arguments, - returnType, c); - f->setFlags(f->flags() | flags); - f->setConstant(true); - AbstractMetaFunctionCPtr newFunction(f); - c->d->addFunction(newFunction); - ReportHandler::addGeneralMessage(msgSynthesizedFunction(newFunction)); + for (int mask = 0x1; (mask & int(ComparisonOperatorType::AllMask)) != 0; mask <<= 1) { + const auto op = ComparisonOperatorType(mask); + if (ops.testFlag(op)) { + const QString name = "operator"_L1 + QLatin1StringView(AbstractMetaFunction::cppComparisonOperator(op)); + auto *f = AbstractMetaClassPrivate::createFunction(name, + AbstractMetaFunction::ComparisonOperator, + Access::Public, arguments, + returnType, c); + f->setFlags(f->flags() | flags); + f->setConstant(true); + AbstractMetaFunctionCPtr newFunction(f); + c->d->addFunction(newFunction); + ReportHandler::addGeneralMessage(msgSynthesizedFunction(newFunction)); + } } } diff --git a/sources/shiboken6_generator/ApiExtractor/abstractmetalang.h b/sources/shiboken6_generator/ApiExtractor/abstractmetalang.h index 8cc2f71f8..fd9b89443 100644 --- a/sources/shiboken6_generator/ApiExtractor/abstractmetalang.h +++ b/sources/shiboken6_generator/ApiExtractor/abstractmetalang.h @@ -128,6 +128,8 @@ public: bool isCopyConstructible() const; static void addSynthesizedComparisonOperators(const AbstractMetaClassPtr &c, + const AbstractMetaArgumentList &arguments, + ComparisonOperators ops, InternalFunctionFlags flags); bool generateExceptionHandling() const; diff --git a/sources/shiboken6_generator/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken6_generator/ApiExtractor/clangparser/clangbuilder.cpp index 407a7a9e7..8e262d6d8 100644 --- a/sources/shiboken6_generator/ApiExtractor/clangparser/clangbuilder.cpp +++ b/sources/shiboken6_generator/ApiExtractor/clangparser/clangbuilder.cpp @@ -397,6 +397,7 @@ FunctionModelItem BuilderPrivate::createMemberFunction(const CXCursor &cursor, result->setAttribute(FunctionAttribute::Static, clang_CXXMethod_isStatic(cursor) != 0); result->setAttribute(FunctionAttribute::Virtual, clang_CXXMethod_isVirtual(cursor) != 0); result->setAttribute(FunctionAttribute::Abstract, clang_CXXMethod_isPureVirtual(cursor) != 0); + result->setAttribute(FunctionAttribute::Defaulted, clang_CXXMethod_isDefaulted(cursor) != 0); return result; } diff --git a/sources/shiboken6_generator/ApiExtractor/parser/codemodel.cpp b/sources/shiboken6_generator/ApiExtractor/parser/codemodel.cpp index 8cbca7bc9..bfccacbac 100644 --- a/sources/shiboken6_generator/ApiExtractor/parser/codemodel.cpp +++ b/sources/shiboken6_generator/ApiExtractor/parser/codemodel.cpp @@ -846,6 +846,13 @@ void _ArgumentModelItem::setScopeResolution(bool v) m_scopeResolution = v; } +bool _ArgumentModelItem::isEquivalent(const _ArgumentModelItem &rhs) const +{ + return m_scopeResolution == rhs.m_scopeResolution && m_defaultValue == rhs.m_defaultValue + && m_defaultValueExpression == rhs.m_defaultValueExpression + && m_type == rhs.m_type; +} + #ifndef QT_NO_DEBUG_STREAM void _ArgumentModelItem::formatDebug(QDebug &d) const { @@ -991,6 +998,16 @@ bool _FunctionModelItem::isOperator() const return result; } +static bool isPointerArgument(const ArgumentModelItem &a) +{ + return !a->type().indirectionsV().isEmpty(); +} + +bool _FunctionModelItem::hasPointerArguments() const +{ + return std::any_of(m_arguments.cbegin(), m_arguments.cend(), isPointerArgument); +} + ExceptionSpecification _FunctionModelItem::exceptionSpecification() const { return m_exceptionSpecification; @@ -1075,6 +1092,19 @@ QString _FunctionModelItem::typeSystemSignature() const // For dumping out type return result; } +static inline bool equivalentArguments(const ArgumentModelItem &lhs, + const ArgumentModelItem &rhs) +{ + return lhs->isEquivalent(*rhs); +} + +bool _FunctionModelItem::hasEquivalentArguments(const _FunctionModelItem &rhs) const +{ + return m_arguments.size() == rhs.m_arguments.size() + && std::equal(m_arguments.cbegin(), m_arguments.cend(), rhs.m_arguments.cbegin(), rhs.m_arguments.cend(), + equivalentArguments); +} + using NameFunctionTypeHash = QHash<QStringView, CodeModel::FunctionType>; static const NameFunctionTypeHash &nameToOperatorFunction() diff --git a/sources/shiboken6_generator/ApiExtractor/parser/codemodel.h b/sources/shiboken6_generator/ApiExtractor/parser/codemodel.h index 8d757e635..7ff0a88e2 100644 --- a/sources/shiboken6_generator/ApiExtractor/parser/codemodel.h +++ b/sources/shiboken6_generator/ApiExtractor/parser/codemodel.h @@ -380,6 +380,8 @@ public: bool scopeResolution() const; void setScopeResolution(bool v); + bool isEquivalent(const _ArgumentModelItem &rhs) const; // Compare all except name + #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const override; #endif @@ -502,6 +504,7 @@ public: bool isSpaceshipOperator() const; bool isOperatorEqual() const; bool isOperatorNotEqual() const; + bool hasPointerArguments() const; bool isSimilar(const FunctionModelItem &other) const; @@ -515,6 +518,9 @@ public: QString classQualifiedSignature() const; QString typeSystemSignature() const; // For dumping out type system files + // Compare all except names + bool hasEquivalentArguments(const _FunctionModelItem &rhs) const; + // Private, for usage by the clang builder. void _determineType(); diff --git a/sources/shiboken6_generator/ApiExtractor/parser/codemodel_enums.h b/sources/shiboken6_generator/ApiExtractor/parser/codemodel_enums.h index 358195799..272140ae3 100644 --- a/sources/shiboken6_generator/ApiExtractor/parser/codemodel_enums.h +++ b/sources/shiboken6_generator/ApiExtractor/parser/codemodel_enums.h @@ -53,6 +53,7 @@ enum class FunctionAttribute : std::uint8_t { Final = 0x00000010, Deprecated = 0x00000020, // Code annotation Explicit = 0x00000040, // Constructor + Defaulted = 0x00000080 }; Q_DECLARE_FLAGS(FunctionAttributes, FunctionAttribute) diff --git a/sources/shiboken6_generator/ApiExtractor/typedatabase.cpp b/sources/shiboken6_generator/ApiExtractor/typedatabase.cpp index 91d39f835..ae06fb140 100644 --- a/sources/shiboken6_generator/ApiExtractor/typedatabase.cpp +++ b/sources/shiboken6_generator/ApiExtractor/typedatabase.cpp @@ -1739,6 +1739,17 @@ void TypeDatabasePrivate::addBuiltInPrimitiveTypes() root, rootPackage, pyUnicodeCustomEntry); } + + // Prevent rejection of operator<=>() due to mismatched return type. + if (clang::emulatedCompilerLanguageLevel() >= LanguageLevel::Cpp20) { + for (const QString &ordering : {u"std::strong_ordering"_s, u"std::partial_ordering"_s}) { + if (!m_entries.contains(ordering)) { + auto entry = std::make_shared<CustomTypeEntry>(ordering, QVersionNumber{}, root); + entry->setTargetLangPackage(rootPackage); + m_entries.insert(ordering, entry); + } + } + } } QDebug operator<<(QDebug d, const TypeDatabase &db) |
