bpo-39947: Move Py_EnterRecursiveCall() to internal C API (GH-18972)

Move the static inline function flavor of Py_EnterRecursiveCall() and
Py_LeaveRecursiveCall() to the internal C API: they access
PyThreadState attributes. The limited C API provides regular
functions which hide implementation details.
diff --git a/Include/cpython/ceval.h b/Include/cpython/ceval.h
index f03b53a..00c7499 100644
--- a/Include/cpython/ceval.h
+++ b/Include/cpython/ceval.h
@@ -31,62 +31,6 @@
 PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *);
 PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *);
 
-PyAPI_DATA(int) _Py_CheckRecursionLimit;
-
-#ifdef USE_STACKCHECK
-/* With USE_STACKCHECK macro defined, trigger stack checks in
-   _Py_CheckRecursiveCall() on every 64th call to Py_EnterRecursiveCall. */
-static inline int _Py_MakeRecCheck(PyThreadState *tstate)  {
-    return (++tstate->recursion_depth > _Py_CheckRecursionLimit
-            || ++tstate->stackcheck_counter > 64);
-}
-#else
-static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
-    return (++tstate->recursion_depth > _Py_CheckRecursionLimit);
-}
-#endif
-
-PyAPI_FUNC(int) _Py_CheckRecursiveCall(
-    PyThreadState *tstate,
-    const char *where);
-
-static inline int _Py_EnterRecursiveCall(PyThreadState *tstate,
-                                         const char *where) {
-    return (_Py_MakeRecCheck(tstate) && _Py_CheckRecursiveCall(tstate, where));
-}
-
-static inline int _Py_EnterRecursiveCall_inline(const char *where) {
-    PyThreadState *tstate = PyThreadState_GET();
-    return _Py_EnterRecursiveCall(tstate, where);
-}
-
-#define Py_EnterRecursiveCall(where) _Py_EnterRecursiveCall_inline(where)
-
-
-/* Compute the "lower-water mark" for a recursion limit. When
- * Py_LeaveRecursiveCall() is called with a recursion depth below this mark,
- * the overflowed flag is reset to 0. */
-#define _Py_RecursionLimitLowerWaterMark(limit) \
-    (((limit) > 200) \
-        ? ((limit) - 50) \
-        : (3 * ((limit) >> 2)))
-
-#define _Py_MakeEndRecCheck(x) \
-    (--(x) < _Py_RecursionLimitLowerWaterMark(_Py_CheckRecursionLimit))
-
-static inline void _Py_LeaveRecursiveCall(PyThreadState *tstate)  {
-    if (_Py_MakeEndRecCheck(tstate->recursion_depth)) {
-        tstate->overflowed = 0;
-    }
-}
-
-static inline void _Py_LeaveRecursiveCall_inline(void)  {
-    PyThreadState *tstate = PyThreadState_GET();
-    _Py_LeaveRecursiveCall(tstate);
-}
-
-#define Py_LeaveRecursiveCall() _Py_LeaveRecursiveCall_inline()
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h
index 23d8091..ae6ef9a 100644
--- a/Include/internal/pycore_ceval.h
+++ b/Include/internal/pycore_ceval.h
@@ -56,6 +56,66 @@
 extern int _PyEval_ThreadsInitialized(_PyRuntimeState *runtime);
 extern PyStatus _PyEval_InitThreads(PyThreadState *tstate);
 
+
+/* --- _Py_EnterRecursiveCall() ----------------------------------------- */
+
+PyAPI_DATA(int) _Py_CheckRecursionLimit;
+
+#ifdef USE_STACKCHECK
+/* With USE_STACKCHECK macro defined, trigger stack checks in
+   _Py_CheckRecursiveCall() on every 64th call to Py_EnterRecursiveCall. */
+static inline int _Py_MakeRecCheck(PyThreadState *tstate)  {
+    return (++tstate->recursion_depth > _Py_CheckRecursionLimit
+            || ++tstate->stackcheck_counter > 64);
+}
+#else
+static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
+    return (++tstate->recursion_depth > _Py_CheckRecursionLimit);
+}
+#endif
+
+PyAPI_FUNC(int) _Py_CheckRecursiveCall(
+    PyThreadState *tstate,
+    const char *where);
+
+static inline int _Py_EnterRecursiveCall(PyThreadState *tstate,
+                                         const char *where) {
+    return (_Py_MakeRecCheck(tstate) && _Py_CheckRecursiveCall(tstate, where));
+}
+
+static inline int _Py_EnterRecursiveCall_inline(const char *where) {
+    PyThreadState *tstate = PyThreadState_GET();
+    return _Py_EnterRecursiveCall(tstate, where);
+}
+
+#define Py_EnterRecursiveCall(where) _Py_EnterRecursiveCall_inline(where)
+
+
+/* Compute the "lower-water mark" for a recursion limit. When
+ * Py_LeaveRecursiveCall() is called with a recursion depth below this mark,
+ * the overflowed flag is reset to 0. */
+#define _Py_RecursionLimitLowerWaterMark(limit) \
+    (((limit) > 200) \
+        ? ((limit) - 50) \
+        : (3 * ((limit) >> 2)))
+
+#define _Py_MakeEndRecCheck(x) \
+    (--(x) < _Py_RecursionLimitLowerWaterMark(_Py_CheckRecursionLimit))
+
+static inline void _Py_LeaveRecursiveCall(PyThreadState *tstate)  {
+    if (_Py_MakeEndRecCheck(tstate->recursion_depth)) {
+        tstate->overflowed = 0;
+    }
+}
+
+static inline void _Py_LeaveRecursiveCall_inline(void)  {
+    PyThreadState *tstate = PyThreadState_GET();
+    _Py_LeaveRecursiveCall(tstate);
+}
+
+#define Py_LeaveRecursiveCall() _Py_LeaveRecursiveCall_inline()
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/Misc/NEWS.d/next/C API/2020-03-13-00-15-19.bpo-39947.w3dIru.rst b/Misc/NEWS.d/next/C API/2020-03-13-00-15-19.bpo-39947.w3dIru.rst
new file mode 100644
index 0000000..f10161c
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2020-03-13-00-15-19.bpo-39947.w3dIru.rst
@@ -0,0 +1,4 @@
+Move the static inline function flavor of Py_EnterRecursiveCall() and
+Py_LeaveRecursiveCall() to the internal C API: they access PyThreadState
+attributes. The limited C API provides regular functions which hide
+implementation details.
diff --git a/Objects/abstract.c b/Objects/abstract.c
index f9be422..02e4ad7 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -1,6 +1,7 @@
 /* Abstract Object Interface (many thanks to Jim Fulton) */
 
 #include "Python.h"
+#include "pycore_ceval.h"   // _Py_EnterRecursiveCall()
 #include "pycore_pyerrors.h"
 #include "pycore_pystate.h"
 #include <ctype.h>
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index b448ec6..cb7572b 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -1,6 +1,7 @@
 /* Descriptors -- a new, flexible way to describe attributes */
 
 #include "Python.h"
+#include "pycore_ceval.h"   // _Py_EnterRecursiveCall()
 #include "pycore_object.h"
 #include "pycore_pystate.h"
 #include "pycore_tupleobject.h"
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index 16abded..44ae00f 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -2,6 +2,7 @@
 /* Method object implementation */
 
 #include "Python.h"
+#include "pycore_ceval.h"   // _Py_EnterRecursiveCall()
 #include "pycore_object.h"
 #include "pycore_pyerrors.h"
 #include "pycore_pymem.h"
diff --git a/Objects/object.c b/Objects/object.c
index bb47cfa..72c4189 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -2,6 +2,7 @@
 /* Generic object operations; and implementation of None */
 
 #include "Python.h"
+#include "pycore_ceval.h"   // _Py_EnterRecursiveCall()
 #include "pycore_context.h"
 #include "pycore_initconfig.h"
 #include "pycore_object.h"