aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp')
-rw-r--r--sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp88
1 files changed, 73 insertions, 15 deletions
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