bpo-40428: Remove PyTuple_ClearFreeList() function (GH-19769)

Remove the following function from the C API:

* PyAsyncGen_ClearFreeLists()
* PyContext_ClearFreeList()
* PyDict_ClearFreeList()
* PyFloat_ClearFreeList()
* PyFrame_ClearFreeList()
* PyList_ClearFreeList()
* PySet_ClearFreeList()
* PyTuple_ClearFreeList()

Make these functions private, move them to the internal C API and
change their return type to void.

Call explicitly PyGC_Collect() to free all free lists.

Note: PySet_ClearFreeList() did nothing.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 8f9d4e7..9c35f3c 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -257,20 +257,17 @@
 
 #include "clinic/dictobject.c.h"
 
-int
-PyDict_ClearFreeList(void)
+void
+_PyDict_ClearFreeList(void)
 {
-    PyDictObject *op;
-    int ret = numfree + numfreekeys;
     while (numfree) {
-        op = free_list[--numfree];
+        PyDictObject *op = free_list[--numfree];
         assert(PyDict_CheckExact(op));
         PyObject_GC_Del(op);
     }
     while (numfreekeys) {
         PyObject_FREE(keys_free_list[--numfreekeys]);
     }
-    return ret;
 }
 
 /* Print summary info about the state of the optimized allocator */
@@ -285,7 +282,7 @@
 void
 _PyDict_Fini(void)
 {
-    PyDict_ClearFreeList();
+    _PyDict_ClearFreeList();
 }
 
 #define DK_SIZE(dk) ((dk)->dk_size)
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index 04f968e..faa02f2 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -1998,25 +1998,22 @@
     return 1;
 }
 
-int
-PyFloat_ClearFreeList(void)
+void
+_PyFloat_ClearFreeList(void)
 {
     PyFloatObject *f = free_list, *next;
-    int i = numfree;
-    while (f) {
+    for (; f; f = next) {
         next = (PyFloatObject*) Py_TYPE(f);
         PyObject_FREE(f);
-        f = next;
     }
     free_list = NULL;
     numfree = 0;
-    return i;
 }
 
 void
 _PyFloat_Fini(void)
 {
-    (void)PyFloat_ClearFreeList();
+    _PyFloat_ClearFreeList();
 }
 
 /* Print summary info about the state of the optimized allocator */
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 533186b..6d288b5 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -1200,11 +1200,9 @@
 }
 
 /* Clear out the free list */
-int
-PyFrame_ClearFreeList(void)
+void
+_PyFrame_ClearFreeList(void)
 {
-    int freelist_size = numfree;
-
     while (free_list != NULL) {
         PyFrameObject *f = free_list;
         free_list = free_list->f_back;
@@ -1212,13 +1210,12 @@
         --numfree;
     }
     assert(numfree == 0);
-    return freelist_size;
 }
 
 void
 _PyFrame_Fini(void)
 {
-    (void)PyFrame_ClearFreeList();
+    _PyFrame_ClearFreeList();
 }
 
 /* Print summary info about the state of the optimized allocator */
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 071def8..6e36690 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -1429,11 +1429,9 @@
 }
 
 
-int
-PyAsyncGen_ClearFreeLists(void)
+void
+_PyAsyncGen_ClearFreeLists(void)
 {
-    int ret = ag_value_freelist_free + ag_asend_freelist_free;
-
     while (ag_value_freelist_free) {
         _PyAsyncGenWrappedValue *o;
         o = ag_value_freelist[--ag_value_freelist_free];
@@ -1447,14 +1445,12 @@
         assert(Py_IS_TYPE(o, &_PyAsyncGenASend_Type));
         PyObject_GC_Del(o);
     }
-
-    return ret;
 }
 
 void
 _PyAsyncGen_Fini(void)
 {
-    PyAsyncGen_ClearFreeLists();
+    _PyAsyncGen_ClearFreeLists();
 }
 
 
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 7d2f006..904bea3 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -103,23 +103,20 @@
 static PyListObject *free_list[PyList_MAXFREELIST];
 static int numfree = 0;
 
-int
-PyList_ClearFreeList(void)
+void
+_PyList_ClearFreeList(void)
 {
-    PyListObject *op;
-    int ret = numfree;
     while (numfree) {
-        op = free_list[--numfree];
+        PyListObject *op = free_list[--numfree];
         assert(PyList_CheckExact(op));
         PyObject_GC_Del(op);
     }
-    return ret;
 }
 
 void
 _PyList_Fini(void)
 {
-    PyList_ClearFreeList();
+    _PyList_ClearFreeList();
 }
 
 /* Print summary info about the state of the optimized allocator */
diff --git a/Objects/setobject.c b/Objects/setobject.c
index 8452546..bbe013b 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -2384,12 +2384,6 @@
     return set_add_key((PySetObject *)anyset, key);
 }
 
-int
-PySet_ClearFreeList(void)
-{
-    return 0;
-}
-
 void
 _PySet_Fini(void)
 {
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index b65b8ab..f8648d2 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -955,26 +955,22 @@
     return 0;
 }
 
-int
-PyTuple_ClearFreeList(void)
+void
+_PyTuple_ClearFreeList(void)
 {
-    int freelist_size = 0;
 #if PyTuple_MAXSAVESIZE > 0
-    int i;
-    for (i = 1; i < PyTuple_MAXSAVESIZE; i++) {
-        PyTupleObject *p, *q;
-        p = free_list[i];
-        freelist_size += numfree[i];
+    for (Py_ssize_t i = 1; i < PyTuple_MAXSAVESIZE; i++) {
+        PyTupleObject *p = free_list[i];
         free_list[i] = NULL;
         numfree[i] = 0;
         while (p) {
-            q = p;
+            PyTupleObject *q = p;
             p = (PyTupleObject *)(p->ob_item[0]);
             PyObject_GC_Del(q);
         }
     }
+    // the empty tuple singleton is only cleared by _PyTuple_Fini()
 #endif
-    return freelist_size;
 }
 
 void
@@ -985,7 +981,7 @@
      * rely on the fact that an empty tuple is a singleton. */
     Py_CLEAR(free_list[0]);
 
-    (void)PyTuple_ClearFreeList();
+    _PyTuple_ClearFreeList();
 #endif
 }