restore a generator's caller's exception state both on yield and (last) return
This prevents generator exception state from leaking into the caller.
Closes #12475.
diff --git a/Python/ceval.c b/Python/ceval.c
index 705ed41..c0f2874 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1881,10 +1881,6 @@
retval = POP();
f->f_stacktop = stack_pointer;
why = WHY_YIELD;
- /* Put aside the current exception state and restore
- that of the calling frame. This only serves when
- "yield" is used inside an except handler. */
- SWAP_EXC_STATE();
goto fast_yield;
TARGET(POP_EXCEPT)
@@ -3021,6 +3017,11 @@
retval = NULL;
fast_yield:
+ if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN))
+ /* Put aside the current exception state and restore that of the
+ calling frame. */
+ SWAP_EXC_STATE();
+
if (tstate->use_tracing) {
if (tstate->c_tracefunc) {
if (why == WHY_RETURN || why == WHY_YIELD) {