aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
Diffstat (limited to 'sources')
-rw-r--r--sources/pyside6/libpyside/pysideproperty.cpp98
-rw-r--r--sources/shiboken6/tests/libsample/spaceship.cpp22
-rw-r--r--sources/shiboken6/tests/libsample/spaceship.h15
-rw-r--r--sources/shiboken6/tests/samplebinding/CMakeLists.txt1
-rw-r--r--sources/shiboken6/tests/samplebinding/spaceship_test.py18
-rw-r--r--sources/shiboken6/tests/samplebinding/typesystem_sample.xml1
-rw-r--r--sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp88
-rw-r--r--sources/shiboken6_generator/ApiExtractor/abstractmetabuilder_p.h2
-rw-r--r--sources/shiboken6_generator/ApiExtractor/abstractmetalang.cpp43
-rw-r--r--sources/shiboken6_generator/ApiExtractor/abstractmetalang.h2
-rw-r--r--sources/shiboken6_generator/ApiExtractor/clangparser/clangbuilder.cpp1
-rw-r--r--sources/shiboken6_generator/ApiExtractor/parser/codemodel.cpp30
-rw-r--r--sources/shiboken6_generator/ApiExtractor/parser/codemodel.h6
-rw-r--r--sources/shiboken6_generator/ApiExtractor/parser/codemodel_enums.h1
-rw-r--r--sources/shiboken6_generator/ApiExtractor/typedatabase.cpp11
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 &currentClass,
+ 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 &currentClass)
{
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 &currentClass);
- void traverseFreeOperatorFunction(const FunctionModelItem &item,
+ void traverseFreeOperatorFunction(const FunctionModelItem &item, const ScopeModelItem &scope,
const AbstractMetaClassPtr &currentClass);
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)