Add _PyArg_UnpackStack() function helper

Issue #29286.
diff --git a/Include/modsupport.h b/Include/modsupport.h
index e6713e2..e464a1c 100644
--- a/Include/modsupport.h
+++ b/Include/modsupport.h
@@ -47,7 +47,16 @@
 PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...);
 PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...);
 #endif
+
 #ifndef Py_LIMITED_API
+PyAPI_FUNC(int) _PyArg_UnpackStack(
+    PyObject **args,
+    Py_ssize_t nargs,
+    const char *name,
+    Py_ssize_t min,
+    Py_ssize_t max,
+    ...);
+
 PyAPI_FUNC(int) _PyArg_NoKeywords(const char *funcname, PyObject *kwargs);
 PyAPI_FUNC(int) _PyArg_NoStackKeywords(const char *funcname, PyObject *kwnames);
 PyAPI_FUNC(int) _PyArg_NoPositional(const char *funcname, PyObject *args);
@@ -56,6 +65,7 @@
 PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,
                                                   const char *, char **, va_list);
 #endif
+
 PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list);
 #ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject **) _Py_VaBuildStack(
diff --git a/Python/getargs.c b/Python/getargs.c
index e3611d8..47b00af 100644
--- a/Python/getargs.c
+++ b/Python/getargs.c
@@ -2363,21 +2363,16 @@
 }
 
 
-int
-PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...)
+static int
+PyArg_UnpackStack_impl(PyObject **args, Py_ssize_t l, const char *name,
+                       Py_ssize_t min, Py_ssize_t max, va_list vargs)
 {
-    Py_ssize_t i, l;
+    Py_ssize_t i;
     PyObject **o;
-    va_list vargs;
 
     assert(min >= 0);
     assert(min <= max);
-    if (!PyTuple_Check(args)) {
-        PyErr_SetString(PyExc_SystemError,
-            "PyArg_UnpackTuple() argument list is not a tuple");
-        return 0;
-    }
-    l = PyTuple_GET_SIZE(args);
+
     if (l < min) {
         if (name != NULL)
             PyErr_Format(
@@ -2392,8 +2387,11 @@
                 (min == max ? "" : "at least "), min, l);
         return 0;
     }
-    if (l == 0)
+
+    if (l == 0) {
         return 1;
+    }
+
     if (l > max) {
         if (name != NULL)
             PyErr_Format(
@@ -2409,17 +2407,54 @@
         return 0;
     }
 
+    for (i = 0; i < l; i++) {
+        o = va_arg(vargs, PyObject **);
+        *o = args[i];
+    }
+    return 1;
+}
+
+int
+PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...)
+{
+    PyObject **stack;
+    Py_ssize_t nargs;
+    int retval;
+    va_list vargs;
+
+    if (!PyTuple_Check(args)) {
+        PyErr_SetString(PyExc_SystemError,
+            "PyArg_UnpackTuple() argument list is not a tuple");
+        return 0;
+    }
+    stack = &PyTuple_GET_ITEM(args, 0);
+    nargs = PyTuple_GET_SIZE(args);
+
 #ifdef HAVE_STDARG_PROTOTYPES
     va_start(vargs, max);
 #else
     va_start(vargs);
 #endif
-    for (i = 0; i < l; i++) {
-        o = va_arg(vargs, PyObject **);
-        *o = PyTuple_GET_ITEM(args, i);
-    }
+    retval = PyArg_UnpackStack_impl(stack, nargs, name, min, max, vargs);
     va_end(vargs);
-    return 1;
+    return retval;
+}
+
+int
+_PyArg_UnpackStack(PyObject **args, Py_ssize_t nargs, const char *name,
+                   Py_ssize_t min, Py_ssize_t max, ...)
+{
+    int retval;
+    va_list vargs;
+
+#ifdef HAVE_STDARG_PROTOTYPES
+    va_start(vargs, max);
+#else
+    va_start(vargs);
+#endif
+    retval = PyArg_UnpackStack_impl(args, nargs, name, min, max, vargs);
+    va_end(vargs);
+    return retval;
 }
 
 
@@ -2431,8 +2466,9 @@
 int
 _PyArg_NoKeywords(const char *funcname, PyObject *kwargs)
 {
-    if (kwargs == NULL)
+    if (kwargs == NULL) {
         return 1;
+    }
     if (!PyDict_CheckExact(kwargs)) {
         PyErr_BadInternalCall();
         return 0;
@@ -2450,8 +2486,9 @@
 int
 _PyArg_NoStackKeywords(const char *funcname, PyObject *kwnames)
 {
-    if (kwnames == NULL)
+    if (kwnames == NULL) {
         return 1;
+    }
     assert(PyTuple_CheckExact(kwnames));
     if (PyTuple_GET_SIZE(kwnames) == 0) {
         return 1;