@@ -476,18 +476,50 @@ inline PyThreadState *get_thread_state_unchecked() {
476476}
477477
478478// Forward declarations
479+ inline bool has_patient (PyObject *nurse, PyObject *patient);
479480inline void keep_alive_impl (handle nurse, handle patient);
480481inline PyObject *make_new_instance (PyTypeObject *type);
481482
482- inline bool reclaim_existing_if_needed (
483- instance *inst, const detail::type_info *tinfo, const void *existing_holder) {
484- // Only reclaim if (a) we have an existing holder and (b) if it's a move-only holder.
485- // TODO: Remove `default_holder`, store more descriptive holder information.
486- if (existing_holder && tinfo->default_holder ) {
487- // Requesting reclaim from C++.
488- value_and_holder v_h = inst->get_value_and_holder (tinfo);
489- // TODO(eric.cousineau): Add `holder_type_erased` to avoid need for `const_cast`.
490- tinfo->ownership_info .reclaim (v_h, const_cast <void *>(existing_holder));
483+ inline void reclaim_instance (
484+ instance *inst, const detail::type_info *tinfo, const void *existing_holder = nullptr ) {
485+ value_and_holder v_h = inst->get_value_and_holder (tinfo);
486+ // TODO(eric.cousineau): Add `holder_type_erased` to avoid need for `const_cast`.
487+ tinfo->ownership_info .reclaim (v_h, const_cast <void *>(existing_holder));
488+ }
489+
490+ inline bool reclaim_instance_if_needed (
491+ instance *inst, const detail::type_info *tinfo, const void *existing_holder,
492+ return_value_policy policy, handle parent) {
493+ // TODO(eric.cousineau): Remove `default_holder`, store more descriptive holder information.
494+ // Only handle reclaim if it's a move-only holder, and not currently owned.
495+ // Let copyable holders do their own thing.
496+ if (!tinfo->default_holder || inst->owned )
497+ // TODO(eric.cousineau): For shared ptrs, there was a point where the holder was constructed,
498+ // but the instance was not owned. What does that mean?
499+ return false ;
500+ bool do_reclaim = false ;
501+ if (existing_holder) {
502+ // This means that we're coming from a holder caster.
503+ do_reclaim = true ;
504+ } else {
505+ // Check existing policies.
506+ switch (policy) {
507+ case return_value_policy::reference_internal: {
508+ handle h = handle ((PyObject *) inst);
509+ if (!has_patient (h.ptr (), parent.ptr ()))
510+ keep_alive_impl (h, parent);
511+ break ;
512+ }
513+ case return_value_policy::take_ownership: {
514+ do_reclaim = true ;
515+ break ;
516+ }
517+ default :
518+ break ;
519+ }
520+ }
521+ if (do_reclaim) {
522+ reclaim_instance (inst, tinfo, existing_holder);
491523 return true ;
492524 }
493525 return false ;
@@ -523,7 +555,7 @@ class type_caster_generic {
523555 if (instance_type && same_type (*instance_type->cpptype , *tinfo->cpptype )) {
524556 // Casting for an already registered type. Return existing reference.
525557 instance *inst = it_i->second ;
526- reclaim_existing_if_needed (inst, tinfo, existing_holder);
558+ reclaim_instance_if_needed (inst, tinfo, existing_holder, policy, parent );
527559 return handle ((PyObject *) inst).inc_ref ();
528560 }
529561 }
0 commit comments