Repository: cython/cython

Issue:
PyMem_RawCalloc missing from cpython.mem
While [`cpython.mem`](http://docs.cython.org/en/latest/src/tutorial/memory_allocation.html) [contains](https://github.com/cython/cython/blob/1593b297d132df0ef894b072ade7b539cd774dd7/Cython/Includes/cpython/mem.pxd#L25-L54) the other [raw allocators](https://docs.python.org/3/c-api/memory.html#raw-memory-interface), it is missing [`PyMem_RawCalloc`](https://docs.python.org/3/c-api/memory.html#c.PyMem_RawCalloc).



Discussion:
PR welcome.

Resolving patch:
diff --git a/runtests.py b/runtests.py
--- a/runtests.py
+++ b/runtests.py
@@ -484,6 +484,7 @@ def get_openmp_compiler_flags(language):
                                          'run.pep526_variable_annotations',  # typing module
                                          'run.test_exceptions',  # copied from Py3.7+
                                          'run.time_pxd',  # _PyTime_GetSystemClock doesn't exist in 3.4
+                                         'run.cpython_capi_py35',
                                          'embedding.embedded',  # From the docs, needs Py_DecodeLocale
                                          ]),
     (3,7): (operator.lt, lambda x: x in ['run.pycontextvar',


Test patch:
diff --git a/tests/run/cpython_capi.pyx b/tests/run/cpython_capi.pyx
--- a/tests/run/cpython_capi.pyx
+++ b/tests/run/cpython_capi.pyx
@@ -25,31 +25,6 @@ def test_pymalloc():
         mem.PyMem_Free(m)
 
 
-def test_pymalloc_raw():
-    """
-    >>> test_pymalloc_raw()
-    3
-    """
-    cdef char* m
-    cdef char* m2 = NULL
-    with nogil:
-        m = <char*> mem.PyMem_RawMalloc(20)
-        if not m:
-            raise MemoryError()
-        try:
-            m[0] = 1
-            m[1] = 2
-            m[2] = 3
-            m2 = <char*> mem.PyMem_RawRealloc(m, 10)
-            if m2:
-                m = m2
-            retval = m[2]
-        finally:
-            mem.PyMem_RawFree(m)
-    assert m2
-    return retval
-
-
 def test_gilstate():
     """
     >>> test_gilstate()
diff --git a/tests/run/cpython_capi_py35.pyx b/tests/run/cpython_capi_py35.pyx
new file mode 100644
--- /dev/null
+++ b/tests/run/cpython_capi_py35.pyx
@@ -0,0 +1,63 @@
+# mode: run
+# tag: c-api
+
+# PyMem_RawMalloc tests that need to be disabled for Python < 3.5
+# (some of these would work of Python 3.4, but it's easier to disable
+# them in one place)
+
+from cpython cimport mem
+
+cdef short _assert_calloc(short* s, int n) except -1 with gil:
+    """Assert array ``s`` of length ``n`` is zero and return 3."""
+    assert not s[0] and not s[n - 1]
+    s[0] += 1
+    s[n - 1] += 3
+    for i in range(1, n - 1):
+        assert not s[i]
+    return s[n - 1]
+
+def test_pycalloc():
+    """
+    >>> test_pycalloc()
+    3
+    """
+    cdef short* s = <short*> mem.PyMem_Calloc(10, sizeof(short))
+    if not s:
+        raise MemoryError()
+    try:
+        return _assert_calloc(s, 10)
+    finally:
+        mem.PyMem_Free(s)
+
+def test_pymalloc_raw():
+    """
+    >>> test_pymalloc_raw()
+    3
+    """
+    cdef short i
+    cdef short* s
+    cdef char* m
+    cdef char* m2 = NULL
+    with nogil:
+        s = <short*> mem.PyMem_RawCalloc(10, sizeof(short))
+        if not s:
+            raise MemoryError()
+        try:
+            i = _assert_calloc(s, 10)
+        finally:
+            mem.PyMem_RawFree(s)
+        m = <char*> mem.PyMem_RawMalloc(20)
+        if not m:
+            raise MemoryError()
+        try:
+            m[0] = 1
+            m[1] = 2
+            m[2] = i
+            m2 = <char*> mem.PyMem_RawRealloc(m, 10)
+            if m2:
+                m = m2
+            retval = m[2]
+        finally:
+            mem.PyMem_RawFree(m)
+    assert m2
+    return retval