Skip to content

Commit c0dab64

Browse files
committed
Fixup cast() functions of smart_holder_type_caster<std::unique_ptr<T, D>>
- forbid to pass a non-const unique_ptr reference - forbid return_value_policy::reference_internal for unique_ptr&&: It's always moved!
1 parent a76c725 commit c0dab64

File tree

2 files changed

+16
-11
lines changed

2 files changed

+16
-11
lines changed

include/pybind11/detail/smart_holder_type_casters.h

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -685,12 +685,10 @@ struct smart_holder_type_caster<std::unique_ptr<T, D>> : smart_holder_type_caste
685685
smart_holder_type_caster_class_hooks {
686686
static constexpr auto name = _<std::unique_ptr<T, D>>();
687687

688-
static handle cast(std::unique_ptr<T, D> &&src, return_value_policy policy, handle parent) {
689-
if (policy != return_value_policy::automatic
690-
&& policy != return_value_policy::reference_internal
691-
&& policy != return_value_policy::move) {
688+
static handle cast(std::unique_ptr<T, D> &&src, return_value_policy policy, handle) {
689+
if (policy != return_value_policy::automatic && policy != return_value_policy::move) {
692690
// SMART_HOLDER_WIP: IMPROVABLE: Error message.
693-
throw cast_error("Invalid return_value_policy for unique_ptr.");
691+
throw cast_error("Invalid return_value_policy: unique_ptr&& can only move");
694692
}
695693

696694
auto src_raw_ptr = src.get();
@@ -712,19 +710,23 @@ struct smart_holder_type_caster<std::unique_ptr<T, D>> : smart_holder_type_caste
712710
auto smhldr = pybindit::memory::smart_holder::from_unique_ptr(std::move(src));
713711
tinfo->init_instance(inst_raw_ptr, static_cast<const void *>(&smhldr));
714712

715-
if (policy == return_value_policy::reference_internal)
716-
keep_alive_impl(inst, parent);
717-
718713
return inst.release();
719714
}
715+
static handle cast(std::unique_ptr<T, D> &, return_value_policy, handle) {
716+
throw cast_error("Passing non-const unique_ptr& is not supported. "
717+
"If you want to transfer ownership, use unique_ptr&&. "
718+
"If you want to return a reference, use unique_ptr const&.");
719+
}
720+
720721
static handle
721722
cast(const std::unique_ptr<T, D> &src, return_value_policy policy, handle parent) {
722723
if (!src)
723724
return none().release();
724725
if (policy == return_value_policy::automatic)
725726
policy = return_value_policy::reference_internal;
726727
if (policy != return_value_policy::reference_internal)
727-
throw cast_error("Invalid return_value_policy for unique_ptr&");
728+
throw cast_error(
729+
"Invalid return_value_policy: unique_ptr const& expects reference_internal");
728730
return smart_holder_type_caster<T>::cast(src.get(), policy, parent);
729731
}
730732

tests/test_class_sh_basic.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,11 @@ def test_unique_ptr_store_roundtrip(rtrn_f, moved_in):
167167
c.pass_uq_valu(orig) # pass object to C++ store c
168168
try:
169169
recycled = rtrn_f(c) # retrieve object back from C++
170-
except RuntimeError: # expect failure for rtrn_uq_lref
171-
assert moved_in is None
170+
except RuntimeError as excinfo: # expect failure for rtrn_uq_lref
171+
assert (
172+
moved_in is None
173+
and "Passing non-const unique_ptr& is not supported" in str(excinfo)
174+
)
172175
return
173176

174177
assert m.get_ptr(recycled) == ptr_orig # do we yield the same object?

0 commit comments

Comments
 (0)