diff options
Diffstat (limited to 'sources/shiboken2')
19 files changed, 394 insertions, 15 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index 8ff2310e9..ed700e4fa 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -1878,12 +1878,40 @@ bool AbstractMetaBuilderPrivate::setArrayArgumentType(AbstractMetaFunction *func return true; } +static bool generateExceptionHandling(const AbstractMetaFunction *func, + ExceptionSpecification spec, + TypeSystem::ExceptionHandling handling) +{ + switch (func->functionType()) { + case AbstractMetaFunction::CopyConstructorFunction: + case AbstractMetaFunction::MoveConstructorFunction: + case AbstractMetaFunction::AssignmentOperatorFunction: + case AbstractMetaFunction::MoveAssignmentOperatorFunction: + case AbstractMetaFunction::DestructorFunction: + return false; + default: + break; + } + switch (handling) { + case TypeSystem::ExceptionHandling::On: + return true; + case TypeSystem::ExceptionHandling::AutoDefaultToOn: + return spec != ExceptionSpecification::NoExcept; + case TypeSystem::ExceptionHandling::AutoDefaultToOff: + return spec == ExceptionSpecification::Throws; + default: + break; + } + return false; +} + AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem) { if (functionItem->isDeleted() || !functionItem->templateParameters().isEmpty()) return nullptr; QString functionName = functionItem->name(); QString className; + TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; if (m_currentClass) { // Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT // and overridden metaObject(), QGADGET helpers @@ -1892,6 +1920,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio return nullptr; } className = m_currentClass->typeEntry()->qualifiedCppName(); + exceptionHandling = m_currentClass->typeEntry()->exceptionHandling(); if (functionName == QLatin1String("metaObject") && className != QLatin1String("QObject")) return nullptr; } @@ -2050,6 +2079,19 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio metaFunction->setArguments(metaArguments); + const FunctionModificationList functionMods = metaFunction->modifications(m_currentClass); + + for (const FunctionModification &mod : functionMods) { + if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) { + exceptionHandling = mod.exceptionHandling(); + break; + } + } + + metaFunction->setGenerateExceptionHandling(generateExceptionHandling(metaFunction, + functionItem->exceptionSpecification(), + exceptionHandling)); + // Find the correct default values for (int i = 0, size = metaArguments.size(); i < size; ++i) { const ArgumentModelItem &arg = arguments.at(i); @@ -2060,9 +2102,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio if (m_currentClass) { replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1); } else { - FunctionModificationList mods = TypeDatabase::instance()->functionModifications(metaFunction->minimalSignature()); - if (!mods.isEmpty()) { - QVector<ArgumentModification> argMods = mods.constFirst().argument_mods; + if (!functionMods.isEmpty()) { + QVector<ArgumentModification> argMods = functionMods.constFirst().argument_mods; if (!argMods.isEmpty()) replacedExpression = argMods.constFirst().replacedDefaultExpression; } @@ -2101,9 +2142,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio } if (!metaArguments.isEmpty()) { - const FunctionModificationList &mods = metaFunction->modifications(m_currentClass); - fixArgumentNames(metaFunction, mods); - for (const FunctionModification &mod : mods) { + fixArgumentNames(metaFunction, functionMods); + for (const FunctionModification &mod : functionMods) { for (const ArgumentModification &argMod : mod.argument_mods) { if (argMod.array) setArrayArgumentType(metaFunction, functionItem, argMod.index - 1); diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp index 878d7fb9e..35e12f780 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp @@ -407,7 +407,8 @@ AbstractMetaFunction::AbstractMetaFunction() m_userAdded(false), m_explicit(false), m_pointerOperator(false), - m_isCallOperator(false) + m_isCallOperator(false), + m_generateExceptionHandling(false) { } @@ -526,6 +527,7 @@ AbstractMetaFunction *AbstractMetaFunction::copy() const cpy->setType(type()->copy()); cpy->setConstant(isConstant()); cpy->setExceptionSpecification(m_exceptionSpecification); + cpy->setGenerateExceptionHandling(m_generateExceptionHandling); for (AbstractMetaArgument *arg : m_arguments) cpy->addArgument(arg->copy()); @@ -1153,6 +1155,8 @@ void AbstractMetaFunction::formatDebugVerbose(QDebug &d) const d << " throw(...)"; break; } + if (m_generateExceptionHandling) + d << "[generate-exception-handling]"; d << '('; for (int i = 0, count = m_arguments.size(); i < count; ++i) { if (i) @@ -1899,6 +1903,11 @@ bool AbstractMetaClass::hasFunction(const AbstractMetaFunction *f) const return functions_contains(m_functions, f); } +bool AbstractMetaClass::generateExceptionHandling() const +{ + return queryFirstFunction(m_functions, AbstractMetaClass::Visible + | AbstractMetaClass::GenerateExceptionHandling) != nullptr; +} /* Goes through the list of functions and returns a list of all functions matching all of the criteria in \a query. */ @@ -1968,6 +1977,9 @@ bool AbstractMetaClass::queryFunction(const AbstractMetaFunction *f, FunctionQue if ((query & OperatorOverloads) && !f->isOperatorOverload()) return false; + if ((query & GenerateExceptionHandling) && !f->generateExceptionHandling()) + return false; + return true; } diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h index 20c7da6e4..42129e9b7 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.h +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h @@ -849,6 +849,9 @@ public: ExceptionSpecification exceptionSpecification() const; void setExceptionSpecification(ExceptionSpecification e); + bool generateExceptionHandling() const { return m_generateExceptionHandling; } + void setGenerateExceptionHandling(bool g) { m_generateExceptionHandling = g; } + bool isConversionOperator() const { return isConversionOperator(originalName()); @@ -1118,6 +1121,7 @@ private: uint m_explicit : 1; uint m_pointerOperator : 1; uint m_isCallOperator : 1; + uint m_generateExceptionHandling: 1; mutable int m_cachedAllowThread = -1; ExceptionSpecification m_exceptionSpecification = ExceptionSpecification::Unknown; }; @@ -1284,7 +1288,8 @@ public: VirtualInCppFunctions = 0x0020000, // Only functions that are virtual in C++ VirtualInTargetLangFunctions = 0x0080000, // Only functions which are virtual in TargetLang NotRemovedFromTargetLang = 0x0400000, // Only functions that have not been removed from TargetLang - OperatorOverloads = 0x2000000 // Only functions that are operator overloads + OperatorOverloads = 0x2000000, // Only functions that are operator overloads + GenerateExceptionHandling = 0x4000000 }; Q_DECLARE_FLAGS(FunctionQueryOptions, FunctionQueryOption) Q_FLAG(FunctionQueryOption) @@ -1386,6 +1391,8 @@ public: return (hasNonPrivateConstructor() || !hasPrivateConstructor()) && !hasPrivateDestructor(); } + bool generateExceptionHandling() const; + AbstractMetaFunctionList queryFunctionsByName(const QString &name) const; static bool queryFunction(const AbstractMetaFunction *f, FunctionQueryOptions query); static AbstractMetaFunctionList queryFunctionList(const AbstractMetaFunctionList &list, diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst index 2d0c40e20..531c4ece8 100644 --- a/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst +++ b/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst @@ -75,6 +75,7 @@ modify-function remove="all | c++" access="public | private | protected" allow-thread="true | auto | false" + exception-handling="off | auto-off | auto-on | on" rename="..." /> </object-type> @@ -92,6 +93,17 @@ modify-function The value ``auto`` means that it will be turned off for functions for which it is deemed to be safe, for example, simple getters. + The ``exception-handling`` attribute specifies whether to generate exception + handling code (nest the function call into try / catch statements). It accepts + the following values: + + * no, false: Do not generate exception handling code + * auto-off: Generate exception handling code for functions + declaring a non-empty ``throw`` list + * auto-on: Generate exception handling code unless function + declares ``noexcept`` + * yes, true: Always generate exception handling code + The ``remove``, ``access`` and ``rename`` attributes are *optional* attributes for added convenience; they serve the same purpose as the deprecated tags :ref:`remove`, :ref:`access` and :ref:`rename`. diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst index c8a31a426..c3180ae88 100644 --- a/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst +++ b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst @@ -11,7 +11,7 @@ typesystem .. code-block:: xml - <typesystem package="..." default-superclass="..."> + <typesystem package="..." default-superclass="..." exception-handling="..."> </typesystem> The **package** attribute is a string describing the package to be used, @@ -19,6 +19,9 @@ typesystem The *optional* **default-superclass** attribute is the canonical C++ base class name of all objects, e.g., "object". + The *optional* **exception-handling** attribute specifies the default exception + handling mode of all objects (see :ref:`modify-function`). + load-typesystem ^^^^^^^^^^^^^^^ @@ -216,6 +219,7 @@ value-type <typesystem> <value-type name="..." since="..." copyable="yes | no" + exception-handling="..." hash-function="..." stream="yes | no" default-constructor="..." @@ -243,6 +247,9 @@ value-type The **revision** attribute can be used to specify a revision for each type, easing the production of ABI compatible bindings. + The *optional* **exception-handling** attribute specifies the default exception + handling mode of all functions (see :ref:`modify-function`). + .. _object-type: object-type @@ -258,6 +265,7 @@ object-type <object-type name="..." since="..." copyable="yes | no" + exception-handling="..." hash-function="..." stream="yes | no" revision="..." /> @@ -278,6 +286,9 @@ object-type The **revision** attribute can be used to specify a revision for each type, easing the production of ABI compatible bindings. + The *optional* **exception-handling** attribute specifies the default exception + handling mode of all functions (see :ref:`modify-function`). + interface-type ^^^^^^^^^^^^^^ diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp index 33d75f804..af24689fe 100644 --- a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp @@ -328,6 +328,7 @@ struct A { <typesystem package="Foo"> <primitive-type name='int'/> <object-type name='A'> + <modify-function signature='throwing()' exception-handling='auto-on'/> </object-type> </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); @@ -339,14 +340,17 @@ struct A { const AbstractMetaFunction *f = classA->findFunction(QStringLiteral("unspecified")); QVERIFY(f); QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Unknown); + QVERIFY(!f->generateExceptionHandling()); f = classA->findFunction(QStringLiteral("nonThrowing")); QVERIFY(f); QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::NoExcept); + QVERIFY(!f->generateExceptionHandling()); f = classA->findFunction(QStringLiteral("throwing")); QVERIFY(f); QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Throws); + QVERIFY(f->generateExceptionHandling()); } QTEST_APPLESS_MAIN(TestModifyFunction) diff --git a/sources/shiboken2/ApiExtractor/typedatabase.cpp b/sources/shiboken2/ApiExtractor/typedatabase.cpp index 04eba87ca..69cddca4c 100644 --- a/sources/shiboken2/ApiExtractor/typedatabase.cpp +++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp @@ -784,7 +784,8 @@ void ComplexTypeEntry::formatDebug(QDebug &d) const FORMAT_BOOL("genericClass", m_genericClass) if (m_typeFlags != 0) d << ", typeFlags=" << m_typeFlags; - d << ", copyableFlag=" << m_copyableFlag; + d << ", copyableFlag=" << m_copyableFlag + << ", except=" << int(m_exceptionHandling); FORMAT_NONEMPTY_STRING("defaultSuperclass", m_defaultSuperclass) FORMAT_NONEMPTY_STRING("polymorphicIdValue", m_polymorphicIdValue) FORMAT_NONEMPTY_STRING("lookupName", m_lookupName) diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp index 20df181b6..ba219cf5f 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.cpp +++ b/sources/shiboken2/ApiExtractor/typesystem.cpp @@ -64,6 +64,7 @@ static inline QString sinceAttribute() { return QStringLiteral("since"); } static inline QString defaultSuperclassAttribute() { return QStringLiteral("default-superclass"); } static inline QString deleteInMainThreadAttribute() { return QStringLiteral("delete-in-main-thread"); } static inline QString deprecatedAttribute() { return QStringLiteral("deprecated"); } +static inline QString exceptionHandlingAttribute() { return QStringLiteral("exception-handling"); } static inline QString extensibleAttribute() { return QStringLiteral("extensible"); } static inline QString flagsAttribute() { return QStringLiteral("flags"); } static inline QString forceAbstractAttribute() { return QStringLiteral("force-abstract"); } @@ -302,6 +303,18 @@ ENUM_LOOKUP_BEGIN(TypeRejection::MatchType, Qt::CaseSensitive, }; ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_BEGIN(TypeSystem::ExceptionHandling, Qt::CaseSensitive, + exceptionHandlingFromAttribute, TypeSystem::ExceptionHandling::Unspecified) +{ + {QStringViewLiteral("no"), TypeSystem::ExceptionHandling::Off}, + {QStringViewLiteral("false"), TypeSystem::ExceptionHandling::Off}, + {QStringViewLiteral("auto-off"), TypeSystem::ExceptionHandling::AutoDefaultToOff}, + {QStringViewLiteral("auto-on"), TypeSystem::ExceptionHandling::AutoDefaultToOn}, + {QStringViewLiteral("yes"), TypeSystem::ExceptionHandling::On}, + {QStringViewLiteral("true"), TypeSystem::ExceptionHandling::On}, +}; +ENUM_LOOKUP_LINEAR_SEARCH() + ENUM_LOOKUP_BEGIN(StackElement::ElementType, Qt::CaseInsensitive, elementFromTag, StackElement::None) { @@ -1240,6 +1253,7 @@ void Handler::applyComplexTypeAttributes(const QXmlStreamReader &reader, { bool generate = true; ctype->setCopyable(ComplexTypeEntry::Unknown); + auto exceptionHandling = m_exceptionHandling; QString package = m_defaultPackage; for (int i = attributes->size() - 1; i >= 0; --i) { @@ -1266,6 +1280,15 @@ void Handler::applyComplexTypeAttributes(const QXmlStreamReader &reader, } else if (name == copyableAttribute()) { const bool v = convertBoolean(attributes->takeAt(i).value(), copyableAttribute(), false); ctype->setCopyable(v ? ComplexTypeEntry::CopyableSet : ComplexTypeEntry::NonCopyableSet); + } else if (name == exceptionHandlingAttribute()) { + const auto attribute = attributes->takeAt(i); + const auto v = exceptionHandlingFromAttribute(attribute.value()); + if (v != TypeSystem::ExceptionHandling::Unspecified) { + exceptionHandling = v; + } else { + qCWarning(lcShiboken, "%s", + qPrintable(msgInvalidAttributeValue(attribute))); + } } else if (name == QLatin1String("held-type")) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); @@ -1285,6 +1308,9 @@ void Handler::applyComplexTypeAttributes(const QXmlStreamReader &reader, } } + if (exceptionHandling != TypeSystem::ExceptionHandling::Unspecified) + ctype->setExceptionHandling(exceptionHandling); + // The generator code relies on container's package being empty. if (ctype->type() != TypeEntry::ContainerType) ctype->setTargetLangPackage(package); @@ -1410,16 +1436,27 @@ bool Handler::parseModifyDocumentation(const QXmlStreamReader &, return true; } +// m_exceptionHandling TypeSystemTypeEntry *Handler::parseRootElement(const QXmlStreamReader &, const QVersionNumber &since, QXmlStreamAttributes *attributes) { for (int i = attributes->size() - 1; i >= 0; --i) { const QStringRef name = attributes->at(i).qualifiedName(); - if (name == packageAttribute()) + if (name == packageAttribute()) { m_defaultPackage = attributes->takeAt(i).value().toString(); - else if (name == defaultSuperclassAttribute()) + } else if (name == defaultSuperclassAttribute()) { m_defaultSuperclass = attributes->takeAt(i).value().toString(); + } else if (name == exceptionHandlingAttribute()) { + const auto attribute = attributes->takeAt(i); + const auto v = exceptionHandlingFromAttribute(attribute.value()); + if (v != TypeSystem::ExceptionHandling::Unspecified) { + m_exceptionHandling = v; + } else { + qCWarning(lcShiboken, "%s", + qPrintable(msgInvalidAttributeValue(attribute))); + } + } } TypeSystemTypeEntry *moduleEntry = @@ -1942,6 +1979,7 @@ bool Handler::parseModifyFunction(const QXmlStreamReader &reader, QString association; bool deprecated = false; bool isThread = false; + TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; TypeSystem::AllowThread allowThread = TypeSystem::AllowThread::Unspecified; for (int i = attributes->size() - 1; i >= 0; --i) { const QStringRef name = attributes->at(i).qualifiedName(); @@ -1970,6 +2008,13 @@ bool Handler::parseModifyFunction(const QXmlStreamReader &reader, m_error = msgInvalidAttributeValue(attribute); return false; } + } else if (name == exceptionHandlingAttribute()) { + const auto attribute = attributes->takeAt(i); + exceptionHandling = exceptionHandlingFromAttribute(attribute.value()); + if (exceptionHandling == TypeSystem::ExceptionHandling::Unspecified) { + qCWarning(lcShiboken, "%s", + qPrintable(msgInvalidAttributeValue(attribute))); + } } else if (name == virtualSlotAttribute()) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); @@ -1992,6 +2037,7 @@ bool Handler::parseModifyFunction(const QXmlStreamReader &reader, if (!mod.setSignature(signature, &m_error)) return false; mod.setOriginalSignature(originalSignature); + mod.setExceptionHandling(exceptionHandling); m_currentSignature = signature; if (!access.isEmpty()) { diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h index 128b4f021..028f016f3 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.h +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -346,6 +346,9 @@ struct FunctionModification: public Modification void setOriginalSignature(const QString &s) { m_originalSignature = s; } QString originalSignature() const { return m_originalSignature; } + TypeSystem::ExceptionHandling exceptionHandling() const { return m_exceptionHandling; } + void setExceptionHandling(TypeSystem::ExceptionHandling e) { m_exceptionHandling = e; } + QString toString() const; QString association; @@ -359,6 +362,7 @@ private: QRegularExpression m_signaturePattern; bool m_thread = false; AllowThread m_allowThread = AllowThread::Unspecified; + TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; }; struct FieldModification: public Modification @@ -1370,6 +1374,9 @@ public: return m_baseContainerType; } + TypeSystem::ExceptionHandling exceptionHandling() const { return m_exceptionHandling; } + void setExceptionHandling(TypeSystem::ExceptionHandling e) { m_exceptionHandling = e; } + QString defaultConstructor() const; void setDefaultConstructor(const QString& defaultConstructor); bool hasDefaultConstructor() const; @@ -1405,6 +1412,8 @@ private: QString m_hashFunction; const ComplexTypeEntry* m_baseContainerType = nullptr; + // For class functions + TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; }; class TypedefEntry : public ComplexTypeEntry diff --git a/sources/shiboken2/ApiExtractor/typesystem_enums.h b/sources/shiboken2/ApiExtractor/typesystem_enums.h index f0ebc197d..df83429d0 100644 --- a/sources/shiboken2/ApiExtractor/typesystem_enums.h +++ b/sources/shiboken2/ApiExtractor/typesystem_enums.h @@ -90,6 +90,14 @@ enum DocModificationMode { DocModificationInvalid }; +enum class ExceptionHandling { + Unspecified, + Off, + AutoDefaultToOff, + AutoDefaultToOn, + On +}; + } // namespace TypeSystem #endif // TYPESYSTEM_ENUMS_H diff --git a/sources/shiboken2/ApiExtractor/typesystem_p.h b/sources/shiboken2/ApiExtractor/typesystem_p.h index 2bd7cfadd..e36df5151 100644 --- a/sources/shiboken2/ApiExtractor/typesystem_p.h +++ b/sources/shiboken2/ApiExtractor/typesystem_p.h @@ -242,6 +242,7 @@ private: int m_ignoreDepth = 0; QString m_defaultPackage; QString m_defaultSuperclass; + TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; QString m_error; const TypeEntry::CodeGeneration m_generate; diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 2d4ea068d..0f94793e9 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -301,6 +301,8 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) // needs the 'set' class from C++ STL. if (hasMultipleInheritanceInAncestry(metaClass)) s << "#include <set>" << endl; + if (metaClass->generateExceptionHandling()) + s << "#include <exception>" << endl; s << endl << "// module include" << endl << "#include \"" << getModuleHeaderFileName() << '"' << endl; @@ -3077,6 +3079,17 @@ QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, in return pyArgName; } +static QStringList defaultExceptionHandling() +{ + static const QStringList result{ + QLatin1String("} catch (const std::exception &e) {"), + QLatin1String(" PyErr_SetString(PyExc_RuntimeError, e.what());"), + QLatin1String("} catch (...) {"), + QLatin1String(" PyErr_SetString(PyExc_RuntimeError, \"An unknown exception was caught\");"), + QLatin1String("}")}; + return result; +} + void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *func, GeneratorContext &context, int maxArgs) { @@ -3334,8 +3347,17 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f if (!injectedCodeCallsCppFunction(func)) { const bool allowThread = func->allowThread(); - if (allowThread) + const bool generateExceptionHandling = func->generateExceptionHandling(); + if (generateExceptionHandling) { + s << INDENT << "try {\n"; + ++INDENT.indent; + if (allowThread) { + s << INDENT << "Shiboken::ThreadStateSaver threadSaver;\n" + << INDENT << "threadSaver.save();\n"; + } + } else if (allowThread) { s << INDENT << BEGIN_ALLOW_THREADS << endl; + } s << INDENT; if (isCtor) { s << (useVAddr.isEmpty() ? @@ -3369,9 +3391,13 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f } else { s << methodCall << ';' << endl; } - if (allowThread) - s << INDENT << END_ALLOW_THREADS << endl; + if (allowThread) { + s << INDENT << (generateExceptionHandling + ? "threadSaver.restore();" : END_ALLOW_THREADS) << '\n'; + } + + // Convert result if (!func->conversionRule(TypeSystem::TargetLangCode, 0).isEmpty()) { writeConversionRule(s, func, TypeSystem::TargetLangCode, QLatin1String(PYTHON_RETURN_VAR)); } else if (!isCtor && !func->isInplaceOperator() && func->type() @@ -3385,6 +3411,13 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f } s << ';' << endl; } + + if (generateExceptionHandling) { // "catch" code + --INDENT.indent; + const QStringList handlingCode = defaultExceptionHandling(); + for (const auto &line : handlingCode) + s << INDENT << line << '\n'; + } } } diff --git a/sources/shiboken2/tests/libsample/CMakeLists.txt b/sources/shiboken2/tests/libsample/CMakeLists.txt index 7bbc0c3dd..ae3d40312 100644 --- a/sources/shiboken2/tests/libsample/CMakeLists.txt +++ b/sources/shiboken2/tests/libsample/CMakeLists.txt @@ -10,6 +10,7 @@ complex.cpp onlycopy.cpp derived.cpp echo.cpp +exceptiontest.cpp functions.cpp handle.cpp implicitconv.cpp diff --git a/sources/shiboken2/tests/libsample/exceptiontest.cpp b/sources/shiboken2/tests/libsample/exceptiontest.cpp new file mode 100644 index 000000000..1302a8e43 --- /dev/null +++ b/sources/shiboken2/tests/libsample/exceptiontest.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of Qt for Python. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "exceptiontest.h" + +class TestException : public std::exception +{ +public: + const char *what() const noexcept override + { return "TestException"; } +}; + +ExceptionTest::ExceptionTest() = default; + +int ExceptionTest::intThrowStdException(bool doThrow) +{ + if (doThrow) + throw TestException(); + return 1; +} + +void ExceptionTest::voidThrowStdException(bool doThrow) +{ + if (doThrow) + throw TestException(); +} + +int ExceptionTest::intThrowInt(bool doThrow) +{ + if (doThrow) + throw 42; + return 1; +} + +void ExceptionTest::voidThrowInt(bool doThrow) +{ + if (doThrow) + throw 42; +} diff --git a/sources/shiboken2/tests/libsample/exceptiontest.h b/sources/shiboken2/tests/libsample/exceptiontest.h new file mode 100644 index 000000000..8ab3e2b67 --- /dev/null +++ b/sources/shiboken2/tests/libsample/exceptiontest.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of Qt for Python. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef EXCEPTIONTEST_H +#define EXCEPTIONTEST_H + +#include "libsamplemacros.h" + +#include <exception> + +class LIBSAMPLE_API ExceptionTest +{ + public: + ExceptionTest(); + + int intThrowStdException(bool doThrow); + void voidThrowStdException(bool doThrow); + + int intThrowInt(bool doThrow); + void voidThrowInt(bool doThrow); +}; + +#endif // EXCEPTIONTEST_H diff --git a/sources/shiboken2/tests/samplebinding/CMakeLists.txt b/sources/shiboken2/tests/samplebinding/CMakeLists.txt index 4a2b70b57..ca737ca08 100644 --- a/sources/shiboken2/tests/samplebinding/CMakeLists.txt +++ b/sources/shiboken2/tests/samplebinding/CMakeLists.txt @@ -29,6 +29,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/derived_someinnerclass_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/echo_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/event_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/expression_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/exceptiontest_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/friendofonlycopy_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/handleholder_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/implicitconv_wrapper.cpp diff --git a/sources/shiboken2/tests/samplebinding/exception_test.py b/sources/shiboken2/tests/samplebinding/exception_test.py new file mode 100644 index 000000000..d6c02433a --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/exception_test.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# +############################################################################# +## +## Copyright (C) 2018 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of Qt for Python. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +import unittest + +from sample import ExceptionTest + +class CppExceptionTest(unittest.TestCase): + + def testVoid(self): + exceptionCount = 0 + et = ExceptionTest() + + et.voidThrowStdException(False) + + try: + et.voidThrowStdException(True) + except: + exceptionCount += 1 + + et.voidThrowInt(False) + + try: + et.voidThrowInt(True) + except: + exceptionCount += 1 + + self.assertEqual(exceptionCount, 2) + + def testReturnValue(self): + exceptionCount = 0 + et = ExceptionTest() + + result = et.intThrowStdException(False); + + try: + result = et.intThrowStdException(True); + except: + exceptionCount += 1 + + result = et.intThrowInt(False); + + try: + result = et.intThrowInt(True); + except: + exceptionCount += 1 + + self.assertEqual(exceptionCount, 2) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/global.h b/sources/shiboken2/tests/samplebinding/global.h index 1bccc4c66..3984102a8 100644 --- a/sources/shiboken2/tests/samplebinding/global.h +++ b/sources/shiboken2/tests/samplebinding/global.h @@ -37,6 +37,7 @@ #include "sbkdate.h" #include "derived.h" #include "echo.h" +#include "exceptiontest.h" #include "functions.h" #include "implicitconv.h" #include "nontypetemplate.h" diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml index 6f92dcb2f..334f0162d 100644 --- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml @@ -2392,6 +2392,8 @@ <value-type name="Expression" /> + <object-type name="ExceptionTest" exception-handling="auto-on"/> + <value-type name="ModelIndex" /> <value-type name="ReferentModelIndex"> <modify-function signature="operator const ModelIndex&()const"> |