aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6_generator/ApiExtractor
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6_generator/ApiExtractor')
-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
9 files changed, 144 insertions, 40 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
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)