From 80e37a91e621c2295ebcca0ee4afe6bb2b9b2257 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 21 Jun 2023 09:59:50 +0300 Subject: [PATCH 1/4] gh-65210: Add const qualifiers in PyArg_VaParseTupleAndKeywords() Change the declaration of the keywords parameter in functions PyArg_ParseTupleAndKeywords() and PyArg_VaParseTupleAndKeywords() from `char **` to `char * const *` in C and `const char * const *` in C++. It makes these functions compatible with argument of type `const char * const *`, `const char **` or `char * const *` in C++ and `char * const *` in C without explicit type cast. --- Doc/c-api/arg.rst | 16 ++++++++++++++-- Doc/extending/extending.rst | 2 +- Doc/whatsnew/3.13.rst | 12 ++++++++++++ Include/modsupport.h | 4 ++-- Include/pyport.h | 8 ++++++++ ...023-06-21-11-53-09.gh-issue-65210.PhFRBJ.rst | 3 +++ Python/getargs.c | 17 +++++++++-------- 7 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-21-11-53-09.gh-issue-65210.PhFRBJ.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index d2ea490732fe59..2929d1efb14ddb 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -410,7 +410,7 @@ API Functions than a variable number of arguments. -.. c:function:: int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *keywords[], ...) +.. c:function:: int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, /*const*/ char * const *keywords, ...) Parse the parameters of a function that takes both positional and keyword parameters into local variables. The *keywords* argument is a @@ -419,12 +419,24 @@ API Functions Returns true on success; on failure, it returns false and raises the appropriate exception. + .. note:: + + The *keywords* parameter declaration is :c:expr:`char * const *` in C and + :c:expr:`const char * const *` in C++. + This can be overridden by defining the macro :c:macro:`PY_CXX_CONST` + before including :file:`Python.h` as ``const`` for the latter and as + empty value for the former. + .. versionchanged:: 3.6 Added support for :ref:`positional-only parameters `. + .. versionchanged:: 3.13 + The *keywords* parameter has now type :c:expr:`char * const *` in C and + :c:expr:`const char * const *` in C++, instead of :c:expr:`char **`. + -.. c:function:: int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *keywords[], va_list vargs) +.. c:function:: int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, /*const*/ char * const *keywords, va_list vargs) Identical to :c:func:`PyArg_ParseTupleAndKeywords`, except that it accepts a va_list rather than a variable number of arguments. diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index ef93848840861c..d64727f187f87a 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -735,7 +735,7 @@ Keyword Parameters for Extension Functions The :c:func:`PyArg_ParseTupleAndKeywords` function is declared as follows:: int PyArg_ParseTupleAndKeywords(PyObject *arg, PyObject *kwdict, - const char *format, char *kwlist[], ...); + const char *format, char * const *kwlist, ...); The *arg* and *format* parameters are identical to those of the :c:func:`PyArg_ParseTuple` function. The *kwdict* parameter is the dictionary of diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index bbe02a9e85b42c..44f6675c63575c 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -426,6 +426,18 @@ New Features APIs accepting the format codes always use ``Py_ssize_t`` for ``#`` formats. (Contributed by Inada Naoki in :gh:`104922`.) +* The *keywords* parameter of :c:func:`PyArg_ParseTupleAndKeywords` and + :c:func:`PyArg_VaParseTupleAndKeywords` has now type :c:expr:`char * const *` + in C and :c:expr:`const char * const *` in C++, instead of :c:expr:`char **`. + It makes these functions compatible with argument of type + :c:expr:`const char * const *`, :c:expr:`const char **` or + :c:expr:`char * const *` in C++ and :c:expr:`char * const *` in C + without explicit type cast. + This can be overridden by defining the macro :c:macro:`PY_CXX_CONST` + before including :file:`Python.h` as ``const`` for the latter and as + empty value for the former. + (Contributed by Serhiy Storchaka in :gh:`65210`.) + * Add :c:func:`PyImport_AddModuleRef`: similar to :c:func:`PyImport_AddModule`, but return a :term:`strong reference` instead of a :term:`borrowed reference`. diff --git a/Include/modsupport.h b/Include/modsupport.h index 7d4cfe853aaa7e..9982a5c9ddf085 100644 --- a/Include/modsupport.h +++ b/Include/modsupport.h @@ -12,10 +12,10 @@ extern "C" { PyAPI_FUNC(int) PyArg_Parse(PyObject *, const char *, ...); PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...); PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *, - const char *, char **, ...); + const char *, PY_CXX_CONST char * const *, ...); PyAPI_FUNC(int) PyArg_VaParse(PyObject *, const char *, va_list); PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *, - const char *, char **, va_list); + const char *, PY_CXX_CONST char * const *, va_list); PyAPI_FUNC(int) PyArg_ValidateKeywordArguments(PyObject *); PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *, const char *, Py_ssize_t, Py_ssize_t, ...); diff --git a/Include/pyport.h b/Include/pyport.h index d7c6ae64f2bf2f..e90584411a4a11 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -776,4 +776,12 @@ extern char * _getpty(int *, int, mode_t, int); # define ALIGNOF_MAX_ALIGN_T _Alignof(long double) #endif +#ifndef PY_CXX_CONST +# ifdef __cplusplus +# define PY_CXX_CONST const +# else +# define PY_CXX_CONST +# endif +#endif + #endif /* Py_PYPORT_H */ diff --git a/Misc/NEWS.d/next/C API/2023-06-21-11-53-09.gh-issue-65210.PhFRBJ.rst b/Misc/NEWS.d/next/C API/2023-06-21-11-53-09.gh-issue-65210.PhFRBJ.rst new file mode 100644 index 00000000000000..a15646f4dad127 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-21-11-53-09.gh-issue-65210.PhFRBJ.rst @@ -0,0 +1,3 @@ +Change the declaration of the *keywords* parameter of +:c:func:`PyArg_ParseTupleAndKeywords` and +:c:func:`PyArg_VaParseTupleAndKeywords` for better compatibility with C++. diff --git a/Python/getargs.c b/Python/getargs.c index 45befab4f8bc37..db15800cd74dd4 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1,6 +1,7 @@ /* New getargs implementation */ +#define PY_CXX_CONST const #include "Python.h" #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "pycore_pylifecycle.h" // _PyArg_Fini @@ -17,10 +18,10 @@ extern "C" { PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...); PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, const char *, ...); PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywords_SizeT(PyObject *, PyObject *, - const char *, char **, ...); + const char *, const char * const *, ...); PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, const char *, va_list); PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *, PyObject *, - const char *, char **, va_list); + const char *, const char * const *, va_list); #define FLAG_COMPAT 1 @@ -59,7 +60,7 @@ static Py_ssize_t convertbuffer(PyObject *, const void **p, const char **); static int getbuffer(PyObject *, Py_buffer *, const char**); static int vgetargskeywords(PyObject *, PyObject *, - const char *, char **, va_list *, int); + const char *, const char * const *, va_list *, int); static int vgetargskeywordsfast(PyObject *, PyObject *, struct _PyArg_Parser *, va_list *, int); static int vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, @@ -1267,7 +1268,7 @@ int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *keywords, const char *format, - char **kwlist, ...) + const char * const *kwlist, ...) { int retval; va_list va; @@ -1291,7 +1292,7 @@ int _PyArg_ParseTupleAndKeywords_SizeT(PyObject *args, PyObject *keywords, const char *format, - char **kwlist, ...) + const char * const *kwlist, ...) { int retval; va_list va; @@ -1317,7 +1318,7 @@ int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *keywords, const char *format, - char **kwlist, va_list va) + const char * const *kwlist, va_list va) { int retval; va_list lva; @@ -1342,7 +1343,7 @@ int _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args, PyObject *keywords, const char *format, - char **kwlist, va_list va) + const char * const *kwlist, va_list va) { int retval; va_list lva; @@ -1494,7 +1495,7 @@ PyArg_ValidateKeywordArguments(PyObject *kwargs) static int vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, - char **kwlist, va_list *p_va, int flags) + const char * const *kwlist, va_list *p_va, int flags) { char msgbuf[512]; int levels[32]; From 1340934c0919a6622e56cc55df95b764ff0afc48 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 22 Jun 2023 08:58:03 +0300 Subject: [PATCH 2/4] Fix doc build. --- Doc/c-api/arg.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index 2929d1efb14ddb..e95e2285f6dd31 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -410,7 +410,7 @@ API Functions than a variable number of arguments. -.. c:function:: int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, /*const*/ char * const *keywords, ...) +.. c:function:: int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char * const *keywords, ...) Parse the parameters of a function that takes both positional and keyword parameters into local variables. The *keywords* argument is a @@ -436,7 +436,7 @@ API Functions :c:expr:`const char * const *` in C++, instead of :c:expr:`char **`. -.. c:function:: int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, /*const*/ char * const *keywords, va_list vargs) +.. c:function:: int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char * const *keywords, va_list vargs) Identical to :c:func:`PyArg_ParseTupleAndKeywords`, except that it accepts a va_list rather than a variable number of arguments. From 040817e7d84ee5f29be417fde76e2b1419a5d148 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 22 Jun 2023 11:09:47 +0300 Subject: [PATCH 3/4] Silence Sphinx warning. --- Doc/whatsnew/3.13.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 44f6675c63575c..79a42d71f5df3b 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -433,7 +433,7 @@ New Features :c:expr:`const char * const *`, :c:expr:`const char **` or :c:expr:`char * const *` in C++ and :c:expr:`char * const *` in C without explicit type cast. - This can be overridden by defining the macro :c:macro:`PY_CXX_CONST` + This can be overridden by defining the macro ``PY_CXX_CONST`` before including :file:`Python.h` as ``const`` for the latter and as empty value for the former. (Contributed by Serhiy Storchaka in :gh:`65210`.) From 0e4dc590805d1db2fe06ebd34e812e0f38ad9c93 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 1 Dec 2023 12:02:55 +0200 Subject: [PATCH 4/4] Apply suggestions. Co-authored-by: C.A.M. Gerlach --- Doc/c-api/arg.rst | 17 ++++++++++++++--- Doc/whatsnew/3.13.rst | 8 +++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index 35dc01e196e777..834aae9372fe3b 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -428,9 +428,7 @@ API Functions The *keywords* parameter declaration is :c:expr:`char * const *` in C and :c:expr:`const char * const *` in C++. - This can be overridden by defining the macro :c:macro:`PY_CXX_CONST` - before including :file:`Python.h` as ``const`` for the latter and as - empty value for the former. + This can be overridden with the :c:macro:`PY_CXX_CONST` macro. .. versionchanged:: 3.6 Added support for :ref:`positional-only parameters @@ -516,6 +514,19 @@ API Functions PyArg_ParseTuple(args, "O|O:ref", &object, &callback) +.. c:macro:: PY_CXX_CONST + + The value to be inserted, if any, before :c:expr:`char * const *` + in the *keywords* parameter declaration of + :c:func:`PyArg_ParseTupleAndKeywords` and + :c:func:`PyArg_VaParseTupleAndKeywords`. + Default empty for C and ``const`` for C++ + (:c:expr:`const char * const *`). + To override, define it to the desired value before including + :file:`Python.h`. + + .. versionadded:: 3.13 + --------------- Building values diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 6127ea7eff0617..8eede2421c6b7d 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -1107,13 +1107,11 @@ New Features * The *keywords* parameter of :c:func:`PyArg_ParseTupleAndKeywords` and :c:func:`PyArg_VaParseTupleAndKeywords` has now type :c:expr:`char * const *` in C and :c:expr:`const char * const *` in C++, instead of :c:expr:`char **`. - It makes these functions compatible with argument of type + It makes these functions compatible with arguments of type :c:expr:`const char * const *`, :c:expr:`const char **` or :c:expr:`char * const *` in C++ and :c:expr:`char * const *` in C - without explicit type cast. - This can be overridden by defining the macro ``PY_CXX_CONST`` - before including :file:`Python.h` as ``const`` for the latter and as - empty value for the former. + without an explicit type cast. + This can be overridden with the :c:macro:`PY_CXX_CONST` macro. (Contributed by Serhiy Storchaka in :gh:`65210`.) * Add :c:func:`PyImport_AddModuleRef`: similar to