mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
gh-92898: Enhance _testcppext test on cast to PyObject* (GH-93111)
* Add StrongRef class.
* Rename and reformat functions of the _Py_CAST() implementation.
(cherry picked from commit 20d30ba2cc
)
Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
parent
33336e46da
commit
9303a5ac30
3 changed files with 53 additions and 33 deletions
|
@ -22,35 +22,33 @@
|
||||||
// _Py_CAST(PyObject*, op) can convert a "const PyObject*" to
|
// _Py_CAST(PyObject*, op) can convert a "const PyObject*" to
|
||||||
// "PyObject*".
|
// "PyObject*".
|
||||||
//
|
//
|
||||||
// The type argument must not be constant. For example, in C++,
|
// The type argument must not be a constant type.
|
||||||
// _Py_CAST(const PyObject*, expr) fails with a compiler error.
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
# define _Py_STATIC_CAST(type, expr) static_cast<type>(expr)
|
# define _Py_STATIC_CAST(type, expr) static_cast<type>(expr)
|
||||||
|
|
||||||
extern "C++" {
|
extern "C++" {
|
||||||
namespace {
|
namespace {
|
||||||
template <typename type, typename expr_type>
|
template <typename type, typename expr_type>
|
||||||
inline type _Py_reinterpret_cast_impl(expr_type *expr) {
|
inline type _Py_CAST_impl(expr_type *expr) {
|
||||||
return reinterpret_cast<type>(expr);
|
return reinterpret_cast<type>(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename type, typename expr_type>
|
template <typename type, typename expr_type>
|
||||||
inline type _Py_reinterpret_cast_impl(expr_type const *expr) {
|
inline type _Py_CAST_impl(expr_type const *expr) {
|
||||||
return reinterpret_cast<type>(const_cast<expr_type *>(expr));
|
return reinterpret_cast<type>(const_cast<expr_type *>(expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename type, typename expr_type>
|
template <typename type, typename expr_type>
|
||||||
inline type _Py_reinterpret_cast_impl(expr_type &expr) {
|
inline type _Py_CAST_impl(expr_type &expr) {
|
||||||
return static_cast<type>(expr);
|
return static_cast<type>(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename type, typename expr_type>
|
template <typename type, typename expr_type>
|
||||||
inline type _Py_reinterpret_cast_impl(expr_type const &expr) {
|
inline type _Py_CAST_impl(expr_type const &expr) {
|
||||||
return static_cast<type>(const_cast<expr_type &>(expr));
|
return static_cast<type>(const_cast<expr_type &>(expr));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
# define _Py_CAST(type, expr) _Py_CAST_impl<type>(expr)
|
||||||
}
|
|
||||||
# define _Py_CAST(type, expr) _Py_reinterpret_cast_impl<type>(expr)
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# define _Py_STATIC_CAST(type, expr) ((type)(expr))
|
# define _Py_STATIC_CAST(type, expr) ((type)(expr))
|
||||||
|
|
|
@ -23,6 +23,26 @@ _testcppext_add(PyObject *Py_UNUSED(module), PyObject *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Class to test operator casting an object to PyObject*
|
||||||
|
class StrongRef
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StrongRef(PyObject *obj) : m_obj(obj) {
|
||||||
|
Py_INCREF(this->m_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
~StrongRef() {
|
||||||
|
Py_DECREF(this->m_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cast to PyObject*: get a borrowed reference
|
||||||
|
inline operator PyObject*() const { return this->m_obj; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
PyObject *m_obj; // Strong reference
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
test_api_casts(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
|
test_api_casts(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
|
||||||
{
|
{
|
||||||
|
@ -30,6 +50,8 @@ test_api_casts(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
|
||||||
if (obj == nullptr) {
|
if (obj == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
Py_ssize_t refcnt = Py_REFCNT(obj);
|
||||||
|
assert(refcnt >= 1);
|
||||||
|
|
||||||
// gh-92138: For backward compatibility, functions of Python C API accepts
|
// gh-92138: For backward compatibility, functions of Python C API accepts
|
||||||
// "const PyObject*". Check that using it does not emit C++ compiler
|
// "const PyObject*". Check that using it does not emit C++ compiler
|
||||||
|
@ -38,22 +60,20 @@ test_api_casts(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
|
||||||
Py_INCREF(const_obj);
|
Py_INCREF(const_obj);
|
||||||
Py_DECREF(const_obj);
|
Py_DECREF(const_obj);
|
||||||
PyTypeObject *type = Py_TYPE(const_obj);
|
PyTypeObject *type = Py_TYPE(const_obj);
|
||||||
assert(Py_REFCNT(const_obj) >= 1);
|
assert(Py_REFCNT(const_obj) == refcnt);
|
||||||
|
|
||||||
struct PyObjectProxy {
|
|
||||||
PyObject* obj;
|
|
||||||
operator PyObject *() { return obj; }
|
|
||||||
} proxy_obj = { obj };
|
|
||||||
Py_INCREF(proxy_obj);
|
|
||||||
Py_DECREF(proxy_obj);
|
|
||||||
assert(Py_REFCNT(proxy_obj) >= 1);
|
|
||||||
|
|
||||||
|
|
||||||
assert(type == &PyTuple_Type);
|
assert(type == &PyTuple_Type);
|
||||||
assert(PyTuple_GET_SIZE(const_obj) == 2);
|
assert(PyTuple_GET_SIZE(const_obj) == 2);
|
||||||
PyObject *one = PyTuple_GET_ITEM(const_obj, 0);
|
PyObject *one = PyTuple_GET_ITEM(const_obj, 0);
|
||||||
assert(PyLong_AsLong(one) == 1);
|
assert(PyLong_AsLong(one) == 1);
|
||||||
|
|
||||||
|
// gh-92898: StrongRef doesn't inherit from PyObject but has an operator to
|
||||||
|
// cast to PyObject*.
|
||||||
|
StrongRef strong_ref(obj);
|
||||||
|
assert(Py_TYPE(strong_ref) == &PyTuple_Type);
|
||||||
|
assert(Py_REFCNT(strong_ref) == (refcnt + 1));
|
||||||
|
Py_INCREF(strong_ref);
|
||||||
|
Py_DECREF(strong_ref);
|
||||||
|
|
||||||
Py_DECREF(obj);
|
Py_DECREF(obj);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fix C++ compiler warnings when casting function arguments to ``PyObject*``.
|
||||||
|
Patch by Serge Guelton.
|
Loading…
Add table
Add a link
Reference in a new issue