https://github.com/python/cpython/commit/50e518e886e6dde5542a2372d5b04acbdda4fc7d
commit: 50e518e886e6dde5542a2372d5b04acbdda4fc7d
branch: main
author: Bénédikt Tran <10796600+picn...@users.noreply.github.com>
committer: picnixz <10796600+picn...@users.noreply.github.com>
date: 2025-04-18T10:15:40+02:00
summary:

gh-132097: allow AC to disable fastcall convention to avoid UBSan failures 
(#131605)

files:
M Modules/_testclinic.c
M Modules/clinic/_testclinic.c.h
M Tools/clinic/libclinic/dsl_parser.py
M Tools/clinic/libclinic/function.py
M Tools/clinic/libclinic/parse_args.py

diff --git a/Modules/_testclinic.c b/Modules/_testclinic.c
index a5c4a4c40b3949..0a1f13db6ca204 100644
--- a/Modules/_testclinic.c
+++ b/Modules/_testclinic.c
@@ -1443,25 +1443,69 @@ 
_testclinic_TestClass_defclass_posonly_varpos_impl(PyObject *self,
 }
 
 
-/*[clinic input]
+/*
+ * # Do NOT use __new__ to generate this method. Compare:
+ *
+ * [1] With __new__ (METH_KEYWORDS must be added even if we don't want to)
+ *
+ *   varpos_no_fastcall(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+ *   varpos_no_fastcall_impl(PyTypeObject *type, PyObject *args)
+ *   no auto-generated METHODDEF macro
+ *
+ * [2] Without __new__ (automatically METH_FASTCALL, not good for this test)
+ *
+ *   varpos_no_fastcall_impl(PyObject *type, PyObject *args)
+ *   varpos_no_fastcall(PyObject *type, PyObject *const *args, Py_ssize_t 
nargs)
+ *   flags = METH_FASTCALL|METH_CLASS
+ *
+ * [3] Without __new__ + "@disable fastcall" (what we want)
+ *
+ *   varpos_no_fastcall(PyObject *type, PyObject *args)
+ *   varpos_no_fastcall_impl(PyTypeObject *type, PyObject *args)
+ *   flags = METH_VARARGS|METH_CLASS
+ *
+ * We want to test a non-fastcall class method but without triggering an
+ * undefined behaviour at runtime in cfunction_call().
+ *
+ * At runtime, a METH_VARARGS method called in cfunction_call() must be:
+ *
+ *       (PyObject *, PyObject *)             -> PyObject *
+ *       (PyObject *, PyObject *, PyObject *) -> PyObject *
+ *
+ * depending on whether METH_KEYWORDS is present or not.
+ *
+ * AC determines whether a method is a __new__-like method solely bsaed
+ * on the method name, and not on its usage or its c_basename, and those
+ * methods must always be used with METH_VARARGS|METH_KEYWORDS|METH_CLASS.
+ *
+ * In particular, using [1] forces us to add METH_KEYWORDS even though
+ * the test shouldn't be expecting keyword arguments. Using [2] is also
+ * not possible since we want to test non-fastcalls. This is the reason
+ * why we need to be able to disable the METH_FASTCALL flag.
+ */
+
+/*[clinic input]
+@disable fastcall
 @classmethod
-_testclinic.TestClass.__new__ as varpos_no_fastcall
+_testclinic.TestClass.varpos_no_fastcall
 
     *args: tuple
 
 [clinic start generated code]*/
 
 static PyObject *
-varpos_no_fastcall_impl(PyTypeObject *type, PyObject *args)
-/*[clinic end generated code: output=04e94f2898bb2dde input=c5d3d30a6589f97f]*/
+_testclinic_TestClass_varpos_no_fastcall_impl(PyTypeObject *type,
+                                              PyObject *args)
+/*[clinic end generated code: output=edfacec733aeb9c5 input=3f298d143aa98048]*/
 {
     return Py_NewRef(args);
 }
 
 
 /*[clinic input]
+@disable fastcall
 @classmethod
-_testclinic.TestClass.__new__ as posonly_varpos_no_fastcall
+_testclinic.TestClass.posonly_varpos_no_fastcall
 
     a: object
     b: object
@@ -1471,17 +1515,20 @@ _testclinic.TestClass.__new__ as 
posonly_varpos_no_fastcall
 [clinic start generated code]*/
 
 static PyObject *
-posonly_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a, PyObject *b,
-                                PyObject *args)
-/*[clinic end generated code: output=b0a0425719f69f5a input=10f29f2c2c6bfdc4]*/
+_testclinic_TestClass_posonly_varpos_no_fastcall_impl(PyTypeObject *type,
+                                                      PyObject *a,
+                                                      PyObject *b,
+                                                      PyObject *args)
+/*[clinic end generated code: output=2c5184aebe020085 input=3621dd172c5193d8]*/
 {
     return pack_arguments_newref(3, a, b, args);
 }
 
 
 /*[clinic input]
+@disable fastcall
 @classmethod
-_testclinic.TestClass.__new__ as posonly_req_opt_varpos_no_fastcall
+_testclinic.TestClass.posonly_req_opt_varpos_no_fastcall
 
     a: object
     b: object = False
@@ -1491,17 +1538,20 @@ _testclinic.TestClass.__new__ as 
posonly_req_opt_varpos_no_fastcall
 [clinic start generated code]*/
 
 static PyObject *
-posonly_req_opt_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a,
-                                        PyObject *b, PyObject *args)
-/*[clinic end generated code: output=3c44915b1a554e2d input=d319302a8748147c]*/
+_testclinic_TestClass_posonly_req_opt_varpos_no_fastcall_impl(PyTypeObject 
*type,
+                                                              PyObject *a,
+                                                              PyObject *b,
+                                                              PyObject *args)
+/*[clinic end generated code: output=08e533d59bceadf6 input=922fa7851b32e2dd]*/
 {
     return pack_arguments_newref(3, a, b, args);
 }
 
 
 /*[clinic input]
+@disable fastcall
 @classmethod
-_testclinic.TestClass.__new__ as posonly_poskw_varpos_no_fastcall
+_testclinic.TestClass.posonly_poskw_varpos_no_fastcall
 
     a: object
     /
@@ -1511,34 +1561,39 @@ _testclinic.TestClass.__new__ as 
posonly_poskw_varpos_no_fastcall
 [clinic start generated code]*/
 
 static PyObject *
-posonly_poskw_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a,
-                                      PyObject *b, PyObject *args)
-/*[clinic end generated code: output=6ad74bed4bdc7f96 input=1f8c113e749414a3]*/
+_testclinic_TestClass_posonly_poskw_varpos_no_fastcall_impl(PyTypeObject *type,
+                                                            PyObject *a,
+                                                            PyObject *b,
+                                                            PyObject *args)
+/*[clinic end generated code: output=8ecfda20850e689f input=60443fe0bb8fe3e0]*/
 {
     return pack_arguments_newref(3, a, b, args);
 }
 
 
 /*[clinic input]
+@disable fastcall
 @classmethod
-_testclinic.TestClass.__new__ as varpos_array_no_fastcall
+_testclinic.TestClass.varpos_array_no_fastcall
 
     *args: array
 
 [clinic start generated code]*/
 
 static PyObject *
-varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject * const *args,
-                              Py_ssize_t args_length)
-/*[clinic end generated code: output=f99d984346c60d42 input=368d8eea6de48c12]*/
+_testclinic_TestClass_varpos_array_no_fastcall_impl(PyTypeObject *type,
+                                                    PyObject * const *args,
+                                                    Py_ssize_t args_length)
+/*[clinic end generated code: output=27c9da663e942617 input=9ba5ae1f1eb58777]*/
 {
     return _PyTuple_FromArray(args, args_length);
 }
 
 
 /*[clinic input]
+@disable fastcall
 @classmethod
-_testclinic.TestClass.__new__ as posonly_varpos_array_no_fastcall
+_testclinic.TestClass.posonly_varpos_array_no_fastcall
 
     a: object
     b: object
@@ -1548,18 +1603,21 @@ _testclinic.TestClass.__new__ as 
posonly_varpos_array_no_fastcall
 [clinic start generated code]*/
 
 static PyObject *
-posonly_varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject *a,
-                                      PyObject *b, PyObject * const *args,
-                                      Py_ssize_t args_length)
-/*[clinic end generated code: output=1eec4da1fb5b5978 input=7330c8d819a23548]*/
+_testclinic_TestClass_posonly_varpos_array_no_fastcall_impl(PyTypeObject *type,
+                                                            PyObject *a,
+                                                            PyObject *b,
+                                                            PyObject * const 
*args,
+                                                            Py_ssize_t 
args_length)
+/*[clinic end generated code: output=71e676f1870b5a7e input=18eadf4c6eaab613]*/
 {
     return pack_arguments_2pos_varpos(a, b, args, args_length);
 }
 
 
 /*[clinic input]
+@disable fastcall
 @classmethod
-_testclinic.TestClass.__new__ as posonly_req_opt_varpos_array_no_fastcall
+_testclinic.TestClass.posonly_req_opt_varpos_array_no_fastcall
 
     a: object
     b: object = False
@@ -1569,19 +1627,21 @@ _testclinic.TestClass.__new__ as 
posonly_req_opt_varpos_array_no_fastcall
 [clinic start generated code]*/
 
 static PyObject *
-posonly_req_opt_varpos_array_no_fastcall_impl(PyTypeObject *type,
-                                              PyObject *a, PyObject *b,
-                                              PyObject * const *args,
-                                              Py_ssize_t args_length)
-/*[clinic end generated code: output=88041c2176135218 input=7f5fd34ee5f9e0bf]*/
+_testclinic_TestClass_posonly_req_opt_varpos_array_no_fastcall_impl(PyTypeObject
 *type,
+                                                                    PyObject 
*a,
+                                                                    PyObject 
*b,
+                                                                    PyObject * 
const *args,
+                                                                    Py_ssize_t 
args_length)
+/*[clinic end generated code: output=abb395cae91d48ac input=5bf791fdad70b480]*/
 {
     return pack_arguments_2pos_varpos(a, b, args, args_length);
 }
 
 
 /*[clinic input]
+@disable fastcall
 @classmethod
-_testclinic.TestClass.__new__ as posonly_poskw_varpos_array_no_fastcall
+_testclinic.TestClass.posonly_poskw_varpos_array_no_fastcall
 
     a: object
     /
@@ -1591,11 +1651,12 @@ _testclinic.TestClass.__new__ as 
posonly_poskw_varpos_array_no_fastcall
 [clinic start generated code]*/
 
 static PyObject *
-posonly_poskw_varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject *a,
-                                            PyObject *b,
-                                            PyObject * const *args,
-                                            Py_ssize_t args_length)
-/*[clinic end generated code: output=70eda18c3667681e input=2b0fcd7bd9bb865c]*/
+_testclinic_TestClass_posonly_poskw_varpos_array_no_fastcall_impl(PyTypeObject 
*type,
+                                                                  PyObject *a,
+                                                                  PyObject *b,
+                                                                  PyObject * 
const *args,
+                                                                  Py_ssize_t 
args_length)
+/*[clinic end generated code: output=aaddd9530048b229 input=9ed3842f4d472d45]*/
 {
     return pack_arguments_2pos_varpos(a, b, args, args_length);
 }
@@ -1606,27 +1667,15 @@ static struct PyMethodDef test_class_methods[] = {
     _TESTCLINIC_TESTCLASS_DEFCLASS_VARPOS_METHODDEF
     _TESTCLINIC_TESTCLASS_DEFCLASS_POSONLY_VARPOS_METHODDEF
 
-    {"varpos_no_fastcall", _PyCFunction_CAST(varpos_no_fastcall),
-        METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
-    {"posonly_varpos_no_fastcall", 
_PyCFunction_CAST(posonly_varpos_no_fastcall),
-        METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
-    {"posonly_req_opt_varpos_no_fastcall", 
_PyCFunction_CAST(posonly_req_opt_varpos_no_fastcall),
-        METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
-    {"posonly_poskw_varpos_no_fastcall", 
_PyCFunction_CAST(posonly_poskw_varpos_no_fastcall),
-        METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
-
-    {"varpos_array_no_fastcall",
-        _PyCFunction_CAST(varpos_array_no_fastcall),
-        METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
-    {"posonly_varpos_array_no_fastcall",
-        _PyCFunction_CAST(posonly_varpos_array_no_fastcall),
-        METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
-    {"posonly_req_opt_varpos_array_no_fastcall",
-        _PyCFunction_CAST(posonly_req_opt_varpos_array_no_fastcall),
-        METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
-    {"posonly_poskw_varpos_array_no_fastcall",
-        _PyCFunction_CAST(posonly_poskw_varpos_array_no_fastcall),
-        METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
+    _TESTCLINIC_TESTCLASS_VARPOS_NO_FASTCALL_METHODDEF
+    _TESTCLINIC_TESTCLASS_POSONLY_VARPOS_NO_FASTCALL_METHODDEF
+    _TESTCLINIC_TESTCLASS_POSONLY_REQ_OPT_VARPOS_NO_FASTCALL_METHODDEF
+    _TESTCLINIC_TESTCLASS_POSONLY_POSKW_VARPOS_NO_FASTCALL_METHODDEF
+
+    _TESTCLINIC_TESTCLASS_VARPOS_ARRAY_NO_FASTCALL_METHODDEF
+    _TESTCLINIC_TESTCLASS_POSONLY_VARPOS_ARRAY_NO_FASTCALL_METHODDEF
+    _TESTCLINIC_TESTCLASS_POSONLY_REQ_OPT_VARPOS_ARRAY_NO_FASTCALL_METHODDEF
+    _TESTCLINIC_TESTCLASS_POSONLY_POSKW_VARPOS_ARRAY_NO_FASTCALL_METHODDEF
 
     {NULL, NULL}
 };
diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h
index f378e95cd6b2d8..56b0ca316d4952 100644
--- a/Modules/clinic/_testclinic.c.h
+++ b/Modules/clinic/_testclinic.c.h
@@ -4067,48 +4067,56 @@ _testclinic_TestClass_defclass_posonly_varpos(PyObject 
*self, PyTypeObject *cls,
     return return_value;
 }
 
+PyDoc_STRVAR(_testclinic_TestClass_varpos_no_fastcall__doc__,
+"varpos_no_fastcall($type, /, *args)\n"
+"--\n"
+"\n");
+
+#define _TESTCLINIC_TESTCLASS_VARPOS_NO_FASTCALL_METHODDEF    \
+    {"varpos_no_fastcall", 
(PyCFunction)_testclinic_TestClass_varpos_no_fastcall, METH_VARARGS|METH_CLASS, 
_testclinic_TestClass_varpos_no_fastcall__doc__},
+
 static PyObject *
-varpos_no_fastcall_impl(PyTypeObject *type, PyObject *args);
+_testclinic_TestClass_varpos_no_fastcall_impl(PyTypeObject *type,
+                                              PyObject *args);
 
 static PyObject *
-varpos_no_fastcall(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+_testclinic_TestClass_varpos_no_fastcall(PyObject *type, PyObject *args)
 {
     PyObject *return_value = NULL;
-    PyTypeObject *base_tp = &PyBaseObject_Type;
     PyObject *__clinic_args = NULL;
 
-    if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
-        !_PyArg_NoKeywords("TestClass", kwargs)) {
-        goto exit;
-    }
     __clinic_args = Py_NewRef(args);
-    return_value = varpos_no_fastcall_impl(type, __clinic_args);
+    return_value = _testclinic_TestClass_varpos_no_fastcall_impl((PyTypeObject 
*)type, __clinic_args);
 
-exit:
     /* Cleanup for args */
     Py_XDECREF(__clinic_args);
 
     return return_value;
 }
 
+PyDoc_STRVAR(_testclinic_TestClass_posonly_varpos_no_fastcall__doc__,
+"posonly_varpos_no_fastcall($type, a, b, /, *args)\n"
+"--\n"
+"\n");
+
+#define _TESTCLINIC_TESTCLASS_POSONLY_VARPOS_NO_FASTCALL_METHODDEF    \
+    {"posonly_varpos_no_fastcall", 
(PyCFunction)_testclinic_TestClass_posonly_varpos_no_fastcall, 
METH_VARARGS|METH_CLASS, 
_testclinic_TestClass_posonly_varpos_no_fastcall__doc__},
+
 static PyObject *
-posonly_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a, PyObject *b,
-                                PyObject *args);
+_testclinic_TestClass_posonly_varpos_no_fastcall_impl(PyTypeObject *type,
+                                                      PyObject *a,
+                                                      PyObject *b,
+                                                      PyObject *args);
 
 static PyObject *
-posonly_varpos_no_fastcall(PyTypeObject *type, PyObject *args, PyObject 
*kwargs)
+_testclinic_TestClass_posonly_varpos_no_fastcall(PyObject *type, PyObject 
*args)
 {
     PyObject *return_value = NULL;
-    PyTypeObject *base_tp = &PyBaseObject_Type;
     PyObject *a;
     PyObject *b;
     PyObject *__clinic_args = NULL;
 
-    if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
-        !_PyArg_NoKeywords("TestClass", kwargs)) {
-        goto exit;
-    }
-    if (!_PyArg_CheckPositional("TestClass", PyTuple_GET_SIZE(args), 2, 
PY_SSIZE_T_MAX)) {
+    if (!_PyArg_CheckPositional("posonly_varpos_no_fastcall", 
PyTuple_GET_SIZE(args), 2, PY_SSIZE_T_MAX)) {
         goto exit;
     }
     a = PyTuple_GET_ITEM(args, 0);
@@ -4117,7 +4125,7 @@ posonly_varpos_no_fastcall(PyTypeObject *type, PyObject 
*args, PyObject *kwargs)
     if (!__clinic_args) {
         goto exit;
     }
-    return_value = posonly_varpos_no_fastcall_impl(type, a, b, __clinic_args);
+    return_value = 
_testclinic_TestClass_posonly_varpos_no_fastcall_impl((PyTypeObject *)type, a, 
b, __clinic_args);
 
 exit:
     /* Cleanup for args */
@@ -4126,24 +4134,29 @@ posonly_varpos_no_fastcall(PyTypeObject *type, PyObject 
*args, PyObject *kwargs)
     return return_value;
 }
 
+PyDoc_STRVAR(_testclinic_TestClass_posonly_req_opt_varpos_no_fastcall__doc__,
+"posonly_req_opt_varpos_no_fastcall($type, a, b=False, /, *args)\n"
+"--\n"
+"\n");
+
+#define _TESTCLINIC_TESTCLASS_POSONLY_REQ_OPT_VARPOS_NO_FASTCALL_METHODDEF    \
+    {"posonly_req_opt_varpos_no_fastcall", 
(PyCFunction)_testclinic_TestClass_posonly_req_opt_varpos_no_fastcall, 
METH_VARARGS|METH_CLASS, 
_testclinic_TestClass_posonly_req_opt_varpos_no_fastcall__doc__},
+
 static PyObject *
-posonly_req_opt_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a,
-                                        PyObject *b, PyObject *args);
+_testclinic_TestClass_posonly_req_opt_varpos_no_fastcall_impl(PyTypeObject 
*type,
+                                                              PyObject *a,
+                                                              PyObject *b,
+                                                              PyObject *args);
 
 static PyObject *
-posonly_req_opt_varpos_no_fastcall(PyTypeObject *type, PyObject *args, 
PyObject *kwargs)
+_testclinic_TestClass_posonly_req_opt_varpos_no_fastcall(PyObject *type, 
PyObject *args)
 {
     PyObject *return_value = NULL;
-    PyTypeObject *base_tp = &PyBaseObject_Type;
     PyObject *a;
     PyObject *b = Py_False;
     PyObject *__clinic_args = NULL;
 
-    if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
-        !_PyArg_NoKeywords("TestClass", kwargs)) {
-        goto exit;
-    }
-    if (!_PyArg_CheckPositional("TestClass", PyTuple_GET_SIZE(args), 1, 
PY_SSIZE_T_MAX)) {
+    if (!_PyArg_CheckPositional("posonly_req_opt_varpos_no_fastcall", 
PyTuple_GET_SIZE(args), 1, PY_SSIZE_T_MAX)) {
         goto exit;
     }
     a = PyTuple_GET_ITEM(args, 0);
@@ -4156,7 +4169,7 @@ posonly_req_opt_varpos_no_fastcall(PyTypeObject *type, 
PyObject *args, PyObject
     if (!__clinic_args) {
         goto exit;
     }
-    return_value = posonly_req_opt_varpos_no_fastcall_impl(type, a, b, 
__clinic_args);
+    return_value = 
_testclinic_TestClass_posonly_req_opt_varpos_no_fastcall_impl((PyTypeObject 
*)type, a, b, __clinic_args);
 
 exit:
     /* Cleanup for args */
@@ -4165,12 +4178,22 @@ posonly_req_opt_varpos_no_fastcall(PyTypeObject *type, 
PyObject *args, PyObject
     return return_value;
 }
 
+PyDoc_STRVAR(_testclinic_TestClass_posonly_poskw_varpos_no_fastcall__doc__,
+"posonly_poskw_varpos_no_fastcall($type, a, /, b, *args)\n"
+"--\n"
+"\n");
+
+#define _TESTCLINIC_TESTCLASS_POSONLY_POSKW_VARPOS_NO_FASTCALL_METHODDEF    \
+    {"posonly_poskw_varpos_no_fastcall", 
_PyCFunction_CAST(_testclinic_TestClass_posonly_poskw_varpos_no_fastcall), 
METH_VARARGS|METH_KEYWORDS|METH_CLASS, 
_testclinic_TestClass_posonly_poskw_varpos_no_fastcall__doc__},
+
 static PyObject *
-posonly_poskw_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a,
-                                      PyObject *b, PyObject *args);
+_testclinic_TestClass_posonly_poskw_varpos_no_fastcall_impl(PyTypeObject *type,
+                                                            PyObject *a,
+                                                            PyObject *b,
+                                                            PyObject *args);
 
 static PyObject *
-posonly_poskw_varpos_no_fastcall(PyTypeObject *type, PyObject *args, PyObject 
*kwargs)
+_testclinic_TestClass_posonly_poskw_varpos_no_fastcall(PyObject *type, 
PyObject *args, PyObject *kwargs)
 {
     PyObject *return_value = NULL;
     #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
@@ -4196,7 +4219,7 @@ posonly_poskw_varpos_no_fastcall(PyTypeObject *type, 
PyObject *args, PyObject *k
     static const char * const _keywords[] = {"", "b", NULL};
     static _PyArg_Parser _parser = {
         .keywords = _keywords,
-        .fname = "TestClass",
+        .fname = "posonly_poskw_varpos_no_fastcall",
         .kwtuple = KWTUPLE,
     };
     #undef KWTUPLE
@@ -4218,7 +4241,7 @@ posonly_poskw_varpos_no_fastcall(PyTypeObject *type, 
PyObject *args, PyObject *k
     if (!__clinic_args) {
         goto exit;
     }
-    return_value = posonly_poskw_varpos_no_fastcall_impl(type, a, b, 
__clinic_args);
+    return_value = 
_testclinic_TestClass_posonly_poskw_varpos_no_fastcall_impl((PyTypeObject 
*)type, a, b, __clinic_args);
 
 exit:
     /* Cleanup for args */
@@ -4227,83 +4250,95 @@ posonly_poskw_varpos_no_fastcall(PyTypeObject *type, 
PyObject *args, PyObject *k
     return return_value;
 }
 
+PyDoc_STRVAR(_testclinic_TestClass_varpos_array_no_fastcall__doc__,
+"varpos_array_no_fastcall($type, /, *args)\n"
+"--\n"
+"\n");
+
+#define _TESTCLINIC_TESTCLASS_VARPOS_ARRAY_NO_FASTCALL_METHODDEF    \
+    {"varpos_array_no_fastcall", 
(PyCFunction)_testclinic_TestClass_varpos_array_no_fastcall, 
METH_VARARGS|METH_CLASS, _testclinic_TestClass_varpos_array_no_fastcall__doc__},
+
 static PyObject *
-varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject * const *args,
-                              Py_ssize_t args_length);
+_testclinic_TestClass_varpos_array_no_fastcall_impl(PyTypeObject *type,
+                                                    PyObject * const *args,
+                                                    Py_ssize_t args_length);
 
 static PyObject *
-varpos_array_no_fastcall(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+_testclinic_TestClass_varpos_array_no_fastcall(PyObject *type, PyObject *args)
 {
     PyObject *return_value = NULL;
-    PyTypeObject *base_tp = &PyBaseObject_Type;
     PyObject * const *__clinic_args;
     Py_ssize_t args_length;
 
-    if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
-        !_PyArg_NoKeywords("TestClass", kwargs)) {
-        goto exit;
-    }
     __clinic_args = _PyTuple_ITEMS(args);
     args_length = PyTuple_GET_SIZE(args);
-    return_value = varpos_array_no_fastcall_impl(type, __clinic_args, 
args_length);
+    return_value = 
_testclinic_TestClass_varpos_array_no_fastcall_impl((PyTypeObject *)type, 
__clinic_args, args_length);
 
-exit:
     return return_value;
 }
 
+PyDoc_STRVAR(_testclinic_TestClass_posonly_varpos_array_no_fastcall__doc__,
+"posonly_varpos_array_no_fastcall($type, a, b, /, *args)\n"
+"--\n"
+"\n");
+
+#define _TESTCLINIC_TESTCLASS_POSONLY_VARPOS_ARRAY_NO_FASTCALL_METHODDEF    \
+    {"posonly_varpos_array_no_fastcall", 
(PyCFunction)_testclinic_TestClass_posonly_varpos_array_no_fastcall, 
METH_VARARGS|METH_CLASS, 
_testclinic_TestClass_posonly_varpos_array_no_fastcall__doc__},
+
 static PyObject *
-posonly_varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject *a,
-                                      PyObject *b, PyObject * const *args,
-                                      Py_ssize_t args_length);
+_testclinic_TestClass_posonly_varpos_array_no_fastcall_impl(PyTypeObject *type,
+                                                            PyObject *a,
+                                                            PyObject *b,
+                                                            PyObject * const 
*args,
+                                                            Py_ssize_t 
args_length);
 
 static PyObject *
-posonly_varpos_array_no_fastcall(PyTypeObject *type, PyObject *args, PyObject 
*kwargs)
+_testclinic_TestClass_posonly_varpos_array_no_fastcall(PyObject *type, 
PyObject *args)
 {
     PyObject *return_value = NULL;
-    PyTypeObject *base_tp = &PyBaseObject_Type;
     PyObject *a;
     PyObject *b;
     PyObject * const *__clinic_args;
     Py_ssize_t args_length;
 
-    if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
-        !_PyArg_NoKeywords("TestClass", kwargs)) {
-        goto exit;
-    }
-    if (!_PyArg_CheckPositional("TestClass", PyTuple_GET_SIZE(args), 2, 
PY_SSIZE_T_MAX)) {
+    if (!_PyArg_CheckPositional("posonly_varpos_array_no_fastcall", 
PyTuple_GET_SIZE(args), 2, PY_SSIZE_T_MAX)) {
         goto exit;
     }
     a = PyTuple_GET_ITEM(args, 0);
     b = PyTuple_GET_ITEM(args, 1);
     __clinic_args = _PyTuple_ITEMS(args) + 2;
     args_length = PyTuple_GET_SIZE(args) - 2;
-    return_value = posonly_varpos_array_no_fastcall_impl(type, a, b, 
__clinic_args, args_length);
+    return_value = 
_testclinic_TestClass_posonly_varpos_array_no_fastcall_impl((PyTypeObject 
*)type, a, b, __clinic_args, args_length);
 
 exit:
     return return_value;
 }
 
+PyDoc_STRVAR(_testclinic_TestClass_posonly_req_opt_varpos_array_no_fastcall__doc__,
+"posonly_req_opt_varpos_array_no_fastcall($type, a, b=False, /, *args)\n"
+"--\n"
+"\n");
+
+#define 
_TESTCLINIC_TESTCLASS_POSONLY_REQ_OPT_VARPOS_ARRAY_NO_FASTCALL_METHODDEF    \
+    {"posonly_req_opt_varpos_array_no_fastcall", 
(PyCFunction)_testclinic_TestClass_posonly_req_opt_varpos_array_no_fastcall, 
METH_VARARGS|METH_CLASS, 
_testclinic_TestClass_posonly_req_opt_varpos_array_no_fastcall__doc__},
+
 static PyObject *
-posonly_req_opt_varpos_array_no_fastcall_impl(PyTypeObject *type,
-                                              PyObject *a, PyObject *b,
-                                              PyObject * const *args,
-                                              Py_ssize_t args_length);
+_testclinic_TestClass_posonly_req_opt_varpos_array_no_fastcall_impl(PyTypeObject
 *type,
+                                                                    PyObject 
*a,
+                                                                    PyObject 
*b,
+                                                                    PyObject * 
const *args,
+                                                                    Py_ssize_t 
args_length);
 
 static PyObject *
-posonly_req_opt_varpos_array_no_fastcall(PyTypeObject *type, PyObject *args, 
PyObject *kwargs)
+_testclinic_TestClass_posonly_req_opt_varpos_array_no_fastcall(PyObject *type, 
PyObject *args)
 {
     PyObject *return_value = NULL;
-    PyTypeObject *base_tp = &PyBaseObject_Type;
     PyObject *a;
     PyObject *b = Py_False;
     PyObject * const *__clinic_args;
     Py_ssize_t args_length;
 
-    if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
-        !_PyArg_NoKeywords("TestClass", kwargs)) {
-        goto exit;
-    }
-    if (!_PyArg_CheckPositional("TestClass", PyTuple_GET_SIZE(args), 1, 
PY_SSIZE_T_MAX)) {
+    if (!_PyArg_CheckPositional("posonly_req_opt_varpos_array_no_fastcall", 
PyTuple_GET_SIZE(args), 1, PY_SSIZE_T_MAX)) {
         goto exit;
     }
     a = PyTuple_GET_ITEM(args, 0);
@@ -4314,20 +4349,29 @@ posonly_req_opt_varpos_array_no_fastcall(PyTypeObject 
*type, PyObject *args, PyO
 skip_optional:
     __clinic_args = PyTuple_GET_SIZE(args) > 2 ? _PyTuple_ITEMS(args) + 2 : 
_PyTuple_ITEMS(args);
     args_length = Py_MAX(0, PyTuple_GET_SIZE(args) - 2);
-    return_value = posonly_req_opt_varpos_array_no_fastcall_impl(type, a, b, 
__clinic_args, args_length);
+    return_value = 
_testclinic_TestClass_posonly_req_opt_varpos_array_no_fastcall_impl((PyTypeObject
 *)type, a, b, __clinic_args, args_length);
 
 exit:
     return return_value;
 }
 
+PyDoc_STRVAR(_testclinic_TestClass_posonly_poskw_varpos_array_no_fastcall__doc__,
+"posonly_poskw_varpos_array_no_fastcall($type, a, /, b, *args)\n"
+"--\n"
+"\n");
+
+#define _TESTCLINIC_TESTCLASS_POSONLY_POSKW_VARPOS_ARRAY_NO_FASTCALL_METHODDEF 
   \
+    {"posonly_poskw_varpos_array_no_fastcall", 
_PyCFunction_CAST(_testclinic_TestClass_posonly_poskw_varpos_array_no_fastcall),
 METH_VARARGS|METH_KEYWORDS|METH_CLASS, 
_testclinic_TestClass_posonly_poskw_varpos_array_no_fastcall__doc__},
+
 static PyObject *
-posonly_poskw_varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject *a,
-                                            PyObject *b,
-                                            PyObject * const *args,
-                                            Py_ssize_t args_length);
+_testclinic_TestClass_posonly_poskw_varpos_array_no_fastcall_impl(PyTypeObject 
*type,
+                                                                  PyObject *a,
+                                                                  PyObject *b,
+                                                                  PyObject * 
const *args,
+                                                                  Py_ssize_t 
args_length);
 
 static PyObject *
-posonly_poskw_varpos_array_no_fastcall(PyTypeObject *type, PyObject *args, 
PyObject *kwargs)
+_testclinic_TestClass_posonly_poskw_varpos_array_no_fastcall(PyObject *type, 
PyObject *args, PyObject *kwargs)
 {
     PyObject *return_value = NULL;
     #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
@@ -4353,7 +4397,7 @@ posonly_poskw_varpos_array_no_fastcall(PyTypeObject 
*type, PyObject *args, PyObj
     static const char * const _keywords[] = {"", "b", NULL};
     static _PyArg_Parser _parser = {
         .keywords = _keywords,
-        .fname = "TestClass",
+        .fname = "posonly_poskw_varpos_array_no_fastcall",
         .kwtuple = KWTUPLE,
     };
     #undef KWTUPLE
@@ -4374,9 +4418,9 @@ posonly_poskw_varpos_array_no_fastcall(PyTypeObject 
*type, PyObject *args, PyObj
     b = fastargs[1];
     __clinic_args = PyTuple_GET_SIZE(args) > 2 ? _PyTuple_ITEMS(args) + 2 : 
_PyTuple_ITEMS(args);
     args_length = Py_MAX(0, PyTuple_GET_SIZE(args) - 2);
-    return_value = posonly_poskw_varpos_array_no_fastcall_impl(type, a, b, 
__clinic_args, args_length);
+    return_value = 
_testclinic_TestClass_posonly_poskw_varpos_array_no_fastcall_impl((PyTypeObject 
*)type, a, b, __clinic_args, args_length);
 
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=a3726ee0a94090d1 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=ea0b8fb0949fa49f input=a9049054013a1b77]*/
diff --git a/Tools/clinic/libclinic/dsl_parser.py 
b/Tools/clinic/libclinic/dsl_parser.py
index 4b4a8b9969d142..282ff64cd33089 100644
--- a/Tools/clinic/libclinic/dsl_parser.py
+++ b/Tools/clinic/libclinic/dsl_parser.py
@@ -260,6 +260,7 @@ class DSLParser:
     preserve_output: bool
     critical_section: bool
     target_critical_section: list[str]
+    disable_fastcall: bool
     from_version_re = re.compile(r'([*/]) +\[from +(.+)\]')
 
     def __init__(self, clinic: Clinic) -> None:
@@ -296,6 +297,7 @@ def reset(self) -> None:
         self.preserve_output = False
         self.critical_section = False
         self.target_critical_section = []
+        self.disable_fastcall = False
 
     def directive_module(self, name: str) -> None:
         fields = name.split('.')[:-1]
@@ -423,6 +425,18 @@ def at_critical_section(self, *args: str) -> None:
         self.target_critical_section.extend(args)
         self.critical_section = True
 
+    def at_disable(self, *args: str) -> None:
+        if self.kind is not CALLABLE:
+            fail("Can't set @disable, function is not a normal callable")
+        if not args:
+            fail("@disable expects at least one argument")
+        features = list(args)
+        if 'fastcall' in features:
+            features.remove('fastcall')
+            self.disable_fastcall = True
+        if features:
+            fail("invalid argument for @disable:", features[0])
+
     def at_getter(self) -> None:
         match self.kind:
             case FunctionKind.GETTER:
@@ -691,6 +705,7 @@ def state_modulename_name(self, line: str) -> None:
             kind=self.kind,
             coexist=self.coexist,
             critical_section=self.critical_section,
+            disable_fastcall=self.disable_fastcall,
             target_critical_section=self.target_critical_section,
             forced_text_signature=self.forced_text_signature
         )
diff --git a/Tools/clinic/libclinic/function.py 
b/Tools/clinic/libclinic/function.py
index 93901263e44c04..e80e2f5f13f648 100644
--- a/Tools/clinic/libclinic/function.py
+++ b/Tools/clinic/libclinic/function.py
@@ -109,6 +109,7 @@ class Function:
     docstring_only: bool = False
     forced_text_signature: str | None = None
     critical_section: bool = False
+    disable_fastcall: bool = False
     target_critical_section: list[str] = dc.field(default_factory=list)
 
     def __post_init__(self) -> None:
diff --git a/Tools/clinic/libclinic/parse_args.py 
b/Tools/clinic/libclinic/parse_args.py
index 978e2f4263b74a..0e15d2f163b816 100644
--- a/Tools/clinic/libclinic/parse_args.py
+++ b/Tools/clinic/libclinic/parse_args.py
@@ -260,7 +260,10 @@ def __init__(self, func: Function, codegen: CodeGen) -> 
None:
         if self.func.critical_section:
             self.codegen.add_include('pycore_critical_section.h',
                                      'Py_BEGIN_CRITICAL_SECTION()')
-        self.fastcall = not self.is_new_or_init()
+        if self.func.disable_fastcall:
+            self.fastcall = False
+        else:
+            self.fastcall = not self.is_new_or_init()
 
         self.pos_only = 0
         self.min_pos = 0

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to