Skip to content

Commit b37a1cd

Browse files
committed
Merge branch 'master' into sh_merge_master
2 parents 4f3a1a8 + 654fe92 commit b37a1cd

File tree

7 files changed

+82
-27
lines changed

7 files changed

+82
-27
lines changed

include/pybind11/detail/common.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,16 @@ template <typename C, typename R, typename... A>
778778
struct remove_class<R (C::*)(A...) const> {
779779
using type = R(A...);
780780
};
781-
781+
#ifdef __cpp_noexcept_function_type
782+
template <typename C, typename R, typename... A>
783+
struct remove_class<R (C::*)(A...) noexcept> {
784+
using type = R(A...);
785+
};
786+
template <typename C, typename R, typename... A>
787+
struct remove_class<R (C::*)(A...) const noexcept> {
788+
using type = R(A...);
789+
};
790+
#endif
782791
/// Helper template to strip away type modifiers
783792
template <typename T>
784793
struct intrinsic_type {

include/pybind11/detail/descr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) {
238238
return descr;
239239
}
240240

241-
#if defined(PYBIND11_CPP17)
241+
#ifdef __cpp_fold_expressions
242242
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
243243
constexpr descr<N1 + N2 + 2, Ts1..., Ts2...> operator,(const descr<N1, Ts1...> &a,
244244
const descr<N2, Ts2...> &b) {

include/pybind11/detail/internals.h

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,18 @@
3535
/// further ABI-incompatible changes may be made before the ABI is officially
3636
/// changed to the new version.
3737
#ifndef PYBIND11_INTERNALS_VERSION
38-
# define PYBIND11_INTERNALS_VERSION 4
38+
# if PY_VERSION_HEX >= 0x030C0000
39+
// Version bump for Python 3.12+, before first 3.12 beta release.
40+
# define PYBIND11_INTERNALS_VERSION 5
41+
# else
42+
# define PYBIND11_INTERNALS_VERSION 4
43+
# endif
3944
#endif
4045

46+
// This requirement is mainly to reduce the support burden (see PR #4570).
47+
static_assert(PY_VERSION_HEX < 0x030C0000 || PYBIND11_INTERNALS_VERSION >= 5,
48+
"pybind11 ABI version 5 is the minimum for Python 3.12+");
49+
4150
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
4251

4352
using ExceptionTranslator = void (*)(std::exception_ptr);
@@ -432,6 +441,38 @@ inline void translate_local_exception(std::exception_ptr p) {
432441
}
433442
#endif
434443

444+
inline object get_python_state_dict() {
445+
object state_dict;
446+
#if PYBIND11_INTERNALS_VERSION <= 4 || PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION)
447+
state_dict = reinterpret_borrow<object>(PyEval_GetBuiltins());
448+
#else
449+
# if PY_VERSION_HEX < 0x03090000
450+
PyInterpreterState *istate = _PyInterpreterState_Get();
451+
# else
452+
PyInterpreterState *istate = PyInterpreterState_Get();
453+
# endif
454+
if (istate) {
455+
state_dict = reinterpret_borrow<object>(PyInterpreterState_GetDict(istate));
456+
}
457+
#endif
458+
if (!state_dict) {
459+
raise_from(PyExc_SystemError, "pybind11::detail::get_python_state_dict() FAILED");
460+
}
461+
return state_dict;
462+
}
463+
464+
inline object get_internals_obj_from_state_dict(handle state_dict) {
465+
return reinterpret_borrow<object>(dict_getitemstring(state_dict.ptr(), PYBIND11_INTERNALS_ID));
466+
}
467+
468+
inline internals **get_internals_pp_from_capsule(handle obj) {
469+
void *raw_ptr = PyCapsule_GetPointer(obj.ptr(), /*name=*/nullptr);
470+
if (raw_ptr == nullptr) {
471+
raise_from(PyExc_SystemError, "pybind11::detail::get_internals_pp_from_capsule() FAILED");
472+
}
473+
return static_cast<internals **>(raw_ptr);
474+
}
475+
435476
/// Return a reference to the current `internals` data
436477
PYBIND11_NOINLINE internals &get_internals() {
437478
auto **&internals_pp = get_internals_pp();
@@ -456,12 +497,12 @@ PYBIND11_NOINLINE internals &get_internals() {
456497
#endif
457498
error_scope err_scope;
458499

459-
PYBIND11_STR_TYPE id(PYBIND11_INTERNALS_ID);
460-
auto builtins = handle(PyEval_GetBuiltins());
461-
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
462-
internals_pp = static_cast<internals **>(capsule(builtins[id]));
463-
464-
// We loaded builtins through python's builtins, which means that our `error_already_set`
500+
dict state_dict = get_python_state_dict();
501+
if (object internals_obj = get_internals_obj_from_state_dict(state_dict)) {
502+
internals_pp = get_internals_pp_from_capsule(internals_obj);
503+
}
504+
if (internals_pp && *internals_pp) {
505+
// We loaded the internals through `state_dict`, which means that our `error_already_set`
465506
// and `builtin_exception` may be different local classes than the ones set up in the
466507
// initial exception translator, below, so add another for our local exception classes.
467508
//
@@ -495,7 +536,7 @@ PYBIND11_NOINLINE internals &get_internals() {
495536
# endif
496537
internals_ptr->istate = tstate->interp;
497538
#endif
498-
builtins[id] = capsule(internals_pp);
539+
state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp);
499540
internals_ptr->registered_exception_translators.push_front(&translate_exception);
500541
internals_ptr->static_property_type = make_static_property_type();
501542
internals_ptr->default_metaclass = make_default_metaclass();

include/pybind11/embed.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -243,16 +243,14 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
243243
244244
\endrst */
245245
inline void finalize_interpreter() {
246-
handle builtins(PyEval_GetBuiltins());
247-
const char *id = PYBIND11_INTERNALS_ID;
248-
249246
// Get the internals pointer (without creating it if it doesn't exist). It's possible for the
250247
// internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()`
251248
// during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
252249
detail::internals **internals_ptr_ptr = detail::get_internals_pp();
253-
// It could also be stashed in builtins, so look there too:
254-
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
255-
internals_ptr_ptr = capsule(builtins[id]);
250+
// It could also be stashed in state_dict, so look there too:
251+
if (object internals_obj
252+
= get_internals_obj_from_state_dict(detail::get_python_state_dict())) {
253+
internals_ptr_ptr = detail::get_internals_pp_from_capsule(internals_obj);
256254
}
257255
// Local internals contains data managed by the current interpreter, so we must clear them to
258256
// avoid undefined behaviors when initializing another interpreter

tests/test_constants_and_functions.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,7 @@ TEST_SUBMODULE(constants_and_functions, m) {
148148
py::arg_v("y", 42, "<the answer>"),
149149
py::arg_v("z", default_value));
150150
});
151+
152+
// test noexcept(true) lambda (#4565)
153+
m.def("l1", []() noexcept(true) { return 0; });
151154
}

tests/test_constants_and_functions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,7 @@ def __repr__(self):
5050
m.register_large_capture_with_invalid_arguments(m)
5151
with pytest.raises(RuntimeError):
5252
m.register_with_raising_repr(m, RaisingRepr())
53+
54+
55+
def test_noexcept_lambda():
56+
assert m.l1() == 0

tests/test_embed/test_interpreter.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,10 @@ TEST_CASE("Add program dir to path using PyConfig") {
255255
}
256256
#endif
257257

258-
bool has_pybind11_internals_builtin() {
259-
auto builtins = py::handle(PyEval_GetBuiltins());
260-
return builtins.contains(PYBIND11_INTERNALS_ID);
261-
};
258+
bool has_state_dict_internals_obj() {
259+
return bool(
260+
py::detail::get_internals_obj_from_state_dict(py::detail::get_python_state_dict()));
261+
}
262262

263263
bool has_pybind11_internals_static() {
264264
auto **&ipp = py::detail::get_internals_pp();
@@ -268,7 +268,7 @@ bool has_pybind11_internals_static() {
268268
TEST_CASE("Restart the interpreter") {
269269
// Verify pre-restart state.
270270
REQUIRE(py::module_::import("widget_module").attr("add")(1, 2).cast<int>() == 3);
271-
REQUIRE(has_pybind11_internals_builtin());
271+
REQUIRE(has_state_dict_internals_obj());
272272
REQUIRE(has_pybind11_internals_static());
273273
REQUIRE(py::module_::import("external_module").attr("A")(123).attr("value").cast<int>()
274274
== 123);
@@ -285,10 +285,10 @@ TEST_CASE("Restart the interpreter") {
285285
REQUIRE(Py_IsInitialized() == 1);
286286

287287
// Internals are deleted after a restart.
288-
REQUIRE_FALSE(has_pybind11_internals_builtin());
288+
REQUIRE_FALSE(has_state_dict_internals_obj());
289289
REQUIRE_FALSE(has_pybind11_internals_static());
290290
pybind11::detail::get_internals();
291-
REQUIRE(has_pybind11_internals_builtin());
291+
REQUIRE(has_state_dict_internals_obj());
292292
REQUIRE(has_pybind11_internals_static());
293293
REQUIRE(reinterpret_cast<uintptr_t>(*py::detail::get_internals_pp())
294294
== py::module_::import("external_module").attr("internals_at")().cast<uintptr_t>());
@@ -303,13 +303,13 @@ TEST_CASE("Restart the interpreter") {
303303
py::detail::get_internals();
304304
*static_cast<bool *>(ran) = true;
305305
});
306-
REQUIRE_FALSE(has_pybind11_internals_builtin());
306+
REQUIRE_FALSE(has_state_dict_internals_obj());
307307
REQUIRE_FALSE(has_pybind11_internals_static());
308308
REQUIRE_FALSE(ran);
309309
py::finalize_interpreter();
310310
REQUIRE(ran);
311311
py::initialize_interpreter();
312-
REQUIRE_FALSE(has_pybind11_internals_builtin());
312+
REQUIRE_FALSE(has_state_dict_internals_obj());
313313
REQUIRE_FALSE(has_pybind11_internals_static());
314314

315315
// C++ modules can be reloaded.
@@ -331,7 +331,7 @@ TEST_CASE("Subinterpreter") {
331331

332332
REQUIRE(m.attr("add")(1, 2).cast<int>() == 3);
333333
}
334-
REQUIRE(has_pybind11_internals_builtin());
334+
REQUIRE(has_state_dict_internals_obj());
335335
REQUIRE(has_pybind11_internals_static());
336336

337337
/// Create and switch to a subinterpreter.
@@ -341,7 +341,7 @@ TEST_CASE("Subinterpreter") {
341341
// Subinterpreters get their own copy of builtins. detail::get_internals() still
342342
// works by returning from the static variable, i.e. all interpreters share a single
343343
// global pybind11::internals;
344-
REQUIRE_FALSE(has_pybind11_internals_builtin());
344+
REQUIRE_FALSE(has_state_dict_internals_obj());
345345
REQUIRE(has_pybind11_internals_static());
346346

347347
// Modules tags should be gone.

0 commit comments

Comments
 (0)