summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2022-05-26 23:12:39 (GMT)
committerGitHub <noreply@github.com>2022-05-26 23:12:39 (GMT)
commit20d30ba2ccf9182e4f08db112f428c909148a40b (patch)
treeb9d0d366c1655495789ec0c218396569df096f79
parent5f8c3fb99746b9a7fadd4ec24cc4025b9c5d79d0 (diff)
downloadcpython-20d30ba2ccf9182e4f08db112f428c909148a40b.zip
cpython-20d30ba2ccf9182e4f08db112f428c909148a40b.tar.gz
cpython-20d30ba2ccf9182e4f08db112f428c909148a40b.tar.bz2
gh-92898: Enhance _testcppext test on cast to PyObject* (#93111)
* Add StrongRef class. * Rename and reformat functions of the _Py_CAST() implementation.
-rw-r--r--Include/pyport.h48
-rw-r--r--Lib/test/_testcppext.cpp42
-rw-r--r--Misc/NEWS.d/next/C API/2022-05-23-15-22-18.gh-issue-92898.Qjc9d3.rst2
3 files changed, 56 insertions, 36 deletions
diff --git a/Include/pyport.h b/Include/pyport.h
index 8e67637..6ea2bba 100644
--- a/Include/pyport.h
+++ b/Include/pyport.h
@@ -22,35 +22,33 @@
// _Py_CAST(PyObject*, op) can convert a "const PyObject*" to
// "PyObject*".
//
-// The type argument must not be constant. For example, in C++,
-// _Py_CAST(const PyObject*, expr) fails with a compiler error.
+// The type argument must not be a constant type.
#ifdef __cplusplus
# define _Py_STATIC_CAST(type, expr) static_cast<type>(expr)
-
extern "C++" {
-namespace {
-template <typename type, typename expr_type>
-inline type _Py_reinterpret_cast_impl(expr_type *expr) {
- return reinterpret_cast<type>(expr);
-}
-
-template <typename type, typename expr_type>
-inline type _Py_reinterpret_cast_impl(expr_type const *expr) {
- return reinterpret_cast<type>(const_cast<expr_type *>(expr));
-}
-
-template <typename type, typename expr_type>
-inline type _Py_reinterpret_cast_impl(expr_type &expr) {
- return static_cast<type>(expr);
-}
-
-template <typename type, typename expr_type>
-inline type _Py_reinterpret_cast_impl(expr_type const &expr) {
- return static_cast<type>(const_cast<expr_type &>(expr));
-}
-} // namespace
+ namespace {
+ template <typename type, typename expr_type>
+ inline type _Py_CAST_impl(expr_type *expr) {
+ return reinterpret_cast<type>(expr);
+ }
+
+ template <typename type, typename expr_type>
+ inline type _Py_CAST_impl(expr_type const *expr) {
+ return reinterpret_cast<type>(const_cast<expr_type *>(expr));
+ }
+
+ template <typename type, typename expr_type>
+ inline type _Py_CAST_impl(expr_type &expr) {
+ return static_cast<type>(expr);
+ }
+
+ template <typename type, typename expr_type>
+ inline type _Py_CAST_impl(expr_type const &expr) {
+ return static_cast<type>(const_cast<expr_type &>(expr));
+ }
+ }
}
-# define _Py_CAST(type, expr) _Py_reinterpret_cast_impl<type>(expr)
+# define _Py_CAST(type, expr) _Py_CAST_impl<type>(expr)
#else
# define _Py_STATIC_CAST(type, expr) ((type)(expr))
diff --git a/Lib/test/_testcppext.cpp b/Lib/test/_testcppext.cpp
index f6049ee..eade7cc 100644
--- a/Lib/test/_testcppext.cpp
+++ b/Lib/test/_testcppext.cpp
@@ -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 *
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) {
return nullptr;
}
+ Py_ssize_t refcnt = Py_REFCNT(obj);
+ assert(refcnt >= 1);
// gh-92138: For backward compatibility, functions of Python C API accepts
// "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_DECREF(const_obj);
PyTypeObject *type = Py_TYPE(const_obj);
- assert(Py_REFCNT(const_obj) >= 1);
-
- 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(Py_REFCNT(const_obj) == refcnt);
assert(type == &PyTuple_Type);
assert(PyTuple_GET_SIZE(const_obj) == 2);
PyObject *one = PyTuple_GET_ITEM(const_obj, 0);
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_RETURN_NONE;
}
diff --git a/Misc/NEWS.d/next/C API/2022-05-23-15-22-18.gh-issue-92898.Qjc9d3.rst b/Misc/NEWS.d/next/C API/2022-05-23-15-22-18.gh-issue-92898.Qjc9d3.rst
new file mode 100644
index 0000000..01eca1d
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2022-05-23-15-22-18.gh-issue-92898.Qjc9d3.rst
@@ -0,0 +1,2 @@
+Fix C++ compiler warnings when casting function arguments to ``PyObject*``.
+Patch by Serge Guelton.