From ab9a1ece1e032b66f6156acefe3ab26de6b37b7f Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Mon, 10 Jan 2022 12:45:51 -0500 Subject: [PATCH 01/21] Add support for nested C++11 exceptions --- include/pybind11/detail/internals.h | 97 +++++++++++++++++++++++++---- tests/test_exceptions.cpp | 10 ++- tests/test_exceptions.py | 7 +++ 3 files changed, 101 insertions(+), 13 deletions(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 98d21eb983..4410356252 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -10,6 +10,9 @@ #pragma once #include "../pytypes.h" +#include <__threading_support> +#include +#include /// Tracks the `internals` and `type_info` ABI version independent of the main library version. /// @@ -280,21 +283,91 @@ inline internals **&get_internals_pp() { return internals_pp; } +#if PY_VERSION_HEX >= 0x03030000 +/* +// For nested_exception support (todo not working) +template +std::exception_ptr get_nested_exception_ptr_impl(const T &e, std::true_type) { + if (auto nep = dynamic_cast(std::addressof(e))) { + return nep->nested_ptr(); + ; + } + return nullptr; +} + +template +std::exception_ptr get_nested_exception_ptr_impl(const T &, std::false_type) { + return nullptr; +} + +template +std::exception_ptr get_nested_exception_ptr(const T &e) { + return get_nested_exception_ptr_impl(e, is_accessible_base_of()); +} +#endif +*/ inline void translate_exception(std::exception_ptr p) { + if (!p) { + return; + } + auto raise_err = PyErr_SetString; +#if PY_VERSION_HEX >= 0x03030000 + // handles nested C++ exceptions if supported try { - if (p) std::rethrow_exception(p); - } catch (error_already_set &e) { e.restore(); return; - } catch (const builtin_exception &e) { e.set_error(); return; - } catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return; - } catch (const std::domain_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; - } catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; - } catch (const std::length_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; - } catch (const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); return; - } catch (const std::range_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; - } catch (const std::overflow_error &e) { PyErr_SetString(PyExc_OverflowError, e.what()); return; - } catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return; + // std::rethrow_if_nested cannot take exception_ptr + // the only non-UB way to deference it is to throw it + try { + std::rethrow_exception(p); + } catch (const std::exception &e) { + // Future performance optimization + // This throw can be removed with our own template + // that gets the nested exception_ptr directly. + std::rethrow_if_nested(e); + } + } catch (...) { + std::exception_ptr nested = std::current_exception(); + if (nested != p) { + translate_exception(nested); + if (PyErr_Occurred()) { + raise_err = raise_from; + } + } + } +#endif + try { + std::rethrow_exception(p); + } catch (error_already_set &e) { + e.restore(); + return; + } catch (const builtin_exception &e) { + e.set_error(); + return; + } catch (const std::bad_alloc &e) { + raise_err(PyExc_MemoryError, e.what()); + return; + } catch (const std::domain_error &e) { + raise_err(PyExc_ValueError, e.what()); + return; + } catch (const std::invalid_argument &e) { + raise_err(PyExc_ValueError, e.what()); + return; + } catch (const std::length_error &e) { + raise_err(PyExc_ValueError, e.what()); + return; + } catch (const std::out_of_range &e) { + raise_err(PyExc_IndexError, e.what()); + return; + } catch (const std::range_error &e) { + raise_err(PyExc_ValueError, e.what()); + return; + } catch (const std::overflow_error &e) { + raise_err(PyExc_OverflowError, e.what()); + return; + } catch (const std::exception &e) { + raise_err(PyExc_RuntimeError, e.what()); + return; } catch (...) { - PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!"); + raise_err(PyExc_RuntimeError, "Caught an unknown exception!"); return; } } diff --git a/tests/test_exceptions.cpp b/tests/test_exceptions.cpp index 25adb32ed1..3aa9673828 100644 --- a/tests/test_exceptions.cpp +++ b/tests/test_exceptions.cpp @@ -11,6 +11,8 @@ #include "local_bindings.h" #include "pybind11_tests.h" +#include +#include #include // A type that should be raised as an exception in Python @@ -105,7 +107,6 @@ struct PythonAlreadySetInDestructor { py::str s; }; - TEST_SUBMODULE(exceptions, m) { m.def("throw_std_exception", []() { throw std::runtime_error("This exception was intentionally thrown."); @@ -281,5 +282,12 @@ TEST_SUBMODULE(exceptions, m) { } }); + m.def("throw_nested_exception", []() { + try { + throw std::runtime_error("Inner Exception"); + } catch (const std::runtime_error &) { + std::throw_with_nested(std::runtime_error("Outer Exception")); + } + }); #endif } diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 56201a81c5..93e372daad 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -239,6 +239,13 @@ def pycatch(exctype, f, *args): assert str(excinfo.value) == "this is a helper-defined translated exception" +def test_throw_nested_exception(): + with pytest.raises(RuntimeError) as excinfo: + m.throw_nested_exception() + if not env.PY2: + assert str(excinfo.value.__cause__) == "Inner Exception" + + # This can often happen if you wrap a pybind11 class in a Python wrapper def test_invalid_repr(): class MyRepr(object): From 269da46410384d47ab7f16a6b5716bebbc0ed11b Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Mon, 10 Jan 2022 12:49:32 -0500 Subject: [PATCH 02/21] Remove wrong include --- include/pybind11/detail/internals.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 4410356252..99bcbcadc9 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -10,7 +10,6 @@ #pragma once #include "../pytypes.h" -#include <__threading_support> #include #include From bf438d981c25200366ddc0208141fbaa022e9db1 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Mon, 10 Jan 2022 12:55:47 -0500 Subject: [PATCH 03/21] Fix if directive --- include/pybind11/detail/internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 99bcbcadc9..be92eff6cf 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -282,8 +282,8 @@ inline internals **&get_internals_pp() { return internals_pp; } -#if PY_VERSION_HEX >= 0x03030000 /* +#if PY_VERSION_HEX >= 0x03030000 // For nested_exception support (todo not working) template std::exception_ptr get_nested_exception_ptr_impl(const T &e, std::true_type) { From 42d5833bbc8e43d70609d3ccd8ea9d5fbd859d6d Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Mon, 10 Jan 2022 13:47:18 -0500 Subject: [PATCH 04/21] Fix missing skipif --- tests/test_exceptions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 93e372daad..abcd668b59 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -239,11 +239,11 @@ def pycatch(exctype, f, *args): assert str(excinfo.value) == "this is a helper-defined translated exception" +@pytest.mark.skipif("env.PY2") def test_throw_nested_exception(): with pytest.raises(RuntimeError) as excinfo: m.throw_nested_exception() - if not env.PY2: - assert str(excinfo.value.__cause__) == "Inner Exception" + assert str(excinfo.value.__cause__) == "Inner Exception" # This can often happen if you wrap a pybind11 class in a Python wrapper From a1ac8413efd16b99ce03ad7b52e25ce9fb0f613f Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Mon, 10 Jan 2022 14:31:51 -0500 Subject: [PATCH 05/21] Simplify code and try to work around MSVC bug --- include/pybind11/detail/internals.h | 54 ++++++++--------------------- 1 file changed, 14 insertions(+), 40 deletions(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index be92eff6cf..d222089f67 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -282,58 +282,32 @@ inline internals **&get_internals_pp() { return internals_pp; } -/* -#if PY_VERSION_HEX >= 0x03030000 -// For nested_exception support (todo not working) -template -std::exception_ptr get_nested_exception_ptr_impl(const T &e, std::true_type) { - if (auto nep = dynamic_cast(std::addressof(e))) { - return nep->nested_ptr(); - ; - } - return nullptr; -} - -template -std::exception_ptr get_nested_exception_ptr_impl(const T &, std::false_type) { - return nullptr; -} - -template -std::exception_ptr get_nested_exception_ptr(const T &e) { - return get_nested_exception_ptr_impl(e, is_accessible_base_of()); -} -#endif -*/ inline void translate_exception(std::exception_ptr p) { if (!p) { return; } auto raise_err = PyErr_SetString; -#if PY_VERSION_HEX >= 0x03030000 - // handles nested C++ exceptions if supported try { - // std::rethrow_if_nested cannot take exception_ptr - // the only non-UB way to deference it is to throw it +#if PY_VERSION_HEX >= 0x03030000 + // handles nested C++ exceptions if supported try { + // Deference the exception_ptr by rethrowing it. + // Dereferencing an exception_ptr is UB otherwise. std::rethrow_exception(p); } catch (const std::exception &e) { - // Future performance optimization - // This throw can be removed with our own template - // that gets the nested exception_ptr directly. - std::rethrow_if_nested(e); - } - } catch (...) { - std::exception_ptr nested = std::current_exception(); - if (nested != p) { - translate_exception(nested); - if (PyErr_Occurred()) { - raise_err = raise_from; + auto nep = dynamic_cast(std::addressof(e)); + std::exception_ptr nested = nullptr; + if (nep) { + nested = nep->nested_ptr(); + } + if (nested != nullptr && nested != p) { + translate_exception(nested); + if (PyErr_Occurred()) { + raise_err = raise_from; + } } } - } #endif - try { std::rethrow_exception(p); } catch (error_already_set &e) { e.restore(); From 4cf2754e956bb76b734da5d27e8c47887812ce63 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Mon, 10 Jan 2022 14:34:08 -0500 Subject: [PATCH 06/21] Clarify comment --- include/pybind11/detail/internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index d222089f67..0e35ee6201 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -291,7 +291,7 @@ inline void translate_exception(std::exception_ptr p) { #if PY_VERSION_HEX >= 0x03030000 // handles nested C++ exceptions if supported try { - // Deference the exception_ptr by rethrowing it. + // Rethrow the exception_ptr to recove type info. // Dereferencing an exception_ptr is UB otherwise. std::rethrow_exception(p); } catch (const std::exception &e) { From eb13bef7029c050dfb836601a8e3a290ef543781 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Mon, 10 Jan 2022 14:48:23 -0500 Subject: [PATCH 07/21] Further simplify code --- include/pybind11/detail/internals.h | 32 ++++++++++++----------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 0e35ee6201..f652f8d3be 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -11,7 +11,6 @@ #include "../pytypes.h" #include -#include /// Tracks the `internals` and `type_info` ABI version independent of the main library version. /// @@ -287,27 +286,22 @@ inline void translate_exception(std::exception_ptr p) { return; } auto raise_err = PyErr_SetString; - try { #if PY_VERSION_HEX >= 0x03030000 - // handles nested C++ exceptions if supported - try { - // Rethrow the exception_ptr to recove type info. - // Dereferencing an exception_ptr is UB otherwise. - std::rethrow_exception(p); - } catch (const std::exception &e) { - auto nep = dynamic_cast(std::addressof(e)); - std::exception_ptr nested = nullptr; - if (nep) { - nested = nep->nested_ptr(); - } - if (nested != nullptr && nested != p) { - translate_exception(nested); - if (PyErr_Occurred()) { - raise_err = raise_from; - } - } + // handles nested C++ exceptions if supported + try { + // Rethrow the exception_ptr to recove type info. + // Dereferencing an exception_ptr is UB otherwise. + std::rethrow_exception(p); + } catch (const std::nested_exception &nep) { + std::exception_ptr nested = nep.nested_ptr(); + if (nested != nullptr && nested != p) { + translate_exception(nested); + raise_err = raise_from; } + } catch (...) { + } #endif + try { std::rethrow_exception(p); } catch (error_already_set &e) { e.restore(); From b89620a99ef4230bd838eaf5c2d7b2c7d031e7b3 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Tue, 11 Jan 2022 17:03:17 -0500 Subject: [PATCH 08/21] Remove the last extra throw statement --- include/pybind11/detail/internals.h | 83 +++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 16 deletions(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index f652f8d3be..975a1b287e 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -281,58 +281,109 @@ inline internals **&get_internals_pp() { return internals_pp; } +#if PY_VERSION_HEX >= 0x03030000 +inline bool raise_err(PyObject *exc_type, const char *msg) { + bool err_occurred = PyErr_Occurred(); + if (err_occurred) { + raise_from(exc_type, msg); + } else { + PyErr_SetString(exc_type, msg); + } + return err_occurred; +}; + +// forward decl +inline void translate_exception(std::exception_ptr); + +template < + class T, + enable_if_t>>::value, + int> = 0> +bool handle_nested_exception(const T &exc, const std::exception_ptr &p) { + std::exception_ptr nested = nullptr; + nested = exc.nested_ptr(); + if (nested != nullptr && nested != p) { + translate_exception(nested); + return true; + } + return false; +} + +template < + class T, + enable_if_t>>::value, + int> = 0> +bool handle_nested_exception(const T &exc, const std::exception_ptr &p) { + if (auto nep = dynamic_cast(std::addressof(exc))) { + return handle_nested_exception(*nep, p); + } + return false; +} +#else +template +void handle_nested_exception(T) { + return; +} + +inline bool raise_err(PyObject *exc_type, const char *msg) { + PyErr_SetString(exc_type, msg); + return false +} +#endif + + inline void translate_exception(std::exception_ptr p) { if (!p) { return; } - auto raise_err = PyErr_SetString; -#if PY_VERSION_HEX >= 0x03030000 - // handles nested C++ exceptions if supported - try { - // Rethrow the exception_ptr to recove type info. - // Dereferencing an exception_ptr is UB otherwise. - std::rethrow_exception(p); - } catch (const std::nested_exception &nep) { - std::exception_ptr nested = nep.nested_ptr(); - if (nested != nullptr && nested != p) { - translate_exception(nested); - raise_err = raise_from; - } - } catch (...) { - } -#endif try { std::rethrow_exception(p); } catch (error_already_set &e) { + handle_nested_exception(e, p); e.restore(); return; } catch (const builtin_exception &e) { + // Could not use template since it's an abstract class. + if (auto *nep = dynamic_cast(std::addressof(e))) { + handle_nested_exception(*nep, p); + } e.set_error(); return; } catch (const std::bad_alloc &e) { + handle_nested_exception(e, p); raise_err(PyExc_MemoryError, e.what()); return; } catch (const std::domain_error &e) { + handle_nested_exception(e, p); raise_err(PyExc_ValueError, e.what()); return; } catch (const std::invalid_argument &e) { + handle_nested_exception(e, p); raise_err(PyExc_ValueError, e.what()); return; } catch (const std::length_error &e) { + handle_nested_exception(e, p); raise_err(PyExc_ValueError, e.what()); return; } catch (const std::out_of_range &e) { + handle_nested_exception(e, p); raise_err(PyExc_IndexError, e.what()); return; } catch (const std::range_error &e) { + handle_nested_exception(e, p); raise_err(PyExc_ValueError, e.what()); return; } catch (const std::overflow_error &e) { + handle_nested_exception(e, p); raise_err(PyExc_OverflowError, e.what()); return; } catch (const std::exception &e) { + handle_nested_exception(e, p); raise_err(PyExc_RuntimeError, e.what()); return; + } catch (const std::nested_exception &e) { + handle_nested_exception(e, p);. + raise_err(PyExc_RuntimeError, "Caught an unknown nested exception!"); } catch (...) { raise_err(PyExc_RuntimeError, "Caught an unknown exception!"); return; From 09d1ad54e7af8b4e63acc529916fed66e7ee5d91 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Tue, 11 Jan 2022 17:05:16 -0500 Subject: [PATCH 09/21] Qualify auto --- include/pybind11/detail/internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 975a1b287e..c31d9aa8c1 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -314,7 +314,7 @@ template < enable_if_t>>::value, int> = 0> bool handle_nested_exception(const T &exc, const std::exception_ptr &p) { - if (auto nep = dynamic_cast(std::addressof(exc))) { + if (auto *nep = dynamic_cast(std::addressof(exc))) { return handle_nested_exception(*nep, p); } return false; From 3a9156cc5d0f24144ac1acdaa770b22956fabe64 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Tue, 11 Jan 2022 17:08:28 -0500 Subject: [PATCH 10/21] Fix typo --- include/pybind11/detail/internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index c31d9aa8c1..c7cbc13746 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -382,7 +382,7 @@ inline void translate_exception(std::exception_ptr p) { raise_err(PyExc_RuntimeError, e.what()); return; } catch (const std::nested_exception &e) { - handle_nested_exception(e, p);. + handle_nested_exception(e, p); raise_err(PyExc_RuntimeError, "Caught an unknown nested exception!"); } catch (...) { raise_err(PyExc_RuntimeError, "Caught an unknown exception!"); From 5145500ebd0f1d3c675c63f3d69e2e506654c35b Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Tue, 11 Jan 2022 17:10:29 -0500 Subject: [PATCH 11/21] Add missing return for consistency --- include/pybind11/detail/internals.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index c7cbc13746..0f11ec1c39 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -384,6 +384,7 @@ inline void translate_exception(std::exception_ptr p) { } catch (const std::nested_exception &e) { handle_nested_exception(e, p); raise_err(PyExc_RuntimeError, "Caught an unknown nested exception!"); + return; } catch (...) { raise_err(PyExc_RuntimeError, "Caught an unknown exception!"); return; From d2b87f27d01283907e3ddfa65d8d22bfc5219634 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Tue, 11 Jan 2022 17:20:14 -0500 Subject: [PATCH 12/21] Fix clang-tidy complaint --- include/pybind11/detail/internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 0f11ec1c39..4aaef04cdd 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -283,7 +283,7 @@ inline internals **&get_internals_pp() { #if PY_VERSION_HEX >= 0x03030000 inline bool raise_err(PyObject *exc_type, const char *msg) { - bool err_occurred = PyErr_Occurred(); + bool err_occurred = PyErr_Occurred() != nullptr; if (err_occurred) { raise_from(exc_type, msg); } else { From c745ee30c59ec86a428b52059c55682000d6163c Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Tue, 11 Jan 2022 17:25:05 -0500 Subject: [PATCH 13/21] Fix python2 stub --- include/pybind11/detail/internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 4aaef04cdd..a1b6b9655c 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -321,7 +321,7 @@ bool handle_nested_exception(const T &exc, const std::exception_ptr &p) { } #else template -void handle_nested_exception(T) { +void handle_nested_exception(T, std::exception_ptr p) { return; } From 442d958290c1cd02841150a107e0e4591ed0c7ee Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Tue, 11 Jan 2022 17:28:53 -0500 Subject: [PATCH 14/21] Make clang-tidy happy --- include/pybind11/detail/internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index a1b6b9655c..8a113d5da5 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -321,7 +321,7 @@ bool handle_nested_exception(const T &exc, const std::exception_ptr &p) { } #else template -void handle_nested_exception(T, std::exception_ptr p) { +void handle_nested_exception(T, std::exception_ptr) { return; } From d369c87699fbbd14efaeecd22fcfcf1f8cd40c14 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Tue, 11 Jan 2022 17:29:16 -0500 Subject: [PATCH 15/21] Fix compile error --- include/pybind11/detail/internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 8a113d5da5..407ccc0ab8 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -327,7 +327,7 @@ void handle_nested_exception(T, std::exception_ptr) { inline bool raise_err(PyObject *exc_type, const char *msg) { PyErr_SetString(exc_type, msg); - return false + return false; } #endif From c49df0de347d4e5e1a64229e93e3cfcceeb57d40 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Tue, 11 Jan 2022 20:32:40 -0500 Subject: [PATCH 16/21] Fix python2 function signature --- include/pybind11/detail/internals.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 407ccc0ab8..a14d520ad9 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -321,8 +321,8 @@ bool handle_nested_exception(const T &exc, const std::exception_ptr &p) { } #else template -void handle_nested_exception(T, std::exception_ptr) { - return; +bool handle_nested_exception(T, std::exception_ptr) { + return false; } inline bool raise_err(PyObject *exc_type, const char *msg) { From 2578c8765283a94efeca53d19f062cd2e0cd15b8 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Thu, 13 Jan 2022 11:32:42 -0500 Subject: [PATCH 17/21] Extract C++20 utility and backport --- include/pybind11/detail/common.h | 18 ++++++++++++++++++ include/pybind11/detail/internals.h | 22 +++++++++------------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index b08bbc5590..25df2373f1 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -36,6 +36,9 @@ # define PYBIND11_CPP14 # if __cplusplus >= 201703L # define PYBIND11_CPP17 +# if __cplusplus >= 202002L +# define PYBIND11_CPP20 +# endif # endif # endif #elif defined(_MSC_VER) && __cplusplus == 199711L @@ -45,6 +48,9 @@ # define PYBIND11_CPP14 # if _MSVC_LANG > 201402L && _MSC_VER >= 1910 # define PYBIND11_CPP17 +# if _MSVC_LANG > 202002L +# define PYBIND11_CPP20 +# endif # endif # endif #endif @@ -612,6 +618,18 @@ template using remove_cv_t = typename std::remove_cv::type; template using remove_reference_t = typename std::remove_reference::type; #endif +#if defined(PYBIND11_CPP20) +using std::remove_cvref; +using std::remove_cvref_t; +#else +template +struct remove_cvref { + using type = remove_cv_t>; +}; +template +using remove_cvref_t = typename remove_cvref::type; +#endif + /// Index sequences #if defined(PYBIND11_CPP14) using std::index_sequence; diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index a14d520ad9..ca1dbee07c 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -295,10 +295,8 @@ inline bool raise_err(PyObject *exc_type, const char *msg) { // forward decl inline void translate_exception(std::exception_ptr); -template < - class T, - enable_if_t>>::value, - int> = 0> +template >::value, int> = 0> bool handle_nested_exception(const T &exc, const std::exception_ptr &p) { std::exception_ptr nested = nullptr; nested = exc.nested_ptr(); @@ -309,29 +307,27 @@ bool handle_nested_exception(const T &exc, const std::exception_ptr &p) { return false; } -template < - class T, - enable_if_t>>::value, - int> = 0> +template >::value, int> = 0> bool handle_nested_exception(const T &exc, const std::exception_ptr &p) { if (auto *nep = dynamic_cast(std::addressof(exc))) { return handle_nested_exception(*nep, p); } return false; } + #else -template -bool handle_nested_exception(T, std::exception_ptr) { +inline bool raise_err(PyObject *exc_type, const char *msg) { + PyErr_SetString(exc_type, msg); return false; } -inline bool raise_err(PyObject *exc_type, const char *msg) { - PyErr_SetString(exc_type, msg); +template +bool handle_nested_exception(const T&, std::exception_ptr) { return false; } #endif - inline void translate_exception(std::exception_ptr p) { if (!p) { return; From 1c526cf0b1d6698725f79a79615b136b3a7e4aeb Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Thu, 13 Jan 2022 11:41:02 -0500 Subject: [PATCH 18/21] Cleanup code a bit more --- include/pybind11/detail/internals.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index ca1dbee07c..978ee3acb3 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -283,13 +283,12 @@ inline internals **&get_internals_pp() { #if PY_VERSION_HEX >= 0x03030000 inline bool raise_err(PyObject *exc_type, const char *msg) { - bool err_occurred = PyErr_Occurred() != nullptr; - if (err_occurred) { + if (PyErr_Occurred()) { raise_from(exc_type, msg); - } else { - PyErr_SetString(exc_type, msg); + return true; } - return err_occurred; + PyErr_SetString(exc_type, msg); + return false; }; // forward decl @@ -298,8 +297,7 @@ inline void translate_exception(std::exception_ptr); template >::value, int> = 0> bool handle_nested_exception(const T &exc, const std::exception_ptr &p) { - std::exception_ptr nested = nullptr; - nested = exc.nested_ptr(); + std::exception_ptr nested = exc.nested_ptr(); if (nested != nullptr && nested != p) { translate_exception(nested); return true; @@ -323,7 +321,7 @@ inline bool raise_err(PyObject *exc_type, const char *msg) { } template -bool handle_nested_exception(const T&, std::exception_ptr) { +bool handle_nested_exception(const T &, std::exception_ptr) { return false; } #endif From 65a5ad8bef8cb9a3fce57db039075f6cf2166581 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Thu, 13 Jan 2022 11:59:07 -0500 Subject: [PATCH 19/21] Improve test case --- tests/test_exceptions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index abcd668b59..d698b1312e 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -243,6 +243,7 @@ def pycatch(exctype, f, *args): def test_throw_nested_exception(): with pytest.raises(RuntimeError) as excinfo: m.throw_nested_exception() + assert str(excinfo.value) == "Outer Exception" assert str(excinfo.value.__cause__) == "Inner Exception" From e6cbe62ab909b6ce24df3d5b887b8500a298d19a Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Fri, 14 Jan 2022 10:18:34 -0500 Subject: [PATCH 20/21] Consolidate code and fix signature --- include/pybind11/detail/internals.h | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 978ee3acb3..462d32474e 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -282,15 +282,6 @@ inline internals **&get_internals_pp() { } #if PY_VERSION_HEX >= 0x03030000 -inline bool raise_err(PyObject *exc_type, const char *msg) { - if (PyErr_Occurred()) { - raise_from(exc_type, msg); - return true; - } - PyErr_SetString(exc_type, msg); - return false; -}; - // forward decl inline void translate_exception(std::exception_ptr); @@ -315,17 +306,24 @@ bool handle_nested_exception(const T &exc, const std::exception_ptr &p) { } #else -inline bool raise_err(PyObject *exc_type, const char *msg) { - PyErr_SetString(exc_type, msg); - return false; -} template -bool handle_nested_exception(const T &, std::exception_ptr) { +bool handle_nested_exception(const T &, std::exception_ptr &) { return false; } #endif +inline bool raise_err(PyObject *exc_type, const char *msg) { +#if PY_VERSION_HEX >= 0x03030000 + if (PyErr_Occurred()) { + raise_from(exc_type, msg); + return true; + } +#endif + PyErr_SetString(exc_type, msg); + return false; +}; + inline void translate_exception(std::exception_ptr p) { if (!p) { return; From 3fa58eecc6138860ed3ad9978b0fbc8095c8339e Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Fri, 14 Jan 2022 10:21:53 -0500 Subject: [PATCH 21/21] Fix typo --- include/pybind11/detail/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 25df2373f1..b3513da83b 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -48,7 +48,7 @@ # define PYBIND11_CPP14 # if _MSVC_LANG > 201402L && _MSC_VER >= 1910 # define PYBIND11_CPP17 -# if _MSVC_LANG > 202002L +# if _MSVC_LANG >= 202002L # define PYBIND11_CPP20 # endif # endif