@@ -476,18 +476,50 @@ inline PyThreadState *get_thread_state_unchecked() {
476
476
}
477
477
478
478
// Forward declarations
479
+ inline bool has_patient (PyObject *nurse, PyObject *patient);
479
480
inline void keep_alive_impl (handle nurse, handle patient);
480
481
inline PyObject *make_new_instance (PyTypeObject *type);
481
482
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);
491
523
return true ;
492
524
}
493
525
return false ;
@@ -523,7 +555,7 @@ class type_caster_generic {
523
555
if (instance_type && same_type (*instance_type->cpptype , *tinfo->cpptype )) {
524
556
// Casting for an already registered type. Return existing reference.
525
557
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 );
527
559
return handle ((PyObject *) inst).inc_ref ();
528
560
}
529
561
}
0 commit comments