aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2')
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp52
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.cpp14
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.h9
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst12
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst13
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp4
-rw-r--r--sources/shiboken2/ApiExtractor/typedatabase.cpp3
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.cpp50
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.h9
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem_enums.h8
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem_p.h1
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp39
-rw-r--r--sources/shiboken2/tests/libsample/CMakeLists.txt1
-rw-r--r--sources/shiboken2/tests/libsample/exceptiontest.cpp64
-rw-r--r--sources/shiboken2/tests/libsample/exceptiontest.h48
-rw-r--r--sources/shiboken2/tests/samplebinding/CMakeLists.txt1
-rw-r--r--sources/shiboken2/tests/samplebinding/exception_test.py78
-rw-r--r--sources/shiboken2/tests/samplebinding/global.h1
-rw-r--r--sources/shiboken2/tests/samplebinding/typesystem_sample.xml2
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&amp;()const">