@@ -5529,6 +5529,8 @@ typedef struct {
5529
5529
PyObject * pushed_locals ;
5530
5530
PyObject * temp_symbols ;
5531
5531
PyObject * fast_hidden ;
5532
+ jump_target_label cleanup ;
5533
+ jump_target_label end ;
5532
5534
} inlined_comprehension_state ;
5533
5535
5534
5536
static int
@@ -5639,11 +5641,45 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
5639
5641
// `pushed_locals` on the stack, but this will be reversed when we swap
5640
5642
// out the comprehension result in pop_inlined_comprehension_state
5641
5643
ADDOP_I (c , loc , SWAP , PyList_GET_SIZE (state -> pushed_locals ) + 1 );
5644
+
5645
+ // Add our own cleanup handler to restore comprehension locals in case
5646
+ // of exception, so they have the correct values inside an exception
5647
+ // handler or finally block.
5648
+ NEW_JUMP_TARGET_LABEL (c , cleanup );
5649
+ state -> cleanup = cleanup ;
5650
+ NEW_JUMP_TARGET_LABEL (c , end );
5651
+ state -> end = end ;
5652
+
5653
+ // no need to push an fblock for this "virtual" try/finally; there can't
5654
+ // be return/continue/break inside a comprehension
5655
+ ADDOP_JUMP (c , loc , SETUP_FINALLY , cleanup );
5642
5656
}
5643
5657
5644
5658
return SUCCESS ;
5645
5659
}
5646
5660
5661
+ static int
5662
+ restore_inlined_comprehension_locals (struct compiler * c , location loc ,
5663
+ inlined_comprehension_state state )
5664
+ {
5665
+ PyObject * k ;
5666
+ // pop names we pushed to stack earlier
5667
+ Py_ssize_t npops = PyList_GET_SIZE (state .pushed_locals );
5668
+ // Preserve the comprehension result (or exception) as TOS. This
5669
+ // reverses the SWAP we did in push_inlined_comprehension_state to get
5670
+ // the outermost iterable to TOS, so we can still just iterate
5671
+ // pushed_locals in simple reverse order
5672
+ ADDOP_I (c , loc , SWAP , npops + 1 );
5673
+ for (Py_ssize_t i = npops - 1 ; i >= 0 ; -- i ) {
5674
+ k = PyList_GetItem (state .pushed_locals , i );
5675
+ if (k == NULL ) {
5676
+ return ERROR ;
5677
+ }
5678
+ ADDOP_NAME (c , loc , STORE_FAST_MAYBE_NULL , k , varnames );
5679
+ }
5680
+ return SUCCESS ;
5681
+ }
5682
+
5647
5683
static int
5648
5684
pop_inlined_comprehension_state (struct compiler * c , location loc ,
5649
5685
inlined_comprehension_state state )
@@ -5660,19 +5696,22 @@ pop_inlined_comprehension_state(struct compiler *c, location loc,
5660
5696
Py_CLEAR (state .temp_symbols );
5661
5697
}
5662
5698
if (state .pushed_locals ) {
5663
- // pop names we pushed to stack earlier
5664
- Py_ssize_t npops = PyList_GET_SIZE (state .pushed_locals );
5665
- // Preserve the list/dict/set result of the comprehension as TOS. This
5666
- // reverses the SWAP we did in push_inlined_comprehension_state to get
5667
- // the outermost iterable to TOS, so we can still just iterate
5668
- // pushed_locals in simple reverse order
5669
- ADDOP_I (c , loc , SWAP , npops + 1 );
5670
- for (Py_ssize_t i = npops - 1 ; i >= 0 ; -- i ) {
5671
- k = PyList_GetItem (state .pushed_locals , i );
5672
- if (k == NULL ) {
5673
- return ERROR ;
5674
- }
5675
- ADDOP_NAME (c , loc , STORE_FAST_MAYBE_NULL , k , varnames );
5699
+ ADDOP (c , NO_LOCATION , POP_BLOCK );
5700
+ ADDOP_JUMP (c , NO_LOCATION , JUMP , state .end );
5701
+
5702
+ // cleanup from an exception inside the comprehension
5703
+ USE_LABEL (c , state .cleanup );
5704
+ // discard incomplete comprehension result (beneath exc on stack)
5705
+ ADDOP_I (c , NO_LOCATION , SWAP , 2 );
5706
+ ADDOP (c , NO_LOCATION , POP_TOP );
5707
+ if (restore_inlined_comprehension_locals (c , loc , state ) < 0 ) {
5708
+ return ERROR ;
5709
+ }
5710
+ ADDOP_I (c , NO_LOCATION , RERAISE , 0 );
5711
+
5712
+ USE_LABEL (c , state .end );
5713
+ if (restore_inlined_comprehension_locals (c , loc , state ) < 0 ) {
5714
+ return ERROR ;
5676
5715
}
5677
5716
Py_CLEAR (state .pushed_locals );
5678
5717
}
@@ -5715,7 +5754,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
5715
5754
expr_ty val )
5716
5755
{
5717
5756
PyCodeObject * co = NULL ;
5718
- inlined_comprehension_state inline_state = {NULL , NULL };
5757
+ inlined_comprehension_state inline_state = {NULL , NULL , NULL , NO_LABEL , NO_LABEL };
5719
5758
comprehension_ty outermost ;
5720
5759
int scope_type = c -> u -> u_scope_type ;
5721
5760
int is_top_level_await = IS_TOP_LEVEL_AWAIT (c );
0 commit comments