Skip to content

[C API] Avoid "const PyObject*" type#91768

@vstinner

Description

@vstinner

When I converted Py_REFCNT(), Py_TYPE() and Py_SIZE() macros to static inline functions (issue #83754), I chose const PyObject* for their argument because these macros don't modify any member of the PyObject structure. When the Py_IS_TYPE() function was added, it followed the trend (commit 8767ce9). The _PyObject_CAST_CONST() macro was added to easily convert any pointer to const PyObject* for these macros expecting const PyObject*.

The problem is that passing PyObject* to one of these functions emits a compiler warning using gcc -Wcast-qual. The _PyObject_CAST_CONST() doesn't make the warning quiet.

Example explaining the issue:

staticinlineintvalue(int*p){return*p} #definevalue(p) value((int*)(p)) intmain(){intx=1; constint*p=&x; returnvalue(p)}

Output:

$ gcc x.c -Wcast-qual -o x && ./x;echo$? x.c: In function'main': x.c:2:24: warning: cast discards 'const' qualifier from pointer target type [-Wcast-qual] 2 |#define value(p) value((int*)(p))| ^ x.c:8:12: note: in expansion of macro 'value' 8 |return value(p);| ^~~~~ 1

In practice, the problem was that building a C extension (which includes <Python.h>) with gcc -Wcast-qual -Werror on Python 3.10 failed with an error on Py_IS_TYPE() implemented as:

staticinlineintPy_IS_TYPE(constPyObject*ob, constPyTypeObject*type){returnPy_TYPE(ob) ==type} #definePy_IS_TYPE(ob, type) Py_IS_TYPE(_PyObject_CAST_CONST(ob), type)

See the issue #88544 for the compiler error. I removed the Py_TYPE() call in Py_IS_TYPE() to work around the issue:

staticinlineintPy_IS_TYPE(constPyObject*ob, constPyTypeObject*type){// bpo-44378: Don't use Py_TYPE() since Py_TYPE() requires a non-const// object.returnob->ob_type==type} #definePy_IS_TYPE(ob, type) Py_IS_TYPE(_PyObject_CAST_CONST(ob), type)

But this problem strikes back when I try to convert unicodeobject.h macros to static inline functions for PEP 670 which removes the cast to PyObject* in the limited C API version 3.11: see PR #91696 and PR #91705. For example, _Py_strhex_with_sep() and _Py_strhex_bytes_with_sep() function get a const PyObject* argument and use PyUnicode C functions like PyUnicode_READY(), PyUnicode_KIND() and PyUnicode_READ_CHAR(), but these PyUnicode functions expect PyObject*: the const qualifier is lost. If Python/pystrhex.c is built with gcc -Wcast-qual, gcc emits warnings on PyUnicode_KIND() and PyUnicode_READ_CHAR() calls. That's just an example of problem which can happen in C extensions as well.

To avoid these problems, I propose to avoid const PyObject* in Python: only use PyObject*.

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions