Skip to content

Commit b994121

Browse files
committed
Cleanup 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 c92279e commit b994121

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
@@ -677,12 +677,10 @@ struct smart_holder_type_caster<std::unique_ptr<T, D>> : smart_holder_type_caste
677677
smart_holder_type_caster_class_hooks {
678678
static constexpr auto name = _<std::unique_ptr<T, D>>();
679679

680-
static handle cast(std::unique_ptr<T, D> &&src, return_value_policy policy, handle parent) {
681-
if (policy != return_value_policy::automatic
682-
&& policy != return_value_policy::reference_internal
683-
&& policy != return_value_policy::move) {
680+
static handle cast(std::unique_ptr<T, D> &&src, return_value_policy policy, handle) {
681+
if (policy != return_value_policy::automatic && policy != return_value_policy::move) {
684682
// SMART_HOLDER_WIP: IMPROVABLE: Error message.
685-
throw cast_error("Invalid return_value_policy for unique_ptr.");
683+
throw cast_error("Invalid return_value_policy: unique_ptr&& can only move");
686684
}
687685

688686
auto src_raw_ptr = src.get();
@@ -704,19 +702,23 @@ struct smart_holder_type_caster<std::unique_ptr<T, D>> : smart_holder_type_caste
704702
auto smhldr = pybindit::memory::smart_holder::from_unique_ptr(std::move(src));
705703
tinfo->init_instance(inst_raw_ptr, static_cast<const void *>(&smhldr));
706704

707-
if (policy == return_value_policy::reference_internal)
708-
keep_alive_impl(inst, parent);
709-
710705
return inst.release();
711706
}
707+
static handle cast(std::unique_ptr<T, D> &, return_value_policy, handle) {
708+
throw cast_error("Passing non-const unique_ptr& is not supported.\n"
709+
"If you want to transfer ownership, use unique_ptr&&.\n"
710+
"If you want to return a reference, use unique_ptr const&.");
711+
}
712+
712713
static handle
713714
cast(const std::unique_ptr<T, D> &src, return_value_policy policy, handle parent) {
714715
if (!src)
715716
return none().release();
716717
if (policy == return_value_policy::automatic)
717718
policy = return_value_policy::reference_internal;
718719
if (policy != return_value_policy::reference_internal)
719-
throw cast_error("Invalid return_value_policy for unique_ptr&");
720+
throw cast_error(
721+
"Invalid return_value_policy: unique_ptr const& expects reference_internal");
720722
return smart_holder_type_caster<T>::cast(src.get(), policy, parent);
721723
}
722724

tests/test_class_sh_basic.py

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

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

0 commit comments

Comments
 (0)