diff options
author | AlexSm <alex@ydb.tech> | 2024-01-09 18:56:40 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-09 18:56:40 +0100 |
commit | e95f266d2a3e48e62015220588a4fd73d5d5a5cb (patch) | |
tree | a8a784b6931fe52ad5f511cfef85af14e5f63991 /contrib/libs/pybind11 | |
parent | 50a65e3b48a82d5b51f272664da389f2e0b0c99a (diff) | |
download | ydb-e95f266d2a3e48e62015220588a4fd73d5d5a5cb.tar.gz |
Library import 6 (#888)
Diffstat (limited to 'contrib/libs/pybind11')
18 files changed, 1717 insertions, 638 deletions
diff --git a/contrib/libs/pybind11/README.rst b/contrib/libs/pybind11/README.rst index 45c4af5a60..80213a4062 100644 --- a/contrib/libs/pybind11/README.rst +++ b/contrib/libs/pybind11/README.rst @@ -32,9 +32,9 @@ this heavy machinery has become an excessively large and unnecessary dependency. Think of this library as a tiny self-contained version of Boost.Python -with everything stripped away that isn’t relevant for binding +with everything stripped away that isn't relevant for binding generation. Without comments, the core header files only require ~4K -lines of code and depend on Python (2.7 or 3.5+, or PyPy) and the C++ +lines of code and depend on Python (3.6+, or PyPy) and the C++ standard library. This compact implementation was possible thanks to some of the new C++11 language features (specifically: tuples, lambda functions and variadic templates). Since its creation, this library has @@ -78,8 +78,8 @@ Goodies In addition to the core functionality, pybind11 provides some extra goodies: -- Python 2.7, 3.5+, and PyPy/PyPy3 7.3 are supported with an - implementation-agnostic interface. +- Python 3.6+, and PyPy3 7.3 are supported with an implementation-agnostic + interface (pybind11 2.9 was the last version to support Python 2 and 3.5). - It is possible to bind C++11 lambda functions with captured variables. The lambda capture data is stored inside the resulting @@ -88,8 +88,8 @@ goodies: - pybind11 uses C++11 move constructors and move assignment operators whenever possible to efficiently transfer custom data types. -- It’s easy to expose the internal storage of custom data types through - Pythons’ buffer protocols. This is handy e.g. for fast conversion +- It's easy to expose the internal storage of custom data types through + Pythons' buffer protocols. This is handy e.g. for fast conversion between C++ matrix classes like Eigen and NumPy without expensive copy operations. @@ -119,10 +119,10 @@ goodies: Supported compilers ------------------- -1. Clang/LLVM 3.3 or newer (for Apple Xcode’s clang, this is 5.0.0 or +1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or newer) 2. GCC 4.8 or newer -3. Microsoft Visual Studio 2015 Update 3 or newer +3. Microsoft Visual Studio 2017 or newer 4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI) 5. Cygwin/GCC (previously tested on 2.5.1) 6. NVCC (CUDA 11.0 tested in CI) @@ -135,7 +135,7 @@ This project was created by `Wenzel Jakob <http://rgl.epfl.ch/people/wjakob>`_. Significant features and/or improvements to the code were contributed by Jonas Adler, Lori A. Burns, Sylvain Corlay, Eric Cousineau, Aaron Gokaslan, Ralf Grosse-Kunstleve, Trent Houliston, Axel -Huebl, @hulucc, Yannick Jadoul, Sergey Lyskov Johan Mabille, Tomasz Miąsko, +Huebl, @hulucc, Yannick Jadoul, Sergey Lyskov, Johan Mabille, Tomasz Miąsko, Dean Moldovan, Ben Pritchard, Jason Rhinelander, Boris Schäling, Pim Schellart, Henry Schreiner, Ivan Smirnov, Boris Staletic, and Patrick Stewart. diff --git a/contrib/libs/pybind11/SECURITY.md b/contrib/libs/pybind11/SECURITY.md new file mode 100644 index 0000000000..3d74611f2d --- /dev/null +++ b/contrib/libs/pybind11/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Supported Versions + +Security updates are applied only to the latest release. + +## Reporting a Vulnerability + +If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. + +Please disclose it at [security advisory](https://github.com/pybind/pybind11/security/advisories/new). + +This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure. diff --git a/contrib/libs/pybind11/include/pybind11/attr.h b/contrib/libs/pybind11/include/pybind11/attr.h index de95f89d0f..1044db94d9 100644 --- a/contrib/libs/pybind11/include/pybind11/attr.h +++ b/contrib/libs/pybind11/include/pybind11/attr.h @@ -10,6 +10,7 @@ #pragma once +#include "detail/common.h" #include "cast.h" #include <functional> @@ -25,6 +26,9 @@ struct is_method { explicit is_method(const handle &c) : class_(c) {} }; +/// Annotation for setters +struct is_setter {}; + /// Annotation for operators struct is_operator {}; @@ -61,7 +65,7 @@ struct base { PYBIND11_DEPRECATED( "base<T>() was deprecated in favor of specifying 'T' as a template argument to class_") - base() {} // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute + base() = default; }; /// Keep patient alive while nurse lives @@ -82,8 +86,7 @@ struct metaclass { handle value; PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.") - // NOLINTNEXTLINE(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute - metaclass() {} + metaclass() = default; /// Override pybind11's default metaclass explicit metaclass(handle value) : value(value) {} @@ -188,8 +191,8 @@ struct argument_record { struct function_record { function_record() : is_constructor(false), is_new_style_constructor(false), is_stateless(false), - is_operator(false), is_method(false), has_args(false), has_kwargs(false), - prepend(false) {} + is_operator(false), is_method(false), is_setter(false), has_args(false), + has_kwargs(false), prepend(false) {} /// Function name char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ @@ -230,6 +233,9 @@ struct function_record { /// True if this is a method bool is_method : 1; + /// True if this is a setter + bool is_setter : 1; + /// True if the function has a '*args' argument bool has_args : 1; @@ -345,9 +351,11 @@ struct type_record { bases.append((PyObject *) base_info->type); - if (base_info->type->tp_dictoffset != 0) { - dynamic_attr = true; - } +#if PY_VERSION_HEX < 0x030B0000 + dynamic_attr |= base_info->type->tp_dictoffset != 0; +#else + dynamic_attr |= (base_info->type->tp_flags & Py_TPFLAGS_MANAGED_DICT) != 0; +#endif if (caster) { base_info->implicit_casts.emplace_back(type, caster); @@ -397,7 +405,7 @@ struct process_attribute<doc> : process_attribute_default<doc> { template <> struct process_attribute<const char *> : process_attribute_default<const char *> { static void init(const char *d, function_record *r) { r->doc = const_cast<char *>(d); } - static void init(const char *d, type_record *r) { r->doc = const_cast<char *>(d); } + static void init(const char *d, type_record *r) { r->doc = d; } }; template <> struct process_attribute<char *> : process_attribute<const char *> {}; @@ -424,6 +432,12 @@ struct process_attribute<is_method> : process_attribute_default<is_method> { } }; +/// Process an attribute which indicates that this function is a setter +template <> +struct process_attribute<is_setter> : process_attribute_default<is_setter> { + static void init(const is_setter &, function_record *r) { r->is_setter = true; } +}; + /// Process an attribute which indicates the parent scope of a method template <> struct process_attribute<scope> : process_attribute_default<scope> { @@ -478,7 +492,7 @@ struct process_attribute<arg_v> : process_attribute_default<arg_v> { } if (!a.value) { -#if !defined(NDEBUG) +#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) std::string descr("'"); if (a.name) { descr += std::string(a.name) + ": "; @@ -499,7 +513,8 @@ struct process_attribute<arg_v> : process_attribute_default<arg_v> { #else pybind11_fail("arg(): could not convert default argument " "into a Python object (type not registered yet?). " - "Compile in debug mode for more information."); + "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for " + "more information."); #endif } r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); diff --git a/contrib/libs/pybind11/include/pybind11/buffer_info.h b/contrib/libs/pybind11/include/pybind11/buffer_info.h index 06120d5563..b99ee8bef4 100644 --- a/contrib/libs/pybind11/include/pybind11/buffer_info.h +++ b/contrib/libs/pybind11/include/pybind11/buffer_info.h @@ -37,6 +37,9 @@ inline std::vector<ssize_t> f_strides(const std::vector<ssize_t> &shape, ssize_t return strides; } +template <typename T, typename SFINAE = void> +struct compare_buffer_info; + PYBIND11_NAMESPACE_END(detail) /// Information record describing a Python buffer object @@ -150,6 +153,17 @@ struct buffer_info { Py_buffer *view() const { return m_view; } Py_buffer *&view() { return m_view; } + /* True if the buffer item type is equivalent to `T`. */ + // To define "equivalent" by example: + // `buffer_info::item_type_is_equivalent_to<int>(b)` and + // `buffer_info::item_type_is_equivalent_to<long>(b)` may both be true + // on some platforms, but `int` and `unsigned` will never be equivalent. + // For the ground truth, please inspect `detail::compare_buffer_info<>`. + template <typename T> + bool item_type_is_equivalent_to() const { + return detail::compare_buffer_info<T>::compare(*this); + } + private: struct private_ctr_tag {}; @@ -170,9 +184,10 @@ private: PYBIND11_NAMESPACE_BEGIN(detail) -template <typename T, typename SFINAE = void> +template <typename T, typename SFINAE> struct compare_buffer_info { static bool compare(const buffer_info &b) { + // NOLINTNEXTLINE(bugprone-sizeof-expression) Needed for `PyObject *` return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T); } }; diff --git a/contrib/libs/pybind11/include/pybind11/cast.h b/contrib/libs/pybind11/include/pybind11/cast.h index 92f65119bf..aa7dd494ad 100644 --- a/contrib/libs/pybind11/include/pybind11/cast.h +++ b/contrib/libs/pybind11/include/pybind11/cast.h @@ -30,6 +30,9 @@ #include <util/generic/string.h> PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +PYBIND11_WARNING_DISABLE_MSVC(4127) + PYBIND11_NAMESPACE_BEGIN(detail) template <typename type, typename SFINAE = void> @@ -89,7 +92,8 @@ public: template <typename T_, \ ::pybind11::detail::enable_if_t< \ std::is_same<type, ::pybind11::detail::remove_cv_t<T_>>::value, \ - int> = 0> \ + int> \ + = 0> \ static ::pybind11::handle cast( \ T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) { \ if (!src) \ @@ -249,7 +253,7 @@ public: return false; } static handle cast(T, return_value_policy /* policy */, handle /* parent */) { - return none().inc_ref(); + return none().release(); } PYBIND11_TYPE_CASTER(T, const_name("None")); }; @@ -292,7 +296,7 @@ public: if (ptr) { return capsule(ptr).release(); } - return none().inc_ref(); + return none().release(); } template <typename T> @@ -330,7 +334,7 @@ public: res = 0; // None is implicitly converted to False } #if defined(PYPY_VERSION) - // On PyPy, check that "__bool__" (or "__nonzero__" on Python 2.7) attr exists + // On PyPy, check that "__bool__" attr exists else if (hasattr(src, PYBIND11_BOOL_ATTR)) { res = PyObject_IsTrue(src.ptr()); } @@ -389,10 +393,10 @@ struct string_caster { } if (!PyUnicode_Check(load_src.ptr())) { #if PY_MAJOR_VERSION >= 3 - return load_bytes(load_src); + return load_raw(load_src); #else if (std::is_same<CharT, char>::value) { - return load_bytes(load_src); + return load_raw(load_src); } // The below is a guaranteed failure in Python 3 when PyUnicode_Check returns false @@ -409,9 +413,9 @@ struct string_caster { } #if PY_VERSION_HEX >= 0x03030000 - // On Python >= 3.3, for UTF-8 we avoid the need for a temporary `bytes` - // object by using `PyUnicode_AsUTF8AndSize`. - if (PYBIND11_SILENCE_MSVC_C4127(UTF_N == 8)) { + // For UTF-8 we avoid the need for a temporary `bytes` object by using + // `PyUnicode_AsUTF8AndSize`. + if (UTF_N == 8) { Py_ssize_t size = -1; const auto *buffer = reinterpret_cast<const CharT *>(PyUnicode_AsUTF8AndSize(load_src.ptr(), &size)); @@ -439,7 +443,7 @@ struct string_caster { = reinterpret_cast<const CharT *>(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT); // Skip BOM for UTF-16/32 - if (PYBIND11_SILENCE_MSVC_C4127(UTF_N > 8)) { + if (UTF_N > 8) { buffer++; length--; } @@ -485,26 +489,37 @@ private: #endif } - // When loading into a std::string or char*, accept a bytes object as-is (i.e. + // When loading into a std::string or char*, accept a bytes/bytearray object as-is (i.e. // without any encoding/decoding attempt). For other C++ char sizes this is a no-op. // which supports loading a unicode from a str, doesn't take this path. template <typename C = CharT> - bool load_bytes(enable_if_t<std::is_same<C, char>::value, handle> src) { + bool load_raw(enable_if_t<std::is_same<C, char>::value, handle> src) { if (PYBIND11_BYTES_CHECK(src.ptr())) { - // We were passed a Python 3 raw bytes; accept it into a std::string or char* + // We were passed raw bytes; accept it into a std::string or char* // without any encoding attempt. const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr()); - if (bytes) { - value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr())); - return true; + if (!bytes) { + pybind11_fail("Unexpected PYBIND11_BYTES_AS_STRING() failure."); + } + value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr())); + return true; + } + if (PyByteArray_Check(src.ptr())) { + // We were passed a bytearray; accept it into a std::string or char* + // without any encoding attempt. + const char *bytearray = PyByteArray_AsString(src.ptr()); + if (!bytearray) { + pybind11_fail("Unexpected PyByteArray_AsString() failure."); } + value = StringType(bytearray, (size_t) PyByteArray_Size(src.ptr())); + return true; } return false; } template <typename C = CharT> - bool load_bytes(enable_if_t<!std::is_same<C, char>::value, handle>) { + bool load_raw(enable_if_t<!std::is_same<C, char>::value, handle>) { return false; } }; @@ -530,7 +545,7 @@ struct type_caster<std::basic_string_view<CharT, Traits>, template <typename CharT> struct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> { using StringType = std::basic_string<CharT>; - using StringCaster = type_caster<StringType>; + using StringCaster = make_caster<StringType>; StringCaster str_caster; bool none = false; CharT one_char = 0; @@ -553,7 +568,7 @@ public: static handle cast(const CharT *src, return_value_policy policy, handle parent) { if (src == nullptr) { - return pybind11::none().inc_ref(); + return pybind11::none().release(); } return StringCaster::cast(StringType(src), policy, parent); } @@ -588,7 +603,7 @@ public: // figure out how long the first encoded character is in bytes to distinguish between these // two errors. We also allow want to allow unicode characters U+0080 through U+00FF, as // those can fit into a single char value. - if (PYBIND11_SILENCE_MSVC_C4127(StringCaster::UTF_N == 8) && str_len > 1 && str_len <= 4) { + if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) { auto v0 = static_cast<unsigned char>(value[0]); // low bits only: 0-127 // 0b110xxxxx - start of 2-byte sequence @@ -614,7 +629,7 @@ public: // UTF-16 is much easier: we can only have a surrogate pair for values above U+FFFF, thus a // surrogate pair with total length 2 instantly indicates a range error (but not a "your // string was too long" error). - else if (PYBIND11_SILENCE_MSVC_C4127(StringCaster::UTF_N == 16) && str_len == 2) { + else if (StringCaster::UTF_N == 16 && str_len == 2) { one_char = static_cast<CharT>(value[0]); if (one_char >= 0xD800 && one_char < 0xE000) { throw value_error("Character code point not in range(0x10000)"); @@ -793,8 +808,9 @@ protected: return true; } throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) " -#if defined(NDEBUG) - "(compile in debug mode for type information)"); +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) + "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for " + "type information)"); #else "of type '" + type_id<holder_type>() + "''"); @@ -861,7 +877,7 @@ struct always_construct_holder { /// Create a specialization for custom holder types (silently ignores std::shared_ptr) #define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type, ...) \ - namespace pybind11 { \ + PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) \ namespace detail { \ template <typename type> \ struct always_construct_holder<holder_type> : always_construct_holder<void, ##__VA_ARGS__> { \ @@ -870,7 +886,7 @@ struct always_construct_holder { class type_caster<holder_type, enable_if_t<!is_shared_ptr<holder_type>::value>> \ : public type_caster_holder<type, holder_type> {}; \ } \ - } + PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) // PYBIND11_DECLARE_HOLDER_TYPE holder types: template <typename base, typename holder> @@ -924,6 +940,14 @@ struct handle_type_name<kwargs> { template <typename type> struct pyobject_caster { template <typename T = type, enable_if_t<std::is_same<T, handle>::value, int> = 0> + pyobject_caster() : value() {} + + // `type` may not be default constructible (e.g. frozenset, anyset). Initializing `value` + // to a nil handle is safe since it will only be accessed if `load` succeeds. + template <typename T = type, enable_if_t<std::is_base_of<object, T>::value, int> = 0> + pyobject_caster() : value(reinterpret_steal<type>(handle())) {} + + template <typename T = type, enable_if_t<std::is_same<T, handle>::value, int> = 0> bool load(handle src, bool /* convert */) { value = src; return static_cast<bool>(value); @@ -935,7 +959,7 @@ struct pyobject_caster { // For Python 2, without this implicit conversion, Python code would // need to be cluttered with six.ensure_text() or similar, only to be // un-cluttered later after Python 2 support is dropped. - if (PYBIND11_SILENCE_MSVC_C4127(std::is_same<T, str>::value) && isinstance<bytes>(src)) { + if ((std::is_same<T, str>::value) && isinstance<bytes>(src)) { PyObject *str_from_bytes = PyUnicode_FromEncodedObject(src.ptr(), "utf-8", nullptr); if (!str_from_bytes) throw error_already_set(); @@ -979,7 +1003,7 @@ struct move_always< enable_if_t< all_of<move_is_plain_type<T>, negation<is_copy_constructible<T>>, - std::is_move_constructible<T>, + is_move_constructible<T>, std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>> : std::true_type {}; template <typename T, typename SFINAE = void> @@ -990,7 +1014,7 @@ struct move_if_unreferenced< enable_if_t< all_of<move_is_plain_type<T>, negation<move_always<T>>, - std::is_move_constructible<T>, + is_move_constructible<T>, std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>> : std::true_type {}; template <typename T> @@ -1028,13 +1052,18 @@ struct return_value_policy_override< // Basic python -> C++ casting; throws if casting fails template <typename T, typename SFINAE> type_caster<T, SFINAE> &load_type(type_caster<T, SFINAE> &conv, const handle &handle) { + static_assert(!detail::is_pyobject<T>::value, + "Internal error: type_caster should only be used for C++ types"); if (!conv.load(handle, true)) { -#if defined(NDEBUG) +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) throw cast_error( - "Unable to cast Python instance to C++ type (compile in debug mode for details)"); + "Unable to cast Python instance of type " + + str(type::handle_of(handle)).cast<std::string>() + + " to C++ type '?' (#define " + "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); #else throw cast_error("Unable to cast Python instance of type " - + (std::string) str(type::handle_of(handle)) + " to C++ type '" + + str(type::handle_of(handle)).cast<std::string>() + " to C++ type '" + type_id<T>() + "'"); #endif } @@ -1051,7 +1080,11 @@ make_caster<T> load_type(const handle &handle) { PYBIND11_NAMESPACE_END(detail) // pytype -> C++ type -template <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> = 0> +template <typename T, + detail::enable_if_t<!detail::is_pyobject<T>::value + && !detail::is_same_ignoring_cvref<T, PyObject *>::value, + int> + = 0> T cast(const handle &handle) { using namespace detail; static_assert(!cast_is_temporary_value_reference<T>::value, @@ -1065,6 +1098,34 @@ T cast(const handle &handle) { return T(reinterpret_borrow<object>(handle)); } +// Note that `cast<PyObject *>(obj)` increments the reference count of `obj`. +// This is necessary for the case that `obj` is a temporary, and could +// not possibly be different, given +// 1. the established convention that the passed `handle` is borrowed, and +// 2. we don't want to force all generic code using `cast<T>()` to special-case +// handling of `T` = `PyObject *` (to increment the reference count there). +// It is the responsibility of the caller to ensure that the reference count +// is decremented. +template <typename T, + typename Handle, + detail::enable_if_t<detail::is_same_ignoring_cvref<T, PyObject *>::value + && detail::is_same_ignoring_cvref<Handle, handle>::value, + int> + = 0> +T cast(Handle &&handle) { + return handle.inc_ref().ptr(); +} +// To optimize way an inc_ref/dec_ref cycle: +template <typename T, + typename Object, + detail::enable_if_t<detail::is_same_ignoring_cvref<T, PyObject *>::value + && detail::is_same_ignoring_cvref<Object, object>::value, + int> + = 0> +T cast(Object &&obj) { + return obj.release().ptr(); +} + // C++ type -> py::object template <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> = 0> object cast(T &&value, @@ -1096,14 +1157,15 @@ inline void handle::cast() const { template <typename T> detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) { if (obj.ref_count() > 1) { -#if defined(NDEBUG) +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) throw cast_error( - "Unable to cast Python instance to C++ rvalue: instance has multiple references" - " (compile in debug mode for details)"); + "Unable to cast Python " + str(type::handle_of(obj)).cast<std::string>() + + " instance to C++ rvalue: instance has multiple references" + " (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); #else - throw cast_error("Unable to move from Python " + (std::string) str(type::handle_of(obj)) - + " instance to C++ " + type_id<T>() - + " instance: instance has multiple references"); + throw cast_error("Unable to move from Python " + + str(type::handle_of(obj)).cast<std::string>() + " instance to C++ " + + type_id<T>() + " instance: instance has multiple references"); #endif } @@ -1118,21 +1180,30 @@ detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) { // - If both movable and copyable, check ref count: if 1, move; otherwise copy // - Otherwise (not movable), copy. template <typename T> -detail::enable_if_t<detail::move_always<T>::value, T> cast(object &&object) { +detail::enable_if_t<!detail::is_pyobject<T>::value && detail::move_always<T>::value, T> +cast(object &&object) { return move<T>(std::move(object)); } template <typename T> -detail::enable_if_t<detail::move_if_unreferenced<T>::value, T> cast(object &&object) { +detail::enable_if_t<!detail::is_pyobject<T>::value && detail::move_if_unreferenced<T>::value, T> +cast(object &&object) { if (object.ref_count() > 1) { return cast<T>(object); } return move<T>(std::move(object)); } template <typename T> -detail::enable_if_t<detail::move_never<T>::value, T> cast(object &&object) { +detail::enable_if_t<!detail::is_pyobject<T>::value && detail::move_never<T>::value, T> +cast(object &&object) { return cast<T>(object); } +// pytype rvalue -> pytype (calls converting constructor) +template <typename T> +detail::enable_if_t<detail::is_pyobject<T>::value, T> cast(object &&object) { + return T(std::move(object)); +} + template <typename T> T object::cast() const & { return pybind11::cast<T>(*this); @@ -1183,24 +1254,26 @@ enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&, // static_assert, even though if it's in dead code, so we provide a "trampoline" to pybind11::cast // that only does anything in cases where pybind11::cast is valid. template <typename T> -enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&o) { - return pybind11::cast<T>(std::move(o)); -} -template <typename T> enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&) { pybind11_fail("Internal error: cast_safe fallback invoked"); } -template <> -inline void cast_safe<void>(object &&) {} +template <typename T> +enable_if_t<std::is_void<T>::value, void> cast_safe(object &&) {} +template <typename T> +enable_if_t<detail::none_of<cast_is_temporary_value_reference<T>, std::is_void<T>>::value, T> +cast_safe(object &&o) { + return pybind11::cast<T>(std::move(o)); +} PYBIND11_NAMESPACE_END(detail) // The overloads could coexist, i.e. the #if is not strictly speaking needed, // but it is an easy minor optimization. -#if defined(NDEBUG) -inline cast_error cast_error_unable_to_convert_call_arg() { - return cast_error( - "Unable to convert call argument to Python object (compile in debug mode for details)"); +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) +inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name) { + return cast_error("Unable to convert call argument '" + name + + "' to Python object (#define " + "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); } #else inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name, @@ -1222,8 +1295,8 @@ tuple make_tuple(Args &&...args_) { detail::make_caster<Args>::cast(std::forward<Args>(args_), policy, nullptr))...}}; for (size_t i = 0; i < args.size(); i++) { if (!args[i]) { -#if defined(NDEBUG) - throw cast_error_unable_to_convert_call_arg(); +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) + throw cast_error_unable_to_convert_call_arg(std::to_string(i)); #else std::array<std::string, size> argtypes{{type_id<Args>()...}}; throw cast_error_unable_to_convert_call_arg(std::to_string(i), argtypes[i]); @@ -1271,10 +1344,10 @@ struct arg_v : arg { private: template <typename T> arg_v(arg &&base, T &&x, const char *descr = nullptr) - : arg(base), value(reinterpret_steal<object>( - detail::make_caster<T>::cast(x, return_value_policy::automatic, {}))), + : arg(base), value(reinterpret_steal<object>(detail::make_caster<T>::cast( + std::forward<T>(x), return_value_policy::automatic, {}))), descr(descr) -#if !defined(NDEBUG) +#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) , type(type_id<T>()) #endif @@ -1314,7 +1387,7 @@ public: object value; /// The (optional) description of the default value const char *descr; -#if !defined(NDEBUG) +#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) /// The C++ type name of the default value (only available when compiled in debug mode) std::string type; #endif @@ -1322,7 +1395,7 @@ public: /// \ingroup annotations /// Annotation indicating that all following arguments are keyword-only; the is the equivalent of -/// an unnamed '*' argument (in Python 3) +/// an unnamed '*' argument struct kw_only {}; /// \ingroup annotations @@ -1512,14 +1585,14 @@ private: auto o = reinterpret_steal<object>( detail::make_caster<T>::cast(std::forward<T>(x), policy, {})); if (!o) { -#if defined(NDEBUG) - throw cast_error_unable_to_convert_call_arg(); +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) + throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size())); #else throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()), type_id<T>()); #endif } - args_list.append(o); + args_list.append(std::move(o)); } void process(list &args_list, detail::args_proxy ap) { @@ -1530,27 +1603,27 @@ private: void process(list & /*args_list*/, arg_v a) { if (!a.name) { -#if defined(NDEBUG) +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) nameless_argument_error(); #else nameless_argument_error(a.type); #endif } if (m_kwargs.contains(a.name)) { -#if defined(NDEBUG) +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) multiple_values_error(); #else multiple_values_error(a.name); #endif } if (!a.value) { -#if defined(NDEBUG) - throw cast_error_unable_to_convert_call_arg(); +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) + throw cast_error_unable_to_convert_call_arg(a.name); #else throw cast_error_unable_to_convert_call_arg(a.name, a.type); #endif } - m_kwargs[a.name] = a.value; + m_kwargs[a.name] = std::move(a.value); } void process(list & /*args_list*/, detail::kwargs_proxy kp) { @@ -1559,7 +1632,7 @@ private: } for (auto k : reinterpret_borrow<dict>(kp)) { if (m_kwargs.contains(k.first)) { -#if defined(NDEBUG) +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) multiple_values_error(); #else multiple_values_error(str(k.first)); @@ -1570,9 +1643,10 @@ private: } [[noreturn]] static void nameless_argument_error() { - throw type_error("Got kwargs without a name; only named arguments " - "may be passed via py::arg() to a python function call. " - "(compile in debug mode for details)"); + throw type_error( + "Got kwargs without a name; only named arguments " + "may be passed via py::arg() to a python function call. " + "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); } [[noreturn]] static void nameless_argument_error(const std::string &type) { throw type_error("Got kwargs without a name of type '" + type @@ -1580,8 +1654,9 @@ private: "arguments may be passed via py::arg() to a python function call. "); } [[noreturn]] static void multiple_values_error() { - throw type_error("Got multiple values for keyword argument " - "(compile in debug mode for details)"); + throw type_error( + "Got multiple values for keyword argument " + "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); } [[noreturn]] static void multiple_values_error(const std::string &name) { @@ -1653,12 +1728,12 @@ handle type::handle_of() { } #define PYBIND11_MAKE_OPAQUE(...) \ - namespace pybind11 { \ + PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) \ namespace detail { \ template <> \ class type_caster<__VA_ARGS__> : public type_caster_base<__VA_ARGS__> {}; \ } \ - } + PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) /// Lets you pass a type containing a `,` through a macro parameter without needing a separate /// typedef, e.g.: diff --git a/contrib/libs/pybind11/include/pybind11/detail/class.h b/contrib/libs/pybind11/include/pybind11/detail/class.h index 0e06b94f10..fd192530b5 100644 --- a/contrib/libs/pybind11/include/pybind11/detail/class.h +++ b/contrib/libs/pybind11/include/pybind11/detail/class.h @@ -19,8 +19,8 @@ PYBIND11_NAMESPACE_BEGIN(detail) # define PYBIND11_BUILTIN_QUALNAME # define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) #else -// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type -// signatures; in 3.3+ this macro expands to nothing: +// In PyPy, we still set __qualname__ so that we can produce reliable function type +// signatures; in CPython this macro expands to nothing: # define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) \ setattr((PyObject *) obj, "__qualname__", nameobj) #endif @@ -55,6 +55,9 @@ extern "C" inline int pybind11_static_set(PyObject *self, PyObject *obj, PyObjec return PyProperty_Type.tp_descr_set(self, cls, value); } +// Forward declaration to use in `make_static_property_type()` +inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type); + /** A `static_property` is the same as a `property` but the `__get__()` and `__set__()` methods are modified to always use the object type instead of a concrete instance. Return value: New reference. */ @@ -87,6 +90,13 @@ inline PyTypeObject *make_static_property_type() { pybind11_fail("make_static_property_type(): failure in PyType_Ready()!"); } +# if PY_VERSION_HEX >= 0x030C0000 + // PRE 3.12 FEATURE FREEZE. PLEASE REVIEW AFTER FREEZE. + // Since Python-3.12 property-derived types are required to + // have dynamic attributes (to set `__doc__`) + enable_dynamic_attributes(heap_type); +# endif + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); @@ -439,9 +449,17 @@ inline void clear_instance(PyObject *self) { /// Instance destructor function for all pybind11 types. It calls `type_info.dealloc` /// to destroy the C++ object itself, while the rest is Python bookkeeping. extern "C" inline void pybind11_object_dealloc(PyObject *self) { + auto *type = Py_TYPE(self); + + // If this is a GC tracked object, untrack it first + // Note that the track call is implicitly done by the + // default tp_alloc, which we never override. + if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC) != 0) { + PyObject_GC_UnTrack(self); + } + clear_instance(self); - auto *type = Py_TYPE(self); type->tp_free(self); #if PY_VERSION_HEX < 0x03080000 @@ -459,6 +477,8 @@ extern "C" inline void pybind11_object_dealloc(PyObject *self) { #endif } +std::string error_string(); + /** Create the type which can be used as a common base for all classes. This is needed in order to satisfy Python's requirements for multiple inheritance. Return value: New reference. */ @@ -494,7 +514,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) { type->tp_weaklistoffset = offsetof(instance, weakrefs); if (PyType_Ready(type) < 0) { - pybind11_fail("PyType_Ready failed in make_object_base_type():" + error_string()); + pybind11_fail("PyType_Ready failed in make_object_base_type(): " + error_string()); } setattr((PyObject *) type, "__module__", str("pybind11_builtins")); @@ -504,6 +524,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) { return (PyObject *) heap_type; } +#if PY_MAJOR_VERSION < 3 /// dynamic_attr: Support for `d = instance.__dict__`. extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) { PyObject *&dict = *_PyObject_GetDictPtr(self); @@ -528,11 +549,16 @@ extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void dict = new_dict; return 0; } +#endif /// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`. extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) { PyObject *&dict = *_PyObject_GetDictPtr(self); Py_VISIT(dict); +// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_traverse +#if PY_VERSION_HEX >= 0x03090000 + Py_VISIT(Py_TYPE(self)); +#endif return 0; } @@ -547,14 +573,31 @@ extern "C" inline int pybind11_clear(PyObject *self) { inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) { auto *type = &heap_type->ht_type; type->tp_flags |= Py_TPFLAGS_HAVE_GC; +#if PY_VERSION_HEX < 0x030B0000 type->tp_dictoffset = type->tp_basicsize; // place dict at the end type->tp_basicsize += (ssize_t) sizeof(PyObject *); // and allocate enough space for it +#else + type->tp_flags |= Py_TPFLAGS_MANAGED_DICT; +#endif type->tp_traverse = pybind11_traverse; type->tp_clear = pybind11_clear; - static PyGetSetDef getset[] = { - {const_cast<char *>("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr}, - {nullptr, nullptr, nullptr, nullptr, nullptr}}; + static PyGetSetDef getset[] = {{ +#if PY_VERSION_HEX < 0x03070000 + const_cast<char *>("__dict__"), +#else + "__dict__", +#endif +#if PY_MAJOR_VERSION < 3 + pybind11_get_dict, + pybind11_set_dict, +#else + PyObject_GenericGetDict, + PyObject_GenericSetDict, +#endif + nullptr, + nullptr}, + {nullptr, nullptr, nullptr, nullptr, nullptr}}; type->tp_getset = getset; } @@ -723,7 +766,7 @@ inline PyObject *make_new_python_type(const type_record &rec) { } if (PyType_Ready(type) < 0) { - pybind11_fail(std::string(rec.name) + ": PyType_Ready failed (" + error_string() + ")!"); + pybind11_fail(std::string(rec.name) + ": PyType_Ready failed: " + error_string()); } assert(!rec.dynamic_attr || PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)); diff --git a/contrib/libs/pybind11/include/pybind11/detail/common.h b/contrib/libs/pybind11/include/pybind11/detail/common.h index 6e8cfd4922..601408153a 100644 --- a/contrib/libs/pybind11/include/pybind11/detail/common.h +++ b/contrib/libs/pybind11/include/pybind11/detail/common.h @@ -10,15 +10,76 @@ #pragma once #define PYBIND11_VERSION_MAJOR 2 -#define PYBIND11_VERSION_MINOR 9 -#define PYBIND11_VERSION_PATCH 2 +#define PYBIND11_VERSION_MINOR 11 +#define PYBIND11_VERSION_PATCH 1 // Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html // Additional convention: 0xD = dev -#define PYBIND11_VERSION_HEX 0x02090200 +#define PYBIND11_VERSION_HEX 0x020B0100 + +// Define some generic pybind11 helper macros for warning management. +// +// Note that compiler-specific push/pop pairs are baked into the +// PYBIND11_NAMESPACE_BEGIN/PYBIND11_NAMESPACE_END pair of macros. Therefore manual +// PYBIND11_WARNING_PUSH/PYBIND11_WARNING_POP are usually only needed in `#include` sections. +// +// If you find you need to suppress a warning, please try to make the suppression as local as +// possible using these macros. Please also be sure to push/pop with the pybind11 macros. Please +// only use compiler specifics if you need to check specific versions, e.g. Apple Clang vs. vanilla +// Clang. +#if defined(_MSC_VER) +# define PYBIND11_COMPILER_MSVC +# define PYBIND11_PRAGMA(...) __pragma(__VA_ARGS__) +# define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(warning(push)) +# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning(pop)) +#elif defined(__INTEL_COMPILER) +# define PYBIND11_COMPILER_INTEL +# define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__) +# define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(warning push) +# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning pop) +#elif defined(__clang__) +# define PYBIND11_COMPILER_CLANG +# define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__) +# define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(clang diagnostic push) +# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(clang diagnostic push) +#elif defined(__GNUC__) +# define PYBIND11_COMPILER_GCC +# define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__) +# define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(GCC diagnostic push) +# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(GCC diagnostic pop) +#endif + +#ifdef PYBIND11_COMPILER_MSVC +# define PYBIND11_WARNING_DISABLE_MSVC(name) PYBIND11_PRAGMA(warning(disable : name)) +#else +# define PYBIND11_WARNING_DISABLE_MSVC(name) +#endif + +#ifdef PYBIND11_COMPILER_CLANG +# define PYBIND11_WARNING_DISABLE_CLANG(name) PYBIND11_PRAGMA(clang diagnostic ignored name) +#else +# define PYBIND11_WARNING_DISABLE_CLANG(name) +#endif + +#ifdef PYBIND11_COMPILER_GCC +# define PYBIND11_WARNING_DISABLE_GCC(name) PYBIND11_PRAGMA(GCC diagnostic ignored name) +#else +# define PYBIND11_WARNING_DISABLE_GCC(name) +#endif + +#ifdef PYBIND11_COMPILER_INTEL +# define PYBIND11_WARNING_DISABLE_INTEL(name) PYBIND11_PRAGMA(warning disable name) +#else +# define PYBIND11_WARNING_DISABLE_INTEL(name) +#endif + +#define PYBIND11_NAMESPACE_BEGIN(name) \ + namespace name { \ + PYBIND11_WARNING_PUSH -#define PYBIND11_NAMESPACE_BEGIN(name) namespace name { -#define PYBIND11_NAMESPACE_END(name) } +#define PYBIND11_NAMESPACE_END(name) \ + PYBIND11_WARNING_POP \ + } // Robust support for some features and loading modules compiled against different pybind versions // requires forcing hidden visibility on pybind code, so we enforce this by setting the attribute @@ -38,6 +99,7 @@ # define PYBIND11_CPP17 # if __cplusplus >= 202002L # define PYBIND11_CPP20 +// Please update tests/pybind11_tests.cpp `cpp_std()` when adding a macro here. # endif # endif # endif @@ -47,7 +109,7 @@ // or newer. # if _MSVC_LANG >= 201402L # define PYBIND11_CPP14 -# if _MSVC_LANG > 201402L && _MSC_VER >= 1910 +# if _MSVC_LANG > 201402L # define PYBIND11_CPP17 # if _MSVC_LANG >= 202002L # define PYBIND11_CPP20 @@ -81,10 +143,8 @@ # error pybind11 requires gcc 4.8 or newer # endif #elif defined(_MSC_VER) -// Pybind hits various compiler bugs in 2015u2 and earlier, and also makes use of some stl features -// (e.g. std::negation) added in 2015u3: -# if _MSC_FULL_VER < 190024210 -# error pybind11 requires MSVC 2015 update 3 or newer +# if _MSC_VER < 1910 +# error pybind11 2.10+ requires MSVC 2017 or newer # endif #endif @@ -97,13 +157,10 @@ #endif #if !defined(PYBIND11_EXPORT_EXCEPTION) -# ifdef __MINGW32__ -// workaround for: -// error: 'dllexport' implies default visibility, but xxx has already been declared with a -// different visibility -# define PYBIND11_EXPORT_EXCEPTION -# else +# if defined(__apple_build_version__) # define PYBIND11_EXPORT_EXCEPTION PYBIND11_EXPORT +# else +# define PYBIND11_EXPORT_EXCEPTION # endif #endif @@ -149,15 +206,15 @@ /* Don't let Python.h #define (v)snprintf as macro because they are implemented properly in Visual Studio since 2015. */ -#if defined(_MSC_VER) && _MSC_VER >= 1900 +#if defined(_MSC_VER) # define HAVE_SNPRINTF 1 #endif /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode #if defined(_MSC_VER) -# pragma warning(push) +PYBIND11_WARNING_PUSH +PYBIND11_WARNING_DISABLE_MSVC(4505) // C4505: 'PySlice_GetIndicesEx': unreferenced local function has been removed (PyPy only) -# pragma warning(disable : 4505) # if defined(_DEBUG) && !defined(Py_DEBUG) // Workaround for a VS 2022 issue. // NOTE: This workaround knowingly violates the Python.h include order requirement: @@ -206,11 +263,8 @@ # endif #endif -#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201811L -# define PYBIND11_HAS_U8STRING -#endif - #include <Python.h> +// Reminder: WITH_THREAD is always defined if PY_VERSION_HEX >= 0x03070000 #include <frameobject.h> #include <pythread.h> @@ -231,12 +285,16 @@ # undef copysign #endif +#if defined(PYPY_VERSION) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) +# define PYBIND11_SIMPLE_GIL_MANAGEMENT +#endif + #if defined(_MSC_VER) # if defined(PYBIND11_DEBUG_MARKER) # define _DEBUG # undef PYBIND11_DEBUG_MARKER # endif -# pragma warning(pop) +PYBIND11_WARNING_POP #endif #include <cstddef> @@ -257,6 +315,20 @@ # endif #endif +// Must be after including <version> or one of the other headers specified by the standard +#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201811L +# define PYBIND11_HAS_U8STRING +#endif + +// See description of PR #4246: +#if PY_MAJOR_VERSION < 3 +# define PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF +#endif +#if !defined(PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF) && !defined(NDEBUG) \ + && !defined(PYPY_VERSION) && !defined(PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF) +# define PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF +#endif + // #define PYBIND11_STR_LEGACY_PERMISSIVE // If DEFINED, pybind11::str can hold PyUnicodeObject or PyBytesObject // (probably surprising and never documented, but this was the @@ -266,7 +338,7 @@ // If UNDEFINED, pybind11::str can only hold PyUnicodeObject, and // pybind11::isinstance<str>() is true only for pybind11::str. // However, for Python 2 only (!), the pybind11::str caster -// implicitly decodes bytes to PyUnicodeObject. This is to ease +// implicitly decoded bytes to PyUnicodeObject. This was to ease // the transition from the legacy behavior to the non-permissive // behavior. @@ -330,15 +402,6 @@ PyObject *pybind11_init_wrapper() #endif -#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200 -extern "C" { -struct _Py_atomic_address { - void *value; -}; -PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current; -} -#endif - #define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code #define PYBIND11_STRINGIFY(x) #x #define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x) @@ -418,7 +481,7 @@ PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current; /** \rst This macro creates the entry point that will be invoked when the Python interpreter - imports an extension module. The module name is given as the fist argument and it + imports an extension module. The module name is given as the first argument and it should not be in quotes. The second macro argument defines a variable of type `py::module_` which can be used to initialize the module. @@ -483,7 +546,7 @@ enum class return_value_policy : uint8_t { /** Reference an existing object (i.e. do not create a new copy) and take ownership. Python will call the destructor and delete operator when the - object’s reference count reaches zero. Undefined behavior ensues when + object's reference count reaches zero. Undefined behavior ensues when the C++ side does the same.. */ take_ownership, @@ -499,7 +562,7 @@ enum class return_value_policy : uint8_t { move, /** Reference an existing object, but do not take ownership. The C++ side - is responsible for managing the object’s lifetime and deallocating it + is responsible for managing the object's lifetime and deallocating it when it is no longer used. Warning: undefined behavior will ensue when the C++ side deletes an object that is still referenced and used by Python. */ @@ -508,7 +571,7 @@ enum class return_value_policy : uint8_t { /** This policy only applies to methods and properties. It references the object without taking ownership similar to the above return_value_policy::reference policy. In contrast to that policy, the - function or property’s implicit this argument (called the parent) is + function or property's implicit this argument (called the parent) is considered to be the the owner of the return value (the child). pybind11 then couples the lifetime of the parent to the child via a reference relationship that ensures that the parent cannot be garbage @@ -615,7 +678,7 @@ static_assert(std::is_standard_layout<instance>::value, "Internal error: `pybind11::detail::instance` is not standard layout!"); /// from __cpp_future__ import (convenient aliases from C++14/17) -#if defined(PYBIND11_CPP14) && (!defined(_MSC_VER) || _MSC_VER >= 1910) +#if defined(PYBIND11_CPP14) using std::conditional_t; using std::enable_if_t; using std::remove_cv_t; @@ -643,6 +706,10 @@ template <class T> using remove_cvref_t = typename remove_cvref<T>::type; #endif +/// Example usage: is_same_ignoring_cvref<T, PyObject *>::value +template <typename T, typename U> +using is_same_ignoring_cvref = std::is_same<detail::remove_cvref_t<T>, U>; + /// Index sequences #if defined(PYBIND11_CPP14) using std::index_sequence; @@ -736,7 +803,16 @@ template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...) const> { using type = R(A...); }; - +#ifdef __cpp_noexcept_function_type +template <typename C, typename R, typename... A> +struct remove_class<R (C::*)(A...) noexcept> { + using type = R(A...); +}; +template <typename C, typename R, typename... A> +struct remove_class<R (C::*)(A...) const noexcept> { + using type = R(A...); +}; +#endif /// Helper template to strip away type modifiers template <typename T> struct intrinsic_type { @@ -878,10 +954,12 @@ struct is_template_base_of_impl { /// Check if a template is the base of a type. For example: /// `is_template_base_of<Base, T>` is true if `struct T : Base<U> {}` where U can be anything template <template <typename...> class Base, typename T> +// Sadly, all MSVC versions incl. 2022 need the workaround, even in C++20 mode. +// See also: https://github.com/pybind/pybind11/pull/3741 #if !defined(_MSC_VER) using is_template_base_of = decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T> *) nullptr)); -#else // MSVC2015 has trouble with decltype in template aliases +#else struct is_template_base_of : decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T> *) nullptr)) { }; @@ -951,12 +1029,6 @@ using expand_side_effects = bool[]; PYBIND11_NAMESPACE_END(detail) -#if defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable : 4275) -// warning C4275: An exported class was derived from a class that wasn't exported. -// Can be ignored when derived from a STL class. -#endif /// C++ bindings of builtin Python exceptions class PYBIND11_EXPORT_EXCEPTION builtin_exception : public std::runtime_error { public: @@ -964,9 +1036,6 @@ public: /// Set the error using the Python C API virtual void set_error() const = 0; }; -#if defined(_MSC_VER) -# pragma warning(pop) -#endif #define PYBIND11_RUNTIME_EXCEPTION(name, type) \ class PYBIND11_EXPORT_EXCEPTION name : public builtin_exception { \ @@ -990,15 +1059,26 @@ PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybin PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally [[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const char *reason) { + assert(!PyErr_Occurred()); throw std::runtime_error(reason); } [[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const std::string &reason) { + assert(!PyErr_Occurred()); throw std::runtime_error(reason); } template <typename T, typename SFINAE = void> struct format_descriptor {}; +template <typename T> +struct format_descriptor< + T, + detail::enable_if_t<detail::is_same_ignoring_cvref<T, PyObject *>::value>> { + static constexpr const char c = 'O'; + static constexpr const char value[2] = {c, '\0'}; + static std::string format() { return std::string(1, c); } +}; + PYBIND11_NAMESPACE_BEGIN(detail) // Returns the index of the given type in the type char array below, and in the list in numpy.h // The order here is: bool; 8 ints ((signed,unsigned)x(8,16,32,64)bits); float,double,long double; @@ -1044,6 +1124,8 @@ constexpr const char struct error_scope { PyObject *type, *value, *trace; error_scope() { PyErr_Fetch(&type, &value, &trace); } + error_scope(const error_scope &) = delete; + error_scope &operator=(const error_scope &) = delete; ~error_scope() { PyErr_Restore(type, value, trace); } }; @@ -1056,9 +1138,6 @@ struct nodelete { PYBIND11_NAMESPACE_BEGIN(detail) template <typename... Args> struct overload_cast_impl { - // NOLINTNEXTLINE(modernize-use-equals-default): MSVC 2015 needs this - constexpr overload_cast_impl() {} - template <typename Return> constexpr auto operator()(Return (*pf)(Args...)) const noexcept -> decltype(pf) { return pf; @@ -1085,8 +1164,7 @@ PYBIND11_NAMESPACE_END(detail) /// - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func) /// - sweet: overload_cast<Arg0, Arg1, Arg2>(&Class::func) template <typename... Args> -static constexpr detail::overload_cast_impl<Args...> overload_cast = {}; -// MSVC 2015 only accepts this particular initialization syntax for this variable template. +static constexpr detail::overload_cast_impl<Args...> overload_cast{}; #endif /// Const member function selector for overload_cast @@ -1172,7 +1250,7 @@ try_get_shared_from_this(std::enable_shared_from_this<T> *holder_value_ptr) { // For silencing "unused" compiler warnings in special situations. template <typename... Args> -#if defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER < 1920 // MSVC 2017 +#if defined(_MSC_VER) && _MSC_VER < 1920 // MSVC 2017 constexpr #endif inline void @@ -1195,15 +1273,30 @@ constexpr # define PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(...) #endif -#if defined(_MSC_VER) // All versions (as of July 2021). - -// warning C4127: Conditional expression is constant -constexpr inline bool silence_msvc_c4127(bool cond) { return cond; } - -# define PYBIND11_SILENCE_MSVC_C4127(...) ::pybind11::detail::silence_msvc_c4127(__VA_ARGS__) +#if defined(__clang__) \ + && (defined(__apple_build_version__) /* AppleClang 13.0.0.13000029 was the only data point \ + available. */ \ + || (__clang_major__ >= 7 \ + && __clang_major__ <= 12) /* Clang 3, 5, 13, 14, 15 do not generate the warning. */ \ + ) +# define PYBIND11_DETECTED_CLANG_WITH_MISLEADING_CALL_STD_MOVE_EXPLICITLY_WARNING +// Example: +// tests/test_kwargs_and_defaults.cpp:46:68: error: local variable 'args' will be copied despite +// being returned by name [-Werror,-Wreturn-std-move] +// m.def("args_function", [](py::args args) -> py::tuple { return args; }); +// ^~~~ +// test_kwargs_and_defaults.cpp:46:68: note: call 'std::move' explicitly to avoid copying +// m.def("args_function", [](py::args args) -> py::tuple { return args; }); +// ^~~~ +// std::move(args) +#endif -#else -# define PYBIND11_SILENCE_MSVC_C4127(...) __VA_ARGS__ +// Pybind offers detailed error messages by default for all builts that are debug (through the +// negation of NDEBUG). This can also be manually enabled by users, for any builds, through +// defining PYBIND11_DETAILED_ERROR_MESSAGES. This information is primarily useful for those +// who are writing (as opposed to merely using) libraries that use pybind11. +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) && !defined(NDEBUG) +# define PYBIND11_DETAILED_ERROR_MESSAGES #endif PYBIND11_NAMESPACE_END(detail) diff --git a/contrib/libs/pybind11/include/pybind11/detail/descr.h b/contrib/libs/pybind11/include/pybind11/detail/descr.h index e7a5e2c145..635614b0d6 100644 --- a/contrib/libs/pybind11/include/pybind11/detail/descr.h +++ b/contrib/libs/pybind11/include/pybind11/detail/descr.h @@ -143,11 +143,24 @@ constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) { return descr; } +#ifdef __cpp_fold_expressions +template <size_t N1, size_t N2, typename... Ts1, typename... Ts2> +constexpr descr<N1 + N2 + 2, Ts1..., Ts2...> operator,(const descr<N1, Ts1...> &a, + const descr<N2, Ts2...> &b) { + return a + const_name(", ") + b; +} + +template <size_t N, typename... Ts, typename... Args> +constexpr auto concat(const descr<N, Ts...> &d, const Args &...args) { + return (d, ..., args); +} +#else template <size_t N, typename... Ts, typename... Args> constexpr auto concat(const descr<N, Ts...> &d, const Args &...args) -> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) { return d + const_name(", ") + concat(args...); } +#endif template <size_t N, typename... Ts> constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) { diff --git a/contrib/libs/pybind11/include/pybind11/detail/init.h b/contrib/libs/pybind11/include/pybind11/detail/init.h index 3807d6d5a3..ca5a5178c8 100644 --- a/contrib/libs/pybind11/include/pybind11/detail/init.h +++ b/contrib/libs/pybind11/include/pybind11/detail/init.h @@ -12,6 +12,9 @@ #include "class.h" PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +PYBIND11_WARNING_DISABLE_MSVC(4127) + PYBIND11_NAMESPACE_BEGIN(detail) template <> @@ -115,7 +118,7 @@ template <typename Class> void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias); no_nullptr(ptr); - if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias && !is_alias<Class>(ptr)) { + if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) { // We're going to try to construct an alias by moving the cpp type. Whether or not // that succeeds, we still need to destroy the original cpp pointer (either the // moved away leftover, if the alias construction works, or the value itself if we @@ -156,7 +159,7 @@ void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) { auto *ptr = holder_helper<Holder<Class>>::get(holder); no_nullptr(ptr); // If we need an alias, check that the held pointer is actually an alias instance - if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias && !is_alias<Class>(ptr)) { + if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) { throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance " "is not an alias instance"); } @@ -172,9 +175,9 @@ void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) { template <typename Class> void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias); - static_assert(std::is_move_constructible<Cpp<Class>>::value, + static_assert(is_move_constructible<Cpp<Class>>::value, "pybind11::init() return-by-value factory function requires a movable class"); - if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias) { + if (Class::has_alias && need_alias) { construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result)); } else { v_h.value_ptr() = new Cpp<Class>(std::move(result)); @@ -187,7 +190,7 @@ void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) { template <typename Class> void construct(value_and_holder &v_h, Alias<Class> &&result, bool) { static_assert( - std::is_move_constructible<Alias<Class>>::value, + is_move_constructible<Alias<Class>>::value, "pybind11::init() return-by-alias-value factory function requires a movable alias class"); v_h.value_ptr() = new Alias<Class>(std::move(result)); } @@ -206,10 +209,11 @@ struct constructor { extra...); } - template <typename Class, - typename... Extra, - enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value, - int> = 0> + template < + typename Class, + typename... Extra, + enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value, int> + = 0> static void execute(Class &cl, const Extra &...extra) { cl.def( "__init__", @@ -226,10 +230,11 @@ struct constructor { extra...); } - template <typename Class, - typename... Extra, - enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value, - int> = 0> + template < + typename Class, + typename... Extra, + enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value, int> + = 0> static void execute(Class &cl, const Extra &...extra) { cl.def( "__init__", @@ -245,10 +250,11 @@ struct constructor { // Implementing class for py::init_alias<...>() template <typename... Args> struct alias_constructor { - template <typename Class, - typename... Extra, - enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, - int> = 0> + template < + typename Class, + typename... Extra, + enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int> + = 0> static void execute(Class &cl, const Extra &...extra) { cl.def( "__init__", @@ -459,4 +465,4 @@ struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> { PYBIND11_NAMESPACE_END(initimpl) PYBIND11_NAMESPACE_END(detail) -PYBIND11_NAMESPACE_END(pybind11) +PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/contrib/libs/pybind11/include/pybind11/detail/internals.h b/contrib/libs/pybind11/include/pybind11/detail/internals.h index eaf8998b4a..5f4ba6959a 100644 --- a/contrib/libs/pybind11/include/pybind11/detail/internals.h +++ b/contrib/libs/pybind11/include/pybind11/detail/internals.h @@ -9,6 +9,12 @@ #pragma once +#include "common.h" + +#if defined(WITH_THREAD) && defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) +# include "../gil.h" +#endif + #include "../pytypes.h" #include <exception> @@ -30,15 +36,26 @@ /// further ABI-incompatible changes may be made before the ABI is officially /// changed to the new version. #ifndef PYBIND11_INTERNALS_VERSION -# define PYBIND11_INTERNALS_VERSION 4 +# if PY_VERSION_HEX >= 0x030C0000 +// Version bump for Python 3.12+, before first 3.12 beta release. +# define PYBIND11_INTERNALS_VERSION 5 +# else +# define PYBIND11_INTERNALS_VERSION 4 +# endif #endif +// This requirement is mainly to reduce the support burden (see PR #4570). +static_assert(PY_VERSION_HEX < 0x030C0000 || PYBIND11_INTERNALS_VERSION >= 5, + "pybind11 ABI version 5 is the minimum for Python 3.12+"); + PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) using ExceptionTranslator = void (*)(std::exception_ptr); PYBIND11_NAMESPACE_BEGIN(detail) +constexpr const char *internals_function_record_capsule_name = "pybind11_function_record_capsule"; + // Forward declarations inline PyTypeObject *make_static_property_type(); inline PyTypeObject *make_default_metaclass(); @@ -51,7 +68,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass); // `Py_LIMITED_API` anyway. # if PYBIND11_INTERNALS_VERSION > 4 # define PYBIND11_TLS_KEY_REF Py_tss_t & -# ifdef __GNUC__ +# if defined(__GNUC__) && !defined(__INTEL_COMPILER) // Clang on macOS warns due to `Py_tss_NEEDS_INIT` not specifying an initializer // for every field. # define PYBIND11_TLS_KEY_INIT(var) \ @@ -108,7 +125,8 @@ inline void tls_replace_value(PYBIND11_TLS_KEY_REF key, void *value) { // libstdc++, this doesn't happen: equality and the type_index hash are based on the type name, // which works. If not under a known-good stl, provide our own name-based hash and equality // functions that use the type name. -#if defined(__GLIBCXX__) +#if (PYBIND11_INTERNALS_VERSION <= 4 && defined(__GLIBCXX__)) \ + || (PYBIND11_INTERNALS_VERSION >= 5 && !defined(_LIBCPP_VERSION)) inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; } using type_hash = std::hash<std::type_index>; using type_equal_to = std::equal_to<std::type_index>; @@ -171,11 +189,23 @@ struct internals { PyTypeObject *default_metaclass; PyObject *instance_base; #if defined(WITH_THREAD) + // Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined: PYBIND11_TLS_KEY_INIT(tstate) # if PYBIND11_INTERNALS_VERSION > 4 PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key) # endif // PYBIND11_INTERNALS_VERSION > 4 + // Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined: PyInterpreterState *istate = nullptr; + +# if PYBIND11_INTERNALS_VERSION > 4 + // Note that we have to use a std::string to allocate memory to ensure a unique address + // We want unique addresses since we use pointer equality to compare function records + std::string function_record_capsule_name = internals_function_record_capsule_name; +# endif + + internals() = default; + internals(const internals &other) = delete; + internals &operator=(const internals &other) = delete; ~internals() { # if PYBIND11_INTERNALS_VERSION > 4 PYBIND11_TLS_FREE(loader_life_support_tls_key); @@ -415,6 +445,46 @@ inline void translate_local_exception(std::exception_ptr p) { } #endif +inline object get_python_state_dict() { + object state_dict; +#if PYBIND11_INTERNALS_VERSION <= 4 || PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION) + state_dict = reinterpret_borrow<object>(PyEval_GetBuiltins()); +#else +# if PY_VERSION_HEX < 0x03090000 + PyInterpreterState *istate = _PyInterpreterState_Get(); +# else + PyInterpreterState *istate = PyInterpreterState_Get(); +# endif + if (istate) { + state_dict = reinterpret_borrow<object>(PyInterpreterState_GetDict(istate)); + } +#endif + if (!state_dict) { +#if PY_VERSION_HEX >= 0x03030000 + raise_from(PyExc_SystemError, "pybind11::detail::get_python_state_dict() FAILED"); +#else + PyErr_SetString(PyExc_SystemError, "pybind11::detail::get_python_state_dict() FAILED"); +#endif + } + return state_dict; +} + +inline object get_internals_obj_from_state_dict(handle state_dict) { + return reinterpret_borrow<object>(dict_getitemstring(state_dict.ptr(), PYBIND11_INTERNALS_ID)); +} + +inline internals **get_internals_pp_from_capsule(handle obj) { + void *raw_ptr = PyCapsule_GetPointer(obj.ptr(), /*name=*/nullptr); + if (raw_ptr == nullptr) { +#if PY_VERSION_HEX >= 0x03030000 + raise_from(PyExc_SystemError, "pybind11::detail::get_internals_pp_from_capsule() FAILED"); +#else + PyErr_SetString(PyExc_SystemError, "pybind11::detail::get_internals_pp_from_capsule() FAILED"); +#endif + } + return static_cast<internals **>(raw_ptr); +} + /// Return a reference to the current `internals` data PYBIND11_NOINLINE internals &get_internals() { auto **&internals_pp = get_internals_pp(); @@ -422,20 +492,29 @@ PYBIND11_NOINLINE internals &get_internals() { return **internals_pp; } +#if defined(WITH_THREAD) +# if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) + gil_scoped_acquire gil; +# else // Ensure that the GIL is held since we will need to make Python calls. // Cannot use py::gil_scoped_acquire here since that constructor calls get_internals. struct gil_scoped_acquire_local { gil_scoped_acquire_local() : state(PyGILState_Ensure()) {} + gil_scoped_acquire_local(const gil_scoped_acquire_local &) = delete; + gil_scoped_acquire_local &operator=(const gil_scoped_acquire_local &) = delete; ~gil_scoped_acquire_local() { PyGILState_Release(state); } const PyGILState_STATE state; } gil; +# endif +#endif + error_scope err_scope; - PYBIND11_STR_TYPE id(PYBIND11_INTERNALS_ID); - auto builtins = handle(PyEval_GetBuiltins()); - if (builtins.contains(id) && isinstance<capsule>(builtins[id])) { - internals_pp = static_cast<internals **>(capsule(builtins[id])); - - // We loaded builtins through python's builtins, which means that our `error_already_set` + dict state_dict = get_python_state_dict(); + if (object internals_obj = get_internals_obj_from_state_dict(state_dict)) { + internals_pp = get_internals_pp_from_capsule(internals_obj); + } + if (internals_pp && *internals_pp) { + // We loaded the internals through `state_dict`, which means that our `error_already_set` // and `builtin_exception` may be different local classes than the ones set up in the // initial exception translator, below, so add another for our local exception classes. // @@ -453,16 +532,15 @@ PYBIND11_NOINLINE internals &get_internals() { internals_ptr = new internals(); #if defined(WITH_THREAD) -# if PY_VERSION_HEX < 0x03090000 - PyEval_InitThreads(); -# endif PyThreadState *tstate = PyThreadState_Get(); + // NOLINTNEXTLINE(bugprone-assignment-in-if-condition) if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->tstate)) { pybind11_fail("get_internals: could not successfully initialize the tstate TSS key!"); } PYBIND11_TLS_REPLACE_VALUE(internals_ptr->tstate, tstate); # if PYBIND11_INTERNALS_VERSION > 4 + // NOLINTNEXTLINE(bugprone-assignment-in-if-condition) if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->loader_life_support_tls_key)) { pybind11_fail("get_internals: could not successfully initialize the " "loader_life_support TSS key!"); @@ -470,7 +548,7 @@ PYBIND11_NOINLINE internals &get_internals() { # endif internals_ptr->istate = tstate->interp; #endif - builtins[id] = capsule(internals_pp); + state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp); internals_ptr->registered_exception_translators.push_front(&translate_exception); internals_ptr->static_property_type = make_static_property_type(); internals_ptr->default_metaclass = make_default_metaclass(); @@ -502,6 +580,7 @@ struct local_internals { struct shared_loader_life_support_data { PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key) shared_loader_life_support_data() { + // NOLINTNEXTLINE(bugprone-assignment-in-if-condition) if (!PYBIND11_TLS_KEY_CREATE(loader_life_support_tls_key)) { pybind11_fail("local_internals: could not successfully initialize the " "loader_life_support TLS key!"); @@ -525,8 +604,13 @@ struct local_internals { /// Works like `get_internals`, but for things which are locally registered. inline local_internals &get_local_internals() { - static local_internals locals; - return locals; + // Current static can be created in the interpreter finalization routine. If the later will be + // destroyed in another static variable destructor, creation of this static there will cause + // static deinitialization fiasco. In order to avoid it we avoid destruction of the + // local_internals static. One can read more about the problem and current solution here: + // https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables + static auto *locals = new local_internals(); + return *locals; } /// Constructs a std::string with the given arguments, stores it in `internals`, and returns its @@ -540,6 +624,25 @@ const char *c_str(Args &&...args) { return strings.front().c_str(); } +inline const char *get_function_record_capsule_name() { +#if PYBIND11_INTERNALS_VERSION > 4 + return get_internals().function_record_capsule_name.c_str(); +#else + return nullptr; +#endif +} + +// Determine whether or not the following capsule contains a pybind11 function record. +// Note that we use `internals` to make sure that only ABI compatible records are touched. +// +// This check is currently used in two places: +// - An important optimization in functional.h to avoid overhead in C++ -> Python -> C++ +// - The sibling feature of cpp_function to allow overloads +inline bool is_function_record_capsule(const capsule &cap) { + // Pointer equality as we rely on internals() to ensure unique pointers + return cap.name() == get_function_record_capsule_name(); +} + PYBIND11_NAMESPACE_END(detail) /// Returns a named pointer that is shared among all extension modules (using the same diff --git a/contrib/libs/pybind11/include/pybind11/detail/type_caster_base.h b/contrib/libs/pybind11/include/pybind11/detail/type_caster_base.h index 3c32aa07c0..245bf99d2d 100644 --- a/contrib/libs/pybind11/include/pybind11/detail/type_caster_base.h +++ b/contrib/libs/pybind11/include/pybind11/detail/type_caster_base.h @@ -226,8 +226,8 @@ PYBIND11_NOINLINE detail::type_info *get_type_info(const std::type_index &tp, if (throw_if_missing) { std::string tname = tp.name(); detail::clean_type_id(tname); - pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname - + "\""); + pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + + std::move(tname) + '"'); } return nullptr; } @@ -259,9 +259,9 @@ struct value_and_holder { // Main constructor for a found value/holder: value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index) - : inst{i}, index{index}, type{type}, vh{inst->simple_layout - ? inst->simple_value_holder - : &inst->nonsimple.values_and_holders[vpos]} {} + : inst{i}, index{index}, type{type}, + vh{inst->simple_layout ? inst->simple_value_holder + : &inst->nonsimple.values_and_holders[vpos]} {} // Default constructor (used to signal a value-and-holder not found by get_value_and_holder()) value_and_holder() = default; @@ -395,15 +395,16 @@ instance::get_value_and_holder(const type_info *find_type /*= nullptr default in return value_and_holder(); } -#if defined(NDEBUG) - pybind11_fail("pybind11::detail::instance::get_value_and_holder: " - "type is not a pybind11 base of the given instance " - "(compile in debug mode for type details)"); -#else +#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) pybind11_fail("pybind11::detail::instance::get_value_and_holder: `" + get_fully_qualified_tp_name(find_type->type) + "' is not a pybind11 base of the given `" + get_fully_qualified_tp_name(Py_TYPE(this)) + "' instance"); +#else + pybind11_fail( + "pybind11::detail::instance::get_value_and_holder: " + "type is not a pybind11 base of the given instance " + "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for type details)"); #endif } @@ -440,10 +441,11 @@ PYBIND11_NOINLINE void instance::allocate_layout() { // instance_registered) // Allocate space for flags, values, and holders, and initialize it to 0 (flags and values, - // in particular, need to be 0). Use Python's memory allocation functions: in Python 3.6 - // they default to using pymalloc, which is designed to be efficient for small allocations - // like the one we're doing here; in earlier versions (and for larger allocations) they are - // just wrappers around malloc. + // in particular, need to be 0). Use Python's memory allocation + // functions: Python is using pymalloc, which is designed to be + // efficient for small allocations like the one we're doing here; + // for larger allocations they are just wrappers around malloc. + // TODO: is this still true for pure Python 3.6? #if PY_VERSION_HEX >= 0x03050000 nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *)); if (!nonsimple.values_and_holders) { @@ -476,70 +478,6 @@ PYBIND11_NOINLINE bool isinstance_generic(handle obj, const std::type_info &tp) return isinstance(obj, type); } -PYBIND11_NOINLINE std::string error_string() { - if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred"); - return "Unknown internal error occurred"; - } - - error_scope scope; // Preserve error state - - std::string errorString; - if (scope.type) { - errorString += handle(scope.type).attr("__name__").cast<std::string>(); - errorString += ": "; - } - if (scope.value) { - errorString += (std::string) str(scope.value); - } - - PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace); - -#if PY_MAJOR_VERSION >= 3 - if (scope.trace != nullptr) { - PyException_SetTraceback(scope.value, scope.trace); - } -#endif - -#if !defined(PYPY_VERSION) - if (scope.trace) { - auto *trace = (PyTracebackObject *) scope.trace; - - /* Get the deepest trace possible */ - while (trace->tb_next) { - trace = trace->tb_next; - } - - PyFrameObject *frame = trace->tb_frame; - Py_XINCREF(frame); - errorString += "\n\nAt:\n"; - while (frame) { -# if PY_VERSION_HEX >= 0x030900B1 - PyCodeObject *f_code = PyFrame_GetCode(frame); -# else - PyCodeObject *f_code = frame->f_code; - Py_INCREF(f_code); -# endif - int lineno = PyFrame_GetLineNumber(frame); - errorString += " " + handle(f_code->co_filename).cast<std::string>() + "(" - + std::to_string(lineno) - + "): " + handle(f_code->co_name).cast<std::string>() + "\n"; - Py_DECREF(f_code); -# if PY_VERSION_HEX >= 0x030900B1 - auto *b_frame = PyFrame_GetBack(frame); -# else - auto *b_frame = frame->f_back; - Py_XINCREF(b_frame); -# endif - Py_DECREF(frame); - frame = b_frame; - } - } -#endif - - return errorString; -} - PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_info *type) { auto &instances = get_internals().registered_instances; auto range = instances.equal_range(ptr); @@ -558,10 +496,6 @@ inline PyThreadState *get_thread_state_unchecked() { return PyThreadState_GET(); #elif PY_VERSION_HEX < 0x03000000 return _PyThreadState_Current; -#elif PY_VERSION_HEX < 0x03050000 - return (PyThreadState *) _Py_atomic_load_relaxed(&_PyThreadState_Current); -#elif PY_VERSION_HEX < 0x03050200 - return (PyThreadState *) _PyThreadState_Current.value; #else return _PyThreadState_UncheckedGet(); #endif @@ -623,14 +557,15 @@ public: if (copy_constructor) { valueptr = copy_constructor(src); } else { -#if defined(NDEBUG) - throw cast_error("return_value_policy = copy, but type is " - "non-copyable! (compile in debug mode for details)"); -#else +#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) std::string type_name(tinfo->cpptype->name()); detail::clean_type_id(type_name); throw cast_error("return_value_policy = copy, but type " + type_name + " is non-copyable!"); +#else + throw cast_error("return_value_policy = copy, but type is " + "non-copyable! (#define PYBIND11_DETAILED_ERROR_MESSAGES or " + "compile in debug mode for details)"); #endif } wrapper->owned = true; @@ -642,15 +577,16 @@ public: } else if (copy_constructor) { valueptr = copy_constructor(src); } else { -#if defined(NDEBUG) - throw cast_error("return_value_policy = move, but type is neither " - "movable nor copyable! " - "(compile in debug mode for details)"); -#else +#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) std::string type_name(tinfo->cpptype->name()); detail::clean_type_id(type_name); throw cast_error("return_value_policy = move, but type " + type_name + " is neither movable nor copyable!"); +#else + throw cast_error("return_value_policy = move, but type is neither " + "movable nor copyable! " + "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in " + "debug mode for details)"); #endif } wrapper->owned = true; @@ -896,23 +832,179 @@ using movable_cast_op_type typename std::add_rvalue_reference<intrinsic_t<T>>::type, typename std::add_lvalue_reference<intrinsic_t<T>>::type>>; -// std::is_copy_constructible isn't quite enough: it lets std::vector<T> (and similar) through when -// T is non-copyable, but code containing such a copy constructor fails to actually compile. -template <typename T, typename SFINAE = void> -struct is_copy_constructible : std::is_copy_constructible<T> {}; +// Does the container have a mapped type and is it recursive? +// Implemented by specializations below. +template <typename Container, typename SFINAE = void> +struct container_mapped_type_traits { + static constexpr bool has_mapped_type = false; + static constexpr bool has_recursive_mapped_type = false; +}; -// Specialization for types that appear to be copy constructible but also look like stl containers -// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if -// so, copy constructability depends on whether the value_type is copy constructible. template <typename Container> -struct is_copy_constructible< +struct container_mapped_type_traits< Container, - enable_if_t< - all_of<std::is_copy_constructible<Container>, - std::is_same<typename Container::value_type &, typename Container::reference>, - // Avoid infinite recursion - negation<std::is_same<Container, typename Container::value_type>>>::value>> - : is_copy_constructible<typename Container::value_type> {}; + typename std::enable_if< + std::is_same<typename Container::mapped_type, Container>::value>::type> { + static constexpr bool has_mapped_type = true; + static constexpr bool has_recursive_mapped_type = true; +}; + +template <typename Container> +struct container_mapped_type_traits< + Container, + typename std::enable_if< + negation<std::is_same<typename Container::mapped_type, Container>>::value>::type> { + static constexpr bool has_mapped_type = true; + static constexpr bool has_recursive_mapped_type = false; +}; + +// Does the container have a value type and is it recursive? +// Implemented by specializations below. +template <typename Container, typename SFINAE = void> +struct container_value_type_traits : std::false_type { + static constexpr bool has_value_type = false; + static constexpr bool has_recursive_value_type = false; +}; + +template <typename Container> +struct container_value_type_traits< + Container, + typename std::enable_if< + std::is_same<typename Container::value_type, Container>::value>::type> { + static constexpr bool has_value_type = true; + static constexpr bool has_recursive_value_type = true; +}; + +template <typename Container> +struct container_value_type_traits< + Container, + typename std::enable_if< + negation<std::is_same<typename Container::value_type, Container>>::value>::type> { + static constexpr bool has_value_type = true; + static constexpr bool has_recursive_value_type = false; +}; + +/* + * Tag to be used for representing the bottom of recursively defined types. + * Define this tag so we don't have to use void. + */ +struct recursive_bottom {}; + +/* + * Implementation detail of `recursive_container_traits` below. + * `T` is the `value_type` of the container, which might need to be modified to + * avoid recursive types and const types. + */ +template <typename T, bool is_this_a_map> +struct impl_type_to_check_recursively { + /* + * If the container is recursive, then no further recursion should be done. + */ + using if_recursive = recursive_bottom; + /* + * Otherwise yield `T` unchanged. + */ + using if_not_recursive = T; +}; + +/* + * For pairs - only as value type of a map -, the first type should remove the `const`. + * Also, if the map is recursive, then the recursive checking should consider + * the first type only. + */ +template <typename A, typename B> +struct impl_type_to_check_recursively<std::pair<A, B>, /* is_this_a_map = */ true> { + using if_recursive = typename std::remove_const<A>::type; + using if_not_recursive = std::pair<typename std::remove_const<A>::type, B>; +}; + +/* + * Implementation of `recursive_container_traits` below. + */ +template <typename Container, typename SFINAE = void> +struct impl_recursive_container_traits { + using type_to_check_recursively = recursive_bottom; +}; + +template <typename Container> +struct impl_recursive_container_traits< + Container, + typename std::enable_if<container_value_type_traits<Container>::has_value_type>::type> { + static constexpr bool is_recursive + = container_mapped_type_traits<Container>::has_recursive_mapped_type + || container_value_type_traits<Container>::has_recursive_value_type; + /* + * This member dictates which type Pybind11 should check recursively in traits + * such as `is_move_constructible`, `is_copy_constructible`, `is_move_assignable`, ... + * Direct access to `value_type` should be avoided: + * 1. `value_type` might recursively contain the type again + * 2. `value_type` of STL map types is `std::pair<A const, B>`, the `const` + * should be removed. + * + */ + using type_to_check_recursively = typename std::conditional< + is_recursive, + typename impl_type_to_check_recursively< + typename Container::value_type, + container_mapped_type_traits<Container>::has_mapped_type>::if_recursive, + typename impl_type_to_check_recursively< + typename Container::value_type, + container_mapped_type_traits<Container>::has_mapped_type>::if_not_recursive>::type; +}; + +/* + * This trait defines the `type_to_check_recursively` which is needed to properly + * handle recursively defined traits such as `is_move_constructible` without going + * into an infinite recursion. + * Should be used instead of directly accessing the `value_type`. + * It cancels the recursion by returning the `recursive_bottom` tag. + * + * The default definition of `type_to_check_recursively` is as follows: + * + * 1. By default, it is `recursive_bottom`, so that the recursion is canceled. + * 2. If the type is non-recursive and defines a `value_type`, then the `value_type` is used. + * If the `value_type` is a pair and a `mapped_type` is defined, + * then the `const` is removed from the first type. + * 3. If the type is recursive and `value_type` is not a pair, then `recursive_bottom` is returned. + * 4. If the type is recursive and `value_type` is a pair and a `mapped_type` is defined, + * then `const` is removed from the first type and the first type is returned. + * + * This behavior can be extended by the user as seen in test_stl_binders.cpp. + * + * This struct is exactly the same as impl_recursive_container_traits. + * The duplication achieves that user-defined specializations don't compete + * with internal specializations, but take precedence. + */ +template <typename Container, typename SFINAE = void> +struct recursive_container_traits : impl_recursive_container_traits<Container> {}; + +template <typename T> +struct is_move_constructible + : all_of<std::is_move_constructible<T>, + is_move_constructible< + typename recursive_container_traits<T>::type_to_check_recursively>> {}; + +template <> +struct is_move_constructible<recursive_bottom> : std::true_type {}; + +// Likewise for std::pair +// (after C++17 it is mandatory that the move constructor not exist when the two types aren't +// themselves move constructible, but this can not be relied upon when T1 or T2 are themselves +// containers). +template <typename T1, typename T2> +struct is_move_constructible<std::pair<T1, T2>> + : all_of<is_move_constructible<T1>, is_move_constructible<T2>> {}; + +// std::is_copy_constructible isn't quite enough: it lets std::vector<T> (and similar) through when +// T is non-copyable, but code containing such a copy constructor fails to actually compile. +template <typename T> +struct is_copy_constructible + : all_of<std::is_copy_constructible<T>, + is_copy_constructible< + typename recursive_container_traits<T>::type_to_check_recursively>> {}; + +template <> +struct is_copy_constructible<recursive_bottom> : std::true_type {}; // Likewise for std::pair // (after C++17 it is mandatory that the copy constructor not exist when the two types aren't @@ -923,14 +1015,16 @@ struct is_copy_constructible<std::pair<T1, T2>> : all_of<is_copy_constructible<T1>, is_copy_constructible<T2>> {}; // The same problems arise with std::is_copy_assignable, so we use the same workaround. -template <typename T, typename SFINAE = void> -struct is_copy_assignable : std::is_copy_assignable<T> {}; -template <typename Container> -struct is_copy_assignable<Container, - enable_if_t<all_of<std::is_copy_assignable<Container>, - std::is_same<typename Container::value_type &, - typename Container::reference>>::value>> - : is_copy_assignable<typename Container::value_type> {}; +template <typename T> +struct is_copy_assignable + : all_of< + std::is_copy_assignable<T>, + is_copy_assignable<typename recursive_container_traits<T>::type_to_check_recursively>> { +}; + +template <> +struct is_copy_assignable<recursive_bottom> : std::true_type {}; + template <typename T1, typename T2> struct is_copy_assignable<std::pair<T1, T2>> : all_of<is_copy_assignable<T1>, is_copy_assignable<T2>> {}; @@ -1068,7 +1162,7 @@ protected: return [](const void *arg) -> void * { return new T(*reinterpret_cast<const T *>(arg)); }; } - template <typename T, typename = enable_if_t<std::is_move_constructible<T>::value>> + template <typename T, typename = enable_if_t<is_move_constructible<T>::value>> static auto make_move_constructor(const T *) -> decltype(new T(std::declval<T &&>()), Constructor{}) { return [](const void *arg) -> void * { @@ -1080,5 +1174,14 @@ protected: static Constructor make_move_constructor(...) { return nullptr; } }; +PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) { + if (auto *type_data = get_type_info(ti)) { + handle th((PyObject *) type_data->type); + return th.attr("__module__").cast<std::string>() + '.' + + th.attr("__qualname__").cast<std::string>(); + } + return clean_type_id(ti.name()); +} + PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/contrib/libs/pybind11/include/pybind11/detail/typeid.h b/contrib/libs/pybind11/include/pybind11/detail/typeid.h index 8d99fc0286..a67b52135b 100644 --- a/contrib/libs/pybind11/include/pybind11/detail/typeid.h +++ b/contrib/libs/pybind11/include/pybind11/detail/typeid.h @@ -20,6 +20,7 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) + /// Erase all occurrences of a substring inline void erase_all(std::string &string, const std::string &search) { for (size_t pos = 0;;) { @@ -46,14 +47,19 @@ PYBIND11_NOINLINE void clean_type_id(std::string &name) { #endif detail::erase_all(name, "pybind11::"); } + +inline std::string clean_type_id(const char *typeid_name) { + std::string name(typeid_name); + detail::clean_type_id(name); + return name; +} + PYBIND11_NAMESPACE_END(detail) /// Return a string representation of a C++ type template <typename T> static std::string type_id() { - std::string name(typeid(T).name()); - detail::clean_type_id(name); - return name; + return detail::clean_type_id(typeid(T).name()); } PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/contrib/libs/pybind11/include/pybind11/gil.h b/contrib/libs/pybind11/include/pybind11/gil.h index 446f4620b2..570a5581d5 100644 --- a/contrib/libs/pybind11/include/pybind11/gil.h +++ b/contrib/libs/pybind11/include/pybind11/gil.h @@ -10,7 +10,10 @@ #pragma once #include "detail/common.h" -#include "detail/internals.h" + +#if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) +# include "detail/internals.h" +#endif PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) @@ -21,7 +24,9 @@ PyThreadState *get_thread_state_unchecked(); PYBIND11_NAMESPACE_END(detail) -#if defined(WITH_THREAD) && !defined(PYPY_VERSION) +#if defined(WITH_THREAD) + +# if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) /* The functions below essentially reproduce the PyGILState_* API using a RAII * pattern, but there are a few important differences: @@ -62,11 +67,11 @@ public: if (!tstate) { tstate = PyThreadState_New(internals.istate); -# if !defined(NDEBUG) +# if defined(PYBIND11_DETAILED_ERROR_MESSAGES) if (!tstate) { pybind11_fail("scoped_acquire: could not create thread state!"); } -# endif +# endif tstate->gilstate_counter = 0; PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate); } else { @@ -80,24 +85,27 @@ public: inc_ref(); } + gil_scoped_acquire(const gil_scoped_acquire &) = delete; + gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete; + void inc_ref() { ++tstate->gilstate_counter; } PYBIND11_NOINLINE void dec_ref() { --tstate->gilstate_counter; -# if !defined(NDEBUG) +# if defined(PYBIND11_DETAILED_ERROR_MESSAGES) if (detail::get_thread_state_unchecked() != tstate) { pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!"); } if (tstate->gilstate_counter < 0) { pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!"); } -# endif +# endif if (tstate->gilstate_counter == 0) { -# if !defined(NDEBUG) +# if defined(PYBIND11_DETAILED_ERROR_MESSAGES) if (!release) { pybind11_fail("scoped_acquire::dec_ref(): internal error!"); } -# endif +# endif PyThreadState_Clear(tstate); if (active) { PyThreadState_DeleteCurrent(); @@ -144,6 +152,9 @@ public: } } + gil_scoped_release(const gil_scoped_release &) = delete; + gil_scoped_release &operator=(const gil_scoped_release &) = delete; + /// This method will disable the PyThreadState_DeleteCurrent call and the /// GIL won't be acquired. This method should be used if the interpreter /// could be shutting down when this is called, as thread deletion is not @@ -172,12 +183,16 @@ private: bool disassoc; bool active = true; }; -#elif defined(PYPY_VERSION) + +# else // PYBIND11_SIMPLE_GIL_MANAGEMENT + class gil_scoped_acquire { PyGILState_STATE state; public: - gil_scoped_acquire() { state = PyGILState_Ensure(); } + gil_scoped_acquire() : state{PyGILState_Ensure()} {} + gil_scoped_acquire(const gil_scoped_acquire &) = delete; + gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete; ~gil_scoped_acquire() { PyGILState_Release(state); } void disarm() {} }; @@ -186,17 +201,39 @@ class gil_scoped_release { PyThreadState *state; public: - gil_scoped_release() { state = PyEval_SaveThread(); } + gil_scoped_release() : state{PyEval_SaveThread()} {} + gil_scoped_release(const gil_scoped_release &) = delete; + gil_scoped_release &operator=(const gil_scoped_release &) = delete; ~gil_scoped_release() { PyEval_RestoreThread(state); } void disarm() {} }; -#else + +# endif // PYBIND11_SIMPLE_GIL_MANAGEMENT + +#else // WITH_THREAD + class gil_scoped_acquire { +public: + gil_scoped_acquire() { + // Trick to suppress `unused variable` error messages (at call sites). + (void) (this != (this + 1)); + } + gil_scoped_acquire(const gil_scoped_acquire &) = delete; + gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete; void disarm() {} }; + class gil_scoped_release { +public: + gil_scoped_release() { + // Trick to suppress `unused variable` error messages (at call sites). + (void) (this != (this + 1)); + } + gil_scoped_release(const gil_scoped_release &) = delete; + gil_scoped_release &operator=(const gil_scoped_release &) = delete; void disarm() {} }; -#endif + +#endif // WITH_THREAD PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/contrib/libs/pybind11/include/pybind11/numpy.h b/contrib/libs/pybind11/include/pybind11/numpy.h index 9f4d516f5f..8162908edd 100644 --- a/contrib/libs/pybind11/include/pybind11/numpy.h +++ b/contrib/libs/pybind11/include/pybind11/numpy.h @@ -36,6 +36,8 @@ static_assert(std::is_signed<Py_intptr_t>::value, "Py_intptr_t must be signed"); PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +PYBIND11_WARNING_DISABLE_MSVC(4127) + class array; // Forward declaration PYBIND11_NAMESPACE_BEGIN(detail) @@ -264,7 +266,7 @@ private: module_ m = module_::import("numpy.core.multiarray"); auto c = m.attr("_ARRAY_API"); #if PY_MAJOR_VERSION >= 3 - void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL); + void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), nullptr); #else void **api_ptr = (void **) PyCObject_AsVoidPtr(c.ptr()); #endif @@ -541,21 +543,21 @@ PYBIND11_NAMESPACE_END(detail) class dtype : public object { public: - PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_); + PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_) explicit dtype(const buffer_info &info) { - dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format))); + dtype descr(_dtype_from_pep3118()(pybind11::str(info.format))); // If info.itemsize == 0, use the value calculated from the format string m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize()) .release() .ptr(); } - explicit dtype(const std::string &format) { - m_ptr = from_args(pybind11::str(format)).release().ptr(); - } + explicit dtype(const pybind11::str &format) : dtype(from_args(format)) {} - explicit dtype(const char *format) : dtype(std::string(format)) {} + explicit dtype(const std::string &format) : dtype(pybind11::str(format)) {} + + explicit dtype(const char *format) : dtype(pybind11::str(format)) {} dtype(list names, list formats, list offsets, ssize_t itemsize) { dict args; @@ -563,11 +565,20 @@ public: args["formats"] = std::move(formats); args["offsets"] = std::move(offsets); args["itemsize"] = pybind11::int_(itemsize); - m_ptr = from_args(std::move(args)).release().ptr(); + m_ptr = from_args(args).release().ptr(); + } + + /// Return dtype for the given typenum (one of the NPY_TYPES). + /// https://numpy.org/devdocs/reference/c-api/array.html#c.PyArray_DescrFromType + explicit dtype(int typenum) + : object(detail::npy_api::get().PyArray_DescrFromType_(typenum), stolen_t{}) { + if (m_ptr == nullptr) { + throw error_already_set(); + } } /// This is essentially the same as calling numpy.dtype(args) in Python. - static dtype from_args(object args) { + static dtype from_args(const object &args) { PyObject *ptr = nullptr; if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr) { throw error_already_set(); @@ -600,6 +611,23 @@ public: return detail::array_descriptor_proxy(m_ptr)->type; } + /// type number of dtype. + int num() const { + // Note: The signature, `dtype::num` follows the naming of NumPy's public + // Python API (i.e., ``dtype.num``), rather than its internal + // C API (``PyArray_Descr::type_num``). + return detail::array_descriptor_proxy(m_ptr)->type_num; + } + + /// Single character for byteorder + char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; } + + /// Alignment of the data type + int alignment() const { return detail::array_descriptor_proxy(m_ptr)->alignment; } + + /// Flags for the array descriptor + char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; } + private: static object _dtype_from_pep3118() { static PyObject *obj = module_::import("numpy.core._internal") @@ -618,22 +646,27 @@ private: } struct field_descr { - PYBIND11_STR_TYPE name; + pybind11::str name; object format; pybind11::int_ offset; + field_descr(pybind11::str &&name, object &&format, pybind11::int_ &&offset) + : name{std::move(name)}, format{std::move(format)}, offset{std::move(offset)} {}; }; + auto field_dict = attr("fields").cast<dict>(); std::vector<field_descr> field_descriptors; + field_descriptors.reserve(field_dict.size()); - for (auto field : attr("fields").attr("items")()) { + for (auto field : field_dict.attr("items")()) { auto spec = field.cast<tuple>(); auto name = spec[0].cast<pybind11::str>(); - auto format = spec[1].cast<tuple>()[0].cast<dtype>(); - auto offset = spec[1].cast<tuple>()[1].cast<pybind11::int_>(); + auto spec_fo = spec[1].cast<tuple>(); + auto format = spec_fo[0].cast<dtype>(); + auto offset = spec_fo[1].cast<pybind11::int_>(); if ((len(name) == 0u) && format.kind() == 'V') { continue; } - field_descriptors.push_back( - {(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset}); + field_descriptors.emplace_back( + std::move(name), format.strip_padding(format.itemsize()), std::move(offset)); } std::sort(field_descriptors.begin(), @@ -644,9 +677,9 @@ private: list names, formats, offsets; for (auto &descr : field_descriptors) { - names.append(descr.name); - formats.append(descr.format); - offsets.append(descr.offset); + names.append(std::move(descr.name)); + formats.append(std::move(descr.format)); + offsets.append(std::move(descr.offset)); } return dtype(std::move(names), std::move(formats), std::move(offsets), itemsize); } @@ -850,7 +883,7 @@ public: */ template <typename T, ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & { - if (PYBIND11_SILENCE_MSVC_C4127(Dims >= 0) && ndim() != Dims) { + if (Dims >= 0 && ndim() != Dims) { throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) + "; expected " + std::to_string(Dims)); @@ -868,7 +901,7 @@ public: */ template <typename T, ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const & { - if (PYBIND11_SILENCE_MSVC_C4127(Dims >= 0) && ndim() != Dims) { + if (Dims >= 0 && ndim() != Dims) { throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) + "; expected " + std::to_string(Dims)); @@ -944,7 +977,7 @@ protected: void fail_dim_check(ssize_t dim, const std::string &msg) const { throw index_error(msg + ": " + std::to_string(dim) + " (ndim = " + std::to_string(ndim()) - + ")"); + + ')'); } template <typename... Ix> @@ -1094,10 +1127,10 @@ public: /** * Returns a proxy object that provides const access to the array's data without bounds or - * dimensionality checking. Unlike `unchecked()`, this does not require that the underlying - * array have the `writable` flag. Use with care: the array must not be destroyed or reshaped - * for the duration of the returned object, and the caller must take care not to access invalid - * dimensions or dimension indices. + * dimensionality checking. Unlike `mutable_unchecked()`, this does not require that the + * underlying array have the `writable` flag. Use with care: the array must not be destroyed + * or reshaped for the duration of the returned object, and the caller must take care not to + * access invalid dimensions or dimension indices. */ template <ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const & { @@ -1148,11 +1181,11 @@ struct format_descriptor<T, detail::enable_if_t<detail::is_pod_struct<T>::value> template <size_t N> struct format_descriptor<char[N]> { - static std::string format() { return std::to_string(N) + "s"; } + static std::string format() { return std::to_string(N) + 's'; } }; template <size_t N> struct format_descriptor<std::array<char, N>> { - static std::string format() { return std::to_string(N) + "s"; } + static std::string format() { return std::to_string(N) + 's'; } }; template <typename T> @@ -1256,12 +1289,16 @@ private: public: static constexpr int value = values[detail::is_fmt_numeric<T>::index]; - static pybind11::dtype dtype() { - if (auto *ptr = npy_api::get().PyArray_DescrFromType_(value)) { - return reinterpret_steal<pybind11::dtype>(ptr); - } - pybind11_fail("Unsupported buffer format!"); - } + static pybind11::dtype dtype() { return pybind11::dtype(/*typenum*/ value); } +}; + +template <typename T> +struct npy_format_descriptor<T, enable_if_t<is_same_ignoring_cvref<T, PyObject *>::value>> { + static constexpr auto name = const_name("object"); + + static constexpr int value = npy_api::NPY_OBJECT_; + + static pybind11::dtype dtype() { return pybind11::dtype(/*typenum*/ value); } }; #define PYBIND11_DECL_CHAR_FMT \ @@ -1292,7 +1329,8 @@ public: static pybind11::dtype dtype() { list shape; array_info<T>::append_extents(shape); - return pybind11::dtype::from_args(pybind11::make_tuple(base_descr::dtype(), shape)); + return pybind11::dtype::from_args( + pybind11::make_tuple(base_descr::dtype(), std::move(shape))); } }; @@ -1338,7 +1376,7 @@ PYBIND11_NOINLINE void register_structured_dtype(any_container<field_descriptor> pybind11_fail(std::string("NumPy: unsupported field dtype: `") + field.name + "` @ " + tinfo.name()); } - names.append(PYBIND11_STR_TYPE(field.name)); + names.append(pybind11::str(field.name)); formats.append(field.descr); offsets.append(pybind11::int_(field.offset)); } @@ -1375,7 +1413,7 @@ PYBIND11_NOINLINE void register_structured_dtype(any_container<field_descriptor> oss << '}'; auto format_str = oss.str(); - // Sanity check: verify that NumPy properly parses our buffer format string + // Smoke test: verify that NumPy properly parses our buffer format string auto &api = npy_api::get(); auto arr = array(buffer_info(nullptr, itemsize, format_str, 1)); if (!api.PyArray_EquivTypes_(dtype_ptr, arr.dtype().ptr())) { @@ -1383,7 +1421,7 @@ PYBIND11_NOINLINE void register_structured_dtype(any_container<field_descriptor> } auto tindex = std::type_index(tinfo); - numpy_internals.registered_dtypes[tindex] = {dtype_ptr, format_str}; + numpy_internals.registered_dtypes[tindex] = {dtype_ptr, std::move(format_str)}; get_internals().direct_conversions[tindex].push_back(direct_converter); } @@ -1443,7 +1481,7 @@ private: } // Extract name, offset and format descriptor for a struct field -# define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, # Field) +# define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #Field) // The main idea of this macro is borrowed from https://github.com/swansontec/map-macro // (C) William Swanson, Paul Fultz @@ -1530,7 +1568,7 @@ public: void *data() const { return p_ptr; } private: - char *p_ptr{0}; + char *p_ptr{nullptr}; container_type m_strides; }; @@ -1840,8 +1878,13 @@ private: auto result = returned_array::create(trivial, shape); + PYBIND11_WARNING_PUSH +#ifdef PYBIND11_DETECTED_CLANG_WITH_MISLEADING_CALL_STD_MOVE_EXPLICITLY_WARNING + PYBIND11_WARNING_DISABLE_CLANG("-Wreturn-std-move") +#endif + if (size == 0) { - return std::move(result); + return result; } /* Call the function */ @@ -1852,7 +1895,8 @@ private: apply_trivial(buffers, params, mutable_data, size, i_seq, vi_seq, bi_seq); } - return std::move(result); + return result; + PYBIND11_WARNING_POP } template <size_t... Index, size_t... VIndex, size_t... BIndex> diff --git a/contrib/libs/pybind11/include/pybind11/options.h b/contrib/libs/pybind11/include/pybind11/options.h index 1e493bdcc4..1b2122522d 100644 --- a/contrib/libs/pybind11/include/pybind11/options.h +++ b/contrib/libs/pybind11/include/pybind11/options.h @@ -47,6 +47,16 @@ public: return *this; } + options &disable_enum_members_docstring() & { + global_state().show_enum_members_docstring = false; + return *this; + } + + options &enable_enum_members_docstring() & { + global_state().show_enum_members_docstring = true; + return *this; + } + // Getter methods (return the global state): static bool show_user_defined_docstrings() { @@ -55,6 +65,10 @@ public: static bool show_function_signatures() { return global_state().show_function_signatures; } + static bool show_enum_members_docstring() { + return global_state().show_enum_members_docstring; + } + // This type is not meant to be allocated on the heap. void *operator new(size_t) = delete; @@ -63,6 +77,8 @@ private: bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings. bool show_function_signatures = true; //< Include auto-generated function signatures // in docstrings. + bool show_enum_members_docstring = true; //< Include auto-generated member list in enum + // docstrings. }; static state &global_state() { diff --git a/contrib/libs/pybind11/include/pybind11/pybind11.h b/contrib/libs/pybind11/include/pybind11/pybind11.h index e349bfdc96..cd30063303 100644 --- a/contrib/libs/pybind11/include/pybind11/pybind11.h +++ b/contrib/libs/pybind11/include/pybind11/pybind11.h @@ -35,6 +35,8 @@ # include <cxxabi.h> #endif +PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + /* https://stackoverflow.com/questions/46798456/handling-gccs-noexcept-type-warning This warning is about ABI compatibility, not code health. It is only actually needed in a couple places, but apparently GCC 7 "generates this warning if @@ -43,11 +45,10 @@ No other GCC version generates this warning. */ #if defined(__GNUC__) && __GNUC__ == 7 -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wnoexcept-type" +PYBIND11_WARNING_DISABLE_GCC("-Wnoexcept-type") #endif -PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +PYBIND11_WARNING_DISABLE_MSVC(4127) PYBIND11_NAMESPACE_BEGIN(detail) @@ -83,6 +84,7 @@ public: cpp_function() = default; // NOLINTNEXTLINE(google-explicit-constructor) cpp_function(std::nullptr_t) {} + cpp_function(std::nullptr_t, const is_setter &) {} /// Construct a cpp_function from a vanilla function pointer template <typename Return, typename... Args, typename... Extra> @@ -177,22 +179,22 @@ protected: auto *rec = unique_rec.get(); /* Store the capture object directly in the function record if there is enough space */ - if (PYBIND11_SILENCE_MSVC_C4127(sizeof(capture) <= sizeof(rec->data))) { + if (sizeof(capture) <= sizeof(rec->data)) { /* Without these pragmas, GCC warns that there might not be enough space to use the placement new operator. However, the 'if' statement above ensures that this is the case. */ -#if defined(__GNUG__) && __GNUC__ >= 6 && !defined(__clang__) && !defined(__INTEL_COMPILER) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wplacement-new" + PYBIND11_WARNING_PUSH + +#if defined(__GNUG__) && __GNUC__ >= 6 + PYBIND11_WARNING_DISABLE_GCC("-Wplacement-new") #endif + new ((capture *) &rec->data) capture{std::forward<Func>(f)}; -#if defined(__GNUG__) && __GNUC__ >= 6 && !defined(__clang__) && !defined(__INTEL_COMPILER) -# pragma GCC diagnostic pop -#endif -#if defined(__GNUG__) && !PYBIND11_HAS_STD_LAUNDER && !defined(__INTEL_COMPILER) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wstrict-aliasing" + +#if !PYBIND11_HAS_STD_LAUNDER + PYBIND11_WARNING_DISABLE_GCC("-Wstrict-aliasing") #endif + // UB without std::launder, but without breaking ABI and/or // a significant refactoring it's "impossible" to solve. if (!std::is_trivially_destructible<capture>::value) { @@ -202,9 +204,7 @@ protected: data->~capture(); }; } -#if defined(__GNUG__) && !PYBIND11_HAS_STD_LAUNDER && !defined(__INTEL_COMPILER) -# pragma GCC diagnostic pop -#endif + PYBIND11_WARNING_POP } else { rec->data[0] = new capture{std::forward<Func>(f)}; rec->free_data = [](function_record *r) { delete ((capture *) r->data[0]); }; @@ -245,10 +245,16 @@ protected: using Guard = extract_guard_t<Extra...>; /* Perform the function call */ - handle result - = cast_out::cast(std::move(args_converter).template call<Return, Guard>(cap->f), - policy, - call.parent); + handle result; + if (call.func.is_setter) { + (void) std::move(args_converter).template call<Return, Guard>(cap->f); + result = none().release(); + } else { + result = cast_out::cast( + std::move(args_converter).template call<Return, Guard>(cap->f), + policy, + call.parent); + } /* Invoke call policy post-call hook */ process_attributes<Extra...>::postcall(call, result); @@ -312,6 +318,10 @@ protected: // along the way. class strdup_guard { public: + strdup_guard() = default; + strdup_guard(const strdup_guard &) = delete; + strdup_guard &operator=(const strdup_guard &) = delete; + ~strdup_guard() { for (auto *s : strings) { std::free(s); @@ -366,7 +376,7 @@ protected: rec->is_constructor = (std::strcmp(rec->name, "__init__") == 0) || (std::strcmp(rec->name, "__setstate__") == 0); -#if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING) +#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING) if (rec->is_constructor && !rec->is_new_style_constructor) { const auto class_name = detail::get_fully_qualified_tp_name((PyTypeObject *) rec->scope.ptr()); @@ -431,9 +441,8 @@ protected: } if (auto *tinfo = detail::get_type_info(*t)) { handle th((PyObject *) tinfo->type); - signature += th.attr("__module__").cast<std::string>() + "." + - // Python 3.3+, but we backport it to earlier versions - th.attr("__qualname__").cast<std::string>(); + signature += th.attr("__module__").cast<std::string>() + "." + + th.attr("__qualname__").cast<std::string>(); } else if (rec->is_new_style_constructor && arg_index == 0) { // A new-style `__init__` takes `self` as `value_and_holder`. // Rewrite it to the proper class type. @@ -474,13 +483,20 @@ protected: if (rec->sibling) { if (PyCFunction_Check(rec->sibling.ptr())) { auto *self = PyCFunction_GET_SELF(rec->sibling.ptr()); - capsule rec_capsule = isinstance<capsule>(self) ? reinterpret_borrow<capsule>(self) - : capsule(self); - chain = (detail::function_record *) rec_capsule; - /* Never append a method to an overload chain of a parent class; - instead, hide the parent's overloads in this case */ - if (!chain->scope.is(rec->scope)) { + if (!isinstance<capsule>(self)) { chain = nullptr; + } else { + auto rec_capsule = reinterpret_borrow<capsule>(self); + if (detail::is_function_record_capsule(rec_capsule)) { + chain = rec_capsule.get_pointer<detail::function_record>(); + /* Never append a method to an overload chain of a parent class; + instead, hide the parent's overloads in this case */ + if (!chain->scope.is(rec->scope)) { + chain = nullptr; + } + } else { + chain = nullptr; + } } } // Don't trigger for things like the default __init__, which are wrapper_descriptors @@ -501,6 +517,7 @@ protected: rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS; capsule rec_capsule(unique_rec.release(), + detail::get_function_record_capsule_name(), [](void *ptr) { destruct((detail::function_record *) ptr); }); guarded_strdup.release(); @@ -524,8 +541,9 @@ protected: if (chain->is_method != rec->is_method) { pybind11_fail( "overloading a method with both static and instance methods is not supported; " -#if defined(NDEBUG) - "compile in debug mode for more details" +#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) + "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more " + "details" #else "error while attempting to bind " + std::string(rec->is_method ? "instance" : "static") + " method " @@ -571,14 +589,14 @@ protected: for (auto *it = chain_start; it != nullptr; it = it->next) { if (options::show_function_signatures()) { if (index > 0) { - signatures += "\n"; + signatures += '\n'; } if (chain) { signatures += std::to_string(++index) + ". "; } signatures += rec->name; signatures += it->signature; - signatures += "\n"; + signatures += '\n'; } if (it->doc && it->doc[0] != '\0' && options::show_user_defined_docstrings()) { // If we're appending another docstring, and aren't printing function signatures, @@ -587,15 +605,15 @@ protected: if (first_user_def) { first_user_def = false; } else { - signatures += "\n"; + signatures += '\n'; } } if (options::show_function_signatures()) { - signatures += "\n"; + signatures += '\n'; } signatures += it->doc; if (options::show_function_signatures()) { - signatures += "\n"; + signatures += '\n'; } } } @@ -666,10 +684,13 @@ protected: /// Main dispatch logic for calls to functions bound using pybind11 static PyObject *dispatcher(PyObject *self, PyObject *args_in, PyObject *kwargs_in) { using namespace detail; + assert(isinstance<capsule>(self)); /* Iterator over the list of potentially admissible overloads */ - const function_record *overloads = (function_record *) PyCapsule_GetPointer(self, nullptr), + const function_record *overloads = reinterpret_cast<function_record *>( + PyCapsule_GetPointer(self, get_function_record_capsule_name())), *it = overloads; + assert(overloads != nullptr); /* Need to know how many arguments + keyword arguments there are to pick the right overload */ @@ -912,7 +933,7 @@ protected: // 5. Put everything in a vector. Not technically step 5, we've been building it // in `call.args` all along. -#if !defined(NDEBUG) +#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) if (call.args.size() != func.nargs || call.args_convert.size() != func.nargs) { pybind11_fail("Internal error: function call dispatcher inserted wrong number " "of arguments!"); @@ -1065,7 +1086,7 @@ protected: msg += it2->signature; } - msg += "\n"; + msg += '\n'; } msg += "\nInvoked with: "; auto args_ = reinterpret_borrow<tuple>(args_in); @@ -1186,9 +1207,16 @@ public: py::module_ m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'"); \endrst */ module_ def_submodule(const char *name, const char *doc = nullptr) { - std::string full_name - = std::string(PyModule_GetName(m_ptr)) + std::string(".") + std::string(name); - auto result = reinterpret_borrow<module_>(PyImport_AddModule(full_name.c_str())); + const char *this_name = PyModule_GetName(m_ptr); + if (this_name == nullptr) { + throw error_already_set(); + } + std::string full_name = std::string(this_name) + '.' + name; + handle submodule = PyImport_AddModule(full_name.c_str()); + if (!submodule) { + throw error_already_set(); + } + auto result = reinterpret_borrow<module_>(submodule); if (doc && options::show_user_defined_docstrings()) { result.attr("__doc__") = pybind11::str(doc); } @@ -1232,7 +1260,7 @@ public: } #if PY_MAJOR_VERSION >= 3 - using module_def = PyModuleDef; + using module_def = PyModuleDef; // TODO: Can this be removed (it was needed only for Python 2)? #else struct module_def {}; #endif @@ -1271,8 +1299,8 @@ public: pybind11_fail("Internal error in module_::create_extension_module()"); } // TODO: Should be reinterpret_steal for Python 3, but Python also steals it again when - // returned from PyInit_... - // For Python 2, reinterpret_borrow is correct. + // returned from PyInit_... + // For Python 2, reinterpret_borrow was correct. return reinterpret_borrow<module_>(m); } }; @@ -1436,9 +1464,9 @@ template <typename T, enable_if_t<has_operator_delete<T>::value, int> = 0> void call_operator_delete(T *p, size_t, size_t) { T::operator delete(p); } -template < - typename T, - enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int> = 0> +template <typename T, + enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int> + = 0> void call_operator_delete(T *p, size_t s, size_t) { T::operator delete(p, s); } @@ -1593,18 +1621,19 @@ public: scope(*this), sibling(getattr(*this, name_, none())), extra...); - attr(cf.name()) = staticmethod(cf); + auto cf_name = cf.name(); + attr(std::move(cf_name)) = staticmethod(std::move(cf)); return *this; } - template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra> - class_ &def(const detail::op_<id, ot, L, R> &op, const Extra &...extra) { + template <typename T, typename... Extra, detail::enable_if_t<T::op_enable_if_hook, int> = 0> + class_ &def(const T &op, const Extra &...extra) { op.execute(*this, extra...); return *this; } - template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra> - class_ &def_cast(const detail::op_<id, ot, L, R> &op, const Extra &...extra) { + template <typename T, typename... Extra, detail::enable_if_t<T::op_enable_if_hook, int> = 0> + class_ &def_cast(const T &op, const Extra &...extra) { op.execute_cast(*this, extra...); return *this; } @@ -1647,7 +1676,7 @@ public: if (!caster.load(obj, false)) { return nullptr; } - return new buffer_info(((capture *) ptr)->func(caster)); + return new buffer_info(((capture *) ptr)->func(std::move(caster))); }, ptr); weakref(m_ptr, cpp_function([ptr](handle wr) { @@ -1738,7 +1767,8 @@ public: template <typename Getter, typename Setter, typename... Extra> class_ & def_property(const char *name, const Getter &fget, const Setter &fset, const Extra &...extra) { - return def_property(name, fget, cpp_function(method_adaptor<type>(fset)), extra...); + return def_property( + name, fget, cpp_function(method_adaptor<type>(fset), is_setter()), extra...); } template <typename Getter, typename... Extra> class_ &def_property(const char *name, @@ -1849,7 +1879,7 @@ private: if (holder_ptr) { init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible<holder_type>()); v_h.set_holder_constructed(); - } else if (inst->owned || detail::always_construct_holder<holder_type>::value) { + } else if (detail::always_construct_holder<holder_type>::value || inst->owned) { new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>()); v_h.set_holder_constructed(); } @@ -1889,9 +1919,22 @@ private: static detail::function_record *get_function_record(handle h) { h = detail::get_function(h); - return h ? (detail::function_record *) reinterpret_borrow<capsule>( - PyCFunction_GET_SELF(h.ptr())) - : nullptr; + if (!h) { + return nullptr; + } + + handle func_self = PyCFunction_GET_SELF(h.ptr()); + if (!func_self) { + throw error_already_set(); + } + if (!isinstance<capsule>(func_self)) { + return nullptr; + } + auto cap = reinterpret_borrow<capsule>(func_self); + if (!detail::is_function_record_capsule(cap)) { + return nullptr; + } + return cap.get_pointer<detail::function_record>(); } }; @@ -1952,7 +1995,8 @@ struct enum_base { [](const object &arg) -> str { handle type = type::handle_of(arg); object type_name = type.attr("__name__"); - return pybind11::str("<{}.{}: {}>").format(type_name, enum_name(arg), int_(arg)); + return pybind11::str("<{}.{}: {}>") + .format(std::move(type_name), enum_name(arg), int_(arg)); }, name("__repr__"), is_method(m_base)); @@ -1962,34 +2006,40 @@ struct enum_base { m_base.attr("__str__") = cpp_function( [](handle arg) -> str { object type_name = type::handle_of(arg).attr("__name__"); - return pybind11::str("{}.{}").format(type_name, enum_name(arg)); + return pybind11::str("{}.{}").format(std::move(type_name), enum_name(arg)); }, name("name"), is_method(m_base)); - m_base.attr("__doc__") = static_property( - cpp_function( - [](handle arg) -> std::string { - std::string docstring; - dict entries = arg.attr("__entries"); - if (((PyTypeObject *) arg.ptr())->tp_doc) { - docstring += std::string(((PyTypeObject *) arg.ptr())->tp_doc) + "\n\n"; - } - docstring += "Members:"; - for (auto kv : entries) { - auto key = std::string(pybind11::str(kv.first)); - auto comment = kv.second[int_(1)]; - docstring += "\n\n " + key; - if (!comment.is_none()) { - docstring += " : " + (std::string) pybind11::str(comment); + if (options::show_enum_members_docstring()) { + m_base.attr("__doc__") = static_property( + cpp_function( + [](handle arg) -> std::string { + std::string docstring; + dict entries = arg.attr("__entries"); + if (((PyTypeObject *) arg.ptr())->tp_doc) { + docstring += std::string( + reinterpret_cast<PyTypeObject *>(arg.ptr())->tp_doc); + docstring += "\n\n"; } - } - return docstring; - }, - name("__doc__")), - none(), - none(), - ""); + docstring += "Members:"; + for (auto kv : entries) { + auto key = std::string(pybind11::str(kv.first)); + auto comment = kv.second[int_(1)]; + docstring += "\n\n "; + docstring += key; + if (!comment.is_none()) { + docstring += " : "; + docstring += pybind11::str(comment).cast<std::string>(); + } + } + return docstring; + }, + name("__doc__")), + none(), + none(), + ""); + } m_base.attr("__members__") = static_property(cpp_function( [](handle arg) -> dict { @@ -2086,12 +2136,12 @@ struct enum_base { str name(name_); if (entries.contains(name)) { std::string type_name = (std::string) str(m_base.attr("__name__")); - throw value_error(type_name + ": element \"" + std::string(name_) + throw value_error(std::move(type_name) + ": element \"" + std::string(name_) + "\" already exists!"); } - entries[name] = std::make_pair(value, doc); - m_base.attr(name) = value; + entries[name] = pybind11::make_tuple(value, doc); + m_base.attr(std::move(name)) = std::move(value); } PYBIND11_NOINLINE void export_values() { @@ -2437,7 +2487,8 @@ template <return_value_policy Policy = return_value_policy::reference_internal, typename Type, typename... Extra> iterator make_iterator(Type &value, Extra &&...extra) { - return make_iterator<Policy>(std::begin(value), std::end(value), extra...); + return make_iterator<Policy>( + std::begin(value), std::end(value), std::forward<Extra>(extra)...); } /// Makes an iterator over the keys (`.first`) of a stl map-like container supporting @@ -2446,7 +2497,8 @@ template <return_value_policy Policy = return_value_policy::reference_internal, typename Type, typename... Extra> iterator make_key_iterator(Type &value, Extra &&...extra) { - return make_key_iterator<Policy>(std::begin(value), std::end(value), extra...); + return make_key_iterator<Policy>( + std::begin(value), std::end(value), std::forward<Extra>(extra)...); } /// Makes an iterator over the values (`.second`) of a stl map-like container supporting @@ -2455,7 +2507,8 @@ template <return_value_policy Policy = return_value_policy::reference_internal, typename Type, typename... Extra> iterator make_value_iterator(Type &value, Extra &&...extra) { - return make_value_iterator<Policy>(std::begin(value), std::end(value), extra...); + return make_value_iterator<Policy>( + std::begin(value), std::end(value), std::forward<Extra>(extra)...); } template <typename InputType, typename OutputType> @@ -2484,7 +2537,7 @@ void implicitly_convertible() { }; if (auto *tinfo = detail::get_type_info(typeid(OutputType))) { - tinfo->implicit_conversions.push_back(implicit_caster); + tinfo->implicit_conversions.emplace_back(std::move(implicit_caster)); } else { pybind11_fail("implicitly_convertible: Unable to find type " + type_id<OutputType>()); } @@ -2520,7 +2573,7 @@ public: exception(handle scope, const char *name, handle base = PyExc_Exception) { std::string full_name = scope.attr("__name__").cast<std::string>() + std::string(".") + name; - m_ptr = PyErr_NewException(const_cast<char *>(full_name.c_str()), base.ptr(), NULL); + m_ptr = PyErr_NewException(const_cast<char *>(full_name.c_str()), base.ptr(), nullptr); if (hasattr(scope, "__dict__") && scope.attr("__dict__").contains(name)) { pybind11_fail("Error during initialization: multiple incompatible " "definitions with name \"" @@ -2602,8 +2655,8 @@ PYBIND11_NOINLINE void print(const tuple &args, const dict &kwargs) { for (size_t i = 0; i < args.size(); ++i) { strings[i] = str(args[i]); } - auto sep = kwargs.contains("sep") ? kwargs["sep"] : cast(" "); - auto line = sep.attr("join")(strings); + auto sep = kwargs.contains("sep") ? kwargs["sep"] : str(" "); + auto line = sep.attr("join")(std::move(strings)); object file; if (kwargs.contains("file")) { @@ -2621,8 +2674,8 @@ PYBIND11_NOINLINE void print(const tuple &args, const dict &kwargs) { } auto write = file.attr("write"); - write(line); - write(kwargs.contains("end") ? kwargs["end"] : cast("\n")); + write(std::move(line)); + write(kwargs.contains("end") ? kwargs["end"] : str("\n")); if (kwargs.contains("flush") && kwargs["flush"].cast<bool>()) { file.attr("flush")(); @@ -2636,17 +2689,21 @@ void print(Args &&...args) { detail::print(c.args(), c.kwargs()); } -error_already_set::~error_already_set() { - if (m_type) { - gil_scoped_acquire gil; - error_scope scope; - m_type.release().dec_ref(); - m_value.release().dec_ref(); - m_trace.release().dec_ref(); - } +inline void +error_already_set::m_fetched_error_deleter(detail::error_fetch_and_normalize *raw_ptr) { + gil_scoped_acquire gil; + error_scope scope; + delete raw_ptr; +} + +inline const char *error_already_set::what() const noexcept { + gil_scoped_acquire gil; + error_scope scope; + return m_fetched_error->error_string().c_str(); } PYBIND11_NAMESPACE_BEGIN(detail) + inline function get_type_override(const void *this_ptr, const type_info *this_type, const char *name) { handle self = get_object_handle(this_ptr, this_type); @@ -2665,7 +2722,7 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char * function override = getattr(self, name, function()); if (override.is_cpp_function()) { - cache.insert(key); + cache.insert(std::move(key)); return function(); } @@ -2865,7 +2922,3 @@ inline function get_overload(const T *this_ptr, const char *name) { PYBIND11_OVERRIDE_PURE(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), fn, __VA_ARGS__); PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) - -#if defined(__GNUC__) && __GNUC__ == 7 -# pragma GCC diagnostic pop // -Wnoexcept-type -#endif diff --git a/contrib/libs/pybind11/include/pybind11/pytypes.h b/contrib/libs/pybind11/include/pybind11/pytypes.h index 75ea7de88e..fcad4c609e 100644 --- a/contrib/libs/pybind11/include/pybind11/pytypes.h +++ b/contrib/libs/pybind11/include/pybind11/pytypes.h @@ -12,7 +12,15 @@ #include "detail/common.h" #include "buffer_info.h" +#include <assert.h> +#include <cstddef> +#include <exception> +#include <frameobject.h> +#include <iterator> +#include <memory> +#include <string> #include <type_traits> +#include <typeinfo> #include <utility> #if defined(PYBIND11_HAS_OPTIONAL) @@ -25,6 +33,8 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +PYBIND11_WARNING_DISABLE_MSVC(4127) + /* A few forward declarations */ class handle; class object; @@ -85,7 +95,9 @@ public: or `object` subclass causes a call to ``__setitem__``. \endrst */ item_accessor operator[](handle key) const; - /// See above (the only difference is that they key is provided as a string literal) + /// See above (the only difference is that the key's reference is stolen) + item_accessor operator[](object &&key) const; + /// See above (the only difference is that the key is provided as a string literal) item_accessor operator[](const char *key) const; /** \rst @@ -95,7 +107,9 @@ public: or `object` subclass causes a call to ``setattr``. \endrst */ obj_attr_accessor attr(handle key) const; - /// See above (the only difference is that they key is provided as a string literal) + /// See above (the only difference is that the key's reference is stolen) + obj_attr_accessor attr(object &&key) const; + /// See above (the only difference is that the key is provided as a string literal) str_attr_accessor attr(const char *key) const; /** \rst @@ -143,23 +157,23 @@ public: object operator-() const; object operator~() const; object operator+(object_api const &other) const; - object operator+=(object_api const &other) const; + object operator+=(object_api const &other); object operator-(object_api const &other) const; - object operator-=(object_api const &other) const; + object operator-=(object_api const &other); object operator*(object_api const &other) const; - object operator*=(object_api const &other) const; + object operator*=(object_api const &other); object operator/(object_api const &other) const; - object operator/=(object_api const &other) const; + object operator/=(object_api const &other); object operator|(object_api const &other) const; - object operator|=(object_api const &other) const; + object operator|=(object_api const &other); object operator&(object_api const &other) const; - object operator&=(object_api const &other) const; + object operator&=(object_api const &other); object operator^(object_api const &other) const; - object operator^=(object_api const &other) const; + object operator^=(object_api const &other); object operator<<(object_api const &other) const; - object operator<<=(object_api const &other) const; + object operator<<=(object_api const &other); object operator>>(object_api const &other) const; - object operator>>=(object_api const &other) const; + object operator>>=(object_api const &other); PYBIND11_DEPRECATED("Use py::str(obj) instead") pybind11::str str() const; @@ -178,8 +192,17 @@ private: bool rich_compare(object_api const &other, int value) const; }; +template <typename T> +using is_pyobj_ptr_or_nullptr_t = detail::any_of<std::is_same<T, PyObject *>, + std::is_same<T, PyObject *const>, + std::is_same<T, std::nullptr_t>>; + PYBIND11_NAMESPACE_END(detail) +#if !defined(PYBIND11_HANDLE_REF_DEBUG) && !defined(NDEBUG) +# define PYBIND11_HANDLE_REF_DEBUG +#endif + /** \rst Holds a reference to a Python object (no reference counting) @@ -195,9 +218,24 @@ class handle : public detail::object_api<handle> { public: /// The default constructor creates a handle with a ``nullptr``-valued pointer handle() = default; - /// Creates a ``handle`` from the given raw Python object pointer + + /// Enable implicit conversion from ``PyObject *`` and ``nullptr``. + /// Not using ``handle(PyObject *ptr)`` to avoid implicit conversion from ``0``. + template <typename T, + detail::enable_if_t<detail::is_pyobj_ptr_or_nullptr_t<T>::value, int> = 0> + // NOLINTNEXTLINE(google-explicit-constructor) + handle(T ptr) : m_ptr(ptr) {} + + /// Enable implicit conversion through ``T::operator PyObject *()``. + template < + typename T, + detail::enable_if_t<detail::all_of<detail::none_of<std::is_base_of<handle, T>, + detail::is_pyobj_ptr_or_nullptr_t<T>>, + std::is_convertible<T, PyObject *>>::value, + int> + = 0> // NOLINTNEXTLINE(google-explicit-constructor) - handle(PyObject *ptr) : m_ptr(ptr) {} // Allow implicit conversion from PyObject* + handle(T &obj) : m_ptr(obj) {} /// Return the underlying ``PyObject *`` pointer PyObject *ptr() const { return m_ptr; } @@ -209,6 +247,14 @@ public: this function automatically. Returns a reference to itself. \endrst */ const handle &inc_ref() const & { +#ifdef PYBIND11_HANDLE_REF_DEBUG + inc_ref_counter(1); +#endif +#ifdef PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF + if (m_ptr != nullptr && !PyGILState_Check()) { + throw_gilstate_error("pybind11::handle::inc_ref()"); + } +#endif Py_XINCREF(m_ptr); return *this; } @@ -219,6 +265,11 @@ public: this function automatically. Returns a reference to itself. \endrst */ const handle &dec_ref() const & { +#ifdef PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF + if (m_ptr != nullptr && !PyGILState_Check()) { + throw_gilstate_error("pybind11::handle::dec_ref()"); + } +#endif Py_XDECREF(m_ptr); return *this; } @@ -244,6 +295,43 @@ public: protected: PyObject *m_ptr = nullptr; + +private: +#ifdef PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF + void throw_gilstate_error(const std::string &function_name) const { + fprintf( + stderr, + "%s is being called while the GIL is either not held or invalid. Please see " + "https://pybind11.readthedocs.io/en/stable/advanced/" + "misc.html#common-sources-of-global-interpreter-lock-errors for debugging advice.\n" + "If you are convinced there is no bug in your code, you can #define " + "PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF" + "to disable this check. In that case you have to ensure this #define is consistently " + "used for all translation units linked into a given pybind11 extension, otherwise " + "there will be ODR violations.", + function_name.c_str()); + fflush(stderr); + if (Py_TYPE(m_ptr)->tp_name != nullptr) { + fprintf(stderr, + "The failing %s call was triggered on a %s object.\n", + function_name.c_str(), + Py_TYPE(m_ptr)->tp_name); + fflush(stderr); + } + throw std::runtime_error(function_name + " PyGILState_Check() failure."); + } +#endif + +#ifdef PYBIND11_HANDLE_REF_DEBUG + static std::size_t inc_ref_counter(std::size_t add) { + thread_local std::size_t counter = 0; + counter += add; + return counter; + } + +public: + static std::size_t inc_ref_counter() { return inc_ref_counter(0); } +#endif }; /** \rst @@ -268,10 +356,7 @@ public: /// Copy constructor; always increases the reference count object(const object &o) : handle(o) { inc_ref(); } /// Move constructor; steals the object from ``other`` and preserves its reference count - object(object &&other) noexcept { - m_ptr = other.m_ptr; - other.m_ptr = nullptr; - } + object(object &&other) noexcept : handle(other) { other.m_ptr = nullptr; } /// Destructor; automatically calls `handle::dec_ref()` ~object() { dec_ref(); } @@ -287,12 +372,15 @@ public: } object &operator=(const object &other) { - other.inc_ref(); - // Use temporary variable to ensure `*this` remains valid while - // `Py_XDECREF` executes, in case `*this` is accessible from Python. - handle temp(m_ptr); - m_ptr = other.m_ptr; - temp.dec_ref(); + // Skip inc_ref and dec_ref if both objects are the same + if (!this->is(other)) { + other.inc_ref(); + // Use temporary variable to ensure `*this` remains valid while + // `Py_XDECREF` executes, in case `*this` is accessible from Python. + handle temp(m_ptr); + m_ptr = other.m_ptr; + temp.dec_ref(); + } return *this; } @@ -306,6 +394,20 @@ public: return *this; } +#define PYBIND11_INPLACE_OP(iop) \ + object iop(object_api const &other) { return operator=(handle::iop(other)); } + + PYBIND11_INPLACE_OP(operator+=) + PYBIND11_INPLACE_OP(operator-=) + PYBIND11_INPLACE_OP(operator*=) + PYBIND11_INPLACE_OP(operator/=) + PYBIND11_INPLACE_OP(operator|=) + PYBIND11_INPLACE_OP(operator&=) + PYBIND11_INPLACE_OP(operator^=) + PYBIND11_INPLACE_OP(operator<<=) + PYBIND11_INPLACE_OP(operator>>=) +#undef PYBIND11_INPLACE_OP + // Calling cast() on an object lvalue just copies (via handle::cast) template <typename T> T cast() const &; @@ -363,51 +465,291 @@ T reinterpret_steal(handle h) { } PYBIND11_NAMESPACE_BEGIN(detail) + +// Equivalent to obj.__class__.__name__ (or obj.__name__ if obj is a class). +inline const char *obj_class_name(PyObject *obj) { + if (PyType_Check(obj)) { + return reinterpret_cast<PyTypeObject *>(obj)->tp_name; + } + return Py_TYPE(obj)->tp_name; +} + std::string error_string(); -PYBIND11_NAMESPACE_END(detail) -#if defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable : 4275 4251) -// warning C4275: An exported class was derived from a class that wasn't exported. -// Can be ignored when derived from a STL class. -#endif -/// Fetch and hold an error which was already set in Python. An instance of this is typically -/// thrown to propagate python-side errors back through C++ which can either be caught manually or -/// else falls back to the function dispatcher (which then raises the captured error back to -/// python). -class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::runtime_error { -public: - /// Constructs a new exception from the current Python error indicator, if any. The current - /// Python error indicator will be cleared. - error_already_set() : std::runtime_error(detail::error_string()) { +// The code in this struct is very unusual, to minimize the chances of +// masking bugs (elsewhere) by errors during the error handling (here). +// This is meant to be a lifeline for troubleshooting long-running processes +// that crash under conditions that are virtually impossible to reproduce. +// Low-level implementation alternatives are preferred to higher-level ones +// that might raise cascading exceptions. Last-ditch-kind-of attempts are made +// to report as much of the original error as possible, even if there are +// secondary issues obtaining some of the details. +struct error_fetch_and_normalize { + // This comment only applies to Python <= 3.11: + // Immediate normalization is long-established behavior (starting with + // https://github.com/pybind/pybind11/commit/135ba8deafb8bf64a15b24d1513899eb600e2011 + // from Sep 2016) and safest. Normalization could be deferred, but this could mask + // errors elsewhere, the performance gain is very minor in typical situations + // (usually the dominant bottleneck is EH unwinding), and the implementation here + // would be more complex. + // Starting with Python 3.12, PyErr_Fetch() normalizes exceptions immediately. + // Any errors during normalization are tracked under __notes__. + explicit error_fetch_and_normalize(const char *called) { PyErr_Fetch(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr()); + if (!m_type) { + pybind11_fail("Internal error: " + std::string(called) + + " called while " + "Python error indicator not set."); + } + const char *exc_type_name_orig = detail::obj_class_name(m_type.ptr()); + if (exc_type_name_orig == nullptr) { + pybind11_fail("Internal error: " + std::string(called) + + " failed to obtain the name " + "of the original active exception type."); + } + m_lazy_error_string = exc_type_name_orig; +#if PY_VERSION_HEX >= 0x030C0000 + // The presence of __notes__ is likely due to exception normalization + // errors, although that is not necessarily true, therefore insert a + // hint only: + if (PyObject_HasAttrString(m_value.ptr(), "__notes__")) { + m_lazy_error_string += "[WITH __notes__]"; + } +#else + // PyErr_NormalizeException() may change the exception type if there are cascading + // failures. This can potentially be extremely confusing. + PyErr_NormalizeException(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr()); + if (m_type.ptr() == nullptr) { + pybind11_fail("Internal error: " + std::string(called) + + " failed to normalize the " + "active exception."); + } + const char *exc_type_name_norm = detail::obj_class_name(m_type.ptr()); + if (exc_type_name_norm == nullptr) { + pybind11_fail("Internal error: " + std::string(called) + + " failed to obtain the name " + "of the normalized active exception type."); + } +# if defined(PYPY_VERSION_NUM) && PYPY_VERSION_NUM < 0x07030a00 + // This behavior runs the risk of masking errors in the error handling, but avoids a + // conflict with PyPy, which relies on the normalization here to change OSError to + // FileNotFoundError (https://github.com/pybind/pybind11/issues/4075). + m_lazy_error_string = exc_type_name_norm; +# else + if (exc_type_name_norm != m_lazy_error_string) { + std::string msg = std::string(called) + + ": MISMATCH of original and normalized " + "active exception types: "; + msg += "ORIGINAL "; + msg += m_lazy_error_string; + msg += " REPLACED BY "; + msg += exc_type_name_norm; + msg += ": " + format_value_and_trace(); + pybind11_fail(msg); + } +# endif +#endif } - error_already_set(const error_already_set &) = default; - error_already_set(error_already_set &&) = default; + error_fetch_and_normalize(const error_fetch_and_normalize &) = delete; + error_fetch_and_normalize(error_fetch_and_normalize &&) = delete; + + std::string format_value_and_trace() const { + std::string result; + std::string message_error_string; + if (m_value) { + auto value_str = reinterpret_steal<object>(PyObject_Str(m_value.ptr())); + constexpr const char *message_unavailable_exc + = "<MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>"; + if (!value_str) { + message_error_string = detail::error_string(); + result = message_unavailable_exc; + } else { + // Not using `value_str.cast<std::string>()`, to not potentially throw a secondary + // error_already_set that will then result in process termination (#4288). + auto value_bytes = reinterpret_steal<object>( + PyUnicode_AsEncodedString(value_str.ptr(), "utf-8", "backslashreplace")); + if (!value_bytes) { + message_error_string = detail::error_string(); + result = message_unavailable_exc; + } else { + char *buffer = nullptr; + Py_ssize_t length = 0; + if (PyBytes_AsStringAndSize(value_bytes.ptr(), &buffer, &length) == -1) { + message_error_string = detail::error_string(); + result = message_unavailable_exc; + } else { + result = std::string(buffer, static_cast<std::size_t>(length)); + } + } + } +#if PY_VERSION_HEX >= 0x030B0000 + auto notes + = reinterpret_steal<object>(PyObject_GetAttrString(m_value.ptr(), "__notes__")); + if (!notes) { + PyErr_Clear(); // No notes is good news. + } else { + auto len_notes = PyList_Size(notes.ptr()); + if (len_notes < 0) { + result += "\nFAILURE obtaining len(__notes__): " + detail::error_string(); + } else { + result += "\n__notes__ (len=" + std::to_string(len_notes) + "):"; + for (ssize_t i = 0; i < len_notes; i++) { + PyObject *note = PyList_GET_ITEM(notes.ptr(), i); + auto note_bytes = reinterpret_steal<object>( + PyUnicode_AsEncodedString(note, "utf-8", "backslashreplace")); + if (!note_bytes) { + result += "\nFAILURE obtaining __notes__[" + std::to_string(i) + + "]: " + detail::error_string(); + } else { + char *buffer = nullptr; + Py_ssize_t length = 0; + if (PyBytes_AsStringAndSize(note_bytes.ptr(), &buffer, &length) + == -1) { + result += "\nFAILURE formatting __notes__[" + std::to_string(i) + + "]: " + detail::error_string(); + } else { + result += '\n'; + result += std::string(buffer, static_cast<std::size_t>(length)); + } + } + } + } + } +#endif + } else { + result = "<MESSAGE UNAVAILABLE>"; + } + if (result.empty()) { + result = "<EMPTY MESSAGE>"; + } + + bool have_trace = false; + if (m_trace) { +#if !defined(PYPY_VERSION) + auto *tb = reinterpret_cast<PyTracebackObject *>(m_trace.ptr()); + + // Get the deepest trace possible. + while (tb->tb_next) { + tb = tb->tb_next; + } - inline ~error_already_set() override; + PyFrameObject *frame = tb->tb_frame; + Py_XINCREF(frame); + result += "\n\nAt:\n"; + while (frame) { +# if PY_VERSION_HEX >= 0x030900B1 + PyCodeObject *f_code = PyFrame_GetCode(frame); +# else + PyCodeObject *f_code = frame->f_code; + Py_INCREF(f_code); +# endif + int lineno = PyFrame_GetLineNumber(frame); + result += " "; + result += handle(f_code->co_filename).cast<std::string>(); + result += '('; + result += std::to_string(lineno); + result += "): "; + result += handle(f_code->co_name).cast<std::string>(); + result += '\n'; + Py_DECREF(f_code); +# if PY_VERSION_HEX >= 0x030900B1 + auto *b_frame = PyFrame_GetBack(frame); +# else + auto *b_frame = frame->f_back; + Py_XINCREF(b_frame); +# endif + Py_DECREF(frame); + frame = b_frame; + } + + have_trace = true; +#endif //! defined(PYPY_VERSION) + } + + if (!message_error_string.empty()) { + if (!have_trace) { + result += '\n'; + } + result += "\nMESSAGE UNAVAILABLE DUE TO EXCEPTION: " + message_error_string; + } + + return result; + } + + std::string const &error_string() const { + if (!m_lazy_error_string_completed) { + m_lazy_error_string += ": " + format_value_and_trace(); + m_lazy_error_string_completed = true; + } + return m_lazy_error_string; + } - /// Give the currently-held error back to Python, if any. If there is currently a Python error - /// already set it is cleared first. After this call, the current object no longer stores the - /// error variables (but the `.what()` string is still available). void restore() { - PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr()); + if (m_restore_called) { + pybind11_fail("Internal error: pybind11::detail::error_fetch_and_normalize::restore() " + "called a second time. ORIGINAL ERROR: " + + error_string()); + } + PyErr_Restore(m_type.inc_ref().ptr(), m_value.inc_ref().ptr(), m_trace.inc_ref().ptr()); + m_restore_called = true; } + bool matches(handle exc) const { + return (PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()) != 0); + } + + // Not protecting these for simplicity. + object m_type, m_value, m_trace; + +private: + // Only protecting invariants. + mutable std::string m_lazy_error_string; + mutable bool m_lazy_error_string_completed = false; + mutable bool m_restore_called = false; +}; + +inline std::string error_string() { + return error_fetch_and_normalize("pybind11::detail::error_string").error_string(); +} + +PYBIND11_NAMESPACE_END(detail) + +/// Fetch and hold an error which was already set in Python. An instance of this is typically +/// thrown to propagate python-side errors back through C++ which can either be caught manually or +/// else falls back to the function dispatcher (which then raises the captured error back to +/// python). +class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::exception { +public: + /// Fetches the current Python exception (using PyErr_Fetch()), which will clear the + /// current Python error indicator. + error_already_set() + : m_fetched_error{new detail::error_fetch_and_normalize("pybind11::error_already_set"), + m_fetched_error_deleter} {} + + /// The what() result is built lazily on demand. + /// WARNING: This member function needs to acquire the Python GIL. This can lead to + /// crashes (undefined behavior) if the Python interpreter is finalizing. + const char *what() const noexcept override; + + /// Restores the currently-held Python error (which will clear the Python error indicator first + /// if already set). + /// NOTE: This member function will always restore the normalized exception, which may or may + /// not be the original Python exception. + /// WARNING: The GIL must be held when this member function is called! + void restore() { m_fetched_error->restore(); } + /// If it is impossible to raise the currently-held error, such as in a destructor, we can /// write it out using Python's unraisable hook (`sys.unraisablehook`). The error context /// should be some object whose `repr()` helps identify the location of the error. Python - /// already knows the type and value of the error, so there is no need to repeat that. After - /// this call, the current object no longer stores the error variables, and neither does - /// Python. + /// already knows the type and value of the error, so there is no need to repeat that. void discard_as_unraisable(object err_context) { restore(); PyErr_WriteUnraisable(err_context.ptr()); } /// An alternate version of `discard_as_unraisable()`, where a string provides information on /// the location of the error. For example, `__func__` could be helpful. + /// WARNING: The GIL must be held when this member function is called! void discard_as_unraisable(const char *err_context) { discard_as_unraisable(reinterpret_steal<object>(PYBIND11_FROM_STRING(err_context))); } @@ -419,20 +761,19 @@ public: /// Check if the currently trapped error type matches the given Python exception class (or a /// subclass thereof). May also be passed a tuple to search for any exception class matches in /// the given tuple. - bool matches(handle exc) const { - return (PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()) != 0); - } + bool matches(handle exc) const { return m_fetched_error->matches(exc); } - const object &type() const { return m_type; } - const object &value() const { return m_value; } - const object &trace() const { return m_trace; } + const object &type() const { return m_fetched_error->m_type; } + const object &value() const { return m_fetched_error->m_value; } + const object &trace() const { return m_fetched_error->m_trace; } private: - object m_type, m_value, m_trace; + std::shared_ptr<detail::error_fetch_and_normalize> m_fetched_error; + + /// WARNING: This custom deleter needs to acquire the Python GIL. This can lead to + /// crashes (undefined behavior) if the Python interpreter is finalizing. + static void m_fetched_error_deleter(detail::error_fetch_and_normalize *raw_ptr); }; -#if defined(_MSC_VER) -# pragma warning(pop) -#endif #if PY_VERSION_HEX >= 0x03030000 @@ -466,8 +807,7 @@ inline void raise_from(PyObject *type, const char *message) { /// Sets the current Python error indicator with the chosen error, performing a 'raise from' /// from the error contained in error_already_set to indicate that the chosen error was -/// caused by the original error. After this function is called error_already_set will -/// no longer contain an error. +/// caused by the original error. inline void raise_from(error_already_set &err, PyObject *type, const char *message) { err.restore(); raise_from(type, message); @@ -611,13 +951,13 @@ inline PyObject *dict_getitemstring(PyObject *v, const char *key) { #if PY_MAJOR_VERSION >= 3 PyObject *kv = nullptr, *rv = nullptr; kv = PyUnicode_FromString(key); - if (kv == NULL) { + if (kv == nullptr) { throw error_already_set(); } rv = PyDict_GetItemWithError(v, kv); Py_DECREF(kv); - if (rv == NULL && PyErr_Occurred()) { + if (rv == nullptr && PyErr_Occurred()) { throw error_already_set(); } return rv; @@ -629,7 +969,7 @@ inline PyObject *dict_getitemstring(PyObject *v, const char *key) { inline PyObject *dict_getitem(PyObject *v, PyObject *key) { #if PY_MAJOR_VERSION >= 3 PyObject *rv = PyDict_GetItemWithError(v, key); - if (rv == NULL && PyErr_Occurred()) { + if (rv == nullptr && PyErr_Occurred()) { throw error_already_set(); } return rv; @@ -651,10 +991,8 @@ object object_or_cast(T &&o); // Match a PyObject*, which we want to convert directly to handle via its converting constructor inline handle object_or_cast(PyObject *ptr) { return ptr; } -#if defined(_MSC_VER) && _MSC_VER < 1920 -# pragma warning(push) -# pragma warning(disable : 4522) // warning C4522: multiple assignment operators specified -#endif +PYBIND11_WARNING_PUSH +PYBIND11_WARNING_DISABLE_MSVC(4522) // warning C4522: multiple assignment operators specified template <typename Policy> class accessor : public object_api<accessor<Policy>> { using key_type = typename Policy::key_type; @@ -675,7 +1013,7 @@ public: } template <typename T> void operator=(T &&value) & { - get_cache() = reinterpret_borrow<object>(object_or_cast(std::forward<T>(value))); + get_cache() = ensure_object(object_or_cast(std::forward<T>(value))); } template <typename T = Policy> @@ -703,6 +1041,9 @@ public: } private: + static object ensure_object(object &&o) { return std::move(o); } + static object ensure_object(handle h) { return reinterpret_borrow<object>(h); } + object &get_cache() const { if (!cache) { cache = Policy::get(obj, key); @@ -715,9 +1056,7 @@ private: key_type key; mutable object cache; }; -#if defined(_MSC_VER) && _MSC_VER < 1920 -# pragma warning(pop) -#endif +PYBIND11_WARNING_POP PYBIND11_NAMESPACE_BEGIN(accessor_policies) struct obj_attr { @@ -1053,17 +1392,17 @@ public: Name(const object &o) \ : Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \ if (!m_ptr) \ - throw error_already_set(); \ + throw ::pybind11::error_already_set(); \ } \ /* NOLINTNEXTLINE(google-explicit-constructor) */ \ Name(object &&o) : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \ if (!m_ptr) \ - throw error_already_set(); \ + throw ::pybind11::error_already_set(); \ } #define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun) \ PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \ - Name() : Parent() {} + Name() = default; #define PYBIND11_OBJECT_CHECK_FAILED(Name, o_ptr) \ ::pybind11::type_error("Object of type '" \ @@ -1086,7 +1425,7 @@ public: #define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun) \ PYBIND11_OBJECT(Name, Parent, CheckFun) \ - Name() : Parent() {} + Name() = default; /// \addtogroup pytypes /// @{ @@ -1155,7 +1494,7 @@ public: private: void advance() { value = reinterpret_steal<object>(PyIter_Next(m_ptr)); - if (PyErr_Occurred()) { + if (value.ptr() == nullptr && PyErr_Occurred()) { throw error_already_set(); } } @@ -1205,6 +1544,9 @@ public: str(const char *c, const SzType &n) : object(PyUnicode_FromStringAndSize(c, ssize_t_cast(n)), stolen_t{}) { if (!m_ptr) { + if (PyErr_Occurred()) { + throw error_already_set(); + } pybind11_fail("Could not allocate string object!"); } } @@ -1214,6 +1556,9 @@ public: // NOLINTNEXTLINE(google-explicit-constructor) str(const char *c = "") : object(PyUnicode_FromString(c), stolen_t{}) { if (!m_ptr) { + if (PyErr_Occurred()) { + throw error_already_set(); + } pybind11_fail("Could not allocate string object!"); } } @@ -1258,8 +1603,8 @@ public: } char *buffer = nullptr; ssize_t length = 0; - if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) { - pybind11_fail("Unable to extract string contents! (invalid type)"); + if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) { + throw error_already_set(); } return std::string(buffer, (size_t) length); } @@ -1321,14 +1666,7 @@ public: explicit bytes(const pybind11::str &s); // NOLINTNEXTLINE(google-explicit-constructor) - operator std::string() const { - char *buffer = nullptr; - ssize_t length = 0; - if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) { - pybind11_fail("Unable to extract bytes contents!"); - } - return std::string(buffer, (size_t) length); - } + operator std::string() const { return string_op<std::string>(); } #ifdef PYBIND11_HAS_STRING_VIEW // enable_if is needed to avoid "ambiguous conversion" errors (see PR #3521). @@ -1340,15 +1678,18 @@ public: // valid so long as the `bytes` instance remains alive and so generally should not outlive the // lifetime of the `bytes` instance. // NOLINTNEXTLINE(google-explicit-constructor) - operator std::string_view() const { + operator std::string_view() const { return string_op<std::string_view>(); } +#endif +private: + template <typename T> + T string_op() const { char *buffer = nullptr; ssize_t length = 0; - if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) { - pybind11_fail("Unable to extract bytes contents!"); + if (PyBytes_AsStringAndSize(m_ptr, &buffer, &length) != 0) { + throw error_already_set(); } return {buffer, static_cast<size_t>(length)}; } -#endif }; // Note: breathe >= 4.17.0 will fail to build docs if the below two constructors // are included in the doxygen group; close here and reopen after as a workaround @@ -1359,13 +1700,13 @@ inline bytes::bytes(const pybind11::str &s) { if (PyUnicode_Check(s.ptr())) { temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(s.ptr())); if (!temp) { - pybind11_fail("Unable to extract string contents! (encoding issue)"); + throw error_already_set(); } } char *buffer = nullptr; ssize_t length = 0; - if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) { - pybind11_fail("Unable to extract string contents! (invalid type)"); + if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) { + throw error_already_set(); } auto obj = reinterpret_steal<object>(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length)); if (!obj) { @@ -1377,11 +1718,14 @@ inline bytes::bytes(const pybind11::str &s) { inline str::str(const bytes &b) { char *buffer = nullptr; ssize_t length = 0; - if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) { - pybind11_fail("Unable to extract bytes contents!"); + if (PyBytes_AsStringAndSize(b.ptr(), &buffer, &length) != 0) { + throw error_already_set(); } auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, length)); if (!obj) { + if (PyErr_Occurred()) { + throw error_already_set(); + } pybind11_fail("Could not allocate string object!"); } m_ptr = obj.release().ptr(); @@ -1459,7 +1803,7 @@ PYBIND11_NAMESPACE_BEGIN(detail) // unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes). template <typename Unsigned> Unsigned as_unsigned(PyObject *o) { - if (PYBIND11_SILENCE_MSVC_C4127(sizeof(Unsigned) <= sizeof(unsigned long)) + if (sizeof(Unsigned) <= sizeof(unsigned long) #if PY_VERSION_HEX < 0x03000000 || PyInt_Check(o) #endif @@ -1480,7 +1824,7 @@ public: template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0> // NOLINTNEXTLINE(google-explicit-constructor) int_(T value) { - if (PYBIND11_SILENCE_MSVC_C4127(sizeof(T) <= sizeof(long))) { + if (sizeof(T) <= sizeof(long)) { if (std::is_signed<T>::value) { m_ptr = PyLong_FromLong((long) value); } else { @@ -1535,6 +1879,9 @@ public: explicit weakref(handle obj, handle callback = {}) : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen_t{}) { if (!m_ptr) { + if (PyErr_Occurred()) { + throw error_already_set(); + } pybind11_fail("Could not allocate weak reference!"); } } @@ -1546,8 +1893,8 @@ private: class slice : public object { public: PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check) - slice(handle start, handle stop, handle step) { - m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr()); + slice(handle start, handle stop, handle step) + : object(PySlice_New(start.ptr(), stop.ptr(), step.ptr()), stolen_t{}) { if (!m_ptr) { pybind11_fail("Could not allocate slice object!"); } @@ -1594,45 +1941,42 @@ public: explicit capsule(const void *value, const char *name = nullptr, - void (*destructor)(PyObject *) = nullptr) + PyCapsule_Destructor destructor = nullptr) : object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) { if (!m_ptr) { - pybind11_fail("Could not allocate capsule object!"); + throw error_already_set(); } } - PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input") - capsule(const void *value, void (*destruct)(PyObject *)) - : object(PyCapsule_New(const_cast<void *>(value), nullptr, destruct), stolen_t{}) { + PYBIND11_DEPRECATED("Please use the ctor with value, name, destructor args") + capsule(const void *value, PyCapsule_Destructor destructor) + : object(PyCapsule_New(const_cast<void *>(value), nullptr, destructor), stolen_t{}) { if (!m_ptr) { - pybind11_fail("Could not allocate capsule object!"); + throw error_already_set(); } } + /// Capsule name is nullptr. capsule(const void *value, void (*destructor)(void *)) { - m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) { - auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o)); - void *ptr = PyCapsule_GetPointer(o, nullptr); - destructor(ptr); - }); - - if (!m_ptr) { - pybind11_fail("Could not allocate capsule object!"); - } + initialize_with_void_ptr_destructor(value, nullptr, destructor); + } - if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) { - pybind11_fail("Could not set capsule context!"); - } + capsule(const void *value, const char *name, void (*destructor)(void *)) { + initialize_with_void_ptr_destructor(value, name, destructor); } explicit capsule(void (*destructor)()) { m_ptr = PyCapsule_New(reinterpret_cast<void *>(destructor), nullptr, [](PyObject *o) { - auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, nullptr)); + const char *name = get_name_in_error_scope(o); + auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, name)); + if (destructor == nullptr) { + throw error_already_set(); + } destructor(); }); if (!m_ptr) { - pybind11_fail("Could not allocate capsule object!"); + throw error_already_set(); } } @@ -1647,8 +1991,7 @@ public: const auto *name = this->name(); T *result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name)); if (!result) { - PyErr_Clear(); - pybind11_fail("Unable to extract capsule contents!"); + throw error_already_set(); } return result; } @@ -1656,12 +1999,63 @@ public: /// Replaces a capsule's pointer *without* calling the destructor on the existing one. void set_pointer(const void *value) { if (PyCapsule_SetPointer(m_ptr, const_cast<void *>(value)) != 0) { - PyErr_Clear(); - pybind11_fail("Could not set capsule pointer"); + throw error_already_set(); + } + } + + const char *name() const { + const char *name = PyCapsule_GetName(m_ptr); + if ((name == nullptr) && PyErr_Occurred()) { + throw error_already_set(); + } + return name; + } + + /// Replaces a capsule's name *without* calling the destructor on the existing one. + void set_name(const char *new_name) { + if (PyCapsule_SetName(m_ptr, new_name) != 0) { + throw error_already_set(); + } + } + +private: + static const char *get_name_in_error_scope(PyObject *o) { + error_scope error_guard; + + const char *name = PyCapsule_GetName(o); + if ((name == nullptr) && PyErr_Occurred()) { + // write out and consume error raised by call to PyCapsule_GetName + PyErr_WriteUnraisable(o); } + + return name; } - const char *name() const { return PyCapsule_GetName(m_ptr); } + void initialize_with_void_ptr_destructor(const void *value, + const char *name, + void (*destructor)(void *)) { + m_ptr = PyCapsule_New(const_cast<void *>(value), name, [](PyObject *o) { + // guard if destructor called while err indicator is set + error_scope error_guard; + auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o)); + if (destructor == nullptr && PyErr_Occurred()) { + throw error_already_set(); + } + const char *name = get_name_in_error_scope(o); + void *ptr = PyCapsule_GetPointer(o, name); + if (ptr == nullptr) { + throw error_already_set(); + } + + if (destructor != nullptr) { + destructor(ptr); + } + }); + + if (!m_ptr || PyCapsule_SetContext(m_ptr, reinterpret_cast<void *>(destructor)) != 0) { + throw error_already_set(); + } + } }; class tuple : public object { @@ -1678,7 +2072,10 @@ public: size_t size() const { return (size_t) PyTuple_Size(m_ptr); } bool empty() const { return size() == 0; } detail::tuple_accessor operator[](size_t index) const { return {*this, index}; } - detail::item_accessor operator[](handle h) const { return object::operator[](h); } + template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0> + detail::item_accessor operator[](T &&o) const { + return object::operator[](std::forward<T>(o)); + } detail::tuple_iterator begin() const { return {*this, 0}; } detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; } }; @@ -1713,7 +2110,11 @@ public: void clear() /* py-non-const */ { PyDict_Clear(ptr()); } template <typename T> bool contains(T &&key) const { - return PyDict_Contains(m_ptr, detail::object_or_cast(std::forward<T>(key)).ptr()) == 1; + auto result = PyDict_Contains(m_ptr, detail::object_or_cast(std::forward<T>(key)).ptr()); + if (result == -1) { + throw error_already_set(); + } + return result == 1; } private: @@ -1738,7 +2139,10 @@ public: } bool empty() const { return size() == 0; } detail::sequence_accessor operator[](size_t index) const { return {*this, index}; } - detail::item_accessor operator[](handle h) const { return object::operator[](h); } + template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0> + detail::item_accessor operator[](T &&o) const { + return object::operator[](std::forward<T>(o)); + } detail::sequence_iterator begin() const { return {*this, 0}; } detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; } }; @@ -1757,19 +2161,28 @@ public: size_t size() const { return (size_t) PyList_Size(m_ptr); } bool empty() const { return size() == 0; } detail::list_accessor operator[](size_t index) const { return {*this, index}; } - detail::item_accessor operator[](handle h) const { return object::operator[](h); } + template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0> + detail::item_accessor operator[](T &&o) const { + return object::operator[](std::forward<T>(o)); + } detail::list_iterator begin() const { return {*this, 0}; } detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; } template <typename T> void append(T &&val) /* py-non-const */ { - PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()); + if (PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) != 0) { + throw error_already_set(); + } } template <typename IdxType, typename ValType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0> void insert(const IdxType &index, ValType &&val) /* py-non-const */ { - PyList_Insert( - m_ptr, ssize_t_cast(index), detail::object_or_cast(std::forward<ValType>(val)).ptr()); + if (PyList_Insert(m_ptr, + ssize_t_cast(index), + detail::object_or_cast(std::forward<ValType>(val)).ptr()) + != 0) { + throw error_already_set(); + } } }; @@ -1780,25 +2193,39 @@ class kwargs : public dict { PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check) }; -class set : public object { +class anyset : public object { public: - PYBIND11_OBJECT_CVT(set, object, PySet_Check, PySet_New) - set() : object(PySet_New(nullptr), stolen_t{}) { + PYBIND11_OBJECT(anyset, object, PyAnySet_Check) + size_t size() const { return static_cast<size_t>(PySet_Size(m_ptr)); } + bool empty() const { return size() == 0; } + template <typename T> + bool contains(T &&val) const { + auto result = PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()); + if (result == -1) { + throw error_already_set(); + } + return result == 1; + } +}; + +class set : public anyset { +public: + PYBIND11_OBJECT_CVT(set, anyset, PySet_Check, PySet_New) + set() : anyset(PySet_New(nullptr), stolen_t{}) { if (!m_ptr) { pybind11_fail("Could not allocate set object!"); } } - size_t size() const { return (size_t) PySet_Size(m_ptr); } - bool empty() const { return size() == 0; } template <typename T> bool add(T &&val) /* py-non-const */ { return PySet_Add(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 0; } void clear() /* py-non-const */ { PySet_Clear(m_ptr); } - template <typename T> - bool contains(T &&val) const { - return PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 1; - } +}; + +class frozenset : public anyset { +public: + PYBIND11_OBJECT_CVT(frozenset, anyset, PyFrozenSet_Check, PyFrozenSet_New) }; class function : public object { @@ -1910,8 +2337,8 @@ public: return memoryview::from_buffer(reinterpret_cast<void *>(ptr), sizeof(T), format_descriptor<T>::value, - shape, - strides, + std::move(shape), + std::move(strides), readonly); } @@ -1919,7 +2346,8 @@ public: static memoryview from_buffer(const T *ptr, detail::any_container<ssize_t> shape, detail::any_container<ssize_t> strides) { - return memoryview::from_buffer(const_cast<T *>(ptr), shape, strides, true); + return memoryview::from_buffer( + const_cast<T *>(ptr), std::move(shape), std::move(strides), true); } #if PY_MAJOR_VERSION >= 3 @@ -1930,8 +2358,6 @@ public: managed by Python. The caller is responsible for managing the lifetime of ``mem``, which MUST outlive the memoryview constructed here. - This method is not available in Python 2. - See also: Python C API documentation for `PyMemoryView_FromBuffer`_. .. _PyMemoryView_FromMemory: @@ -2062,6 +2488,10 @@ item_accessor object_api<D>::operator[](handle key) const { return {derived(), reinterpret_borrow<object>(key)}; } template <typename D> +item_accessor object_api<D>::operator[](object &&key) const { + return {derived(), std::move(key)}; +} +template <typename D> item_accessor object_api<D>::operator[](const char *key) const { return {derived(), pybind11::str(key)}; } @@ -2070,6 +2500,10 @@ obj_attr_accessor object_api<D>::attr(handle key) const { return {derived(), reinterpret_borrow<object>(key)}; } template <typename D> +obj_attr_accessor object_api<D>::attr(object &&key) const { + return {derived(), std::move(key)}; +} +template <typename D> str_attr_accessor object_api<D>::attr(const char *key) const { return {derived(), key}; } @@ -2125,29 +2559,39 @@ bool object_api<D>::rich_compare(object_api const &other, int value) const { return result; \ } +#define PYBIND11_MATH_OPERATOR_BINARY_INPLACE(iop, fn) \ + template <typename D> \ + object object_api<D>::iop(object_api const &other) { \ + object result = reinterpret_steal<object>(fn(derived().ptr(), other.derived().ptr())); \ + if (!result.ptr()) \ + throw error_already_set(); \ + return result; \ + } + PYBIND11_MATH_OPERATOR_UNARY(operator~, PyNumber_Invert) PYBIND11_MATH_OPERATOR_UNARY(operator-, PyNumber_Negative) PYBIND11_MATH_OPERATOR_BINARY(operator+, PyNumber_Add) -PYBIND11_MATH_OPERATOR_BINARY(operator+=, PyNumber_InPlaceAdd) +PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator+=, PyNumber_InPlaceAdd) PYBIND11_MATH_OPERATOR_BINARY(operator-, PyNumber_Subtract) -PYBIND11_MATH_OPERATOR_BINARY(operator-=, PyNumber_InPlaceSubtract) +PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator-=, PyNumber_InPlaceSubtract) PYBIND11_MATH_OPERATOR_BINARY(operator*, PyNumber_Multiply) -PYBIND11_MATH_OPERATOR_BINARY(operator*=, PyNumber_InPlaceMultiply) +PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator*=, PyNumber_InPlaceMultiply) PYBIND11_MATH_OPERATOR_BINARY(operator/, PyNumber_TrueDivide) -PYBIND11_MATH_OPERATOR_BINARY(operator/=, PyNumber_InPlaceTrueDivide) +PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator/=, PyNumber_InPlaceTrueDivide) PYBIND11_MATH_OPERATOR_BINARY(operator|, PyNumber_Or) -PYBIND11_MATH_OPERATOR_BINARY(operator|=, PyNumber_InPlaceOr) +PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator|=, PyNumber_InPlaceOr) PYBIND11_MATH_OPERATOR_BINARY(operator&, PyNumber_And) -PYBIND11_MATH_OPERATOR_BINARY(operator&=, PyNumber_InPlaceAnd) +PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator&=, PyNumber_InPlaceAnd) PYBIND11_MATH_OPERATOR_BINARY(operator^, PyNumber_Xor) -PYBIND11_MATH_OPERATOR_BINARY(operator^=, PyNumber_InPlaceXor) +PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator^=, PyNumber_InPlaceXor) PYBIND11_MATH_OPERATOR_BINARY(operator<<, PyNumber_Lshift) -PYBIND11_MATH_OPERATOR_BINARY(operator<<=, PyNumber_InPlaceLshift) +PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator<<=, PyNumber_InPlaceLshift) PYBIND11_MATH_OPERATOR_BINARY(operator>>, PyNumber_Rshift) -PYBIND11_MATH_OPERATOR_BINARY(operator>>=, PyNumber_InPlaceRshift) +PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator>>=, PyNumber_InPlaceRshift) #undef PYBIND11_MATH_OPERATOR_UNARY #undef PYBIND11_MATH_OPERATOR_BINARY +#undef PYBIND11_MATH_OPERATOR_BINARY_INPLACE PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/contrib/libs/pybind11/ya.make b/contrib/libs/pybind11/ya.make index d8f9d60781..95a7f21ea3 100644 --- a/contrib/libs/pybind11/ya.make +++ b/contrib/libs/pybind11/ya.make @@ -1,4 +1,4 @@ -# Generated by devtools/yamaker from nixpkgs 22.05. +# Generated by devtools/yamaker from nixpkgs 22.11. LIBRARY() @@ -6,9 +6,9 @@ LICENSE(BSD-3-Clause) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(2.9.2) +VERSION(2.11.1) -ORIGINAL_SOURCE(https://github.com/pybind/pybind11/archive/v2.9.2.tar.gz) +ORIGINAL_SOURCE(https://github.com/pybind/pybind11/archive/v2.11.1.tar.gz) ADDINCL( GLOBAL contrib/libs/pybind11/include |