@@ -1725,16 +1725,33 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {
17251725 string name1 = methodNameFromCppName (func, " " , false );
17261726 string name2 = methodNameFromCppName (func, " " , true );
17271727
1728+ bool exclusive_fastcall = true ;
1729+ for (FunctionRemap *remap : func->_remaps ) {
1730+ if (((remap->_flags & FunctionRemap::F_fastcall) == 0 ||
1731+ (remap->_flags & FunctionRemap::F_explicit_args) == 0 ) && is_remap_legal (remap)) {
1732+ exclusive_fastcall = false ;
1733+ }
1734+ }
1735+
17281736 string flags;
17291737 string fptr = " &" + func->_name ;
17301738 switch (func->_args_type ) {
17311739 case AT_keyword_args:
1732- flags = " METH_VARARGS | METH_KEYWORDS" ;
1740+ if (exclusive_fastcall) {
1741+ flags = " METH_FASTCALL_OR_VARARGS | METH_KEYWORDS" ;
1742+ } else {
1743+ flags = " METH_VARARGS | METH_KEYWORDS" ;
1744+ }
17331745 fptr = " (PyCFunction) " + fptr;
17341746 break ;
17351747
17361748 case AT_varargs:
1737- flags = " METH_VARARGS" ;
1749+ if (exclusive_fastcall) {
1750+ flags = " METH_FASTCALL_OR_VARARGS" ;
1751+ fptr = " (PyCFunction) " + fptr;
1752+ } else {
1753+ flags = " METH_VARARGS" ;
1754+ }
17381755 break ;
17391756
17401757 case AT_single_arg:
@@ -1903,19 +1920,36 @@ write_module_class(ostream &out, Object *obj) {
19031920 got_deepcopy = true ;
19041921 }
19051922
1923+ bool exclusive_fastcall = true ;
1924+ for (FunctionRemap *remap : func->_remaps ) {
1925+ if (((remap->_flags & FunctionRemap::F_fastcall) == 0 ||
1926+ (remap->_flags & FunctionRemap::F_explicit_args) == 0 ) && is_remap_legal (remap)) {
1927+ exclusive_fastcall = false ;
1928+ }
1929+ }
1930+
19061931 string name1 = methodNameFromCppName (func, export_class_name, false );
19071932 string name2 = methodNameFromCppName (func, export_class_name, true );
19081933
19091934 string flags;
19101935 string fptr = " &" + func->_name ;
19111936 switch (func->_args_type ) {
19121937 case AT_keyword_args:
1913- flags = " METH_VARARGS | METH_KEYWORDS" ;
1938+ if (exclusive_fastcall) {
1939+ flags = " METH_FASTCALL_OR_VARARGS | METH_KEYWORDS" ;
1940+ } else {
1941+ flags = " METH_VARARGS | METH_KEYWORDS" ;
1942+ }
19141943 fptr = " (PyCFunction) " + fptr;
19151944 break ;
19161945
19171946 case AT_varargs:
1918- flags = " METH_VARARGS" ;
1947+ if (exclusive_fastcall) {
1948+ flags = " METH_FASTCALL_OR_VARARGS" ;
1949+ fptr = " (PyCFunction) " + fptr;
1950+ } else {
1951+ flags = " METH_VARARGS" ;
1952+ }
19191953 break ;
19201954
19211955 case AT_single_arg:
@@ -3945,12 +3979,18 @@ write_function_for_top(ostream &out, InterfaceMaker::Object *obj, InterfaceMaker
39453979 // First check if this function has non-slotted and legal remaps, ie. if we
39463980 // should even write it.
39473981 bool has_remaps = false ;
3982+ bool exclusive_fastcall = true ;
39483983
39493984 for (FunctionRemap *remap : func->_remaps ) {
39503985 if (!is_remap_legal (remap)) {
39513986 continue ;
39523987 }
39533988
3989+ if (((remap->_flags & FunctionRemap::F_fastcall) == 0 ||
3990+ (remap->_flags & FunctionRemap::F_explicit_args) == 0 ) && is_remap_legal (remap)) {
3991+ exclusive_fastcall = false ;
3992+ }
3993+
39543994 SlottedFunctionDef slotted_def;
39553995 if (!get_slotted_function_def (obj, func, remap, slotted_def) || slotted_def._keep_method ) {
39563996 // It has a non-slotted remap, so we should write it.
@@ -3994,11 +4034,19 @@ write_function_for_top(ostream &out, InterfaceMaker::Object *obj, InterfaceMaker
39944034
39954035 switch (func->_args_type ) {
39964036 case AT_keyword_args:
3997- prototype += " , PyObject *args, PyObject *kwds" ;
4037+ if (exclusive_fastcall) {
4038+ prototype += " , FASTCALL_OR_VARARGS_KEYWORDS_ARGS" ;
4039+ } else {
4040+ prototype += " , PyObject *args, PyObject *kwds" ;
4041+ }
39984042 break ;
39994043
40004044 case AT_varargs:
4001- prototype += " , PyObject *args" ;
4045+ if (exclusive_fastcall) {
4046+ prototype += " , FASTCALL_OR_VARARGS_ARGS" ;
4047+ } else {
4048+ prototype += " , PyObject *args" ;
4049+ }
40024050 break ;
40034051
40044052 case AT_single_arg:
@@ -4012,7 +4060,7 @@ write_function_for_top(ostream &out, InterfaceMaker::Object *obj, InterfaceMaker
40124060 prototype += " )" ;
40134061
40144062 string expected_params;
4015- write_function_for_name (out, obj, func->_remaps , prototype, expected_params, true , func->_args_type , RF_pyobject | RF_err_null);
4063+ write_function_for_name (out, obj, func->_remaps , prototype, expected_params, true , func->_args_type , RF_pyobject | RF_err_null, exclusive_fastcall );
40164064
40174065 // Now synthesize a variable for the docstring.
40184066 ostringstream comment;
@@ -4047,7 +4095,8 @@ write_function_for_name(ostream &out, Object *obj,
40474095 const string &function_name,
40484096 string &expected_params,
40494097 bool coercion_allowed,
4050- ArgsType args_type, int return_flags) {
4098+ ArgsType args_type, int return_flags,
4099+ bool exclusive_fastcall) {
40514100 std::map<int , std::set<FunctionRemap *> > map_sets;
40524101 std::map<int , std::set<FunctionRemap *> >::iterator mii;
40534102 std::set<FunctionRemap *>::iterator sii;
@@ -4151,7 +4200,15 @@ write_function_for_name(ostream &out, Object *obj,
41514200
41524201 if (args_type == AT_keyword_args && !has_keywords) {
41534202 // We don't actually take keyword arguments. Make sure we didn't get any.
4203+ if (exclusive_fastcall) {
4204+ out << " #if METH_FASTCALL_OR_VARARGS == METH_FASTCALL\n " ;
4205+ out << " if (fc_kwnames != nullptr && PyTuple_GET_SIZE(fc_kwnames) > 0) {\n " ;
4206+ out << " #else\n " ;
4207+ }
41544208 out << " if (kwds != nullptr && PyDict_Size(kwds) > 0) {\n " ;
4209+ if (exclusive_fastcall) {
4210+ out << " #endif\n " ;
4211+ }
41554212 out << " #ifdef NDEBUG\n " ;
41564213 error_raise_return (out, 4 , return_flags, " TypeError" , " function takes no keyword arguments" );
41574214 out << " #else\n " ;
@@ -4175,6 +4232,11 @@ write_function_for_name(ostream &out, Object *obj,
41754232 }
41764233
41774234 if (has_fastcall) {
4235+ // Generate backward compatibility for older Python versions that don't
4236+ // support the fastcall protocol.
4237+ if (exclusive_fastcall) {
4238+ out << " #if METH_FASTCALL_OR_VARARGS != METH_FASTCALL\n " ;
4239+ }
41784240 if (args_type == AT_keyword_args && has_keywords) {
41794241 out << " Py_ssize_t fc_nargs = PyTuple_GET_SIZE(args);\n " ;
41804242 out << " PyObject *const *fc_args;\n " ;
@@ -4224,6 +4286,15 @@ write_function_for_name(ostream &out, Object *obj,
42244286 out << " PyObject *fc_kwnames = nullptr;\n " ;
42254287 }
42264288 }
4289+ if (exclusive_fastcall) {
4290+ if (return_flags & RF_decref_kwnames) {
4291+ // If we decref this later (unconditionally), we need to unref this
4292+ // in the case where we don't construct in ourselves
4293+ out << " #else\n " ;
4294+ out << " Py_XINCREF(fc_kwnames);\n " ;
4295+ }
4296+ out << " #endif\n " ;
4297+ }
42274298 }
42284299
42294300 if (remap->_flags & FunctionRemap::F_explicit_args) {
0 commit comments