diff --git a/include/boost/python/converter/return_from_python.hpp b/include/boost/python/converter/return_from_python.hpp index 18c2d227..72527b0b 100755 --- a/include/boost/python/converter/return_from_python.hpp +++ b/include/boost/python/converter/return_from_python.hpp @@ -40,13 +40,7 @@ namespace detail template struct return_rvalue_from_python { - typedef typename mpl::if_< - mpl::logical_and< - has_trivial_copy, mpl::bool_c<(sizeof(T) <= 2 * sizeof(double))> - > - , T - , T& - >::type result_type; + typedef T result_type; return_rvalue_from_python(); result_type operator()(PyObject*); @@ -127,6 +121,12 @@ namespace detail inline typename return_rvalue_from_python::result_type return_rvalue_from_python::operator()(PyObject* obj) { + // Take possession of the source object here. If the result is in + // fact going to be a copy of an lvalue embedded in the object, + // and we take possession inside rvalue_result_from_python, it + // will be destroyed too early. + handle<> holder(obj); + return *(T*) (rvalue_result_from_python)(obj, m_data.stage1); } diff --git a/src/converter/from_python.cpp b/src/converter/from_python.cpp index 904f66ff..e633debf 100644 --- a/src/converter/from_python.cpp +++ b/src/converter/from_python.cpp @@ -83,9 +83,6 @@ BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1( BOOST_PYTHON_DECL void* rvalue_result_from_python( PyObject* src, rvalue_from_python_stage1_data& data) { - // Take possession of the source object. - handle<> holder(src); - // Retrieve the registration // Cast in two steps for less-capable compilers void const* converters_ = data.convertible; diff --git a/test/Jamfile b/test/Jamfile index eb767745..f667159b 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -95,6 +95,8 @@ bpl-test back_reference ; bpl-test implicit ; bpl-test data_members ; +bpl-test ben_scott1 ; + bpl-test bienstman1 ; bpl-test bienstman2 ; bpl-test bienstman3 ; diff --git a/test/ben_scott1.cpp b/test/ben_scott1.cpp new file mode 100644 index 00000000..3c0d5522 --- /dev/null +++ b/test/ben_scott1.cpp @@ -0,0 +1,51 @@ +#include +#include +using namespace boost::python; +using namespace boost; + +struct Product {}; +typedef shared_ptr ProductPtr; + + +struct Creator +{ + virtual ~Creator() {} + virtual ProductPtr create() = 0; +}; + + +struct Factory +{ + void reg(Creator* c) { mC = c; } + ProductPtr create() + { + std::cout << "Name: " << (typeid(*mC)).name() << std::endl; + return mC->create(); + } + +private: + Creator* mC; +}; + +struct CreatorWrap : public Creator +{ + CreatorWrap(PyObject* self) : mSelf(self) {} + ProductPtr create() { return call_method(mSelf, "create"); } + PyObject* mSelf; +}; + +BOOST_PYTHON_MODULE(ben_scott1_ext) +{ + class_("Product"); + + class_("Creator") + .def("create", &CreatorWrap::create) + ; + + class_("Factory") + .def("reg", &Factory::reg, with_custodian_and_ward<1,2>()) + .def("create", &Factory::create) + ; +} + +#include "../test/module_tail.cpp" diff --git a/test/ben_scott1.py b/test/ben_scott1.py new file mode 100644 index 00000000..1475e3d0 --- /dev/null +++ b/test/ben_scott1.py @@ -0,0 +1,14 @@ +# This regression test checks that call_method(...) where T is a +# non-reference, non-pointer type that happens to be held inside the +# result object (and thus is found as an lvalue) works. +from ben_scott1_ext import * + +class CreatorImpl(Creator): + def create(self): + return Product() + +factory = Factory() +c = CreatorImpl() +factory.reg(c) + +a = factory.create()