]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-65210: Add const qualifiers in PyArg_VaParseTupleAndKeywords() (GH-105958)
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 4 Dec 2023 11:14:56 +0000 (13:14 +0200)
committerGitHub <noreply@github.com>
Mon, 4 Dec 2023 11:14:56 +0000 (13:14 +0200)
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.

Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM>
Doc/c-api/arg.rst
Doc/extending/extending.rst
Doc/whatsnew/3.13.rst
Include/modsupport.h
Include/pyport.h
Misc/NEWS.d/next/C API/2023-06-21-11-53-09.gh-issue-65210.PhFRBJ.rst [new file with mode: 0644]
Python/getargs.c

index 62d87d898e682c5520a4c152ebe0d14f9b57a8b6..834aae9372fe3bd84db89c7f241a58cd8f63f7d3 100644 (file)
@@ -413,7 +413,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, char * const *keywords, ...)
 
    Parse the parameters of a function that takes both positional and keyword
    parameters into local variables.
@@ -424,15 +424,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 with the :c:macro:`PY_CXX_CONST` macro.
+
    .. versionchanged:: 3.6
       Added support for :ref:`positional-only parameters
       <positional-only_parameter>`.
 
    .. 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 **`.
       Added support for non-ASCII keyword parameter names.
 
 
-.. 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, 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.
@@ -505,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
index 1ee7f28b2ba2206681c17125837ccfdbb7b394f3..745fc10a22d1612733295da7089898bb098edeab 100644 (file)
@@ -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
index 676305c6e1d06a82ab606a46a07f369ff568287a..be890ff314dfa44965f6d4f05b1bbbf9c11217a5 100644 (file)
@@ -1111,6 +1111,16 @@ 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 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 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
   :c:func:`PyImport_AddModule`, but return a :term:`strong reference` instead
   of a :term:`borrowed reference`.
index 450cc99c404c17007eeddd9d6c9f0588a5404baf..ea4c0fce9f4562c0bc046ecc2c3396fb34b13b51 100644 (file)
@@ -9,10 +9,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, ...);
index abb526d503fddd737bf420ad279f13978951519f..328471085f959da634c8def000eba478bdc18859 100644 (file)
@@ -586,6 +586,14 @@ extern "C" {
 #   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
+
 #if defined(__sgi) && !defined(_SGI_MP_SOURCE)
 #  define _SGI_MP_SOURCE
 #endif
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 (file)
index 0000000..a15646f
--- /dev/null
@@ -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++.
index 5ff8f7473609f5ebdddc223682b874f95305672f..0c4ce282f48764868ff62fa283a53edb9f344a03 100644 (file)
@@ -1,6 +1,7 @@
 
 /* New getargs implementation */
 
+#define PY_CXX_CONST const
 #include "Python.h"
 #include "pycore_abstract.h"      // _PyNumber_Index()
 #include "pycore_dict.h"          // _PyDict_HasOnlyStringKeys()
 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
 
@@ -54,7 +55,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,
@@ -1247,7 +1248,7 @@ int
 PyArg_ParseTupleAndKeywords(PyObject *args,
                             PyObject *keywords,
                             const char *format,
-                            char **kwlist, ...)
+                            const char * const *kwlist, ...)
 {
     int retval;
     va_list va;
@@ -1271,7 +1272,7 @@ int
 _PyArg_ParseTupleAndKeywords_SizeT(PyObject *args,
                                   PyObject *keywords,
                                   const char *format,
-                                  char **kwlist, ...)
+                                  const char * const *kwlist, ...)
 {
     int retval;
     va_list va;
@@ -1297,7 +1298,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;
@@ -1322,7 +1323,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;
@@ -1460,7 +1461,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];