Issue #18408: PyEval_EvalFrameEx() and PyEval_CallObjectWithKeywords() now fail
with an assertion error if they are called with an exception set
(PyErr_Occurred()).

If these functions are called with an exception set, the exception may be
cleared and so the caller looses its exception.

Add also assertions to PyEval_CallObjectWithKeywords() and call_function() to
check if the function succeed with no exception set, or the function failed
with an exception set.
diff --git a/Python/ceval.c b/Python/ceval.c
index 2d84c09..8a732a0 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1203,6 +1203,13 @@
     if (throwflag) /* support for generator.throw() */
         goto error;
 
+#ifdef Py_DEBUG
+    /* PyEval_EvalFrameEx() must not be called with an exception set,
+       because it may clear it (directly or indirectly) and so the
+       caller looses its exception */
+    assert(!PyErr_Occurred());
+#endif
+
     for (;;) {
 #ifdef WITH_TSC
         if (inst1 == 0) {
@@ -1223,6 +1230,7 @@
 #endif
         assert(stack_pointer >= f->f_valuestack); /* else underflow */
         assert(STACK_LEVEL() <= co->co_stacksize);  /* else overflow */
+        assert(!PyErr_Occurred());
 
         /* Do periodic things.  Doing this every time through
            the loop would add too much overhead, so we do it
@@ -3125,6 +3133,8 @@
             break;
         READ_TIMESTAMP(loop1);
 
+        assert(!PyErr_Occurred());
+
     } /* main loop */
 
     assert(why != WHY_YIELD);
@@ -3137,6 +3147,9 @@
     if (why != WHY_RETURN)
         retval = NULL;
 
+    assert((retval != NULL && !PyErr_Occurred())
+            || (retval == NULL && PyErr_Occurred()));
+
 fast_yield:
     if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) {
         /* The purpose of this block is to put aside the generator's exception
@@ -4044,6 +4057,13 @@
 {
     PyObject *result;
 
+#ifdef Py_DEBUG
+    /* PyEval_CallObjectWithKeywords() must not be called with an exception
+       set, because it may clear it (directly or indirectly)
+       and so the caller looses its exception */
+    assert(!PyErr_Occurred());
+#endif
+
     if (arg == NULL) {
         arg = PyTuple_New(0);
         if (arg == NULL)
@@ -4066,6 +4086,9 @@
 
     result = PyObject_Call(func, arg, kw);
     Py_DECREF(arg);
+
+    assert((result != NULL && !PyErr_Occurred())
+           || (result == NULL && PyErr_Occurred()));
     return result;
 }
 
@@ -4228,6 +4251,9 @@
         Py_DECREF(w);
         PCALL(PCALL_POP);
     }
+
+    assert((x != NULL && !PyErr_Occurred())
+           || (x == NULL && PyErr_Occurred()));
     return x;
 }