Add workaround for clang 3.3/3.4

As reported in #1349, clang before 3.5 can segfault on a function-local
variable referenced inside a lambda.  This moves the function-local
static into a separate function that the lambda can invoke to avoid the
issue.

Fixes #1349
This commit is contained in:
Jason Rhinelander 2018-04-05 11:04:15 -03:00
parent 6c62d2797c
commit 6862cb9b35

View File

@ -1650,6 +1650,7 @@ void register_exception_translator(ExceptionTranslator&& translator) {
template <typename type> template <typename type>
class exception : public object { class exception : public object {
public: public:
exception() = default;
exception(handle scope, const char *name, PyObject *base = PyExc_Exception) { exception(handle scope, const char *name, PyObject *base = PyExc_Exception) {
std::string full_name = scope.attr("__name__").cast<std::string>() + std::string full_name = scope.attr("__name__").cast<std::string>() +
std::string(".") + name; std::string(".") + name;
@ -1666,6 +1667,14 @@ public:
} }
}; };
NAMESPACE_BEGIN(detail)
// Returns a reference to a function-local static exception object used in the simple
// register_exception approach below. (It would be simpler to have the static local variable
// directly in register_exception, but that makes clang <3.5 segfault - issue #1349).
template <typename CppException>
exception<CppException> &get_exception_object() { static exception<CppException> ex; return ex; }
NAMESPACE_END(detail)
/** /**
* Registers a Python exception in `m` of the given `name` and installs an exception translator to * Registers a Python exception in `m` of the given `name` and installs an exception translator to
* translate the C++ exception to the created Python exception using the exceptions what() method. * translate the C++ exception to the created Python exception using the exceptions what() method.
@ -1676,13 +1685,15 @@ template <typename CppException>
exception<CppException> &register_exception(handle scope, exception<CppException> &register_exception(handle scope,
const char *name, const char *name,
PyObject *base = PyExc_Exception) { PyObject *base = PyExc_Exception) {
static exception<CppException> ex(scope, name, base); auto &ex = detail::get_exception_object<CppException>();
if (!ex) ex = exception<CppException>(scope, name, base);
register_exception_translator([](std::exception_ptr p) { register_exception_translator([](std::exception_ptr p) {
if (!p) return; if (!p) return;
try { try {
std::rethrow_exception(p); std::rethrow_exception(p);
} catch (const CppException &e) { } catch (const CppException &e) {
ex(e.what()); detail::get_exception_object<CppException>()(e.what());
} }
}); });
return ex; return ex;