diff options
Diffstat (limited to 'sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp')
| -rw-r--r-- | sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp | 88 |
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 ¤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 |
