@@ -5438,6 +5438,8 @@ typedef struct {
5438
5438
PyObject * pushed_locals ;
5439
5439
PyObject * temp_symbols ;
5440
5440
PyObject * fast_hidden ;
5441
+ jump_target_label cleanup ;
5442
+ jump_target_label end ;
5441
5443
} inlined_comprehension_state ;
5442
5444
5443
5445
static int
@@ -5543,11 +5545,45 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
5543
5545
// `pushed_locals` on the stack, but this will be reversed when we swap
5544
5546
// out the comprehension result in pop_inlined_comprehension_state
5545
5547
ADDOP_I (c , loc , SWAP , PyList_GET_SIZE (state -> pushed_locals ) + 1 );
5548
+
5549
+ // Add our own cleanup handler to restore comprehension locals in case
5550
+ // of exception, so they have the correct values inside an exception
5551
+ // handler or finally block.
5552
+ NEW_JUMP_TARGET_LABEL (c , cleanup );
5553
+ state -> cleanup = cleanup ;
5554
+ NEW_JUMP_TARGET_LABEL (c , end );
5555
+ state -> end = end ;
5556
+
5557
+ // no need to push an fblock for this "virtual" try/finally; there can't
5558
+ // be return/continue/break inside a comprehension
5559
+ ADDOP_JUMP (c , loc , SETUP_FINALLY , cleanup );
5546
5560
}
5547
5561
5548
5562
return SUCCESS ;
5549
5563
}
5550
5564
5565
+ static int
5566
+ restore_inlined_comprehension_locals (struct compiler * c , location loc ,
5567
+ inlined_comprehension_state state )
5568
+ {
5569
+ PyObject * k ;
5570
+ // pop names we pushed to stack earlier
5571
+ Py_ssize_t npops = PyList_GET_SIZE (state .pushed_locals );
5572
+ // Preserve the comprehension result (or exception) as TOS. This
5573
+ // reverses the SWAP we did in push_inlined_comprehension_state to get
5574
+ // the outermost iterable to TOS, so we can still just iterate
5575
+ // pushed_locals in simple reverse order
5576
+ ADDOP_I (c , loc , SWAP , npops + 1 );
5577
+ for (Py_ssize_t i = npops - 1 ; i >= 0 ; -- i ) {
5578
+ k = PyList_GetItem (state .pushed_locals , i );
5579
+ if (k == NULL ) {
5580
+ return ERROR ;
5581
+ }
5582
+ ADDOP_NAME (c , loc , STORE_FAST_MAYBE_NULL , k , varnames );
5583
+ }
5584
+ return SUCCESS ;
5585
+ }
5586
+
5551
5587
static int
5552
5588
pop_inlined_comprehension_state (struct compiler * c , location loc ,
5553
5589
inlined_comprehension_state state )
@@ -5564,19 +5600,22 @@ pop_inlined_comprehension_state(struct compiler *c, location loc,
5564
5600
Py_CLEAR (state .temp_symbols );
5565
5601
}
5566
5602
if (state .pushed_locals ) {
5567
- // pop names we pushed to stack earlier
5568
- Py_ssize_t npops = PyList_GET_SIZE (state .pushed_locals );
5569
- // Preserve the list/dict/set result of the comprehension as TOS. This
5570
- // reverses the SWAP we did in push_inlined_comprehension_state to get
5571
- // the outermost iterable to TOS, so we can still just iterate
5572
- // pushed_locals in simple reverse order
5573
- ADDOP_I (c , loc , SWAP , npops + 1 );
5574
- for (Py_ssize_t i = npops - 1 ; i >= 0 ; -- i ) {
5575
- k = PyList_GetItem (state .pushed_locals , i );
5576
- if (k == NULL ) {
5577
- return ERROR ;
5578
- }
5579
- ADDOP_NAME (c , loc , STORE_FAST_MAYBE_NULL , k , varnames );
5603
+ ADDOP (c , NO_LOCATION , POP_BLOCK );
5604
+ ADDOP_JUMP (c , NO_LOCATION , JUMP , state .end );
5605
+
5606
+ // cleanup from an exception inside the comprehension
5607
+ USE_LABEL (c , state .cleanup );
5608
+ // discard incomplete comprehension result (beneath exc on stack)
5609
+ ADDOP_I (c , NO_LOCATION , SWAP , 2 );
5610
+ ADDOP (c , NO_LOCATION , POP_TOP );
5611
+ if (restore_inlined_comprehension_locals (c , loc , state ) < 0 ) {
5612
+ return ERROR ;
5613
+ }
5614
+ ADDOP_I (c , NO_LOCATION , RERAISE , 0 );
5615
+
5616
+ USE_LABEL (c , state .end );
5617
+ if (restore_inlined_comprehension_locals (c , loc , state ) < 0 ) {
5618
+ return ERROR ;
5580
5619
}
5581
5620
Py_CLEAR (state .pushed_locals );
5582
5621
}
@@ -5619,7 +5658,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
5619
5658
expr_ty val )
5620
5659
{
5621
5660
PyCodeObject * co = NULL ;
5622
- inlined_comprehension_state inline_state = {NULL , NULL };
5661
+ inlined_comprehension_state inline_state = {NULL , NULL , NULL , NO_LABEL , NO_LABEL };
5623
5662
comprehension_ty outermost ;
5624
5663
int scope_type = c -> u -> u_scope_type ;
5625
5664
int is_top_level_await = IS_TOP_LEVEL_AWAIT (c );
0 commit comments