bpo-44298: Fix line numbers for early exits in with statements. (GH-26513)

This commit is contained in:
Mark Shannon 2021-06-03 16:45:58 +01:00 committed by GitHub
parent 4eed2821d4
commit 937cebc93b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 3036 additions and 2980 deletions

View file

@ -995,6 +995,52 @@ class TraceTestCase(unittest.TestCase):
(5, 'line'), (5, 'line'),
(5, 'return')]) (5, 'return')])
def test_early_exit_with(self):
class C:
def __enter__(self):
return self
def __exit__(*args):
pass
def func_break():
for i in (1,2):
with C():
break
pass
def func_return():
with C():
return
self.run_and_compare(func_break,
[(0, 'call'),
(1, 'line'),
(2, 'line'),
(-5, 'call'),
(-4, 'line'),
(-4, 'return'),
(3, 'line'),
(2, 'line'),
(-3, 'call'),
(-2, 'line'),
(-2, 'return'),
(4, 'line'),
(4, 'return')])
self.run_and_compare(func_return,
[(0, 'call'),
(1, 'line'),
(-11, 'call'),
(-10, 'line'),
(-10, 'return'),
(2, 'line'),
(1, 'line'),
(-9, 'call'),
(-8, 'line'),
(-8, 'return'),
(1, 'return')])
class SkipLineEventsTraceTestCase(TraceTestCase): class SkipLineEventsTraceTestCase(TraceTestCase):
"""Repeat the trace tests, but with per-line events skipped""" """Repeat the trace tests, but with per-line events skipped"""

View file

@ -1796,7 +1796,6 @@ static int
compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
int preserve_tos) int preserve_tos)
{ {
int loc;
switch (info->fb_type) { switch (info->fb_type) {
case WHILE_LOOP: case WHILE_LOOP:
case EXCEPTION_HANDLER: case EXCEPTION_HANDLER:
@ -1850,7 +1849,6 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
case WITH: case WITH:
case ASYNC_WITH: case ASYNC_WITH:
loc = c->u->u_lineno;
SET_LOC(c, (stmt_ty)info->fb_datum); SET_LOC(c, (stmt_ty)info->fb_datum);
ADDOP(c, POP_BLOCK); ADDOP(c, POP_BLOCK);
if (preserve_tos) { if (preserve_tos) {
@ -1865,7 +1863,10 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
ADDOP(c, YIELD_FROM); ADDOP(c, YIELD_FROM);
} }
ADDOP(c, POP_TOP); ADDOP(c, POP_TOP);
c->u->u_lineno = loc; /* The exit block should appear to execute after the
* statement causing the unwinding, so make the unwinding
* instruction artificial */
c->u->u_lineno = -1;
return 1; return 1;
case HANDLER_CLEANUP: case HANDLER_CLEANUP:
@ -3020,12 +3021,17 @@ compiler_return(struct compiler *c, stmt_ty s)
if (preserve_tos) { if (preserve_tos) {
VISIT(c, expr, s->v.Return.value); VISIT(c, expr, s->v.Return.value);
} else { } else {
/* Emit instruction with line number for expression */ /* Emit instruction with line number for return value */
if (s->v.Return.value != NULL) { if (s->v.Return.value != NULL) {
SET_LOC(c, s->v.Return.value); SET_LOC(c, s->v.Return.value);
ADDOP(c, NOP); ADDOP(c, NOP);
} }
} }
if (s->v.Return.value == NULL || s->v.Return.value->lineno != s->lineno) {
SET_LOC(c, s);
ADDOP(c, NOP);
}
if (!compiler_unwind_fblock_stack(c, preserve_tos, NULL)) if (!compiler_unwind_fblock_stack(c, preserve_tos, NULL))
return 0; return 0;
if (s->v.Return.value == NULL) { if (s->v.Return.value == NULL) {
@ -3044,6 +3050,8 @@ static int
compiler_break(struct compiler *c) compiler_break(struct compiler *c)
{ {
struct fblockinfo *loop = NULL; struct fblockinfo *loop = NULL;
/* Emit instruction with line number */
ADDOP(c, NOP);
if (!compiler_unwind_fblock_stack(c, 0, &loop)) { if (!compiler_unwind_fblock_stack(c, 0, &loop)) {
return 0; return 0;
} }
@ -3062,6 +3070,8 @@ static int
compiler_continue(struct compiler *c) compiler_continue(struct compiler *c)
{ {
struct fblockinfo *loop = NULL; struct fblockinfo *loop = NULL;
/* Emit instruction with line number */
ADDOP(c, NOP);
if (!compiler_unwind_fblock_stack(c, 0, &loop)) { if (!compiler_unwind_fblock_stack(c, 0, &loop)) {
return 0; return 0;
} }

3544
Python/importlib.h generated

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff