Skip to content

Fix auto type deduction failures when var name is an existing type name #1431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,7 @@ template <typename type> class type_caster_base : public type_caster_generic {
using itype = intrinsic_t<type>;

public:
static constexpr auto name = _<type>();
static constexpr auto name_ = _<type>();

type_caster_base() : type_caster_base(typeid(type)) { }
explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { }
Expand Down Expand Up @@ -917,7 +917,7 @@ template <typename type> class type_caster<std::reference_wrapper<type>> {
"std::reference_wrapper<T> caster requires T to have a caster with an `T &` operator");
public:
bool load(handle src, bool convert) { return subcaster.load(src, convert); }
static constexpr auto name = caster_t::name;
static constexpr auto name_ = caster_t::name_;
static handle cast(const std::reference_wrapper<type> &src, return_value_policy policy, handle parent) {
// It is definitely wrong to take ownership of this pointer, so mask that rvp
if (policy == return_value_policy::take_ownership || policy == return_value_policy::automatic)
Expand All @@ -932,7 +932,7 @@ template <typename type> class type_caster<std::reference_wrapper<type>> {
protected: \
type value; \
public: \
static constexpr auto name = py_name; \
static constexpr auto name_ = py_name; \
template <typename T_, enable_if_t<std::is_same<type, remove_cv_t<T_>>::value, int> = 0> \
static handle cast(T_ *src, return_value_policy policy, handle parent) { \
if (!src) return none().release(); \
Expand Down Expand Up @@ -1350,7 +1350,7 @@ template <template<typename...> class Tuple, typename... Ts> class tuple_caster
return cast_impl(std::forward<T>(src), policy, parent, indices{});
}

static constexpr auto name = _("Tuple[") + concat(make_caster<Ts>::name...) + _("]");
static constexpr auto name_ = _("Tuple[") + concat(make_caster<Ts>::name_...) + _("]");

template <typename T> using cast_op_type = type;

Expand Down Expand Up @@ -1526,10 +1526,10 @@ template <typename base, typename holder> struct is_holder_type :
template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> :
std::true_type {};

template <typename T> struct handle_type_name { static constexpr auto name = _<T>(); };
template <> struct handle_type_name<bytes> { static constexpr auto name = _(PYBIND11_BYTES_NAME); };
template <> struct handle_type_name<args> { static constexpr auto name = _("*args"); };
template <> struct handle_type_name<kwargs> { static constexpr auto name = _("**kwargs"); };
template <typename T> struct handle_type_name { static constexpr auto name_ = _<T>(); };
template <> struct handle_type_name<bytes> { static constexpr auto name_ = _(PYBIND11_BYTES_NAME); };
template <> struct handle_type_name<args> { static constexpr auto name_ = _("*args"); };
template <> struct handle_type_name<kwargs> { static constexpr auto name_ = _("**kwargs"); };

template <typename type>
struct pyobject_caster {
Expand All @@ -1547,7 +1547,7 @@ struct pyobject_caster {
static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
return src.inc_ref();
}
PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name);
PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name_);
};

template <typename T>
Expand Down Expand Up @@ -1867,7 +1867,7 @@ class argument_loader {
static constexpr bool has_kwargs = kwargs_pos < 0;
static constexpr bool has_args = args_pos < 0;

static constexpr auto arg_names = concat(type_descr(make_caster<Args>::name)...);
static constexpr auto arg_names = concat(type_descr(make_caster<Args>::name_)...);

bool load_args(function_call &call) {
return load_impl_sequence(call, indices{});
Expand Down
61 changes: 31 additions & 30 deletions include/pybind11/detail/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ extern "C" inline int pybind11_static_set(PyObject *self, PyObject *obj, PyObjec
methods are modified to always use the object type instead of a concrete instance.
Return value: New reference. */
inline PyTypeObject *make_static_property_type() {
constexpr auto *name = "pybind11_static_property";
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
constexpr auto name_value = "pybind11_static_property";
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name_value));

/* Danger zone: from now (and until PyType_Ready), make sure to
issue no Python C API calls which could potentially invoke the
Expand All @@ -62,7 +62,7 @@ inline PyTypeObject *make_static_property_type() {
#endif

auto type = &heap_type->ht_type;
type->tp_name = name;
type->tp_name = name_value;
type->tp_base = type_incref(&PyProperty_Type);
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
type->tp_descr_get = pybind11_static_get;
Expand Down Expand Up @@ -159,8 +159,8 @@ extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name
for static properties to function correctly. Users may override this using `py::metaclass`.
Return value: New reference. */
inline PyTypeObject* make_default_metaclass() {
constexpr auto *name = "pybind11_type";
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
constexpr auto name_value = "pybind11_type";
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name_value));

/* Danger zone: from now (and until PyType_Ready), make sure to
issue no Python C API calls which could potentially invoke the
Expand All @@ -176,7 +176,7 @@ inline PyTypeObject* make_default_metaclass() {
#endif

auto type = &heap_type->ht_type;
type->tp_name = name;
type->tp_name = name_value;
type->tp_base = type_incref(&PyType_Type);
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;

Expand Down Expand Up @@ -288,14 +288,14 @@ extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject

inline void add_patient(PyObject *nurse, PyObject *patient) {
auto &internals = get_internals();
auto instance = reinterpret_cast<detail::instance *>(nurse);
instance->has_patients = true;
auto instance_ptr = reinterpret_cast<detail::instance *>(nurse);
instance_ptr->has_patients = true;
Py_INCREF(patient);
internals.patients[nurse].push_back(patient);
}

inline void clear_patients(PyObject *self) {
auto instance = reinterpret_cast<detail::instance *>(self);
auto instance_ptr = reinterpret_cast<detail::instance *>(self);
auto &internals = get_internals();
auto pos = internals.patients.find(self);
assert(pos != internals.patients.end());
Expand All @@ -304,40 +304,40 @@ inline void clear_patients(PyObject *self) {
// from the unordered_map first.
auto patients = std::move(pos->second);
internals.patients.erase(pos);
instance->has_patients = false;
instance_ptr->has_patients = false;
for (PyObject *&patient : patients)
Py_CLEAR(patient);
}

/// Clears all internal data from the instance and removes it from registered instances in
/// preparation for deallocation.
inline void clear_instance(PyObject *self) {
auto instance = reinterpret_cast<detail::instance *>(self);
auto instance_ptr = reinterpret_cast<detail::instance *>(self);

// Deallocate any values/holders, if present:
for (auto &v_h : values_and_holders(instance)) {
for (auto &v_h : values_and_holders(instance_ptr)) {
if (v_h) {

// We have to deregister before we call dealloc because, for virtual MI types, we still
// need to be able to get the parent pointers.
if (v_h.instance_registered() && !deregister_instance(instance, v_h.value_ptr(), v_h.type))
if (v_h.instance_registered() && !deregister_instance(instance_ptr, v_h.value_ptr(), v_h.type))
pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!");

if (instance->owned || v_h.holder_constructed())
if (instance_ptr->owned || v_h.holder_constructed())
v_h.type->dealloc(v_h);
}
}
// Deallocate the value/holder layout internals:
instance->deallocate_layout();
instance_ptr->deallocate_layout();

if (instance->weakrefs)
if (instance_ptr->weakrefs)
PyObject_ClearWeakRefs(self);

PyObject **dict_ptr = _PyObject_GetDictPtr(self);
if (dict_ptr)
Py_CLEAR(*dict_ptr);

if (instance->has_patients)
if (instance_ptr->has_patients)
clear_patients(self);
}

Expand All @@ -362,8 +362,8 @@ extern "C" inline void pybind11_object_dealloc(PyObject *self) {
needed in order to satisfy Python's requirements for multiple inheritance.
Return value: New reference. */
inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
constexpr auto *name = "pybind11_object";
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
constexpr auto name_value = "pybind11_object";
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name_value));

/* Danger zone: from now (and until PyType_Ready), make sure to
issue no Python C API calls which could potentially invoke the
Expand All @@ -379,7 +379,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
#endif

auto type = &heap_type->ht_type;
type->tp_name = name;
type->tp_name = name_value;
type->tp_base = type_incref(&PyBaseObject_Type);
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
Expand Down Expand Up @@ -514,13 +514,13 @@ inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
/** Create a brand new Python type according to the `type_record` specification.
Return value: New reference. */
inline PyObject* make_new_python_type(const type_record &rec) {
auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name));
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name));

auto qualname = name;
auto qualname = name_obj;
if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) {
#if PY_MAJOR_VERSION >= 3
qualname = reinterpret_steal<object>(
PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr()));
PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name_obj.ptr()));
#else
qualname = str(rec.scope.attr("__qualname__").cast<std::string>() + "." + rec.name);
#endif
Expand Down Expand Up @@ -551,29 +551,30 @@ inline PyObject* make_new_python_type(const type_record &rec) {

auto &internals = get_internals();
auto bases = tuple(rec.bases);
auto base = (bases.size() == 0) ? internals.instance_base
: bases[0].ptr();
auto base_ptr = (bases.size() == 0) ? internals.instance_base
: bases[0].ptr();

/* Danger zone: from now (and until PyType_Ready), make sure to
issue no Python C API calls which could potentially invoke the
garbage collector (the GC will call type_traverse(), which will in
turn find the newly constructed type in an invalid state) */
auto metaclass = rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr()
: internals.default_metaclass;
auto metaclass_ptr =
rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr()
: internals.default_metaclass;

auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
auto heap_type = (PyHeapTypeObject *) metaclass_ptr->tp_alloc(metaclass_ptr, 0);
if (!heap_type)
pybind11_fail(std::string(rec.name) + ": Unable to create type object!");

heap_type->ht_name = name.release().ptr();
heap_type->ht_name = name_obj.release().ptr();
#ifdef PYBIND11_BUILTIN_QUALNAME
heap_type->ht_qualname = qualname.inc_ref().ptr();
#endif

auto type = &heap_type->ht_type;
type->tp_name = full_name;
type->tp_doc = tp_doc;
type->tp_base = type_incref((PyTypeObject *)base);
type->tp_base = type_incref((PyTypeObject *)base_ptr);
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
if (bases.size() > 0)
type->tp_bases = bases.release().ptr();
Expand Down
2 changes: 1 addition & 1 deletion include/pybind11/detail/init.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class type_caster<value_and_holder> {

template <typename> using cast_op_type = value_and_holder &;
operator value_and_holder &() { return *value; }
static constexpr auto name = _<value_and_holder>();
static constexpr auto name_ = _<value_and_holder>();

private:
value_and_holder *value = nullptr;
Expand Down
10 changes: 5 additions & 5 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ class cpp_function : public function {
process_attributes<Extra...>::init(extra..., rec);

/* Generate a readable signature describing the function's arguments and return value types */
static constexpr auto signature = _("(") + cast_in::arg_names + _(") -> ") + cast_out::name;
static constexpr auto signature = _("(") + cast_in::arg_names + _(") -> ") + cast_out::name_;
PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types();

/* Register the function with Python from generic (non-templated) code */
Expand Down Expand Up @@ -738,15 +738,15 @@ class cpp_function : public function {
msg += pybind11::repr(args_[ti]);
}
if (kwargs_in) {
auto kwargs = reinterpret_borrow<dict>(kwargs_in);
if (kwargs.size() > 0) {
auto kwargs_ = reinterpret_borrow<dict>(kwargs_in);
if (kwargs_.size() > 0) {
if (some_args) msg += "; ";
msg += "kwargs: ";
bool first = true;
for (auto kwarg : kwargs) {
for (auto kwarg_ : kwargs_) {
if (first) first = false;
else msg += ", ";
msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second);
msg += pybind11::str("{}={!r}").format(kwarg_.first, kwarg_.second);
}
}
}
Expand Down