Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions tests/test_smart_ptr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,24 @@ class const_only_shared_ptr {
// 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:
Expand Down Expand Up @@ -239,6 +257,17 @@ struct SharedFromThisRef {
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;
Expand Down Expand Up @@ -341,6 +370,7 @@ struct holder_helper<ref<T>> {
// 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>)
Expand Down Expand Up @@ -501,6 +531,10 @@ TEST_SUBMODULE(smart_ptr, m) {
.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");
Expand Down Expand Up @@ -559,6 +593,7 @@ TEST_SUBMODULE(smart_ptr, m) {
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>;
Expand Down
24 changes: 24 additions & 0 deletions tests/test_smart_ptr.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,3 +368,27 @@ def test_move_only_holder_caster_shared_ptr_with_smart_holder_support_enabled():
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()
Loading