summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2023-12-04 11:14:56 (GMT)
committerGitHub <noreply@github.com>2023-12-04 11:14:56 (GMT)
commitda6760bdf5ed8ede203618d5118f4ceb2cb1652d (patch)
treeb6ba925bc254f38e392ff77ca0530523ff8b7012
parentcda737924fd616c4e08027888258f97e81f34447 (diff)
downloadcpython-da6760bdf5ed8ede203618d5118f4ceb2cb1652d.zip
cpython-da6760bdf5ed8ede203618d5118f4ceb2cb1652d.tar.gz
cpython-da6760bdf5ed8ede203618d5118f4ceb2cb1652d.tar.bz2
gh-65210: Add const qualifiers in PyArg_VaParseTupleAndKeywords() (GH-105958)
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>
-rw-r--r--Doc/c-api/arg.rst26
-rw-r--r--Doc/extending/extending.rst2
-rw-r--r--Doc/whatsnew/3.13.rst10
-rw-r--r--Include/modsupport.h4
-rw-r--r--Include/pyport.h8
-rw-r--r--Misc/NEWS.d/next/C API/2023-06-21-11-53-09.gh-issue-65210.PhFRBJ.rst3
-rw-r--r--Python/getargs.c17
7 files changed, 57 insertions, 13 deletions
diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst
index 62d87d8..834aae9 100644
--- a/Doc/c-api/arg.rst
+++ b/Doc/c-api/arg.rst
@@ -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
diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst
index 1ee7f28..745fc10 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 676305c..be890ff 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -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`.
diff --git a/Include/modsupport.h b/Include/modsupport.h
index 450cc99..ea4c0fc 100644
--- a/Include/modsupport.h
+++ b/Include/modsupport.h
@@ -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, ...);
diff --git a/Include/pyport.h b/Include/pyport.h
index abb526d..3284710 100644
--- a/Include/pyport.h
+++ b/Include/pyport.h
@@ -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
index 0000000..a15646f
--- /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 5ff8f74..0c4ce28 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_abstract.h" // _PyNumber_Index()
#include "pycore_dict.h" // _PyDict_HasOnlyStringKeys()
@@ -12,10 +13,10 @@
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];