Skip to content

Commit

Permalink
importing Robert's patch as-is
Browse files Browse the repository at this point in the history
  • Loading branch information
Ralf W. Grosse-Kunstleve committed Nov 18, 2020
1 parent 17c22b9 commit 9f04c67
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 26 deletions.
102 changes: 78 additions & 24 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -586,25 +586,11 @@ class type_caster_generic {
return inst.release();
}

// Base methods for generic caster; there are overridden in copyable_holder_caster
// Base methods for generic caster; they are overridden in copyable_holder_caster
void load_value(value_and_holder &&v_h) {
auto *&vptr = v_h.value_ptr();
// Lazy allocation for unallocated values:
if (vptr == nullptr) {
auto *type = v_h.type ? v_h.type : typeinfo;
if (type->operator_new) {
vptr = type->operator_new(type->type_size);
} else {
#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
vptr = ::operator new(type->type_size,
std::align_val_t(type->type_align));
else
#endif
vptr = ::operator new(type->type_size);
}
}
value = vptr;
value = v_h.value_ptr();
if (value == nullptr)
throw cast_error("Invalid object instance");
}
bool try_implicit_casts(handle src, bool convert) {
for (auto &cast : typeinfo->implicit_casts) {
Expand Down Expand Up @@ -1568,15 +1554,81 @@ template <typename T>
class type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> { };

template <typename type, typename holder_type>
struct move_only_holder_caster {
static_assert(std::is_base_of<type_caster_base<type>, type_caster<type>>::value,
struct move_only_holder_caster : public type_caster_base<type> {
public:
using base = type_caster_base<type>;
static_assert(std::is_base_of<base, type_caster<type>>::value,
"Holder classes are only supported for custom types");
using base::base;
using base::cast;
using base::typeinfo;
using base::value;

bool load(handle& src, bool convert) {
bool success = base::template load_impl<move_only_holder_caster<type, holder_type>>(src, convert);
if (success) // On success, remember src pointer to withdraw later
this->v_h = reinterpret_cast<instance *>(src.ptr())->get_value_and_holder();
return success;
}

static handle cast(holder_type &&src, return_value_policy, handle) {
auto *ptr = holder_helper<holder_type>::get(src);
return type_caster_base<type>::cast_holder(ptr, std::addressof(src));
template <typename T> using cast_op_type = detail::movable_cast_op_type<T>;

// Workaround for Intel compiler bug
// see pybind11 issue 94
#if !defined(__ICC) && !defined(__INTEL_COMPILER)
explicit
#endif
operator holder_type&&() {
// In load_value() value_ptr was still valid. If it's invalid now, another argument consumed the same value before.
if (!v_h.value_ptr())
throw cast_error("Multiple access to moved argument");
v_h.value_ptr() = nullptr;
// TODO: release object instance in python
// clear_instance(src_handle->ptr()); ???

return std::move(*holder_ptr);
}

static handle cast(const holder_type &src, return_value_policy, handle) {
const auto *ptr = holder_helper<holder_type>::get(src);
return type_caster_base<type>::cast_holder(ptr, &src);
}

protected:
friend class type_caster_generic;
void check_holder_compat() {
// if (typeinfo->default_holder)
// throw cast_error("Unable to load a custom holder type from a default-holder instance");
}
static constexpr auto name = type_caster_base<type>::name;

bool load_value(value_and_holder &&v_h) {
if (v_h.holder_constructed()) {
holder_ptr = std::addressof(v_h.template holder<holder_type>());
value = const_cast<void*>(reinterpret_cast<const void*>(holder_helper<holder_type>::get(*holder_ptr)));
if (!value)
throw cast_error("Invalid object instance");
return true;
} else {
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
#if defined(NDEBUG)
"(compile in debug mode for type information)");
#else
"of type '" + type_id<holder_type>() + "''");
#endif
}
}

template <typename T = holder_type, detail::enable_if_t<!std::is_constructible<T, const T &, type*>::value, int> = 0>
bool try_implicit_casts(handle, bool) { return false; }

template <typename T = holder_type, detail::enable_if_t<std::is_constructible<T, const T &, type*>::value, int> = 0>
bool try_implicit_casts(handle, bool) { return false; }

static bool try_direct_conversions(handle) { return false; }


holder_type* holder_ptr = nullptr;
value_and_holder v_h;
};

template <typename type, typename deleter>
Expand Down Expand Up @@ -1998,6 +2050,8 @@ class argument_loader {
if ((... || !std::get<Is>(argcasters).load(call.args[Is], call.args_convert[Is])))
return false;
#else
// BUG: When loading the arguments, the actual argument type (pointer, lvalue reference, rvalue reference)
// is already lost (argcasters only know the intrinsic type), while the behaviour should differ for them, e.g. for rvalue references.
for (bool r : {std::get<Is>(argcasters).load(call.args[Is], call.args_convert[Is])...})
if (!r)
return false;
Expand Down
4 changes: 2 additions & 2 deletions include/pybind11/detail/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -719,8 +719,8 @@ PYBIND11_RUNTIME_EXCEPTION(value_error, PyExc_ValueError)
PYBIND11_RUNTIME_EXCEPTION(type_error, PyExc_TypeError)
PYBIND11_RUNTIME_EXCEPTION(buffer_error, PyExc_BufferError)
PYBIND11_RUNTIME_EXCEPTION(import_error, PyExc_ImportError)
PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybind11::cast or handle::call fail due to a type casting error
PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally
PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_TypeError) /// Thrown when pybind11::cast or handle::call fail due to a type casting error
PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_TypeError) /// Used internally

[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); }
[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); }
Expand Down

0 comments on commit 9f04c67

Please sign in to comment.