[skip ci] test: reject shared_ptr casts for custom holders (#6069)

Lock down the current behavior discussed in issue #6064: py::cast() from std::shared_ptr<T> remains rejected for custom holder bindings that are not std::shared_ptr or py::smart_holder.

This extracts the incompatible-holder coverage from PR #6068 and adds a test shaped like issue #6064, while PR #6065 and PR #6066 explore alternative support paths.
diff --git a/tests/test_smart_ptr.cpp b/tests/test_smart_ptr.cpp
index 3617fa3..1409089 100644
--- a/tests/test_smart_ptr.cpp
+++ b/tests/test_smart_ptr.cpp
@@ -83,6 +83,24 @@
     // for demonstration purpose only, this imitates smart pointer with a const-only pointer
 };
 
+template <typename T>
+class shared_ptr_as_custom_holder {
+    std::shared_ptr<T> ptr_;
+
+public:
+    using element_type = T;
+
+    shared_ptr_as_custom_holder() = default;
+
+    explicit shared_ptr_as_custom_holder(T *) {
+        throw std::runtime_error("invalid shared_ptr_as_custom_holder constructor call");
+    }
+
+    explicit shared_ptr_as_custom_holder(std::shared_ptr<T> ptr) : ptr_(std::move(ptr)) {}
+
+    T *get() const { return ptr_.get(); }
+};
+
 // Custom object with builtin reference counting (see 'object.h' for the implementation)
 class MyObject1 : public Object {
 public:
@@ -239,6 +257,17 @@
     std::shared_ptr<B> shared = std::make_shared<B>();
 };
 
+class Issue6064UnsafePath {
+public:
+    static std::shared_ptr<Issue6064UnsafePath> create() {
+        return {new Issue6064UnsafePath(), [](Issue6064UnsafePath *ptr) { delete ptr; }};
+    }
+
+private:
+    Issue6064UnsafePath() = default;
+    ~Issue6064UnsafePath() = default;
+};
+
 // Issue #865: shared_from_this doesn't work with virtual inheritance
 struct SharedFromThisVBase : std::enable_shared_from_this<SharedFromThisVBase> {
     SharedFromThisVBase() = default;
@@ -341,6 +370,7 @@
 // Make pybind aware of the ref-counted wrapper type (s):
 PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true)
 PYBIND11_DECLARE_HOLDER_TYPE(T, const_only_shared_ptr<T>, true)
+PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_as_custom_holder<T>)
 // The following is not required anymore for std::shared_ptr, but it should compile without error:
 PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>)
 PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>)
@@ -501,6 +531,10 @@
         .def(py::init([](const std::string &value) { return MyObject6::createObject(value); }))
         .def_property_readonly("value", &MyObject6::value);
 
+    py::class_<Issue6064UnsafePath, shared_ptr_as_custom_holder<Issue6064UnsafePath>>(
+        m, "Issue6064UnsafePath");
+    m.def("get_issue6064_unsafe_path_shared_ptr", []() { return Issue6064UnsafePath::create(); });
+
     // test_shared_ptr_and_references
     using A = SharedPtrRef::A;
     py::class_<A, std::shared_ptr<A>>(m, "A");
@@ -559,6 +593,7 @@
     py::class_<C, custom_unique_ptr<C>>(m, "TypeWithMoveOnlyHolder")
         .def_static("make", []() { return custom_unique_ptr<C>(new C); })
         .def_static("make_as_object", []() { return py::cast(custom_unique_ptr<C>(new C)); });
+    m.def("get_type_with_move_only_holder_shared_ptr", []() { return std::make_shared<C>(); });
 
     // test_holder_with_addressof_operator
     using HolderWithAddressOf = shared_ptr_with_addressof_operator<TypeForHolderWithAddressOf>;
diff --git a/tests/test_smart_ptr.py b/tests/test_smart_ptr.py
index 76ebd8c..7ee4b78 100644
--- a/tests/test_smart_ptr.py
+++ b/tests/test_smart_ptr.py
@@ -368,3 +368,27 @@
 def test_const_only_holder():
     o = m.MyObject6("my_data")
     assert o.value == "my_data"
+
+
+@pytest.mark.parametrize(
+    "cast_shared_ptr",
+    [
+        pytest.param(
+            m.get_type_with_move_only_holder_shared_ptr,
+            id="incompatible-custom-holder",
+        ),
+        pytest.param(
+            m.get_issue6064_unsafe_path_shared_ptr,
+            id="issue6064-unsafe-path",
+        ),
+    ],
+)
+def test_shared_ptr_cast_for_custom_holder_throws(cast_shared_ptr):
+    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"
+        ),
+    ):
+        cast_shared_ptr()