Resolve empty statement warning when using PYBIND11_OVERLOAD_PURE_NAME and PYBIND11_OVERLOAD_PURE (#2325)

* Wrap PYBIND11_OVERLOAD_NAME and PYBIND11_OVERLOAD_PURE_NAME in do { ... } while (false), and resolve trailing semicolon

* Deprecate PYBIND11_OVERLOAD_* and get_overload in favor of PYBIND11_OVERRIDE_* and get_override

* Correct erroneous usage of 'overload' instead of 'override' in the implementation and internals

* Fix tests to use non-deprecated PYBIND11_OVERRIDE_* macros

* Update docs to use override instead of overload where appropriate, and add warning about deprecated aliases

* Add semicolons to deprecated PYBIND11_OVERLOAD macros to match original behavior

* Remove deprecation of PYBIND11_OVERLOAD_* macros and get_overload

* Add note to changelog and upgrade guide
This commit is contained in:
Yannick Jadoul
2020-09-15 14:56:20 +02:00
committed by GitHub
parent 9df13835c8
commit d65e34d61d
15 changed files with 169 additions and 119 deletions

View File

@@ -1797,16 +1797,16 @@ PYBIND11_NAMESPACE_BEGIN(detail)
template <typename T, enable_if_t<!is_pyobject<T>::value, int>>
object object_or_cast(T &&o) { return pybind11::cast(std::forward<T>(o)); }
struct overload_unused {}; // Placeholder type for the unneeded (and dead code) static variable in the OVERLOAD_INT macro
template <typename ret_type> using overload_caster_t = conditional_t<
cast_is_temporary_value_reference<ret_type>::value, make_caster<ret_type>, overload_unused>;
struct override_unused {}; // Placeholder type for the unneeded (and dead code) static variable in the PYBIND11_OVERRIDE_OVERRIDE macro
template <typename ret_type> using override_caster_t = conditional_t<
cast_is_temporary_value_reference<ret_type>::value, make_caster<ret_type>, override_unused>;
// Trampoline use: for reference/pointer types to value-converted values, we do a value cast, then
// store the result in the given variable. For other types, this is a no-op.
template <typename T> enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&o, make_caster<T> &caster) {
return cast_op<T>(load_type(caster, o));
}
template <typename T> enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&, overload_unused &) {
template <typename T> enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&, override_unused &) {
pybind11_fail("Internal error: cast_ref fallback invoked"); }
// Trampoline use: Having a pybind11::cast with an invalid reference type is going to static_assert, even
@@ -2222,7 +2222,7 @@ type type::of() {
}}
/// Lets you pass a type containing a `,` through a macro parameter without needing a separate
/// typedef, e.g.: `PYBIND11_OVERLOAD(PYBIND11_TYPE(ReturnType<A, B>), PYBIND11_TYPE(Parent<C, D>), f, arg)`
/// typedef, e.g.: `PYBIND11_OVERRIDE(PYBIND11_TYPE(ReturnType<A, B>), PYBIND11_TYPE(Parent<C, D>), f, arg)`
#define PYBIND11_TYPE(...) __VA_ARGS__
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -82,10 +82,10 @@ struct type_equal_to {
template <typename value_type>
using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
struct overload_hash {
struct override_hash {
inline size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
size_t value = std::hash<const void *>()(v.first);
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2);
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2);
return value;
}
};
@@ -97,7 +97,7 @@ struct internals {
type_map<type_info *> registered_types_cpp; // std::type_index -> pybind11's type information
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py; // PyTypeObject* -> base type_info(s)
std::unordered_multimap<const void *, instance*> registered_instances; // void * -> instance*
std::unordered_set<std::pair<const PyObject *, const char *>, overload_hash> inactive_overload_cache;
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash> inactive_override_cache;
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
std::forward_list<void (*) (std::exception_ptr)> registered_exception_translators;

View File

@@ -2110,21 +2110,22 @@ error_already_set::~error_already_set() {
}
}
inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) {
handle self = detail::get_object_handle(this_ptr, this_type);
PYBIND11_NAMESPACE_BEGIN(detail)
inline function get_type_override(const void *this_ptr, const type_info *this_type, const char *name) {
handle self = get_object_handle(this_ptr, this_type);
if (!self)
return function();
handle type = self.get_type();
auto key = std::make_pair(type.ptr(), name);
/* Cache functions that aren't overloaded in Python to avoid
/* Cache functions that aren't overridden in Python to avoid
many costly Python dictionary lookups below */
auto &cache = detail::get_internals().inactive_overload_cache;
auto &cache = get_internals().inactive_override_cache;
if (cache.find(key) != cache.end())
return function();
function overload = getattr(self, name, function());
if (overload.is_cpp_function()) {
function override = getattr(self, name, function());
if (override.is_cpp_function()) {
cache.insert(key);
return function();
}
@@ -2164,34 +2165,36 @@ inline function get_type_overload(const void *this_ptr, const detail::type_info
Py_DECREF(result);
#endif
return overload;
return override;
}
PYBIND11_NAMESPACE_END(detail)
/** \rst
Try to retrieve a python method by the provided name from the instance pointed to by the this_ptr.
:this_ptr: The pointer to the object the overload should be retrieved for. This should be the first
non-trampoline class encountered in the inheritance chain.
:name: The name of the overloaded Python method to retrieve.
:this_ptr: The pointer to the object the overriden method should be retrieved for. This should be
the first non-trampoline class encountered in the inheritance chain.
:name: The name of the overridden Python method to retrieve.
:return: The Python method by this name from the object or an empty function wrapper.
\endrst */
template <class T> function get_overload(const T *this_ptr, const char *name) {
template <class T> function get_override(const T *this_ptr, const char *name) {
auto tinfo = detail::get_type_info(typeid(T));
return tinfo ? get_type_overload(this_ptr, tinfo, name) : function();
return tinfo ? detail::get_type_override(this_ptr, tinfo, name) : function();
}
#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) { \
#define PYBIND11_OVERRIDE_IMPL(ret_type, cname, name, ...) \
do { \
pybind11::gil_scoped_acquire gil; \
pybind11::function overload = pybind11::get_overload(static_cast<const cname *>(this), name); \
if (overload) { \
auto o = overload(__VA_ARGS__); \
pybind11::function override = pybind11::get_override(static_cast<const cname *>(this), name); \
if (override) { \
auto o = override(__VA_ARGS__); \
if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value) { \
static pybind11::detail::overload_caster_t<ret_type> caster; \
static pybind11::detail::override_caster_t<ret_type> caster; \
return pybind11::detail::cast_ref<ret_type>(std::move(o), caster); \
} \
else return pybind11::detail::cast_safe<ret_type>(std::move(o)); \
} \
}
} while (false)
/** \rst
Macro to populate the virtual method in the trampoline class. This macro tries to look up a method named 'fn'
@@ -2202,7 +2205,7 @@ template <class T> function get_overload(const T *this_ptr, const char *name) {
.. code-block:: cpp
std::string toString() override {
PYBIND11_OVERLOAD_NAME(
PYBIND11_OVERRIDE_NAME(
std::string, // Return type (ret_type)
Animal, // Parent class (cname)
"__str__", // Name of method in Python (name)
@@ -2210,17 +2213,21 @@ template <class T> function get_overload(const T *this_ptr, const char *name) {
);
}
\endrst */
#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \
PYBIND11_OVERLOAD_INT(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__) \
return cname::fn(__VA_ARGS__)
#define PYBIND11_OVERRIDE_NAME(ret_type, cname, name, fn, ...) \
do { \
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \
return cname::fn(__VA_ARGS__); \
} while (false)
/** \rst
Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERLOAD_NAME`, except that it
throws if no overload can be found.
Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERRIDE_NAME`, except that it
throws if no override can be found.
\endrst */
#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \
PYBIND11_OVERLOAD_INT(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__) \
pybind11::pybind11_fail("Tried to call pure virtual function \"" PYBIND11_STRINGIFY(cname) "::" name "\"");
#define PYBIND11_OVERRIDE_PURE_NAME(ret_type, cname, name, fn, ...) \
do { \
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \
pybind11::pybind11_fail("Tried to call pure virtual function \"" PYBIND11_STRINGIFY(cname) "::" name "\""); \
} while (false)
/** \rst
Macro to populate the virtual method in the trampoline class. This macro tries to look up the method
@@ -2237,7 +2244,7 @@ template <class T> function get_overload(const T *this_ptr, const char *name) {
// Trampoline (need one for each virtual function)
std::string go(int n_times) override {
PYBIND11_OVERLOAD_PURE(
PYBIND11_OVERRIDE_PURE(
std::string, // Return type (ret_type)
Animal, // Parent class (cname)
go, // Name of function in C++ (must match Python name) (fn)
@@ -2246,15 +2253,39 @@ template <class T> function get_overload(const T *this_ptr, const char *name) {
}
};
\endrst */
#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \
PYBIND11_OVERLOAD_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
#define PYBIND11_OVERRIDE(ret_type, cname, fn, ...) \
PYBIND11_OVERRIDE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
/** \rst
Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERLOAD`, except that it throws
if no overload can be found.
Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERRIDE`, except that it throws
if no override can be found.
\endrst */
#define PYBIND11_OVERRIDE_PURE(ret_type, cname, fn, ...) \
PYBIND11_OVERRIDE_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
// Deprecated versions
PYBIND11_DEPRECATED("get_type_overload has been deprecated")
inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) {
return detail::get_type_override(this_ptr, this_type, name);
}
template <class T>
inline function get_overload(const T *this_ptr, const char *name) {
return get_override(this_ptr, name);
}
#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) \
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__)
#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \
PYBIND11_OVERRIDE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, fn, __VA_ARGS__)
#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \
PYBIND11_OVERRIDE_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, fn, __VA_ARGS__);
#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \
PYBIND11_OVERRIDE(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), fn, __VA_ARGS__)
#define PYBIND11_OVERLOAD_PURE(ret_type, cname, fn, ...) \
PYBIND11_OVERLOAD_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
PYBIND11_OVERRIDE_PURE(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), fn, __VA_ARGS__);
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)