@@ -685,6 +685,31 @@ gc_collect(void)
685685}
686686
687687
688+ static PyObject *
689+ func_varargs (PyObject * Py_UNUSED (module ), PyObject * args , PyObject * kwargs )
690+ {
691+ if (kwargs != NULL ) {
692+ return PyTuple_Pack (2 , args , kwargs );
693+ }
694+ else {
695+ return PyTuple_Pack (1 , args );
696+ }
697+ }
698+
699+
700+ static void
701+ check_int (PyObject * obj , int value )
702+ {
703+ #ifdef PYTHON3
704+ assert (PyLong_Check (obj ));
705+ assert (PyLong_AsLong (obj ) == value );
706+ #else
707+ assert (PyInt_Check (obj ));
708+ assert (PyInt_AsLong (obj ) == value );
709+ #endif
710+ }
711+
712+
688713static PyObject *
689714test_weakref (PyObject * Py_UNUSED (module ), PyObject * Py_UNUSED (args ))
690715{
@@ -743,7 +768,164 @@ test_weakref(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
743768#endif
744769
745770 Py_DECREF (weakref );
771+ Py_RETURN_NONE ;
772+ }
773+
774+
775+ static void
776+ test_vectorcall_noargs (PyObject * func_varargs )
777+ {
778+ PyObject * res = PyObject_Vectorcall (func_varargs , NULL , 0 , NULL );
779+ assert (res != NULL );
780+
781+ assert (PyTuple_Check (res ));
782+ assert (PyTuple_GET_SIZE (res ) == 1 );
783+ PyObject * posargs = PyTuple_GET_ITEM (res , 0 );
784+
785+ assert (PyTuple_Check (posargs ));
786+ assert (PyTuple_GET_SIZE (posargs ) == 0 );
787+
788+ Py_DECREF (res );
789+ }
790+
791+
792+ static void
793+ test_vectorcall_args (PyObject * func_varargs )
794+ {
795+ PyObject * args_tuple = Py_BuildValue ("ii" , 1 , 2 );
796+ assert (args_tuple != NULL );
797+ size_t nargs = (size_t )PyTuple_GET_SIZE (args_tuple );
798+ PyObject * * args = & PyTuple_GET_ITEM (args_tuple , 0 );
799+
800+ PyObject * res = PyObject_Vectorcall (func_varargs , args , nargs , NULL );
801+ Py_DECREF (args_tuple );
802+ assert (res != NULL );
803+
804+ assert (PyTuple_Check (res ));
805+ assert (PyTuple_GET_SIZE (res ) == 1 );
806+ PyObject * posargs = PyTuple_GET_ITEM (res , 0 );
807+
808+ assert (PyTuple_Check (posargs ));
809+ assert (PyTuple_GET_SIZE (posargs ) == 2 );
810+ check_int (PyTuple_GET_ITEM (posargs , 0 ), 1 );
811+ check_int (PyTuple_GET_ITEM (posargs , 1 ), 2 );
812+
813+ Py_DECREF (res );
814+ }
815+
816+
817+ static void
818+ test_vectorcall_args_offset (PyObject * func_varargs )
819+ {
820+ // args contains 3 values, but only pass 2 last values
821+ PyObject * args_tuple = Py_BuildValue ("iii" , 1 , 2 , 3 );
822+ assert (args_tuple != NULL );
823+ size_t nargs = 2 | PY_VECTORCALL_ARGUMENTS_OFFSET ;
824+ PyObject * * args = & PyTuple_GET_ITEM (args_tuple , 1 );
825+ PyObject * arg0 = PyTuple_GET_ITEM (args_tuple , 0 );
826+
827+ PyObject * res = PyObject_Vectorcall (func_varargs , args , nargs , NULL );
828+ assert (PyTuple_GET_ITEM (args_tuple , 0 ) == arg0 );
829+ Py_DECREF (args_tuple );
830+ assert (res != NULL );
831+
832+ assert (PyTuple_Check (res ));
833+ assert (PyTuple_GET_SIZE (res ) == 1 );
834+ PyObject * posargs = PyTuple_GET_ITEM (res , 0 );
835+
836+ assert (PyTuple_Check (posargs ));
837+ assert (PyTuple_GET_SIZE (posargs ) == 2 );
838+ check_int (PyTuple_GET_ITEM (posargs , 0 ), 2 );
839+ check_int (PyTuple_GET_ITEM (posargs , 1 ), 3 );
840+
841+ Py_DECREF (res );
842+ }
843+
844+
845+ static void
846+ test_vectorcall_args_kwnames (PyObject * func_varargs )
847+ {
848+ PyObject * args_tuple = Py_BuildValue ("iiiii" , 1 , 2 , 3 , 4 , 5 );
849+ assert (args_tuple != NULL );
850+ PyObject * * args = & PyTuple_GET_ITEM (args_tuple , 0 );
851+
852+ #ifdef PYTHON3
853+ PyObject * key1 = PyUnicode_FromString ("key1" );
854+ PyObject * key2 = PyUnicode_FromString ("key2" );
855+ #else
856+ PyObject * key1 = PyString_FromString ("key1" );
857+ PyObject * key2 = PyString_FromString ("key2" );
858+ #endif
859+ assert (key1 != NULL );
860+ assert (key2 != NULL );
861+ PyObject * kwnames = PyTuple_Pack (2 , key1 , key2 );
862+ assert (kwnames != NULL );
863+ size_t nargs = (size_t )(PyTuple_GET_SIZE (args_tuple ) - PyTuple_GET_SIZE (kwnames ));
864+
865+ PyObject * res = PyObject_Vectorcall (func_varargs , args , nargs , kwnames );
866+ Py_DECREF (args_tuple );
867+ Py_DECREF (kwnames );
868+ assert (res != NULL );
869+
870+ assert (PyTuple_Check (res ));
871+ assert (PyTuple_GET_SIZE (res ) == 2 );
872+ PyObject * posargs = PyTuple_GET_ITEM (res , 0 );
873+ PyObject * kwargs = PyTuple_GET_ITEM (res , 1 );
874+
875+ assert (PyTuple_Check (posargs ));
876+ assert (PyTuple_GET_SIZE (posargs ) == 3 );
877+ check_int (PyTuple_GET_ITEM (posargs , 0 ), 1 );
878+ check_int (PyTuple_GET_ITEM (posargs , 1 ), 2 );
879+ check_int (PyTuple_GET_ITEM (posargs , 2 ), 3 );
880+
881+ assert (PyDict_Check (kwargs ));
882+ assert (PyDict_Size (kwargs ) == 2 );
883+
884+ Py_ssize_t pos = 0 ;
885+ PyObject * key , * value ;
886+ while (PyDict_Next (kwargs , & pos , & key , & value )) {
887+ #ifdef PYTHON3
888+ assert (PyUnicode_Check (key ));
889+ #else
890+ assert (PyString_Check (key ));
891+ #endif
892+ if (PyObject_RichCompareBool (key , key1 , Py_EQ )) {
893+ check_int (value , 4 );
894+ }
895+ else {
896+ assert (PyObject_RichCompareBool (key , key2 , Py_EQ ));
897+ check_int (value , 5 );
898+ }
899+ }
900+
901+ Py_DECREF (res );
902+ Py_DECREF (key1 );
903+ Py_DECREF (key2 );
904+ }
905+
906+
907+ static PyObject *
908+ test_vectorcall (PyObject * module , PyObject * Py_UNUSED (args ))
909+ {
910+ #ifndef PYTHON3
911+ module = PyImport_ImportModule (MODULE_NAME_STR );
912+ assert (module != NULL );
913+ #endif
914+ PyObject * func_varargs = PyObject_GetAttrString (module , "func_varargs" );
915+ #ifndef PYTHON3
916+ Py_DECREF (module );
917+ #endif
918+ if (func_varargs == NULL ) {
919+ return NULL ;
920+ }
921+
922+ // test PyObject_Vectorcall()
923+ test_vectorcall_noargs (func_varargs );
924+ test_vectorcall_args (func_varargs );
925+ test_vectorcall_args_offset (func_varargs );
926+ test_vectorcall_args_kwnames (func_varargs );
746927
928+ Py_DECREF (func_varargs );
747929 Py_RETURN_NONE ;
748930}
749931
@@ -768,6 +950,8 @@ static struct PyMethodDef methods[] = {
768950 {"test_api_casts" , test_api_casts , METH_NOARGS , _Py_NULL },
769951 {"test_import" , test_import , METH_NOARGS , _Py_NULL },
770952 {"test_weakref" , test_weakref , METH_NOARGS , _Py_NULL },
953+ {"func_varargs" , (PyCFunction )(void * )func_varargs , METH_VARARGS | METH_KEYWORDS , _Py_NULL },
954+ {"test_vectorcall" , test_vectorcall , METH_NOARGS , _Py_NULL },
771955 {_Py_NULL , _Py_NULL , 0 , _Py_NULL }
772956};
773957
0 commit comments