Merge branch 'abstract-conversion-operators'

* abstract-conversion-operators:
  Add test cases for abstract user-defined conversion operators
  Recognize C++ conversion operators with trailing '= 0' as abstract
diff --git a/CHANGES.current b/CHANGES.current
index c12c5eb..27945c0 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -7,6 +7,9 @@
 Version 4.0.2 (in progress)
 ===========================
 
+2020-02-13: ddurham2
+            [Python] #1512 Fix memleak when using STL containers of shared_ptr objects.
+
 2020-02-06: wsfulton
             [Python] #1673 #1674 Fix setting 'this' when extending a proxy class with __slots__.
 
diff --git a/Examples/test-suite/python/cpp11_shared_ptr_upcast_runme.py b/Examples/test-suite/python/cpp11_shared_ptr_upcast_runme.py
new file mode 100644
index 0000000..08546a4
--- /dev/null
+++ b/Examples/test-suite/python/cpp11_shared_ptr_upcast_runme.py
@@ -0,0 +1,63 @@
+from cpp11_shared_ptr_upcast import *
+
+# This is a port from the Ruby equivalent test and some tests ported from
+# Examples/test-suite/ruby/cpp11_shared_ptr_upcast_runme.rb are not working and commented out with:
+# not working:
+
+def swig_assert_equal_simple(expected, got):
+    if expected != got:
+        raise RuntimeError("Expected: {}. Got: {}")
+
+# non-overloaded
+swig_assert_equal_simple(7, derived_num1(Derived(7)))
+swig_assert_equal_simple(7, derived_num2([Derived(7)]))
+swig_assert_equal_simple(7, derived_num3({0: Derived(7)}))
+
+swig_assert_equal_simple(-1, base_num1(Derived(7)))
+swig_assert_equal_simple(-1, base_num2([Derived(7)]))
+swig_assert_equal_simple(-1, base_num3({0: Derived(7)}))
+
+swig_assert_equal_simple(999, derived_num1(None))
+# not working: swig_assert_equal_simple(999, derived_num2([None]))
+# not working: swig_assert_equal_simple(999, derived_num3({0: None}))
+
+swig_assert_equal_simple(999, base_num1(None))
+# not working: swig_assert_equal_simple(999, base_num2([None]))
+# not working: swig_assert_equal_simple(999, base_num3({0: None}))
+
+# overloaded
+swig_assert_equal_simple(7, derived_num(Derived(7)))
+swig_assert_equal_simple(7, derived_num([Derived(7)]))
+swig_assert_equal_simple(7, derived_num({0: Derived(7)}))
+
+swig_assert_equal_simple(-1, base_num(Derived(7)))
+swig_assert_equal_simple(-1, base_num([Derived(7)]))
+swig_assert_equal_simple(-1, base_num({0: Derived(7)}))
+
+# ptr to shared_ptr
+swig_assert_equal_simple(7, derived2_num1(Derived2(7)))
+swig_assert_equal_simple(7, derived2_num2([Derived2(7)]))
+swig_assert_equal_simple(7, derived2_num3({0: Derived2(7)}))
+
+swig_assert_equal_simple(-1, base2_num1(Derived2(7)))
+
+# not working: try:
+# not working:     # Upcast for pointers to shared_ptr in this generic framework has not been implemented
+# not working:     swig_assert_equal_simple(-1, base2_num2([Derived2(7)]))
+# not working:     raise RuntimeError, "Failed to catch TypeError"
+# not working: except TypeError:
+# not working:     pass
+# not working: try:
+# not working:     # Upcast for pointers to shared_ptr in this generic framework has not been implemented
+# not working:     swig_assert_equal_simple(-1, base2_num3({0: Derived2(7)}))
+# not working:     raise RuntimeError, "Failed to catch TypeError"
+# not working: except TypeError:
+# not working:     pass
+
+swig_assert_equal_simple(888, derived2_num1(None))
+swig_assert_equal_simple(999, derived2_num2([None])) # although 888 would be more consistent
+swig_assert_equal_simple(999, derived2_num3({0: None})) # although 888 would be more consistent
+
+swig_assert_equal_simple(888, base2_num1(None))
+swig_assert_equal_simple(999, base2_num2([None])) # although 888 would be more consistent
+swig_assert_equal_simple(999, base2_num3({0: None})) # although 888 would be more consistent
diff --git a/Lib/python/pystdcommon.swg b/Lib/python/pystdcommon.swg
index 0242e4d..afa7135 100644
--- a/Lib/python/pystdcommon.swg
+++ b/Lib/python/pystdcommon.swg
@@ -45,11 +45,20 @@
   template <class Type>
   struct traits_asptr {   
     static int asptr(PyObject *obj, Type **val) {
-      Type *p = 0;
+      int res = SWIG_ERROR;
       swig_type_info *descriptor = type_info<Type>();
-      int res = descriptor ? SWIG_ConvertPtr(obj, (void **)&p, descriptor, 0) : SWIG_ERROR;
-      if (SWIG_IsOK(res)) {
-	if (val) *val = p;
+      if (val) {
+        Type *p = 0;
+        int newmem = 0;
+        res = descriptor ? SWIG_ConvertPtrAndOwn(obj, (void **)&p, descriptor, 0, &newmem) : SWIG_ERROR;
+        if (SWIG_IsOK(res)) {
+          if (newmem & SWIG_CAST_NEW_MEMORY) {
+            res |= SWIG_NEWOBJMASK;
+          }
+          *val = p;
+        }
+      } else {
+        res = descriptor ? SWIG_ConvertPtr(obj, 0, descriptor, 0) : SWIG_ERROR;
       }
       return res;
     }
diff --git a/Lib/ruby/std_shared_ptr.i b/Lib/ruby/std_shared_ptr.i
index dee35ec..086e308 100644
--- a/Lib/ruby/std_shared_ptr.i
+++ b/Lib/ruby/std_shared_ptr.i
@@ -13,24 +13,27 @@
   template <class Type>
   struct traits_asptr<std::shared_ptr<Type> > {
     static int asptr(VALUE obj, std::shared_ptr<Type> **val) {
-      std::shared_ptr<Type> *p = 0;
+      int res = SWIG_ERROR;
       swig_type_info *descriptor = type_info<std::shared_ptr<Type> >();
-      swig_ruby_owntype newmem = {0, 0};
-      int res = descriptor ? SWIG_ConvertPtrAndOwn(obj, (void **)&p, descriptor, 0, &newmem) : SWIG_ERROR;
-      if (SWIG_IsOK(res)) {
-	if (val) {
-	  if (*val) {
-	    **val = p ? *p : std::shared_ptr<Type>();
-	  } else {
-	    *val = p;
-	    if (newmem.own & SWIG_CAST_NEW_MEMORY) {
-	      // Upcast for pointers to shared_ptr in this generic framework has not been implemented
-	      res = SWIG_ERROR;
-	    }
-	  }
-	}
-	if (newmem.own & SWIG_CAST_NEW_MEMORY)
-	  delete p;
+      if (val) {
+        std::shared_ptr<Type> *p = 0;
+        swig_ruby_owntype newmem = {0, 0};
+        res = descriptor ? SWIG_ConvertPtrAndOwn(obj, (void **)&p, descriptor, 0, &newmem) : SWIG_ERROR;
+        if (SWIG_IsOK(res)) {
+          if (*val) {
+            **val = p ? *p : std::shared_ptr<Type>();
+          } else {
+            *val = p;
+            if (newmem.own & SWIG_CAST_NEW_MEMORY) {
+              // Upcast for pointers to shared_ptr in this generic framework has not been implemented
+              res = SWIG_ERROR;
+            }
+          }
+          if (newmem.own & SWIG_CAST_NEW_MEMORY)
+            delete p;
+        }
+      } else {
+        res = descriptor ? SWIG_ConvertPtr(obj, 0, descriptor, 0) : SWIG_ERROR;
       }
       return res;
     }