Skip to content

Commit b7c3300

Browse files
authored
Start pybind11v3: Remove all code for PYBIND11_INTERNALS_VERSIONs 4 and 5 (#5530)
* Start pybind11v3 * Remove all code for PYBIND11_INTERNALS_VERSION 4 and 5 * Fix oversight: pybind11/_version.py needs to be updated as well. * Add @pytest.mark.skipif("env.GRAALPY", reason="TODO debug segfault")
1 parent 2415242 commit b7c3300

File tree

8 files changed

+36
-112
lines changed

8 files changed

+36
-112
lines changed

include/pybind11/detail/common.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414
# error "PYTHON < 3.8 IS UNSUPPORTED. pybind11 v2.13 was the last to support Python 3.7."
1515
#endif
1616

17-
#define PYBIND11_VERSION_MAJOR 2
18-
#define PYBIND11_VERSION_MINOR 14
17+
#define PYBIND11_VERSION_MAJOR 3
18+
#define PYBIND11_VERSION_MINOR 0
1919
#define PYBIND11_VERSION_PATCH 0.dev1
2020

2121
// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html
2222
// Additional convention: 0xD = dev
23-
#define PYBIND11_VERSION_HEX 0x020E00D1
23+
#define PYBIND11_VERSION_HEX 0x030000D1
2424

2525
// Define some generic pybind11 helper macros for warning management.
2626
//

include/pybind11/detail/internals.h

+30-88
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,9 @@
4040
# define PYBIND11_INTERNALS_VERSION 6
4141
#endif
4242

43-
// This requirement is mainly to reduce the support burden (see PR #4570).
44-
static_assert(PY_VERSION_HEX < 0x030C0000 || PYBIND11_INTERNALS_VERSION >= 5,
45-
"pybind11 ABI version 5 is the minimum for Python 3.12+");
46-
static_assert(PYBIND11_INTERNALS_VERSION >= 4,
47-
"pybind11 ABI version 4 is the minimum for all platforms.");
43+
#if PYBIND11_INTERNALS_VERSION < 6
44+
# error "PYBIND11_INTERNALS_VERSION 6 is the minimum for all platforms for pybind11v3."
45+
#endif
4846

4947
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
5048

@@ -63,49 +61,37 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass);
6361
// Thread Specific Storage (TSS) API.
6462
// Avoid unnecessary allocation of `Py_tss_t`, since we cannot use
6563
// `Py_LIMITED_API` anyway.
66-
#if PYBIND11_INTERNALS_VERSION > 4
67-
# define PYBIND11_TLS_KEY_REF Py_tss_t &
68-
# if defined(__clang__)
69-
# define PYBIND11_TLS_KEY_INIT(var) \
70-
_Pragma("clang diagnostic push") /**/ \
71-
_Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
72-
Py_tss_t var \
73-
= Py_tss_NEEDS_INIT; \
74-
_Pragma("clang diagnostic pop")
75-
# elif defined(__GNUC__) && !defined(__INTEL_COMPILER)
76-
# define PYBIND11_TLS_KEY_INIT(var) \
77-
_Pragma("GCC diagnostic push") /**/ \
78-
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
79-
Py_tss_t var \
80-
= Py_tss_NEEDS_INIT; \
81-
_Pragma("GCC diagnostic pop")
82-
# else
83-
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;
84-
# endif
85-
# define PYBIND11_TLS_KEY_CREATE(var) (PyThread_tss_create(&(var)) == 0)
86-
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get(&(key))
87-
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set(&(key), (value))
88-
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set(&(key), nullptr)
89-
# define PYBIND11_TLS_FREE(key) PyThread_tss_delete(&(key))
64+
#define PYBIND11_TLS_KEY_REF Py_tss_t &
65+
#if defined(__clang__)
66+
# define PYBIND11_TLS_KEY_INIT(var) \
67+
_Pragma("clang diagnostic push") /**/ \
68+
_Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
69+
Py_tss_t var \
70+
= Py_tss_NEEDS_INIT; \
71+
_Pragma("clang diagnostic pop")
72+
#elif defined(__GNUC__) && !defined(__INTEL_COMPILER)
73+
# define PYBIND11_TLS_KEY_INIT(var) \
74+
_Pragma("GCC diagnostic push") /**/ \
75+
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
76+
Py_tss_t var \
77+
= Py_tss_NEEDS_INIT; \
78+
_Pragma("GCC diagnostic pop")
9079
#else
91-
# define PYBIND11_TLS_KEY_REF Py_tss_t *
92-
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr;
93-
# define PYBIND11_TLS_KEY_CREATE(var) \
94-
(((var) = PyThread_tss_alloc()) != nullptr && (PyThread_tss_create((var)) == 0))
95-
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
96-
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
97-
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
98-
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
80+
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;
9981
#endif
82+
#define PYBIND11_TLS_KEY_CREATE(var) (PyThread_tss_create(&(var)) == 0)
83+
#define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get(&(key))
84+
#define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set(&(key), (value))
85+
#define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set(&(key), nullptr)
86+
#define PYBIND11_TLS_FREE(key) PyThread_tss_delete(&(key))
10087

10188
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
10289
// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module
10390
// even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under
10491
// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name,
10592
// which works. If not under a known-good stl, provide our own name-based hash and equality
10693
// functions that use the type name.
107-
#if (PYBIND11_INTERNALS_VERSION <= 4 && defined(__GLIBCXX__)) \
108-
|| (PYBIND11_INTERNALS_VERSION >= 5 && !defined(_LIBCPP_VERSION))
94+
#if !defined(_LIBCPP_VERSION)
10995
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; }
11096
using type_hash = std::hash<std::type_index>;
11197
using type_equal_to = std::equal_to<std::type_index>;
@@ -193,35 +179,26 @@ struct internals {
193179
std::forward_list<ExceptionTranslator> registered_exception_translators;
194180
std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across
195181
// extensions
196-
#if PYBIND11_INTERNALS_VERSION == 4
197-
std::vector<PyObject *> unused_loader_patient_stack_remove_at_v5;
198-
#endif
199-
std::forward_list<std::string> static_strings; // Stores the std::strings backing
200-
// detail::c_str()
182+
std::forward_list<std::string> static_strings; // Stores the std::strings backing
183+
// detail::c_str()
201184
PyTypeObject *static_property_type;
202185
PyTypeObject *default_metaclass;
203186
PyObject *instance_base;
204187
// Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
205188
PYBIND11_TLS_KEY_INIT(tstate)
206-
#if PYBIND11_INTERNALS_VERSION > 4
207189
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
208-
#endif // PYBIND11_INTERNALS_VERSION > 4
209190
// Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
210191
PyInterpreterState *istate = nullptr;
211192

212-
#if PYBIND11_INTERNALS_VERSION > 4
213193
// Note that we have to use a std::string to allocate memory to ensure a unique address
214194
// We want unique addresses since we use pointer equality to compare function records
215195
std::string function_record_capsule_name = internals_function_record_capsule_name;
216-
#endif
217196

218197
internals() = default;
219198
internals(const internals &other) = delete;
220199
internals &operator=(const internals &other) = delete;
221200
~internals() {
222-
#if PYBIND11_INTERNALS_VERSION > 4
223201
PYBIND11_TLS_FREE(loader_life_support_tls_key);
224-
#endif // PYBIND11_INTERNALS_VERSION > 4
225202

226203
// This destructor is called *after* Py_Finalize() in finalize_interpreter().
227204
// That *SHOULD BE* fine. The following details what happens when PyThread_tss_free is
@@ -386,7 +363,7 @@ inline void translate_local_exception(std::exception_ptr p) {
386363

387364
inline object get_python_state_dict() {
388365
object state_dict;
389-
#if PYBIND11_INTERNALS_VERSION <= 4 || defined(PYPY_VERSION) || defined(GRAALVM_PYTHON)
366+
#if defined(PYPY_VERSION) || defined(GRAALVM_PYTHON)
390367
state_dict = reinterpret_borrow<object>(PyEval_GetBuiltins());
391368
#else
392369
# if PY_VERSION_HEX < 0x03090000
@@ -484,13 +461,12 @@ PYBIND11_NOINLINE internals &get_internals() {
484461
}
485462
PYBIND11_TLS_REPLACE_VALUE(internals_ptr->tstate, tstate);
486463

487-
#if PYBIND11_INTERNALS_VERSION > 4
488464
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
489465
if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->loader_life_support_tls_key)) {
490466
pybind11_fail("get_internals: could not successfully initialize the "
491467
"loader_life_support TSS key!");
492468
}
493-
#endif
469+
494470
internals_ptr->istate = tstate->interp;
495471
state_dict[PYBIND11_INTERNALS_ID] = capsule(reinterpret_cast<void *>(internals_pp));
496472
internals_ptr->registered_exception_translators.push_front(&translate_exception);
@@ -520,40 +496,6 @@ PYBIND11_NOINLINE internals &get_internals() {
520496
struct local_internals {
521497
type_map<type_info *> registered_types_cpp;
522498
std::forward_list<ExceptionTranslator> registered_exception_translators;
523-
#if PYBIND11_INTERNALS_VERSION == 4
524-
525-
// For ABI compatibility, we can't store the loader_life_support TLS key in
526-
// the `internals` struct directly. Instead, we store it in `shared_data` and
527-
// cache a copy in `local_internals`. If we allocated a separate TLS key for
528-
// each instance of `local_internals`, we could end up allocating hundreds of
529-
// TLS keys if hundreds of different pybind11 modules are loaded (which is a
530-
// plausible number).
531-
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
532-
533-
// Holds the shared TLS key for the loader_life_support stack.
534-
struct shared_loader_life_support_data {
535-
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
536-
shared_loader_life_support_data() {
537-
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
538-
if (!PYBIND11_TLS_KEY_CREATE(loader_life_support_tls_key)) {
539-
pybind11_fail("local_internals: could not successfully initialize the "
540-
"loader_life_support TLS key!");
541-
}
542-
}
543-
// We can't help but leak the TLS key, because Python never unloads extension modules.
544-
};
545-
546-
local_internals() {
547-
auto &internals = get_internals();
548-
// Get or create the `loader_life_support_stack_key`.
549-
auto &ptr = internals.shared_data["_life_support"];
550-
if (!ptr) {
551-
ptr = new shared_loader_life_support_data;
552-
}
553-
loader_life_support_tls_key
554-
= static_cast<shared_loader_life_support_data *>(ptr)->loader_life_support_tls_key;
555-
}
556-
#endif // PYBIND11_INTERNALS_VERSION == 4
557499
};
558500

559501
/// Works like `get_internals`, but for things which are locally registered.
@@ -660,7 +602,7 @@ const char *c_str(Args &&...args) {
660602

661603
inline const char *get_function_record_capsule_name() {
662604
// On GraalPy, pointer equality of the names is currently not guaranteed
663-
#if PYBIND11_INTERNALS_VERSION > 4 && !defined(GRAALVM_PYTHON)
605+
#if !defined(GRAALVM_PYTHON)
664606
return get_internals().function_record_capsule_name.c_str();
665607
#else
666608
return nullptr;

include/pybind11/detail/type_caster_base.h

-4
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,7 @@ class loader_life_support {
4343

4444
// Store stack pointer in thread-local storage.
4545
static PYBIND11_TLS_KEY_REF get_stack_tls_key() {
46-
#if PYBIND11_INTERNALS_VERSION == 4
47-
return get_local_internals().loader_life_support_tls_key;
48-
#else
4946
return get_internals().loader_life_support_tls_key;
50-
#endif
5147
}
5248
static loader_life_support *get_stack_top() {
5349
return static_cast<loader_life_support *>(PYBIND11_TLS_GET_VALUE(get_stack_tls_key()));

pybind11/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ def _to_int(s: str) -> int | str:
88
return s
99

1010

11-
__version__ = "2.14.0.dev1"
11+
__version__ = "3.0.0.dev1"
1212
version_info = tuple(_to_int(s) for s in __version__.split("."))

tests/test_callbacks.cpp

-5
Original file line numberDiff line numberDiff line change
@@ -269,12 +269,7 @@ TEST_SUBMODULE(callbacks, m) {
269269
rec_capsule.set_name(rec_capsule_name);
270270
m.add_object("custom_function", PyCFunction_New(custom_def, rec_capsule.ptr()));
271271

272-
// This test requires a new ABI version to pass
273-
#if PYBIND11_INTERNALS_VERSION > 4 && !defined(GRAALVM_PYTHON)
274272
// rec_capsule with nullptr name
275273
py::capsule rec_capsule2(std::malloc(1), [](void *data) { std::free(data); });
276274
m.add_object("custom_function2", PyCFunction_New(custom_def, rec_capsule2.ptr()));
277-
#else
278-
m.add_object("custom_function2", py::none());
279-
#endif
280275
}

tests/test_callbacks.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,7 @@ def test_custom_func():
217217
assert m.roundtrip(m.custom_function)(4) == 36
218218

219219

220-
@pytest.mark.skipif(
221-
m.custom_function2 is None, reason="Current PYBIND11_INTERNALS_VERSION too low"
222-
)
220+
@pytest.mark.skipif("env.GRAALPY", reason="TODO debug segfault")
223221
def test_custom_func2():
224222
assert m.custom_function2(3) == 27
225223
assert m.roundtrip(m.custom_function2)(3) == 27

tests/test_unnamed_namespace_a.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ TEST_SUBMODULE(unnamed_namespace_a, m) {
1010
} else {
1111
m.attr("unnamed_namespace_a_any_struct") = py::none();
1212
}
13-
m.attr("PYBIND11_INTERNALS_VERSION") = PYBIND11_INTERNALS_VERSION;
1413
m.attr("defined_WIN32_or__WIN32") =
1514
#if defined(WIN32) || defined(_WIN32)
1615
true;

tests/test_unnamed_namespace_a.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,7 @@
55
from pybind11_tests import unnamed_namespace_a as m
66
from pybind11_tests import unnamed_namespace_b as mb
77

8-
XFAIL_CONDITION = (
9-
"(m.PYBIND11_INTERNALS_VERSION <= 4 and (m.defined___clang__ or not m.defined___GLIBCXX__))"
10-
" or "
11-
"(m.PYBIND11_INTERNALS_VERSION >= 5 and not m.defined_WIN32_or__WIN32"
12-
" and "
13-
"(m.defined___clang__ or m.defined__LIBCPP_VERSION))"
14-
)
8+
XFAIL_CONDITION = "not m.defined_WIN32_or__WIN32 and (m.defined___clang__ or m.defined__LIBCPP_VERSION)"
159
XFAIL_REASON = "Known issues: https://github.com/pybind/pybind11/pull/4319"
1610

1711

0 commit comments

Comments
 (0)