Merge tag 'v3.0.3' into stable

v3.0.3 release
diff --git a/.github/workflows/nightlies.yml b/.github/workflows/nightlies.yml
index 9b4f933..98211ca 100644
--- a/.github/workflows/nightlies.yml
+++ b/.github/workflows/nightlies.yml
@@ -33,7 +33,7 @@
           nox -s build
           nox -s build_global
 
-      - uses: actions/upload-artifact@v6
+      - uses: actions/upload-artifact@v7
         with:
           name: Packages
           path: dist/*
@@ -44,7 +44,7 @@
     needs: [build_wheel]
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/download-artifact@v7
+      - uses: actions/download-artifact@v8
         with:
           name: Packages
           path: dist
diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml
index b7555a5..981884a 100644
--- a/.github/workflows/pip.yml
+++ b/.github/workflows/pip.yml
@@ -72,13 +72,13 @@
       run: twine check dist/*
 
     - name: Save standard package
-      uses: actions/upload-artifact@v6
+      uses: actions/upload-artifact@v7
       with:
         name: standard
         path: dist/pybind11-*
 
     - name: Save global package
-      uses: actions/upload-artifact@v6
+      uses: actions/upload-artifact@v7
       with:
         name: global
         path: dist/*global-*
@@ -100,10 +100,10 @@
 
     steps:
     # Downloads all to directories matching the artifact names
-    - uses: actions/download-artifact@v7
+    - uses: actions/download-artifact@v8
 
     - name: Generate artifact attestation for sdist and wheel
-      uses: actions/attest-build-provenance@v3
+      uses: actions/attest-build-provenance@v4
       with:
         subject-path: "*/pybind11*"
 
diff --git a/.github/workflows/tests-cibw.yml b/.github/workflows/tests-cibw.yml
index 5dfb5dc..bf53431 100644
--- a/.github/workflows/tests-cibw.yml
+++ b/.github/workflows/tests-cibw.yml
@@ -70,24 +70,6 @@
       if: contains(matrix.runs-on, 'macos')
       run: echo "CIBW_TEST_COMMAND=" >> "$GITHUB_ENV"
 
-    # Temporarily disable Android tests on ubuntu-latest due to emulator issues.
-    # See https://github.com/pybind/pybind11/pull/5914.
-    - name: "NOTE: Android tests are disabled on ubuntu-latest"
-      if: contains(matrix.runs-on, 'ubuntu')
-      run: |
-        echo "CIBW_TEST_COMMAND=" >> "$GITHUB_ENV"
-        echo '::warning::Android cibuildwheel tests are disabled on ubuntu-latest (CIBW_TEST_COMMAND is empty). See PR 5914.'
-
-    # https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/
-    - name: Enable KVM for Android emulator
-      if: contains(matrix.runs-on, 'ubuntu')
-      run: |
-        echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
-        sudo udevadm control --reload-rules
-        sudo udevadm trigger --name-match=kvm
-
-    - run: pipx install patchelf
-
     - uses: pypa/cibuildwheel@v3.3
       env:
         CIBW_PLATFORM: android
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 0562615..5ee5846 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -25,14 +25,14 @@
 
 # Clang format the codebase automatically
 - repo: https://github.com/pre-commit/mirrors-clang-format
-  rev: "v21.1.8"
+  rev: "v22.1.0"
   hooks:
   - id: clang-format
     types_or: [c++, c, cuda]
 
 # Ruff, the Python auto-correcting linter/formatter written in Rust
 - repo: https://github.com/astral-sh/ruff-pre-commit
-  rev: v0.14.14
+  rev: v0.15.4
   hooks:
   - id: ruff-check
     args: ["--fix", "--show-fixes"]
@@ -122,7 +122,7 @@
 # Use mirror because pre-commit autoupdate confuses tags in the upstream repo.
 # See https://github.com/crate-ci/typos/issues/390
 - repo: https://github.com/adhtruong/mirrors-typos
-  rev: "v1.42.3"
+  rev: "v1.44.0"
   hooks:
   - id: typos
     args: []
@@ -144,14 +144,14 @@
 
 # PyLint has native support - not always usable, but works for us
 - repo: https://github.com/PyCQA/pylint
-  rev: "v4.0.4"
+  rev: "v4.0.5"
   hooks:
   - id: pylint
     files: ^pybind11
 
 # Check schemas on some of our YAML files
 - repo: https://github.com/python-jsonschema/check-jsonschema
-  rev: 0.36.1
+  rev: 0.37.0
   hooks:
   - id: check-readthedocs
   - id: check-github-workflows
diff --git a/docs/changelog.md b/docs/changelog.md
index 209da97..f993034 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -13,6 +13,62 @@
 entry" block in pull request descriptions.
 
 
+## Version 3.0.3 (March 31, 2026)
+
+Bug fixes:
+
+- Fixed TSS key exhaustion in `implicitly_convertible()` when many implicit conversions are registered across large module sets.
+  [#6020](https://github.com/pybind/pybind11/pull/6020)
+
+- Fixed heap-buffer-overflow in `pythonbuf` with undersized buffers by enforcing a minimum buffer size.
+  [#6019](https://github.com/pybind/pybind11/pull/6019)
+
+- Fixed virtual-inheritance pointer offset crashes when dispatching inherited methods through virtual bases.
+  [#6017](https://github.com/pybind/pybind11/pull/6017)
+
+- Fixed `free(): invalid pointer` crashes during interpreter shutdown with `py::enum_<>` by duplicating late-added `def_property_static` argument strings.
+  [#6015](https://github.com/pybind/pybind11/pull/6015)
+
+- Fixed `function_record` heap-type deallocation to call `PyObject_Free()` and decref the type.
+  [#6010](https://github.com/pybind/pybind11/pull/6010)
+
+- Hardened `PYBIND11_MODULE_PYINIT` and `get_internals()` against module-initialization crashes.
+  [#6018](https://github.com/pybind/pybind11/pull/6018)
+
+- Fixed `static_pointer_cast` build failure with virtual inheritance in `holder_caster_foreign_helpers.h`.
+  [#6014](https://github.com/pybind/pybind11/pull/6014)
+
+- Fixed ambiguous `factory` template specialization that caused compilation failures with nvcc + GCC 14.
+  [#6011](https://github.com/pybind/pybind11/pull/6011)
+
+- Fixed crash in `def_readwrite` for non-smart-holder properties of smart-holder classes.
+  [#6008](https://github.com/pybind/pybind11/pull/6008)
+
+- Fixed memory leak for `py::dynamic_attr()` objects on Python 3.13+ by clearing managed `__dict__` contents during deallocation.
+  [#5999](https://github.com/pybind/pybind11/pull/5999)
+
+- Fixed binding of `noexcept` and ref-qualified (`&`, `&&`) methods inherited from unregistered base classes.
+  [#5992](https://github.com/pybind/pybind11/pull/5992)
+
+Internal:
+
+- Moved `tomlkit` dependency to the dev dependency group.
+  [#5990](https://github.com/pybind/pybind11/pull/5990)
+
+- Switched to newer public CPython APIs (`PyType_GetFlags` and public vectorcall APIs where available).
+  [#6005](https://github.com/pybind/pybind11/pull/6005)
+
+Tests:
+
+- Made an async callback test deterministic by replacing fixed sleep with bounded waiting.
+  [#5986](https://github.com/pybind/pybind11/pull/5986)
+
+CI:
+
+- Re-enabled Android tests in the cibuildwheel workflow.
+  [#6001](https://github.com/pybind/pybind11/pull/6001)
+
+
 ## Version 3.0.2 (February 16, 2026)
 
 New Features:
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 1b6bcf0..c19fbf2 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -41,13 +41,13 @@
     # via -r requirements.in
 packaging==24.0
     # via sphinx
-pygments==2.17.2
+pygments==2.20.0
     # via
     #   furo
     #   sphinx
 pyyaml==6.0.2
     # via myst-parser
-requests==2.32.4
+requests==2.33.0
     # via sphinx
 snowballstemmer==2.2.0
     # via sphinx
diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h
index b4486dc..d337595 100644
--- a/include/pybind11/attr.h
+++ b/include/pybind11/attr.h
@@ -378,7 +378,7 @@
 #ifdef PYBIND11_BACKWARD_COMPATIBILITY_TP_DICTOFFSET
         dynamic_attr |= base_info->type->tp_dictoffset != 0;
 #else
-        dynamic_attr |= (base_info->type->tp_flags & Py_TPFLAGS_MANAGED_DICT) != 0;
+        dynamic_attr |= (PyType_GetFlags(base_info->type) & Py_TPFLAGS_MANAGED_DICT) != 0;
 #endif
 
         if (caster) {
diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index f5a94da..f07abfe 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -199,8 +199,7 @@
     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)                                                                                 \
@@ -1020,7 +1019,19 @@
             return smart_holder_type_caster_support::smart_holder_from_shared_ptr(
                 src, policy, parent, srcs.result);
         }
-        return type_caster_base<type>::cast_holder(srcs, &src);
+
+        auto *tinfo = srcs.result.tinfo;
+        if (tinfo != nullptr && tinfo->holder_enum_v == holder_enum_t::std_shared_ptr) {
+            return type_caster_base<type>::cast_holder(srcs, &src);
+        }
+
+        if (parent) {
+            return type_caster_base<type>::cast(
+                srcs, return_value_policy::reference_internal, parent);
+        }
+
+        throw cast_error("Unable to convert std::shared_ptr<T> to Python when the bound type "
+                         "does not use std::shared_ptr or py::smart_holder as its holder type");
     }
 
     // This function will succeed even if the `responsible_parent` does not own the
@@ -1662,8 +1673,7 @@
 template <typename T,
           detail::enable_if_t<!detail::is_pyobject<T>::value
                                   && !detail::is_same_ignoring_cvref<T, PyObject *>::value,
-                              int>
-          = 0>
+                              int> = 0>
 T cast(const handle &handle) {
     using namespace detail;
     constexpr bool is_enum_cast = type_uses_type_caster_enum_type<intrinsic_t<T>>::value;
@@ -1698,8 +1708,7 @@
           typename Handle,
           detail::enable_if_t<detail::is_same_ignoring_cvref<T, PyObject *>::value
                                   && detail::is_same_ignoring_cvref<Handle, handle>::value,
-                              int>
-          = 0>
+                              int> = 0>
 T cast(Handle &&handle) {
     return handle.inc_ref().ptr();
 }
@@ -1708,8 +1717,7 @@
           typename Object,
           detail::enable_if_t<detail::is_same_ignoring_cvref<T, PyObject *>::value
                                   && detail::is_same_ignoring_cvref<Object, object>::value,
-                              int>
-          = 0>
+                              int> = 0>
 T cast(Object &&obj) {
     return obj.release().ptr();
 }
@@ -2243,8 +2251,13 @@
         if (m_names) {
             nargs -= m_names.size();
         }
-        PyObject *result = _PyObject_Vectorcall(
-            ptr, m_args.data() + 1, nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, m_names.ptr());
+        PyObject *result =
+#if PY_VERSION_HEX >= 0x03090000
+            PyObject_Vectorcall(
+#else
+            _PyObject_Vectorcall(
+#endif
+                ptr, m_args.data() + 1, nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, m_names.ptr());
         if (!result) {
             throw error_already_set();
         }
diff --git a/include/pybind11/chrono.h b/include/pybind11/chrono.h
index d9bcc4b..668e458 100644
--- a/include/pybind11/chrono.h
+++ b/include/pybind11/chrono.h
@@ -64,8 +64,7 @@
         return src;
     }
     static const std::chrono::duration<rep, period> &
-    get_duration(const std::chrono::duration<rep, period> &&)
-        = delete;
+    get_duration(const std::chrono::duration<rep, period> &&) = delete;
 
     // If this is a time_point get the time_since_epoch
     template <typename Clock>
diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h
index 480c369..4b7422e 100644
--- a/include/pybind11/detail/class.h
+++ b/include/pybind11/detail/class.h
@@ -503,6 +503,17 @@
         PyObject_GC_UnTrack(self);
     }
 
+#if PY_VERSION_HEX >= 0x030D0000
+    // PyObject_ClearManagedDict() is available from Python 3.13+. It must be
+    // called before tp_free() because on Python 3.14+ tp_free no longer
+    // implicitly clears the managed dict, which would abandon the refcounts of
+    // objects stored in __dict__ of py::dynamic_attr() types, causing permanent
+    // memory leaks.
+    if (PyType_HasFeature(type, Py_TPFLAGS_MANAGED_DICT)) {
+        PyObject_ClearManagedDict(self);
+    }
+#endif
+
     clear_instance(self);
 
     type->tp_free(self);
diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h
index b03d0c2..7158923 100644
--- a/include/pybind11/detail/common.h
+++ b/include/pybind11/detail/common.h
@@ -19,7 +19,7 @@
 /* -- start version constants -- */
 #define PYBIND11_VERSION_MAJOR 3
 #define PYBIND11_VERSION_MINOR 0
-#define PYBIND11_VERSION_MICRO 2
+#define PYBIND11_VERSION_MICRO 3
 // ALPHA = 0xA, BETA = 0xB, GAMMA = 0xC (release candidate), FINAL = 0xF (stable release)
 // - The release level is set to "alpha" for development versions.
 //   Use 0xA0 (LEVEL=0xA, SERIAL=0) for development versions.
@@ -27,7 +27,7 @@
 #define PYBIND11_VERSION_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL
 #define PYBIND11_VERSION_RELEASE_SERIAL 0
 // String version of (micro, release level, release serial), e.g.: 0a0, 0b1, 0rc1, 0
-#define PYBIND11_VERSION_PATCH 2
+#define PYBIND11_VERSION_PATCH 3
 /* -- end version constants -- */
 
 #if !defined(Py_PACK_FULL_VERSION)
@@ -167,6 +167,14 @@
 #    define PYBIND11_NOINLINE __attribute__((noinline)) inline
 #endif
 
+#if defined(_MSC_VER)
+#    define PYBIND11_ALWAYS_INLINE __forceinline
+#elif defined(__GNUC__)
+#    define PYBIND11_ALWAYS_INLINE __attribute__((__always_inline__)) inline
+#else
+#    define PYBIND11_ALWAYS_INLINE inline
+#endif
+
 #if defined(__MINGW32__)
 // For unknown reasons all PYBIND11_DEPRECATED member trigger a warning when declared
 // whether it is used or not
@@ -449,19 +457,24 @@
     static int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject *);                                 \
     PYBIND11_PLUGIN_IMPL(name) {                                                                  \
         PYBIND11_CHECK_PYTHON_VERSION                                                             \
-        pybind11::detail::ensure_internals();                                                     \
-        static ::pybind11::detail::slots_array mod_def_slots = ::pybind11::detail::init_slots(    \
-            &PYBIND11_CONCAT(pybind11_exec_, name), ##__VA_ARGS__);                               \
-        static PyModuleDef def{/* m_base */ PyModuleDef_HEAD_INIT,                                \
-                               /* m_name */ PYBIND11_TOSTRING(name),                              \
-                               /* m_doc */ nullptr,                                               \
-                               /* m_size */ 0,                                                    \
-                               /* m_methods */ nullptr,                                           \
-                               /* m_slots */ mod_def_slots.data(),                                \
-                               /* m_traverse */ nullptr,                                          \
-                               /* m_clear */ nullptr,                                             \
-                               /* m_free */ nullptr};                                             \
-        return PyModuleDef_Init(&def);                                                            \
+        try {                                                                                     \
+            pybind11::detail::ensure_internals();                                                 \
+            static ::pybind11::detail::slots_array mod_def_slots                                  \
+                = ::pybind11::detail::init_slots(&PYBIND11_CONCAT(pybind11_exec_, name),          \
+                                                 ##__VA_ARGS__);                                  \
+            static PyModuleDef def{/* m_base */ PyModuleDef_HEAD_INIT,                            \
+                                   /* m_name */ PYBIND11_TOSTRING(name),                          \
+                                   /* m_doc */ nullptr,                                           \
+                                   /* m_size */ 0,                                                \
+                                   /* m_methods */ nullptr,                                       \
+                                   /* m_slots */ mod_def_slots.data(),                            \
+                                   /* m_traverse */ nullptr,                                      \
+                                   /* m_clear */ nullptr,                                         \
+                                   /* m_free */ nullptr};                                         \
+            return PyModuleDef_Init(&def);                                                        \
+        }                                                                                         \
+        PYBIND11_CATCH_INIT_EXCEPTIONS                                                            \
+        return nullptr;                                                                           \
     }
 
 #define PYBIND11_MODULE_EXEC(name, variable)                                                      \
@@ -1026,6 +1039,17 @@
 template <typename T>
 using is_shared_ptr = is_instantiation<std::shared_ptr, T>;
 
+/// Detects whether static_cast<Derived*>(Base*) is valid, i.e. the inheritance is non-virtual.
+/// Used to detect virtual bases: if this is false, pointer adjustments require the implicit_casts
+/// chain rather than reinterpret_cast.
+template <typename Base, typename Derived, typename = void>
+struct is_static_downcastable : std::false_type {};
+template <typename Base, typename Derived>
+struct is_static_downcastable<Base,
+                              Derived,
+                              void_t<decltype(static_cast<Derived *>(std::declval<Base *>()))>>
+    : std::true_type {};
+
 /// Check if T looks like an input iterator
 template <typename T, typename = void>
 struct is_input_iterator : std::false_type {};
@@ -1048,14 +1072,30 @@
     using type = typename remove_class<decltype(&F::operator())>::type;
 };
 
+// Strip noexcept from a free function type (C++17: noexcept is part of the type).
+template <typename T>
+struct remove_noexcept {
+    using type = T;
+};
+#ifdef __cpp_noexcept_function_type
+template <typename R, typename... A>
+struct remove_noexcept<R(A...) noexcept> {
+    using type = R(A...);
+};
+#endif
+template <typename T>
+using remove_noexcept_t = typename remove_noexcept<T>::type;
+
 // Extracts the function signature from a function, function pointer or lambda.
+// Strips noexcept from the result so that factory/pickle_factory partial specializations
+// (which match plain Return(Args...)) work correctly with noexcept callables (issue #2234).
 template <typename Function, typename F = remove_reference_t<Function>>
-using function_signature_t = conditional_t<
+using function_signature_t = remove_noexcept_t<conditional_t<
     std::is_function<F>::value,
     F,
     typename conditional_t<std::is_pointer<F>::value || std::is_member_pointer<F>::value,
                            std::remove_pointer<F>,
-                           strip_function_object<F>>::type>;
+                           strip_function_object<F>>::type>>;
 
 /// Returns true if the type looks like a lambda: that is, isn't a function, pointer or member
 /// pointer.  Note that this can catch all sorts of other things, too; this is intended to be used
@@ -1204,6 +1244,36 @@
         -> decltype(pmf) {
         return pmf;
     }
+
+    // Define const/non-const member-pointer selector pairs for qualifier combinations.
+    // The `qualifiers` parameter is used in type position, where extra parentheses are invalid.
+    // NOLINTBEGIN(bugprone-macro-parentheses)
+#define PYBIND11_OVERLOAD_CAST_MEMBER_PTR(qualifiers)                                             \
+    template <typename Return, typename Class>                                                    \
+    constexpr auto operator()(Return (Class::*pmf)(Args...) qualifiers, std::false_type = {})     \
+        const noexcept -> decltype(pmf) {                                                         \
+        return pmf;                                                                               \
+    }                                                                                             \
+    template <typename Return, typename Class>                                                    \
+    constexpr auto operator()(Return (Class::*pmf)(Args...) const qualifiers, std::true_type)     \
+        const noexcept -> decltype(pmf) {                                                         \
+        return pmf;                                                                               \
+    }
+    PYBIND11_OVERLOAD_CAST_MEMBER_PTR(&)
+    PYBIND11_OVERLOAD_CAST_MEMBER_PTR(&&)
+
+#ifdef __cpp_noexcept_function_type
+    template <typename Return>
+    constexpr auto operator()(Return (*pf)(Args...) noexcept) const noexcept -> decltype(pf) {
+        return pf;
+    }
+
+    PYBIND11_OVERLOAD_CAST_MEMBER_PTR(noexcept)
+    PYBIND11_OVERLOAD_CAST_MEMBER_PTR(& noexcept)
+    PYBIND11_OVERLOAD_CAST_MEMBER_PTR(&& noexcept)
+#endif
+#undef PYBIND11_OVERLOAD_CAST_MEMBER_PTR
+    // NOLINTEND(bugprone-macro-parentheses)
 };
 PYBIND11_NAMESPACE_END(detail)
 
diff --git a/include/pybind11/detail/holder_caster_foreign_helpers.h b/include/pybind11/detail/holder_caster_foreign_helpers.h
index f636618..cae571b 100644
--- a/include/pybind11/detail/holder_caster_foreign_helpers.h
+++ b/include/pybind11/detail/holder_caster_foreign_helpers.h
@@ -31,13 +31,31 @@
         PyObject *o;
     };
 
+    // Downcast shared_ptr from the enable_shared_from_this base to the target type.
+    // SFINAE probe: use static_pointer_cast when the static downcast is valid (common case),
+    // fall back to dynamic_pointer_cast when it isn't (virtual inheritance — issue #5989).
+    // We can't use dynamic_pointer_cast unconditionally because it requires polymorphic types;
+    // we can't use is_polymorphic to choose because that's orthogonal to virtual inheritance.
+    // (The implementation uses the "tag dispatch via overload priority" trick.)
+    template <typename type, typename esft_base>
+    static auto esft_downcast(const std::shared_ptr<esft_base> &existing, int /*preferred*/)
+        -> decltype(static_cast<type *>(std::declval<esft_base *>()), std::shared_ptr<type>()) {
+        return std::static_pointer_cast<type>(existing);
+    }
+
+    template <typename type, typename esft_base>
+    static std::shared_ptr<type> esft_downcast(const std::shared_ptr<esft_base> &existing,
+                                               ... /*fallback*/) {
+        return std::dynamic_pointer_cast<type>(existing);
+    }
+
     template <typename type>
     static auto set_via_shared_from_this(type *value, std::shared_ptr<type> *holder_out)
         -> decltype(value->shared_from_this(), bool()) {
         // object derives from enable_shared_from_this;
         // try to reuse an existing shared_ptr if one is known
         if (auto existing = try_get_shared_from_this(value)) {
-            *holder_out = std::static_pointer_cast<type>(existing);
+            *holder_out = esft_downcast<type>(existing, 0);
             return true;
         }
         return false;
diff --git a/include/pybind11/detail/init.h b/include/pybind11/detail/init.h
index b7f8d5a..a1083f8 100644
--- a/include/pybind11/detail/init.h
+++ b/include/pybind11/detail/init.h
@@ -304,11 +304,10 @@
             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__",
@@ -325,11 +324,10 @@
             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__",
@@ -345,11 +343,10 @@
 // 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__",
@@ -370,8 +367,15 @@
 struct factory;
 
 // Specialization for py::init(Func)
+// Note: The 4th template parameter `void_type()` is explicitly specified to resolve a
+// template ambiguity with the dual-factory specialization below when compiled with
+// nvcc + GCC (see #5565). Without it, both specializations match equally well for the
+// single-factory case, since the 4th parameter defaults to
+// `function_signature_t<void_type(*)()>` = `void_type()`, which the dual-factory
+// specialization can also decompose as `AReturn(AArgs...)` with `AReturn=void_type`
+// and `AArgs={}`.
 template <typename Func, typename Return, typename... Args>
-struct factory<Func, void_type (*)(), Return(Args...)> {
+struct factory<Func, void_type (*)(), Return(Args...), void_type()> {
     remove_reference_t<Func> class_factory;
 
     // NOLINTNEXTLINE(google-explicit-constructor)
diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h
index b681529..a49cdaa 100644
--- a/include/pybind11/detail/internals.h
+++ b/include/pybind11/detail/internals.h
@@ -59,15 +59,13 @@
 #    define PYBIND11_TLS_KEY_INIT(var)                                                            \
         _Pragma("clang diagnostic push")                                         /**/             \
             _Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") /**/             \
-            Py_tss_t var                                                                          \
-            = Py_tss_NEEDS_INIT;                                                                  \
+            Py_tss_t var = Py_tss_NEEDS_INIT;                                                     \
         _Pragma("clang diagnostic pop")
 #elif defined(__GNUC__) && !defined(__INTEL_COMPILER)
 #    define PYBIND11_TLS_KEY_INIT(var)                                                            \
         _Pragma("GCC diagnostic push")                                         /**/               \
             _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/               \
-            Py_tss_t var                                                                          \
-            = Py_tss_NEEDS_INIT;                                                                  \
+            Py_tss_t var = Py_tss_NEEDS_INIT;                                                     \
         _Pragma("GCC diagnostic pop")
 #else
 #    define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;
@@ -864,7 +862,11 @@
 /// Return a reference to the current `internals` data
 PYBIND11_NOINLINE internals &get_internals() {
     auto &ppmgr = get_internals_pp_manager();
-    auto &internals_ptr = *ppmgr.get_pp();
+    auto *pp = ppmgr.get_pp();
+    if (!pp) {
+        pybind11_fail("get_internals: get_pp() returned nullptr");
+    }
+    auto &internals_ptr = *pp;
     if (!internals_ptr) {
         // Slow path, something needs fetched from the state dict or created
         gil_scoped_acquire_simple gil;
@@ -872,6 +874,9 @@
 
         ppmgr.create_pp_content_once(&internals_ptr);
 
+        if (!internals_ptr) {
+            pybind11_fail("get_internals: create_pp_content_once() produced nullptr");
+        }
         if (!internals_ptr->instance_base) {
             // This calls get_internals, so cannot be called from within the internals constructor
             // called above because internals_ptr must be set before get_internals is called again
diff --git a/include/pybind11/iostream.h b/include/pybind11/iostream.h
index 1878089..44261e8 100644
--- a/include/pybind11/iostream.h
+++ b/include/pybind11/iostream.h
@@ -117,8 +117,16 @@
     int sync() override { return _sync(); }
 
 public:
+    // Minimum buffer size must accommodate the largest incomplete UTF-8 sequence
+    // (3 bytes) plus one position reserved for overflow(), i.e. 4 bytes total.
+    static constexpr size_t minimum_buffer_size = 4;
+
     explicit pythonbuf(const object &pyostream, size_t buffer_size = 1024)
-        : buf_size(buffer_size), d_buffer(new char[buf_size]), pywrite(pyostream.attr("write")),
+        : buf_size(buffer_size < minimum_buffer_size // ternary avoids C++14 std::max ODR-use of
+                                                     // static constexpr
+                       ? minimum_buffer_size
+                       : buffer_size),
+          d_buffer(new char[buf_size]), pywrite(pyostream.attr("write")),
           pyflush(pyostream.attr("flush")) {
         setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
     }
diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h
index 408d169..10c0c94 100644
--- a/include/pybind11/numpy.h
+++ b/include/pybind11/numpy.h
@@ -2327,4 +2327,86 @@
     return Helper(std::mem_fn(f));
 }
 
+// Intentionally no &&/const&& overloads: vectorized method calls operate on the bound Python
+// instance and should not consume/move-from self.
+// Vectorize a class method (non-const, lvalue ref-qualified):
+template <typename Return,
+          typename Class,
+          typename... Args,
+          typename Helper = detail::vectorize_helper<
+              decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) &>())),
+              Return,
+              Class *,
+              Args...>>
+Helper vectorize(Return (Class::*f)(Args...) &) {
+    return Helper(std::mem_fn(f));
+}
+
+// Vectorize a class method (const, lvalue ref-qualified):
+template <typename Return,
+          typename Class,
+          typename... Args,
+          typename Helper = detail::vectorize_helper<
+              decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) const &>())),
+              Return,
+              const Class *,
+              Args...>>
+Helper vectorize(Return (Class::*f)(Args...) const &) {
+    return Helper(std::mem_fn(f));
+}
+
+#ifdef __cpp_noexcept_function_type
+// Vectorize a class method (non-const, noexcept):
+template <typename Return,
+          typename Class,
+          typename... Args,
+          typename Helper = detail::vectorize_helper<
+              decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) noexcept>())),
+              Return,
+              Class *,
+              Args...>>
+Helper vectorize(Return (Class::*f)(Args...) noexcept) {
+    return Helper(std::mem_fn(f));
+}
+
+// Vectorize a class method (const, noexcept):
+template <typename Return,
+          typename Class,
+          typename... Args,
+          typename Helper = detail::vectorize_helper<
+              decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) const noexcept>())),
+              Return,
+              const Class *,
+              Args...>>
+Helper vectorize(Return (Class::*f)(Args...) const noexcept) {
+    return Helper(std::mem_fn(f));
+}
+
+// Vectorize a class method (non-const, lvalue ref-qualified, noexcept):
+template <typename Return,
+          typename Class,
+          typename... Args,
+          typename Helper = detail::vectorize_helper<
+              decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) & noexcept>())),
+              Return,
+              Class *,
+              Args...>>
+Helper vectorize(Return (Class::*f)(Args...) & noexcept) {
+    return Helper(std::mem_fn(f));
+}
+
+// Vectorize a class method (const, lvalue ref-qualified, noexcept):
+template <typename Return,
+          typename Class,
+          typename... Args,
+          typename Helper = detail::vectorize_helper<
+              decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) const & noexcept>())),
+              Return,
+              const Class *,
+              Args...>>
+Helper vectorize(Return (Class::*f)(Args...) const & noexcept) {
+    return Helper(std::mem_fn(f));
+}
+#endif
+
 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h
index 0f31262..b5a97db 100644
--- a/include/pybind11/pybind11.h
+++ b/include/pybind11/pybind11.h
@@ -369,6 +369,96 @@
                    extra...);
     }
 
+    /// Construct a cpp_function from a class method (non-const, rvalue ref-qualifier)
+    template <typename Return, typename Class, typename... Arg, typename... Extra>
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    cpp_function(Return (Class::*f)(Arg...) &&, const Extra &...extra) {
+        initialize(
+            [f](Class *c, Arg... args) -> Return {
+                return (std::move(*c).*f)(std::forward<Arg>(args)...);
+            },
+            (Return (*)(Class *, Arg...)) nullptr,
+            extra...);
+    }
+
+    /// Construct a cpp_function from a class method (const, rvalue ref-qualifier)
+    template <typename Return, typename Class, typename... Arg, typename... Extra>
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    cpp_function(Return (Class::*f)(Arg...) const &&, const Extra &...extra) {
+        initialize(
+            [f](const Class *c, Arg... args) -> Return {
+                return (std::move(*c).*f)(std::forward<Arg>(args)...);
+            },
+            (Return (*)(const Class *, Arg...)) nullptr,
+            extra...);
+    }
+
+#ifdef __cpp_noexcept_function_type
+    /// Construct a cpp_function from a class method (non-const, no ref-qualifier, noexcept)
+    template <typename Return, typename Class, typename... Arg, typename... Extra>
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    cpp_function(Return (Class::*f)(Arg...) noexcept, const Extra &...extra) {
+        initialize(
+            [f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
+            (Return (*)(Class *, Arg...)) nullptr,
+            extra...);
+    }
+
+    /// Construct a cpp_function from a class method (non-const, lvalue ref-qualifier, noexcept)
+    template <typename Return, typename Class, typename... Arg, typename... Extra>
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    cpp_function(Return (Class::*f)(Arg...) & noexcept, const Extra &...extra) {
+        initialize(
+            [f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
+            (Return (*)(Class *, Arg...)) nullptr,
+            extra...);
+    }
+
+    /// Construct a cpp_function from a class method (const, no ref-qualifier, noexcept)
+    template <typename Return, typename Class, typename... Arg, typename... Extra>
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    cpp_function(Return (Class::*f)(Arg...) const noexcept, const Extra &...extra) {
+        initialize([f](const Class *c,
+                       Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
+                   (Return (*)(const Class *, Arg...)) nullptr,
+                   extra...);
+    }
+
+    /// Construct a cpp_function from a class method (const, lvalue ref-qualifier, noexcept)
+    template <typename Return, typename Class, typename... Arg, typename... Extra>
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    cpp_function(Return (Class::*f)(Arg...) const & noexcept, const Extra &...extra) {
+        initialize([f](const Class *c,
+                       Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
+                   (Return (*)(const Class *, Arg...)) nullptr,
+                   extra...);
+    }
+
+    /// Construct a cpp_function from a class method (non-const, rvalue ref-qualifier, noexcept)
+    template <typename Return, typename Class, typename... Arg, typename... Extra>
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    cpp_function(Return (Class::*f)(Arg...) && noexcept, const Extra &...extra) {
+        initialize(
+            [f](Class *c, Arg... args) -> Return {
+                return (std::move(*c).*f)(std::forward<Arg>(args)...);
+            },
+            (Return (*)(Class *, Arg...)) nullptr,
+            extra...);
+    }
+
+    /// Construct a cpp_function from a class method (const, rvalue ref-qualifier, noexcept)
+    template <typename Return, typename Class, typename... Arg, typename... Extra>
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    cpp_function(Return (Class::*f)(Arg...) const && noexcept, const Extra &...extra) {
+        initialize(
+            [f](const Class *c, Arg... args) -> Return {
+                return (std::move(*c).*f)(std::forward<Arg>(args)...);
+            },
+            (Return (*)(const Class *, Arg...)) nullptr,
+            extra...);
+    }
+#endif
+
     /// Return the function name
     object name() const { return attr("__name__"); }
 
@@ -1321,9 +1411,15 @@
 
 // This implementation needs the definition of `class cpp_function`.
 inline void tp_dealloc_impl(PyObject *self) {
+    // Save type before PyObject_Free invalidates self.
+    auto *type = Py_TYPE(self);
     auto *py_func_rec = reinterpret_cast<function_record_PyObject *>(self);
     cpp_function::destruct(py_func_rec->cpp_func_rec);
     py_func_rec->cpp_func_rec = nullptr;
+    // PyObject_New increments the heap type refcount and allocates via
+    // PyObject_Malloc; balance both here
+    PyObject_Free(self);
+    Py_DECREF(type);
 }
 
 PYBIND11_NAMESPACE_END(function_record_PyTypeObject_methods)
@@ -1859,29 +1955,89 @@
     }
 }
 
+/// Type trait to rebind a member function pointer's class to `Derived`, preserving all
+/// cv/ref/noexcept qualifiers. The primary template has no `type` member, providing SFINAE
+/// failure for unsupported member function pointer types. `source_class` holds the original
+/// class for use in `is_accessible_base_of` checks.
+template <typename Derived, typename T>
+struct rebind_member_ptr {};
+
+// Define one specialization per supported qualifier combination via a local macro.
+// The qualifiers argument appears in type position, not expression position, so
+// parenthesizing it would produce invalid C++.
+// The no-qualifier specialization is written out explicitly to avoid invoking the macro with an
+// empty argument, which triggers MSVC warning C4003.
+template <typename Derived, typename Return, typename Class, typename... Args>
+struct rebind_member_ptr<Derived, Return (Class::*)(Args...)> {
+    using type = Return (Derived::*)(Args...);
+    using source_class = Class;
+};
+// NOLINTBEGIN(bugprone-macro-parentheses)
+#define PYBIND11_REBIND_MEMBER_PTR(qualifiers)                                                    \
+    template <typename Derived, typename Return, typename Class, typename... Args>                \
+    struct rebind_member_ptr<Derived, Return (Class::*)(Args...) qualifiers> {                    \
+        using type = Return (Derived::*)(Args...) qualifiers;                                     \
+        using source_class = Class;                                                               \
+    }
+PYBIND11_REBIND_MEMBER_PTR(const);
+PYBIND11_REBIND_MEMBER_PTR(&);
+PYBIND11_REBIND_MEMBER_PTR(const &);
+PYBIND11_REBIND_MEMBER_PTR(&&);
+PYBIND11_REBIND_MEMBER_PTR(const &&);
+#ifdef __cpp_noexcept_function_type
+PYBIND11_REBIND_MEMBER_PTR(noexcept);
+PYBIND11_REBIND_MEMBER_PTR(const noexcept);
+PYBIND11_REBIND_MEMBER_PTR(& noexcept);
+PYBIND11_REBIND_MEMBER_PTR(const & noexcept);
+PYBIND11_REBIND_MEMBER_PTR(&& noexcept);
+PYBIND11_REBIND_MEMBER_PTR(const && noexcept);
+#endif
+#undef PYBIND11_REBIND_MEMBER_PTR
+// NOLINTEND(bugprone-macro-parentheses)
+
+/// Shared implementation body for all method_adaptor member-function-pointer overloads.
+/// Asserts Base is accessible from Derived, then casts the member pointer.
+template <typename Derived,
+          typename T,
+          typename Traits = rebind_member_ptr<Derived, T>,
+          typename Adapted = typename Traits::type>
+constexpr PYBIND11_ALWAYS_INLINE Adapted adapt_member_ptr(T pmf) {
+    static_assert(
+        detail::is_accessible_base_of<typename Traits::source_class, Derived>::value,
+        "Cannot bind an inaccessible base class method; use a lambda definition instead");
+    return pmf;
+}
+
 PYBIND11_NAMESPACE_END(detail)
 
 /// Given a pointer to a member function, cast it to its `Derived` version.
-/// Forward everything else unchanged.
-template <typename /*Derived*/, typename F>
-auto method_adaptor(F &&f) -> decltype(std::forward<F>(f)) {
+/// For all other callables (lambdas, function pointers, etc.), forward unchanged.
+///
+/// Two overloads cover all cases without explicit per-qualifier instantiations:
+///
+///  (1) Generic fallback — disabled for member function pointers so that (2) wins
+///      without any partial-ordering ambiguity.
+///  (2) MFP overload — SFINAE on rebind_member_ptr::type, which exists for every
+///      supported qualifier combination (const, &, &&, noexcept, ...).  A single
+///      template therefore covers all combinations that rebind_member_ptr handles.
+template <
+    typename /*Derived*/,
+    typename F,
+    detail::enable_if_t<!std::is_member_function_pointer<detail::remove_reference_t<F>>::value,
+                        int> = 0>
+constexpr auto method_adaptor(F &&f) -> decltype(std::forward<F>(f)) {
     return std::forward<F>(f);
 }
 
-template <typename Derived, typename Return, typename Class, typename... Args>
-auto method_adaptor(Return (Class::*pmf)(Args...)) -> Return (Derived::*)(Args...) {
-    static_assert(
-        detail::is_accessible_base_of<Class, Derived>::value,
-        "Cannot bind an inaccessible base class method; use a lambda definition instead");
-    return pmf;
-}
-
-template <typename Derived, typename Return, typename Class, typename... Args>
-auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(Args...) const {
-    static_assert(
-        detail::is_accessible_base_of<Class, Derived>::value,
-        "Cannot bind an inaccessible base class method; use a lambda definition instead");
-    return pmf;
+template <typename Derived,
+          typename T,
+          typename Adapted = typename detail::rebind_member_ptr<Derived, T>::type>
+constexpr Adapted method_adaptor(T pmf) {
+    // Expected to be redundant (SFINAE on rebind_member_ptr) but cheap and makes the intent
+    // explicit.
+    static_assert(std::is_member_function_pointer<T>::value,
+                  "method_adaptor: T must be a member function pointer");
+    return detail::adapt_member_ptr<Derived>(pmf);
 }
 
 PYBIND11_NAMESPACE_BEGIN(detail)
@@ -2239,6 +2395,13 @@
         rec.add_base(typeid(Base), [](void *src) -> void * {
             return static_cast<Base *>(reinterpret_cast<type *>(src));
         });
+        // Virtual inheritance means the base subobject is at a dynamic offset,
+        // so the reinterpret_cast shortcut in load_impl Case 2a is invalid.
+        // Force the MI path (implicit_casts) for correct pointer adjustment.
+        // Detection: static_cast<Derived*>(Base*) is ill-formed for virtual bases.
+        if PYBIND11_MAYBE_CONSTEXPR (!detail::is_static_downcastable<Base, type>::value) {
+            rec.multiple_inheritance = true;
+        }
     }
 
     template <typename Base, detail::enable_if_t<!is_base<Base>::value, int> = 0>
@@ -2340,6 +2503,40 @@
         return def_buffer([func](const type &obj) { return (obj.*func)(); });
     }
 
+    // Intentionally no &&/const&& overloads: buffer protocol callbacks are invoked on an
+    // existing Python object and should not move-from self.
+    template <typename Return, typename Class, typename... Args>
+    class_ &def_buffer(Return (Class::*func)(Args...) &) {
+        return def_buffer([func](type &obj) { return (obj.*func)(); });
+    }
+
+    template <typename Return, typename Class, typename... Args>
+    class_ &def_buffer(Return (Class::*func)(Args...) const &) {
+        return def_buffer([func](const type &obj) { return (obj.*func)(); });
+    }
+
+#ifdef __cpp_noexcept_function_type
+    template <typename Return, typename Class, typename... Args>
+    class_ &def_buffer(Return (Class::*func)(Args...) noexcept) {
+        return def_buffer([func](type &obj) { return (obj.*func)(); });
+    }
+
+    template <typename Return, typename Class, typename... Args>
+    class_ &def_buffer(Return (Class::*func)(Args...) const noexcept) {
+        return def_buffer([func](const type &obj) { return (obj.*func)(); });
+    }
+
+    template <typename Return, typename Class, typename... Args>
+    class_ &def_buffer(Return (Class::*func)(Args...) & noexcept) {
+        return def_buffer([func](type &obj) { return (obj.*func)(); });
+    }
+
+    template <typename Return, typename Class, typename... Args>
+    class_ &def_buffer(Return (Class::*func)(Args...) const & noexcept) {
+        return def_buffer([func](const type &obj) { return (obj.*func)(); });
+    }
+#endif
+
     template <typename C, typename D, typename... Extra>
     class_ &def_readwrite(const char *name, D C::*pm, const Extra &...extra) {
         static_assert(std::is_same<C, type>::value || std::is_base_of<C, type>::value,
@@ -2467,19 +2664,41 @@
         if (rec_fget) {
             char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific
                                                documentation string */
+            auto args_before = rec_fget->args.size();
             detail::process_attributes<Extra...>::init(extra..., rec_fget);
             if (rec_fget->doc && rec_fget->doc != doc_prev) {
                 std::free(doc_prev);
                 rec_fget->doc = PYBIND11_COMPAT_STRDUP(rec_fget->doc);
             }
+            // Args added by process_attributes (e.g. "self" via is_method + pos_only/kw_only)
+            // need their strings strdup'd: initialize_generic's strdup loop already ran during
+            // cpp_function construction, so it won't process these late additions. Without this,
+            // destruct() would call free() on string literals. See gh-5976.
+            for (auto i = args_before; i < rec_fget->args.size(); ++i) {
+                if (rec_fget->args[i].name) {
+                    rec_fget->args[i].name = PYBIND11_COMPAT_STRDUP(rec_fget->args[i].name);
+                }
+                if (rec_fget->args[i].descr) {
+                    rec_fget->args[i].descr = PYBIND11_COMPAT_STRDUP(rec_fget->args[i].descr);
+                }
+            }
         }
         if (rec_fset) {
             char *doc_prev = rec_fset->doc;
+            auto args_before = rec_fset->args.size();
             detail::process_attributes<Extra...>::init(extra..., rec_fset);
             if (rec_fset->doc && rec_fset->doc != doc_prev) {
                 std::free(doc_prev);
                 rec_fset->doc = PYBIND11_COMPAT_STRDUP(rec_fset->doc);
             }
+            for (auto i = args_before; i < rec_fset->args.size(); ++i) {
+                if (rec_fset->args[i].name) {
+                    rec_fset->args[i].name = PYBIND11_COMPAT_STRDUP(rec_fset->args[i].name);
+                }
+                if (rec_fset->args[i].descr) {
+                    rec_fset->args[i].descr = PYBIND11_COMPAT_STRDUP(rec_fset->args[i].descr);
+                }
+            }
             if (!rec_active) {
                 rec_active = rec_fset;
             }
@@ -3299,13 +3518,10 @@
 
 template <typename InputType, typename OutputType>
 void implicitly_convertible() {
-    static int tss_sentinel_pointee = 1; // arbitrary value
     struct set_flag {
-        thread_specific_storage<int> &flag;
-        explicit set_flag(thread_specific_storage<int> &flag_) : flag(flag_) {
-            flag = &tss_sentinel_pointee; // trick: the pointer itself is the sentinel
-        }
-        ~set_flag() { flag.reset(nullptr); }
+        bool &flag;
+        explicit set_flag(bool &flag_) : flag(flag_) { flag_ = true; }
+        ~set_flag() { flag = false; }
 
         // Prevent copying/moving to ensure RAII guard is used safely
         set_flag(const set_flag &) = delete;
@@ -3314,7 +3530,7 @@
         set_flag &operator=(set_flag &&) = delete;
     };
     auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * {
-        static thread_specific_storage<int> currently_used;
+        thread_local bool currently_used = false;
         if (currently_used) { // implicit conversions are non-reentrant
             return nullptr;
         }
diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h
index 30eae09..ff4be6a 100644
--- a/include/pybind11/pytypes.h
+++ b/include/pybind11/pytypes.h
@@ -259,8 +259,7 @@
         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>
+                            int> = 0>
     // NOLINTNEXTLINE(google-explicit-constructor)
     handle(T &obj) : m_ptr(obj) {}
 
@@ -1694,8 +1693,7 @@
     template <typename T,
               detail::enable_if_t<!std::is_base_of<object, detail::remove_cvref_t<T>>::value
                                       && std::is_constructible<handle, T>::value,
-                                  int>
-              = 0>
+                                  int> = 0>
     explicit str(T &&h) : object(raw_str(handle(std::forward<T>(h)).ptr()), stolen_t{}) {
         if (!m_ptr) {
             throw error_already_set();
diff --git a/pyproject.toml b/pyproject.toml
index 7a12eed..6a30098 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -57,9 +57,11 @@
 test = [
   "pytest",
   "build",
-  "tomlkit",
 ]
-dev = [{ include-group = "test" }]
+dev = [
+  "tomlkit",
+  { include-group = "test" }
+]
 
 
 [tool.scikit-build]
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 9a35052..e87b1e9 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -172,6 +172,7 @@
     test_scoped_critical_section
     test_sequences_and_iterators
     test_smart_ptr
+    test_standalone_enum_module.py
     test_stl
     test_stl_binders
     test_tagbased_polymorphic
@@ -249,6 +250,7 @@
 tests_extra_targets("test_gil_scoped.py" "cross_module_gil_utils")
 tests_extra_targets("test_cpp_conduit.py"
                     "exo_planet_pybind11;exo_planet_c_api;home_planet_very_lonely_traveler")
+tests_extra_targets("test_standalone_enum_module.py" "standalone_enum_module")
 
 set(PYBIND11_EIGEN_REPO
     "https://gitlab.com/libeigen/eigen.git"
diff --git a/tests/env.py b/tests/env.py
index 790a010..12acde7 100644
--- a/tests/env.py
+++ b/tests/env.py
@@ -4,6 +4,8 @@
 import sys
 import sysconfig
 
+import pytest
+
 ANDROID = sys.platform.startswith("android")
 IOS = sys.platform.startswith("ios")
 LINUX = sys.platform.startswith("linux")
@@ -50,6 +52,9 @@
     import sys
     import textwrap
 
+    if ANDROID or IOS or sys.platform.startswith("emscripten"):
+        pytest.skip("Requires subprocess support")
+
     code = textwrap.dedent(code).strip()
     try:
         for _ in range(rerun):  # run flakily failing test multiple times
diff --git a/tests/pybind11_tests.cpp b/tests/pybind11_tests.cpp
index 4317925..5dacd7a 100644
--- a/tests/pybind11_tests.cpp
+++ b/tests/pybind11_tests.cpp
@@ -96,6 +96,12 @@
 #else
         false;
 #endif
+    m.attr("PYBIND11_TEST_SMART_HOLDER") =
+#if defined(PYBIND11_RUN_TESTING_WITH_SMART_HOLDER_AS_DEFAULT_BUT_NEVER_USE_IN_PRODUCTION_PLEASE)
+        true;
+#else
+        false;
+#endif
 
     bind_ConstructorStats(m);
 
@@ -105,6 +111,12 @@
     m.attr("detailed_error_messages_enabled") = false;
 #endif
 
+#if defined(__cpp_noexcept_function_type)
+    m.attr("defined___cpp_noexcept_function_type") = true;
+#else
+    m.attr("defined___cpp_noexcept_function_type") = false;
+#endif
+
     py::class_<UserType>(m, "UserType", "A `py::class_` type for testing")
         .def(py::init<>())
         .def(py::init<int>())
diff --git a/tests/standalone_enum_module.cpp b/tests/standalone_enum_module.cpp
new file mode 100644
index 0000000..7e917b9
--- /dev/null
+++ b/tests/standalone_enum_module.cpp
@@ -0,0 +1,13 @@
+// Copyright (c) 2026 The pybind Community.
+
+#include <pybind11/pybind11.h>
+
+namespace standalone_enum_module_ns {
+enum SomeEnum {};
+} // namespace standalone_enum_module_ns
+
+using namespace standalone_enum_module_ns;
+
+PYBIND11_MODULE(standalone_enum_module, m) { // Added in PR #6015
+    pybind11::enum_<SomeEnum> some_enum_wrapper(m, "SomeEnum");
+}
diff --git a/tests/test_buffers.cpp b/tests/test_buffers.cpp
index 525be80..5ac4553 100644
--- a/tests/test_buffers.cpp
+++ b/tests/test_buffers.cpp
@@ -439,4 +439,133 @@
         PyBuffer_Release(&buffer);
         return result;
     });
+
+    // test_noexcept_def_buffer (issue #2234)
+    // def_buffer(Return (Class::*)(Args...) noexcept) and
+    // def_buffer(Return (Class::*)(Args...) const noexcept) must compile and work correctly.
+    struct OneDBuffer {
+        // Declare m_data before m_n to match initialiser list order below.
+        float *m_data;
+        py::ssize_t m_n;
+        explicit OneDBuffer(py::ssize_t n) : m_data(new float[(size_t) n]()), m_n(n) {}
+        ~OneDBuffer() { delete[] m_data; }
+        // Exercises def_buffer(Return (Class::*)(Args...) noexcept)
+        py::buffer_info get_buffer() noexcept {
+            return py::buffer_info(m_data,
+                                   sizeof(float),
+                                   py::format_descriptor<float>::format(),
+                                   1,
+                                   {m_n},
+                                   {(py::ssize_t) sizeof(float)});
+        }
+    };
+
+    // non-const noexcept member function form
+    py::class_<OneDBuffer>(m, "OneDBuffer", py::buffer_protocol())
+        .def(py::init<py::ssize_t>())
+        .def_buffer(&OneDBuffer::get_buffer);
+
+    // const noexcept member function form (separate class to avoid ambiguity)
+    struct OneDBufferConst {
+        float *m_data;
+        py::ssize_t m_n;
+        explicit OneDBufferConst(py::ssize_t n) : m_data(new float[(size_t) n]()), m_n(n) {}
+        ~OneDBufferConst() { delete[] m_data; }
+        // Exercises def_buffer(Return (Class::*)(Args...) const noexcept)
+        py::buffer_info get_buffer() const noexcept {
+            return py::buffer_info(m_data,
+                                   sizeof(float),
+                                   py::format_descriptor<float>::format(),
+                                   1,
+                                   {m_n},
+                                   {(py::ssize_t) sizeof(float)},
+                                   /*readonly=*/true);
+        }
+    };
+    py::class_<OneDBufferConst>(m, "OneDBufferConst", py::buffer_protocol())
+        .def(py::init<py::ssize_t>())
+        .def_buffer(&OneDBufferConst::get_buffer);
+
+    // test_ref_qualified_def_buffer
+    struct OneDBufferLRef {
+        float *m_data;
+        py::ssize_t m_n;
+        explicit OneDBufferLRef(py::ssize_t n) : m_data(new float[(size_t) n]()), m_n(n) {}
+        ~OneDBufferLRef() { delete[] m_data; }
+        // Exercises def_buffer(Return (Class::*)(Args...) &)
+        py::buffer_info get_buffer() & {
+            return py::buffer_info(m_data,
+                                   sizeof(float),
+                                   py::format_descriptor<float>::format(),
+                                   1,
+                                   {m_n},
+                                   {(py::ssize_t) sizeof(float)});
+        }
+    };
+    py::class_<OneDBufferLRef>(m, "OneDBufferLRef", py::buffer_protocol())
+        .def(py::init<py::ssize_t>())
+        .def_buffer(&OneDBufferLRef::get_buffer);
+
+    struct OneDBufferConstLRef {
+        float *m_data;
+        py::ssize_t m_n;
+        explicit OneDBufferConstLRef(py::ssize_t n) : m_data(new float[(size_t) n]()), m_n(n) {}
+        ~OneDBufferConstLRef() { delete[] m_data; }
+        // Exercises def_buffer(Return (Class::*)(Args...) const &)
+        py::buffer_info get_buffer() const & {
+            return py::buffer_info(m_data,
+                                   sizeof(float),
+                                   py::format_descriptor<float>::format(),
+                                   1,
+                                   {m_n},
+                                   {(py::ssize_t) sizeof(float)},
+                                   /*readonly=*/true);
+        }
+    };
+    py::class_<OneDBufferConstLRef>(m, "OneDBufferConstLRef", py::buffer_protocol())
+        .def(py::init<py::ssize_t>())
+        .def_buffer(&OneDBufferConstLRef::get_buffer);
+
+#ifdef __cpp_noexcept_function_type
+    struct OneDBufferLRefNoexcept {
+        float *m_data;
+        py::ssize_t m_n;
+        explicit OneDBufferLRefNoexcept(py::ssize_t n) : m_data(new float[(size_t) n]()), m_n(n) {}
+        ~OneDBufferLRefNoexcept() { delete[] m_data; }
+        // Exercises def_buffer(Return (Class::*)(Args...) & noexcept)
+        py::buffer_info get_buffer() & noexcept {
+            return py::buffer_info(m_data,
+                                   sizeof(float),
+                                   py::format_descriptor<float>::format(),
+                                   1,
+                                   {m_n},
+                                   {(py::ssize_t) sizeof(float)});
+        }
+    };
+    py::class_<OneDBufferLRefNoexcept>(m, "OneDBufferLRefNoexcept", py::buffer_protocol())
+        .def(py::init<py::ssize_t>())
+        .def_buffer(&OneDBufferLRefNoexcept::get_buffer);
+
+    struct OneDBufferConstLRefNoexcept {
+        float *m_data;
+        py::ssize_t m_n;
+        explicit OneDBufferConstLRefNoexcept(py::ssize_t n)
+            : m_data(new float[(size_t) n]()), m_n(n) {}
+        ~OneDBufferConstLRefNoexcept() { delete[] m_data; }
+        // Exercises def_buffer(Return (Class::*)(Args...) const & noexcept)
+        py::buffer_info get_buffer() const & noexcept {
+            return py::buffer_info(m_data,
+                                   sizeof(float),
+                                   py::format_descriptor<float>::format(),
+                                   1,
+                                   {m_n},
+                                   {(py::ssize_t) sizeof(float)},
+                                   /*readonly=*/true);
+        }
+    };
+    py::class_<OneDBufferConstLRefNoexcept>(
+        m, "OneDBufferConstLRefNoexcept", py::buffer_protocol())
+        .def(py::init<py::ssize_t>())
+        .def_buffer(&OneDBufferConstLRefNoexcept::get_buffer);
+#endif
 }
diff --git a/tests/test_buffers.py b/tests/test_buffers.py
index f666df5..c1d5770 100644
--- a/tests/test_buffers.py
+++ b/tests/test_buffers.py
@@ -7,7 +7,7 @@
 import pytest
 
 import env
-from pybind11_tests import ConstructorStats
+from pybind11_tests import ConstructorStats, defined___cpp_noexcept_function_type
 from pybind11_tests import buffers as m
 
 np = pytest.importorskip("numpy")
@@ -399,3 +399,73 @@
         m.get_py_buffer(dmat, m.PyBUF_ANY_CONTIGUOUS)
     with pytest.raises(expected_exception):
         m.get_py_buffer(dmat, m.PyBUF_F_CONTIGUOUS)
+
+
+def test_noexcept_def_buffer():
+    """Test issue #2234: def_buffer with noexcept member function pointers.
+
+    Covers both new def_buffer specialisations:
+      - def_buffer(Return (Class::*)(Args...) noexcept)
+      - def_buffer(Return (Class::*)(Args...) const noexcept)
+    """
+    # non-const noexcept member function form
+    buf = m.OneDBuffer(5)
+    arr = np.frombuffer(buf, dtype=np.float32)
+    assert arr.shape == (5,)
+    arr[2] = 3.14
+    arr2 = np.frombuffer(buf, dtype=np.float32)
+    assert arr2[2] == pytest.approx(3.14)
+
+    # const noexcept member function form
+    cbuf = m.OneDBufferConst(4)
+    carr = np.frombuffer(cbuf, dtype=np.float32)
+    assert carr.shape == (4,)
+    assert carr.flags["WRITEABLE"] is False
+
+
+def test_ref_qualified_def_buffer():
+    """Test issue #2234 follow-up: def_buffer with ref-qualified member function pointers.
+
+    Covers:
+      - def_buffer(Return (Class::*)(Args...) &)
+      - def_buffer(Return (Class::*)(Args...) const &)
+      - def_buffer(Return (Class::*)(Args...) & noexcept)
+      - def_buffer(Return (Class::*)(Args...) const & noexcept)
+    """
+    # non-const lvalue ref-qualified member function form
+    buf = m.OneDBufferLRef(5)
+    arr = np.frombuffer(buf, dtype=np.float32)
+    assert arr.shape == (5,)
+    arr[1] = 2.5
+    arr2 = np.frombuffer(buf, dtype=np.float32)
+    assert arr2[1] == pytest.approx(2.5)
+
+    # const lvalue ref-qualified member function form
+    cbuf = m.OneDBufferConstLRef(4)
+    carr = np.frombuffer(cbuf, dtype=np.float32)
+    assert carr.shape == (4,)
+    assert carr.flags["WRITEABLE"] is False
+
+
+@pytest.mark.skipif(
+    not defined___cpp_noexcept_function_type,
+    reason="Requires __cpp_noexcept_function_type",
+)
+def test_ref_qualified_noexcept_def_buffer():
+    """Test issue #2234 follow-up: def_buffer with noexcept ref-qualified member pointers.
+
+    Covers:
+      - def_buffer(Return (Class::*)(Args...) & noexcept)
+      - def_buffer(Return (Class::*)(Args...) const & noexcept)
+    """
+    nbuf = m.OneDBufferLRefNoexcept(3)
+    narr = np.frombuffer(nbuf, dtype=np.float32)
+    assert narr.shape == (3,)
+    narr[2] = 7.0
+    narr2 = np.frombuffer(nbuf, dtype=np.float32)
+    assert narr2[2] == pytest.approx(7.0)
+
+    ncbuf = m.OneDBufferConstLRefNoexcept(2)
+    ncarr = np.frombuffer(ncbuf, dtype=np.float32)
+    assert ncarr.shape == (2,)
+    assert ncarr.flags["WRITEABLE"] is False
diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py
index c0a57a7..327e41e 100644
--- a/tests/test_callbacks.py
+++ b/tests/test_callbacks.py
@@ -179,10 +179,11 @@
     # do some work async
     work = [1, 2, 3, 4]
     m.test_async_callback(gen_f(), work)
-    # wait until work is done
-    from time import sleep
-
-    sleep(0.5)
+    # Wait for all detached worker threads to finish.
+    deadline = time.monotonic() + 5.0
+    while len(res) < len(work) and time.monotonic() < deadline:
+        time.sleep(0.01)
+    assert len(res) == len(work), f"Timed out waiting for callbacks: res={res!r}"
     assert sum(res) == sum(x + 3 for x in work)
 
 
diff --git a/tests/test_class_sh_property.cpp b/tests/test_class_sh_property.cpp
index 8863ad7..8777bdc 100644
--- a/tests/test_class_sh_property.cpp
+++ b/tests/test_class_sh_property.cpp
@@ -43,6 +43,24 @@
     const char *const_char_ptr_member = "ConstChar*";
 };
 
+// See PR #6008
+enum class EnumAB {
+    A = 0,
+    B = 1,
+};
+
+struct ShWithEnumABMember {
+    EnumAB level = EnumAB::A;
+};
+
+struct SimpleStruct {
+    int value = 7;
+};
+
+struct ShWithSimpleStructMember {
+    SimpleStruct legacy;
+};
+
 } // namespace test_class_sh_property
 
 TEST_SUBMODULE(class_sh_property, m) {
@@ -91,4 +109,21 @@
     py::classh<WithConstCharPtrMember>(m, "WithConstCharPtrMember")
         .def(py::init<>())
         .def_readonly("const_char_ptr_member", &WithConstCharPtrMember::const_char_ptr_member);
+
+    // See PR #6008
+    py::enum_<EnumAB>(m, "EnumAB").value("A", EnumAB::A).value("B", EnumAB::B);
+
+    py::classh<ShWithEnumABMember>(m, "ShWithEnumABMember")
+        .def(py::init<>())
+        .def_readwrite("level", &ShWithEnumABMember::level);
+
+    py::class_<SimpleStruct>(m, "SimpleStruct")
+        .def(py::init<>())
+        .def_readwrite("value", &SimpleStruct::value);
+
+    py::classh<ShWithSimpleStructMember>(m, "ShWithSimpleStructMember")
+        .def(py::init<>())
+        .def_readwrite("legacy", &ShWithSimpleStructMember::legacy);
+
+    m.def("getSimpleStructAsShared", []() { return std::make_shared<SimpleStruct>(); });
 }
diff --git a/tests/test_class_sh_property.py b/tests/test_class_sh_property.py
index 0250a7f..4a7b77c 100644
--- a/tests/test_class_sh_property.py
+++ b/tests/test_class_sh_property.py
@@ -5,6 +5,7 @@
 import pytest
 
 import env  # noqa: F401
+import pybind11_tests
 from pybind11_tests import class_sh_property as m
 
 
@@ -164,3 +165,42 @@
 def test_readonly_const_char_ptr_member():
     obj = m.WithConstCharPtrMember()
     assert obj.const_char_ptr_member == "ConstChar*"
+
+
+# See PR #6008
+def test_enum_member_with_smart_holder_def_readwrite():
+    obj = m.ShWithEnumABMember()
+    assert obj.level == m.EnumAB.A
+    for _ in range(100):
+        v = obj.level
+        assert v == m.EnumAB.A
+        del v
+
+
+# See PR #6008
+def test_non_smart_holder_member_type_with_smart_holder_owner():
+    obj = m.ShWithSimpleStructMember()
+    for _ in range(1000):
+        v = obj.legacy
+        assert v.value == 7
+        del v
+
+
+# See PR #6008, previously this was UB
+@pytest.mark.skipif(
+    pybind11_tests.PYBIND11_TEST_SMART_HOLDER,
+    reason="PYBIND11_TEST_SMART_HOLDER changes the default holder",
+)
+def test_shared_ptr_return_for_unique_ptr_holder():
+    with pytest.raises(
+        RuntimeError,
+        match="Unable to convert std::shared_ptr<T> to Python when the bound type does not use std::shared_ptr or py::smart_holder as its holder type",
+    ):
+        m.getSimpleStructAsShared()
+
+
+def test_non_smart_holder_member_type_with_smart_holder_owner_aliases_member():
+    obj = m.ShWithSimpleStructMember()
+    legacy = obj.legacy
+    legacy.value = 13
+    assert obj.legacy.value == 13
diff --git a/tests/test_custom_type_setup.py b/tests/test_custom_type_setup.py
index 4c6b951..a200b02 100644
--- a/tests/test_custom_type_setup.py
+++ b/tests/test_custom_type_setup.py
@@ -2,7 +2,6 @@
 
 import gc
 import os
-import sys
 import weakref
 
 import pytest
@@ -52,10 +51,6 @@
     gc_tester(obj)
 
 
-@pytest.mark.skipif(
-    env.IOS or sys.platform.startswith("emscripten"),
-    reason="Requires subprocess support",
-)
 @pytest.mark.skipif("env.PYPY or env.GRAALPY")
 def test_py_cast_useable_on_shutdown():
     """Test that py::cast works during interpreter shutdown.
diff --git a/tests/test_gil_scoped.py b/tests/test_gil_scoped.py
index 84a7a99..fc998b0 100644
--- a/tests/test_gil_scoped.py
+++ b/tests/test_gil_scoped.py
@@ -168,6 +168,9 @@
 
 
 def _run_in_process(target, *args, **kwargs):
+    if env.ANDROID or env.IOS or sys.platform.startswith("emscripten"):
+        pytest.skip("Requires subprocess support")
+
     test_fn = target if len(args) == 0 else args[0]
     # Do not need to wait much, 10s should be more than enough.
     timeout = 0.1 if test_fn is _intentional_deadlock else 10
diff --git a/tests/test_methods_and_attributes.cpp b/tests/test_methods_and_attributes.cpp
index e324c8b..86b7493 100644
--- a/tests/test_methods_and_attributes.cpp
+++ b/tests/test_methods_and_attributes.cpp
@@ -11,6 +11,12 @@
 #include "constructor_stats.h"
 #include "pybind11_tests.h"
 
+#if !defined(PYPY_VERSION)
+// Flag set by the capsule destructor in test_dynamic_attr_dealloc_frees_dict_contents.
+// File scope so the captureless capsule destructor (void(*)(void*)) can access it.
+static bool s_dynamic_attr_capsule_freed = false;
+#endif
+
 #if !defined(PYBIND11_OVERLOAD_CAST)
 template <typename... Args>
 using overload_cast_ = pybind11::detail::overload_cast_impl<Args...>;
@@ -161,6 +167,123 @@
     double sum() const { return rw_value + ro_value; }
 };
 
+// Issue #2234: noexcept methods in an unregistered base should be bindable on the derived class.
+// In C++17, noexcept is part of the function type, so &Derived::method resolves to
+// a Base member function pointer with noexcept, requiring explicit template specializations.
+class NoexceptUnregisteredBase {
+public:
+    // Exercises cpp_function(Return (Class::*)(Args...) const noexcept, ...)
+    int value() const noexcept { return m_value; }
+    // Exercises cpp_function(Return (Class::*)(Args...) noexcept, ...)
+    void set_value(int v) noexcept { m_value = v; }
+    // Exercises cpp_function(Return (Class::*)(Args...) & noexcept, ...)
+    void increment() & noexcept { ++m_value; }
+    // Exercises cpp_function(Return (Class::*)(Args...) const & noexcept, ...)
+    int capped_value() const & noexcept { return m_value < 100 ? m_value : 100; }
+
+private:
+    int m_value = 99;
+};
+class NoexceptDerived : public NoexceptUnregisteredBase {
+public:
+    using NoexceptUnregisteredBase::NoexceptUnregisteredBase;
+};
+
+// Exercises cpp_function(Return (Class::*)(Args...) &&, ...) and
+// cpp_function(Return (Class::*)(Args...) const &&, ...) via an unregistered base.
+class RValueRefUnregisteredBase {
+public:
+    // Exercises cpp_function(Return (Class::*)(Args...) &&, ...).
+    // Moves m_payload to verify that std::move(*c).*f is used in the lambda body.
+    std::string take() && { // NOLINT(readability-make-member-function-const)
+        return std::move(m_payload);
+    }
+    // Exercises cpp_function(Return (Class::*)(Args...) const &&, ...)
+    int peek() const && { return m_value; }
+#ifdef __cpp_noexcept_function_type
+    // Exercises cpp_function(Return (Class::*)(Args...) && noexcept, ...)
+    std::string take_noexcept() && noexcept { // NOLINT(readability-make-member-function-const)
+        return std::move(m_payload);
+    }
+    // Exercises cpp_function(Return (Class::*)(Args...) const && noexcept, ...)
+    int peek_noexcept() const && noexcept { return m_value; }
+#endif
+
+private:
+    int m_value = 77;
+    std::string m_payload{"rref_payload"};
+};
+class RValueRefDerived : public RValueRefUnregisteredBase {
+public:
+    using RValueRefUnregisteredBase::RValueRefUnregisteredBase;
+};
+
+// Exercises overload_cast with noexcept member function pointers (issue #2234).
+// In C++17, overload_cast must have noexcept variants to resolve noexcept overloads.
+struct NoexceptOverloaded {
+    py::str method(int) noexcept { return "(int)"; }
+    py::str method(int) const noexcept { return "(int) const"; }
+    py::str method(float) noexcept { return "(float)"; }
+};
+// Exercises overload_cast with noexcept free function pointers.
+int noexcept_free_func(int x) noexcept { return x + 1; }
+int noexcept_free_func(float x) noexcept { return static_cast<int>(x) + 2; }
+
+// Exercises overload_cast with ref-qualified member function pointers.
+struct RefQualifiedOverloaded {
+    py::str method(int) & { return "(int) &"; }
+    py::str method(int) const & { return "(int) const &"; }
+    py::str method(float) && { return "(float) &&"; }
+    py::str method(float) const && { return "(float) const &&"; }
+#ifdef __cpp_noexcept_function_type
+    py::str method(long) & noexcept { return "(long) & noexcept"; }
+    py::str method(long) const & noexcept { return "(long) const & noexcept"; }
+    py::str method(double) && noexcept { return "(double) && noexcept"; }
+    py::str method(double) const && noexcept { return "(double) const && noexcept"; }
+#endif
+};
+
+// Compile-only guard: catch overload_cast resolution regressions/ambiguities early.
+using RefQualifiedOverloadedIntCast = py::detail::overload_cast_impl<int>;
+using RefQualifiedOverloadedFloatCast = py::detail::overload_cast_impl<float>;
+static_assert(
+    std::is_same<decltype(RefQualifiedOverloadedIntCast{}(&RefQualifiedOverloaded::method)),
+                 py::str (RefQualifiedOverloaded::*)(int) &>::value,
+    "");
+static_assert(std::is_same<decltype(RefQualifiedOverloadedIntCast{}(
+                               &RefQualifiedOverloaded::method, py::const_)),
+                           py::str (RefQualifiedOverloaded::*)(int) const &>::value,
+              "");
+static_assert(
+    std::is_same<decltype(RefQualifiedOverloadedFloatCast{}(&RefQualifiedOverloaded::method)),
+                 py::str (RefQualifiedOverloaded::*)(float) &&>::value,
+    "");
+static_assert(std::is_same<decltype(RefQualifiedOverloadedFloatCast{}(
+                               &RefQualifiedOverloaded::method, py::const_)),
+                           py::str (RefQualifiedOverloaded::*)(float) const &&>::value,
+              "");
+
+#ifdef __cpp_noexcept_function_type
+using RefQualifiedOverloadedLongCast = py::detail::overload_cast_impl<long>;
+using RefQualifiedOverloadedDoubleCast = py::detail::overload_cast_impl<double>;
+static_assert(
+    std::is_same<decltype(RefQualifiedOverloadedLongCast{}(&RefQualifiedOverloaded::method)),
+                 py::str (RefQualifiedOverloaded::*)(long) & noexcept>::value,
+    "");
+static_assert(std::is_same<decltype(RefQualifiedOverloadedLongCast{}(
+                               &RefQualifiedOverloaded::method, py::const_)),
+                           py::str (RefQualifiedOverloaded::*)(long) const & noexcept>::value,
+              "");
+static_assert(
+    std::is_same<decltype(RefQualifiedOverloadedDoubleCast{}(&RefQualifiedOverloaded::method)),
+                 py::str (RefQualifiedOverloaded::*)(double) && noexcept>::value,
+    "");
+static_assert(std::is_same<decltype(RefQualifiedOverloadedDoubleCast{}(
+                               &RefQualifiedOverloaded::method, py::const_)),
+                           py::str (RefQualifiedOverloaded::*)(double) const && noexcept>::value,
+              "");
+#endif
+
 // Test explicit lvalue ref-qualification
 struct RefQualified {
     int value = 0;
@@ -388,6 +511,24 @@
 
     class CppDerivedDynamicClass : public DynamicClass {};
     py::class_<CppDerivedDynamicClass, DynamicClass>(m, "CppDerivedDynamicClass").def(py::init());
+
+    // test_dynamic_attr_dealloc_frees_dict_contents
+    // Regression test: pybind11_object_dealloc() must call PyObject_ClearManagedDict()
+    // before tp_free() so that objects stored in a py::dynamic_attr() instance __dict__
+    // have their refcounts decremented when the pybind11 object is freed. On Python 3.14+
+    // tp_free no longer implicitly clears the managed dict, causing permanent leaks.
+    m.def("make_dynamic_attr_with_capsule", []() -> py::object {
+        s_dynamic_attr_capsule_freed = false;
+        auto *dummy = new int(0);
+        py::capsule cap(dummy, [](void *ptr) {
+            delete static_cast<int *>(ptr);
+            s_dynamic_attr_capsule_freed = true;
+        });
+        py::object obj = py::cast(new DynamicClass(), py::return_value_policy::take_ownership);
+        obj.attr("data") = cap;
+        return obj;
+    });
+    m.def("is_dynamic_attr_capsule_freed", []() { return s_dynamic_attr_capsule_freed; });
 #endif
 
     // test_bad_arg_default
@@ -474,6 +615,161 @@
         = decltype(py::method_adaptor<RegisteredDerived>(&RegisteredDerived::do_nothing));
     static_assert(std::is_same<Adapted, void (RegisteredDerived::*)() const>::value, "");
 
+    // test_noexcept_base (issue #2234)
+    // In C++17, noexcept is part of the function type. Binding a noexcept method from an
+    // unregistered base class must resolve `self` to the derived type, not the base type.
+    py::class_<NoexceptDerived>(m, "NoexceptDerived")
+        .def(py::init<>())
+        // cpp_function(Return (Class::*)(Args...) const noexcept, ...)
+        .def("value", &NoexceptDerived::value)
+        // cpp_function(Return (Class::*)(Args...) noexcept, ...)
+        .def("set_value", &NoexceptDerived::set_value)
+        // cpp_function(Return (Class::*)(Args...) & noexcept, ...)
+        .def("increment", &NoexceptDerived::increment)
+        // cpp_function(Return (Class::*)(Args...) const & noexcept, ...)
+        .def("capped_value", &NoexceptDerived::capped_value);
+
+    // test_rvalue_ref_qualified_methods: rvalue-ref-qualified methods from an unregistered base.
+    // method_adaptor must rebind &&/const&& member pointers to the derived type.
+    py::class_<RValueRefDerived>(m, "RValueRefDerived")
+        .def(py::init<>())
+        // cpp_function(Return (Class::*)(Args...) &&, ...)
+        .def("take", &RValueRefDerived::take)
+        // cpp_function(Return (Class::*)(Args...) const &&, ...)
+        .def("peek", &RValueRefDerived::peek)
+#ifdef __cpp_noexcept_function_type
+        // cpp_function(Return (Class::*)(Args...) && noexcept, ...)
+        .def("take_noexcept", &RValueRefDerived::take_noexcept)
+        // cpp_function(Return (Class::*)(Args...) const && noexcept, ...)
+        .def("peek_noexcept", &RValueRefDerived::peek_noexcept)
+#endif
+        ;
+
+    // Verify that &&-qualified methods cannot be called on lvalues, only on rvalues.
+    // This confirms that the cpp_function lambda must use std::move(*c).*f, not c->*f.
+#if __cplusplus >= 201703L
+    static_assert(!std::is_invocable<std::string (RValueRefUnregisteredBase::*)() &&,
+                                     RValueRefUnregisteredBase &>::value,
+                  "&&-qualified method must not be callable on lvalue");
+    static_assert(std::is_invocable<std::string (RValueRefUnregisteredBase::*)() &&,
+                                    RValueRefUnregisteredBase &&>::value,
+                  "&&-qualified method must be callable on rvalue");
+#endif
+
+    // Verify method_adaptor preserves &&/const&& qualifiers when rebinding.
+    using AdaptedRRef = decltype(py::method_adaptor<RValueRefDerived>(&RValueRefDerived::take));
+    static_assert(std::is_same<AdaptedRRef, std::string (RValueRefDerived::*)() &&>::value, "");
+    using AdaptedConstRRef
+        = decltype(py::method_adaptor<RValueRefDerived>(&RValueRefDerived::peek));
+    static_assert(std::is_same<AdaptedConstRRef, int (RValueRefDerived::*)() const &&>::value, "");
+
+#ifdef __cpp_noexcept_function_type
+    // method_adaptor must also handle noexcept member function pointers (issue #2234).
+    // Verify the noexcept specifier is preserved in the resulting Derived pointer type.
+    using AdaptedConstNoexcept
+        = decltype(py::method_adaptor<NoexceptDerived>(&NoexceptDerived::value));
+    static_assert(
+        std::is_same<AdaptedConstNoexcept, int (NoexceptDerived::*)() const noexcept>::value, "");
+    using AdaptedNoexcept
+        = decltype(py::method_adaptor<NoexceptDerived>(&NoexceptDerived::set_value));
+    static_assert(std::is_same<AdaptedNoexcept, void (NoexceptDerived::*)(int) noexcept>::value,
+                  "");
+    using AdaptedRRefNoexcept
+        = decltype(py::method_adaptor<RValueRefDerived>(&RValueRefDerived::take_noexcept));
+    static_assert(std::is_same < AdaptedRRefNoexcept,
+                  std::string (RValueRefDerived::*)() && noexcept > ::value,
+                  "");
+    using AdaptedConstRRefNoexcept
+        = decltype(py::method_adaptor<RValueRefDerived>(&RValueRefDerived::peek_noexcept));
+    static_assert(std::is_same < AdaptedConstRRefNoexcept,
+                  int (RValueRefDerived::*)() const && noexcept > ::value,
+                  "");
+#endif
+
+    // test_noexcept_overload_cast (issue #2234)
+    // overload_cast must have noexcept operator() overloads so it can resolve noexcept methods.
+#ifdef PYBIND11_OVERLOAD_CAST
+    py::class_<NoexceptOverloaded>(m, "NoexceptOverloaded")
+        .def(py::init<>())
+        // overload_cast_impl::operator()(Return (Class::*)(Args...) noexcept, false_type)
+        .def("method", py::overload_cast<int>(&NoexceptOverloaded::method))
+        // overload_cast_impl::operator()(Return (Class::*)(Args...) const noexcept, true_type)
+        .def("method_const", py::overload_cast<int>(&NoexceptOverloaded::method, py::const_))
+        // overload_cast_impl::operator()(Return (Class::*)(Args...) noexcept, false_type) float
+        .def("method_float", py::overload_cast<float>(&NoexceptOverloaded::method));
+    // overload_cast_impl::operator()(Return (*)(Args...) noexcept)
+    m.def("noexcept_free_func", py::overload_cast<int>(noexcept_free_func));
+    m.def("noexcept_free_func_float", py::overload_cast<float>(noexcept_free_func));
+
+    py::class_<RefQualifiedOverloaded>(m, "RefQualifiedOverloaded")
+        .def(py::init<>())
+        // overload_cast_impl::operator()(Return (Class::*)(Args...) &, false_type)
+        .def("method_lref", py::overload_cast<int>(&RefQualifiedOverloaded::method))
+        // overload_cast_impl::operator()(Return (Class::*)(Args...) const &, true_type)
+        .def("method_const_lref",
+             py::overload_cast<int>(&RefQualifiedOverloaded::method, py::const_))
+        // overload_cast_impl::operator()(Return (Class::*)(Args...) &&, false_type)
+        .def("method_rref", py::overload_cast<float>(&RefQualifiedOverloaded::method))
+        // overload_cast_impl::operator()(Return (Class::*)(Args...) const &&, true_type)
+        .def("method_const_rref",
+             py::overload_cast<float>(&RefQualifiedOverloaded::method, py::const_))
+#    ifdef __cpp_noexcept_function_type
+        // overload_cast_impl::operator()(Return (Class::*)(Args...) & noexcept, false_type)
+        .def("method_lref_noexcept", py::overload_cast<long>(&RefQualifiedOverloaded::method))
+        // overload_cast_impl::operator()(Return (Class::*)(Args...) const & noexcept, true_type)
+        .def("method_const_lref_noexcept",
+             py::overload_cast<long>(&RefQualifiedOverloaded::method, py::const_))
+        // overload_cast_impl::operator()(Return (Class::*)(Args...) && noexcept, false_type)
+        .def("method_rref_noexcept", py::overload_cast<double>(&RefQualifiedOverloaded::method))
+        // overload_cast_impl::operator()(Return (Class::*)(Args...) const && noexcept, true_type)
+        .def("method_const_rref_noexcept",
+             py::overload_cast<double>(&RefQualifiedOverloaded::method, py::const_))
+#    endif
+        ;
+#else
+    // Fallback using explicit static_cast for C++11/14
+    py::class_<NoexceptOverloaded>(m, "NoexceptOverloaded")
+        .def(py::init<>())
+        .def("method",
+             static_cast<py::str (NoexceptOverloaded::*)(int)>(&NoexceptOverloaded::method))
+        .def("method_const",
+             static_cast<py::str (NoexceptOverloaded::*)(int) const>(&NoexceptOverloaded::method))
+        .def("method_float",
+             static_cast<py::str (NoexceptOverloaded::*)(float)>(&NoexceptOverloaded::method));
+    m.def("noexcept_free_func", static_cast<int (*)(int)>(noexcept_free_func));
+    m.def("noexcept_free_func_float", static_cast<int (*)(float)>(noexcept_free_func));
+
+    py::class_<RefQualifiedOverloaded>(m, "RefQualifiedOverloaded")
+        .def(py::init<>())
+        .def("method_lref",
+             static_cast<py::str (RefQualifiedOverloaded::*)(int) &>(
+                 &RefQualifiedOverloaded::method))
+        .def("method_const_lref",
+             static_cast<py::str (RefQualifiedOverloaded::*)(int) const &>(
+                 &RefQualifiedOverloaded::method))
+        .def("method_rref",
+             static_cast<py::str (RefQualifiedOverloaded::*)(float) &&>(
+                 &RefQualifiedOverloaded::method))
+        .def("method_const_rref",
+             static_cast<py::str (RefQualifiedOverloaded::*)(float) const &&>(
+                 &RefQualifiedOverloaded::method))
+#    ifdef __cpp_noexcept_function_type
+        .def("method_lref_noexcept",
+             static_cast<py::str (RefQualifiedOverloaded::*)(long) & noexcept>(
+                 &RefQualifiedOverloaded::method))
+        .def("method_const_lref_noexcept",
+             static_cast<py::str (RefQualifiedOverloaded::*)(long) const & noexcept>(
+                 &RefQualifiedOverloaded::method))
+        .def("method_rref_noexcept",
+             static_cast < py::str (RefQualifiedOverloaded::*)(double)
+                 && noexcept > (&RefQualifiedOverloaded::method))
+        .def("method_const_rref_noexcept",
+             static_cast < py::str (RefQualifiedOverloaded::*)(double) const && noexcept
+                 > (&RefQualifiedOverloaded::method))
+#    endif
+        ;
+#endif
+
     // test_methods_and_attributes
     py::class_<RefQualified>(m, "RefQualified")
         .def(py::init<>())
diff --git a/tests/test_methods_and_attributes.py b/tests/test_methods_and_attributes.py
index 553d5bf..c094374 100644
--- a/tests/test_methods_and_attributes.py
+++ b/tests/test_methods_and_attributes.py
@@ -5,7 +5,7 @@
 import pytest
 
 import env
-from pybind11_tests import ConstructorStats
+from pybind11_tests import ConstructorStats, defined___cpp_noexcept_function_type
 from pybind11_tests import methods_and_attributes as m
 
 NO_GETTER_MSG = (
@@ -383,6 +383,23 @@
     assert cstats.alive() == 0
 
 
+@pytest.mark.xfail("env.PYPY", strict=False)
+@pytest.mark.skipif("env.GRAALPY", reason="Cannot reliably trigger GC")
+def test_dynamic_attr_dealloc_frees_dict_contents():
+    """Regression: py::dynamic_attr() objects must free __dict__ contents on dealloc.
+
+    pybind11_object_dealloc() did not call PyObject_ClearManagedDict() before tp_free(),
+    causing objects stored in __dict__ to have their refcounts permanently abandoned on
+    Python 3.14+ (where tp_free no longer implicitly clears the managed dict).
+    This caused capsule destructors to never run, leaking the underlying C++ data.
+    """
+    instance = m.make_dynamic_attr_with_capsule()
+    assert not m.is_dynamic_attr_capsule_freed()
+    del instance
+    pytest.gc_collect()
+    assert m.is_dynamic_attr_capsule_freed()
+
+
 def test_bad_arg_default(msg):
     from pybind11_tests import detailed_error_messages_enabled
 
@@ -517,6 +534,130 @@
     assert a.ro_value_prop == 1.75
 
 
+def test_noexcept_base():
+    """Test issue #2234: binding noexcept methods inherited from an unregistered base class.
+
+    In C++17 noexcept is part of the function type, so &Derived::noexcept_method resolves
+    to a Base member-function pointer with noexcept specifier.  pybind11 must use the Derived
+    type as `self`, not the Base type, otherwise the call raises TypeError at runtime.
+
+    Covers all four new cpp_function constructor specialisations:
+      - Return (Class::*)(Args...) noexcept          (set_value)
+      - Return (Class::*)(Args...) const noexcept    (value)
+      - Return (Class::*)(Args...) & noexcept        (increment)
+      - Return (Class::*)(Args...) const & noexcept  (capped_value)
+    """
+    obj = m.NoexceptDerived()
+    # const noexcept
+    assert obj.value() == 99
+    # noexcept (non-const)
+    obj.set_value(7)
+    assert obj.value() == 7
+    # & noexcept (non-const lvalue ref-qualified)
+    obj.increment()
+    assert obj.value() == 8
+    # const & noexcept (const lvalue ref-qualified)
+    assert obj.capped_value() == 8
+    obj.set_value(200)
+    assert obj.capped_value() == 100  # capped at 100
+
+
+def test_rvalue_ref_qualified_methods():
+    """Test that rvalue-ref-qualified (&&/const&&) methods from an unregistered base bind
+    correctly with `self` resolved to the derived type.
+
+    take() moves m_payload out on each call, so the second call returns "".
+    This confirms that the cpp_function lambda uses std::move(*c).*f rather than c->*f.
+
+    Covers:
+      - Return (Class::*)(Args...) &&              (take)
+      - Return (Class::*)(Args...) const &&        (peek)
+    """
+    obj = m.RValueRefDerived()
+    # && moves m_payload: first call gets the value, second gets empty string
+    assert obj.take() == "rref_payload"
+    assert obj.take() == ""
+    # const && doesn't move: peek() is stable across calls
+    assert obj.peek() == 77
+    assert obj.peek() == 77
+
+
+@pytest.mark.skipif(
+    not defined___cpp_noexcept_function_type,
+    reason="Requires __cpp_noexcept_function_type",
+)
+def test_noexcept_rvalue_ref_qualified_methods():
+    """Test noexcept rvalue-ref-qualified methods from an unregistered base.
+
+    Covers:
+      - Return (Class::*)(Args...) && noexcept       (take_noexcept)
+      - Return (Class::*)(Args...) const && noexcept (peek_noexcept)
+    """
+    obj = m.RValueRefDerived()
+    assert obj.take_noexcept() == "rref_payload"
+    assert obj.take_noexcept() == ""
+    assert obj.peek_noexcept() == 77
+    assert obj.peek_noexcept() == 77
+
+
+def test_noexcept_overload_cast():
+    """Test issue #2234: overload_cast must handle noexcept member and free function pointers.
+
+    In C++17 noexcept is part of the function type, so overload_cast_impl needs dedicated
+    operator() overloads for noexcept free functions and non-const/const member functions.
+    """
+    obj = m.NoexceptOverloaded()
+    # overload_cast_impl::operator()(Return (Class::*)(Args...) noexcept, false_type)
+    assert obj.method(1) == "(int)"
+    # overload_cast_impl::operator()(Return (Class::*)(Args...) const noexcept, true_type)
+    assert obj.method_const(2) == "(int) const"
+    # overload_cast_impl::operator()(Return (Class::*)(Args...) noexcept, false_type) float
+    assert obj.method_float(3.0) == "(float)"
+    # overload_cast_impl::operator()(Return (*)(Args...) noexcept)
+    assert m.noexcept_free_func(10) == 11
+    assert m.noexcept_free_func_float(10.0) == 12
+
+
+def test_ref_qualified_overload_cast():
+    """Test issue #2234 follow-up: overload_cast with ref-qualified member pointers.
+
+    Covers:
+      - overload_cast_impl::operator()(Return (Class::*)(Args...) &, false_type)
+      - overload_cast_impl::operator()(Return (Class::*)(Args...) const &, true_type)
+      - overload_cast_impl::operator()(Return (Class::*)(Args...) &&, false_type)
+      - overload_cast_impl::operator()(Return (Class::*)(Args...) const &&, true_type)
+      - overload_cast_impl::operator()(Return (Class::*)(Args...) & noexcept, false_type)
+      - overload_cast_impl::operator()(Return (Class::*)(Args...) const & noexcept, true_type)
+      - overload_cast_impl::operator()(Return (Class::*)(Args...) && noexcept, false_type)
+      - overload_cast_impl::operator()(Return (Class::*)(Args...) const && noexcept, true_type)
+    """
+    obj = m.RefQualifiedOverloaded()
+    assert obj.method_lref(1) == "(int) &"
+    assert obj.method_const_lref(1) == "(int) const &"
+    assert obj.method_rref(1.0) == "(float) &&"
+    assert obj.method_const_rref(1.0) == "(float) const &&"
+
+
+@pytest.mark.skipif(
+    not defined___cpp_noexcept_function_type,
+    reason="Requires __cpp_noexcept_function_type",
+)
+def test_noexcept_ref_qualified_overload_cast():
+    """Test issue #2234 follow-up: overload_cast with noexcept ref-qualified member pointers.
+
+    Covers:
+      - overload_cast_impl::operator()(Return (Class::*)(Args...) & noexcept, false_type)
+      - overload_cast_impl::operator()(Return (Class::*)(Args...) const & noexcept, true_type)
+      - overload_cast_impl::operator()(Return (Class::*)(Args...) && noexcept, false_type)
+      - overload_cast_impl::operator()(Return (Class::*)(Args...) const && noexcept, true_type)
+    """
+    obj = m.RefQualifiedOverloaded()
+    assert obj.method_lref_noexcept(1) == "(long) & noexcept"
+    assert obj.method_const_lref_noexcept(1) == "(long) const & noexcept"
+    assert obj.method_rref_noexcept(1.0) == "(double) && noexcept"
+    assert obj.method_const_rref_noexcept(1.0) == "(double) const && noexcept"
+
+
 def test_ref_qualified():
     """Tests that explicit lvalue ref-qualified methods can be called just like their
     non ref-qualified counterparts."""
diff --git a/tests/test_numpy_vectorize.cpp b/tests/test_numpy_vectorize.cpp
index dcc4c6a..2334521 100644
--- a/tests/test_numpy_vectorize.cpp
+++ b/tests/test_numpy_vectorize.cpp
@@ -78,6 +78,27 @@
     struct VectorizeTestClass {
         explicit VectorizeTestClass(int v) : value{v} {};
         float method(int x, float y) const { return y + (float) (x + value); }
+        // Exercises vectorize(Return (Class::*)(Args...) &)
+        // NOLINTNEXTLINE(readability-make-member-function-const)
+        float method_lref(int x, float y) & { return y + (float) (x + value); }
+        // Exercises vectorize(Return (Class::*)(Args...) const &)
+        float method_const_lref(int x, float y) const & { return y + (float) (x + value); }
+        // Exercises vectorize(Return (Class::*)(Args...) noexcept)
+        // NOLINTNEXTLINE(readability-make-member-function-const)
+        float method_noexcept(int x, float y) noexcept { return y + (float) (x + value); }
+        // Exercises vectorize(Return (Class::*)(Args...) const noexcept)
+        float method_const_noexcept(int x, float y) const noexcept {
+            return y + (float) (x + value);
+        }
+#ifdef __cpp_noexcept_function_type
+        // Exercises vectorize(Return (Class::*)(Args...) & noexcept)
+        // NOLINTNEXTLINE(readability-make-member-function-const)
+        float method_lref_noexcept(int x, float y) & noexcept { return y + (float) (x + value); }
+        // Exercises vectorize(Return (Class::*)(Args...) const & noexcept)
+        float method_const_lref_noexcept(int x, float y) const & noexcept {
+            return y + (float) (x + value);
+        }
+#endif
         int value = 0;
     };
     py::class_<VectorizeTestClass> vtc(m, "VectorizeTestClass");
@@ -85,6 +106,15 @@
 
     // Automatic vectorizing of methods
     vtc.def("method", py::vectorize(&VectorizeTestClass::method));
+    vtc.def("method_lref", py::vectorize(&VectorizeTestClass::method_lref));
+    vtc.def("method_const_lref", py::vectorize(&VectorizeTestClass::method_const_lref));
+    vtc.def("method_noexcept", py::vectorize(&VectorizeTestClass::method_noexcept));
+    vtc.def("method_const_noexcept", py::vectorize(&VectorizeTestClass::method_const_noexcept));
+#ifdef __cpp_noexcept_function_type
+    vtc.def("method_lref_noexcept", py::vectorize(&VectorizeTestClass::method_lref_noexcept));
+    vtc.def("method_const_lref_noexcept",
+            py::vectorize(&VectorizeTestClass::method_const_lref_noexcept));
+#endif
 
     // test_trivial_broadcasting
     // Internal optimization test for whether the input is trivially broadcastable:
diff --git a/tests/test_numpy_vectorize.py b/tests/test_numpy_vectorize.py
index 05f7c70..030abec 100644
--- a/tests/test_numpy_vectorize.py
+++ b/tests/test_numpy_vectorize.py
@@ -2,6 +2,7 @@
 
 import pytest
 
+from pybind11_tests import defined___cpp_noexcept_function_type
 from pybind11_tests import numpy_vectorize as m
 
 np = pytest.importorskip("numpy")
@@ -246,6 +247,56 @@
     assert np.all(o.method(x, y) == [[14, 15], [24, 25]])
 
 
+def test_ref_qualified_method_vectorization():
+    """Test issue #2234 follow-up: vectorize with lvalue-ref-qualified member pointers.
+
+    Covers:
+      - vectorize(Return (Class::*)(Args...) &)
+      - vectorize(Return (Class::*)(Args...) const &)
+      - vectorize(Return (Class::*)(Args...) & noexcept)
+      - vectorize(Return (Class::*)(Args...) const & noexcept)
+    """
+    o = m.VectorizeTestClass(3)
+    x = np.array([1, 2], dtype="int")
+    y = np.array([[10], [20]], dtype="float32")
+    assert np.all(o.method_lref(x, y) == [[14, 15], [24, 25]])
+    assert np.all(o.method_const_lref(x, y) == [[14, 15], [24, 25]])
+
+
+@pytest.mark.skipif(
+    not defined___cpp_noexcept_function_type,
+    reason="Requires __cpp_noexcept_function_type",
+)
+def test_noexcept_ref_qualified_method_vectorization():
+    """Test issue #2234 follow-up: vectorize with noexcept lvalue-ref-qualified member pointers.
+
+    Covers:
+      - vectorize(Return (Class::*)(Args...) & noexcept)
+      - vectorize(Return (Class::*)(Args...) const & noexcept)
+    """
+    o = m.VectorizeTestClass(3)
+    x = np.array([1, 2], dtype="int")
+    y = np.array([[10], [20]], dtype="float32")
+    assert np.all(o.method_lref_noexcept(x, y) == [[14, 15], [24, 25]])
+    assert np.all(o.method_const_lref_noexcept(x, y) == [[14, 15], [24, 25]])
+
+
+def test_noexcept_method_vectorization():
+    """Test issue #2234: vectorize must handle noexcept member function pointers.
+
+    Covers both new vectorize specialisations:
+      - vectorize(Return (Class::*)(Args...) noexcept)
+      - vectorize(Return (Class::*)(Args...) const noexcept)
+    """
+    o = m.VectorizeTestClass(3)
+    x = np.array([1, 2], dtype="int")
+    y = np.array([[10], [20]], dtype="float32")
+    # vectorize(Return (Class::*)(Args...) noexcept)
+    assert np.all(o.method_noexcept(x, y) == [[14, 15], [24, 25]])
+    # vectorize(Return (Class::*)(Args...) const noexcept)
+    assert np.all(o.method_const_noexcept(x, y) == [[14, 15], [24, 25]])
+
+
 def test_array_collapse():
     assert not isinstance(m.vectorized_func(1, 2, 3), np.ndarray)
     assert not isinstance(m.vectorized_func(np.array(1), 2, 3), np.ndarray)
diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp
index e214350..ff77940 100644
--- a/tests/test_pytypes.cpp
+++ b/tests/test_pytypes.cpp
@@ -1086,8 +1086,7 @@
     static_class.def(py::init());
     static_class.attr_with_type_hint<py::typing::ClassVar<float>>("x") = 1.0;
     static_class.attr_with_type_hint<py::typing::ClassVar<py::typing::Dict<py::str, int>>>(
-        "dict_str_int")
-        = py::dict();
+        "dict_str_int") = py::dict();
 
     struct Instance {};
     auto instance = py::class_<Instance>(m, "Instance", py::dynamic_attr());
diff --git a/tests/test_smart_ptr.cpp b/tests/test_smart_ptr.cpp
index 0ac1a41..3617fa3 100644
--- a/tests/test_smart_ptr.cpp
+++ b/tests/test_smart_ptr.cpp
@@ -247,6 +247,28 @@
 };
 struct SharedFromThisVirt : virtual SharedFromThisVBase {};
 
+// Issue #5989: static_pointer_cast where dynamic_pointer_cast is needed
+// (virtual inheritance with shared_ptr holder)
+struct SftVirtBase : std::enable_shared_from_this<SftVirtBase> {
+    SftVirtBase() = default;
+    virtual ~SftVirtBase() = default;
+    static std::shared_ptr<SftVirtBase> create() { return std::make_shared<SftVirtBase>(); }
+    virtual std::string name() { return "SftVirtBase"; }
+};
+struct SftVirtDerived : SftVirtBase {
+    using SftVirtBase::SftVirtBase;
+    static std::shared_ptr<SftVirtDerived> create() { return std::make_shared<SftVirtDerived>(); }
+    std::string name() override { return "SftVirtDerived"; }
+};
+struct SftVirtDerived2 : virtual SftVirtDerived {
+    using SftVirtDerived::SftVirtDerived;
+    static std::shared_ptr<SftVirtDerived2> create() {
+        return std::make_shared<SftVirtDerived2>();
+    }
+    std::string name() override { return "SftVirtDerived2"; }
+    std::string call_name(const std::shared_ptr<SftVirtDerived2> &d2) { return d2->name(); }
+};
+
 // test_move_only_holder
 struct C {
     C() { print_created(this); }
@@ -522,6 +544,17 @@
     py::class_<SharedFromThisVirt, std::shared_ptr<SharedFromThisVirt>>(m, "SharedFromThisVirt")
         .def_static("get", []() { return sft.get(); });
 
+    // Issue #5989: static_pointer_cast where dynamic_pointer_cast is needed
+    py::class_<SftVirtBase, std::shared_ptr<SftVirtBase>>(m, "SftVirtBase")
+        .def(py::init<>(&SftVirtBase::create))
+        .def("name", &SftVirtBase::name);
+    py::class_<SftVirtDerived, SftVirtBase, std::shared_ptr<SftVirtDerived>>(m, "SftVirtDerived")
+        .def(py::init<>(&SftVirtDerived::create));
+    py::class_<SftVirtDerived2, SftVirtDerived, std::shared_ptr<SftVirtDerived2>>(
+        m, "SftVirtDerived2")
+        .def(py::init<>(&SftVirtDerived2::create))
+        .def("call_name", &SftVirtDerived2::call_name, py::arg("d2"));
+
     // test_move_only_holder
     py::class_<C, custom_unique_ptr<C>>(m, "TypeWithMoveOnlyHolder")
         .def_static("make", []() { return custom_unique_ptr<C>(new C); })
diff --git a/tests/test_smart_ptr.py b/tests/test_smart_ptr.py
index 2d48aac..76ebd8c 100644
--- a/tests/test_smart_ptr.py
+++ b/tests/test_smart_ptr.py
@@ -251,6 +251,19 @@
     assert y is z
 
 
+def test_shared_from_this_virt_shared_ptr_arg():
+    """Issue #5989: static_pointer_cast fails with virtual inheritance."""
+    b = m.SftVirtBase()
+    assert b.name() == "SftVirtBase"
+
+    d = m.SftVirtDerived()
+    assert d.name() == "SftVirtDerived"
+
+    d2 = m.SftVirtDerived2()
+    assert d2.name() == "SftVirtDerived2"
+    assert d2.call_name(d2) == "SftVirtDerived2"
+
+
 @pytest.mark.skipif("env.GRAALPY", reason="Cannot reliably trigger GC")
 def test_move_only_holder():
     a = m.TypeWithMoveOnlyHolder.make()
diff --git a/tests/test_standalone_enum_module.py b/tests/test_standalone_enum_module.py
new file mode 100644
index 0000000..3358b88
--- /dev/null
+++ b/tests/test_standalone_enum_module.py
@@ -0,0 +1,18 @@
+from __future__ import annotations
+
+import os
+
+import env
+
+
+def test_enum_import_exit_no_crash():
+    # Added in PR #6015. Modeled after reproducer under issue #5976
+    env.check_script_success_in_subprocess(
+        f"""
+        import sys
+        sys.path.insert(0, {os.path.dirname(env.__file__)!r})
+        import standalone_enum_module as m
+        assert m.SomeEnum.__class__.__name__ == "pybind11_type"
+        """,
+        rerun=1,
+    )
diff --git a/tests/test_virtual_functions.cpp b/tests/test_virtual_functions.cpp
index a6164eb..78a4fdf 100644
--- a/tests/test_virtual_functions.cpp
+++ b/tests/test_virtual_functions.cpp
@@ -173,8 +173,7 @@
     using DataVisitor = std::function<void(const Data &)>;
 
     virtual void
-    operator()(const Data &first, const Data &second, const DataVisitor &visitor) const
-        = 0;
+    operator()(const Data &first, const Data &second, const DataVisitor &visitor) const = 0;
     virtual ~AdderBase() = default;
     AdderBase() = default;
     AdderBase(const AdderBase &) = delete;
diff --git a/tests/test_with_catch/catch_skip.h b/tests/test_with_catch/catch_skip.h
index 72ffdb6..9e2954d 100644
--- a/tests/test_with_catch/catch_skip.h
+++ b/tests/test_with_catch/catch_skip.h
@@ -4,13 +4,18 @@
 
 #pragma once
 
+#include <pybind11/detail/pybind11_namespace_macros.h>
+
 #include <catch.hpp>
 
 #define PYBIND11_CATCH2_SKIP_IF(condition, reason)                                                \
     do {                                                                                          \
+        PYBIND11_WARNING_PUSH                                                                     \
+        PYBIND11_WARNING_DISABLE_MSVC(4127)                                                       \
         if (condition) {                                                                          \
             Catch::cout() << "[ SKIPPED  ] " << (reason) << '\n';                                 \
             Catch::cout().flush();                                                                \
             return;                                                                               \
         }                                                                                         \
+        PYBIND11_WARNING_POP                                                                      \
     } while (0)
diff --git a/tests/test_with_catch/test_interpreter.cpp b/tests/test_with_catch/test_interpreter.cpp
index d227eec..4103c0f 100644
--- a/tests/test_with_catch/test_interpreter.cpp
+++ b/tests/test_with_catch/test_interpreter.cpp
@@ -5,6 +5,8 @@
 // catch 2.0.1; this should be fixed in the next catch release after 2.0.1).
 PYBIND11_WARNING_DISABLE_MSVC(4996)
 
+#include "catch_skip.h"
+
 #include <catch.hpp>
 #include <cstdlib>
 #include <fstream>
@@ -84,6 +86,14 @@
         .def("func", &test_override_cache_helper::func);
 }
 
+enum class SomeEnum { value1, value2 }; // Added in PR #6015
+
+PYBIND11_EMBEDDED_MODULE(enum_module, m, py::multiple_interpreters::per_interpreter_gil()) {
+    py::enum_<SomeEnum>(m, "SomeEnum")
+        .value("value1", SomeEnum::value1)
+        .value("value2", SomeEnum::value2);
+}
+
 PYBIND11_EMBEDDED_MODULE(throw_exception, ) { throw std::runtime_error("C++ Error"); }
 
 PYBIND11_EMBEDDED_MODULE(throw_error_already_set, ) {
@@ -343,6 +353,24 @@
     REQUIRE(py_widget.attr("the_message").cast<std::string>() == "Hello after restart");
 }
 
+TEST_CASE("Enum module survives restart") { // Added in PR #6015
+    // Regression test for gh-5976: py::enum_ uses def_property_static, which
+    // calls process_attributes::init after initialize_generic's strdup loop,
+    // leaving arg names as string literals. Without the fix, destruct() would
+    // call free() on those literals during interpreter finalization.
+    PYBIND11_CATCH2_SKIP_IF(PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 12,
+                            "Pre-existing crash in enum cleanup during finalize on Python 3.12");
+
+    auto enum_mod = py::module_::import("enum_module");
+    REQUIRE(enum_mod.attr("SomeEnum").attr("value1").attr("name").cast<std::string>() == "value1");
+
+    py::finalize_interpreter();
+    py::initialize_interpreter();
+
+    enum_mod = py::module_::import("enum_module");
+    REQUIRE(enum_mod.attr("SomeEnum").attr("value2").attr("name").cast<std::string>() == "value2");
+}
+
 TEST_CASE("Execution frame") {
     // When the interpreter is embedded, there is no execution frame, but `py::exec`
     // should still function by using reasonable globals: `__main__.__dict__`.