Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-44298: Fix line numbers for early exits in with statements. #26513

Merged
merged 2 commits into from Jun 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 46 additions & 0 deletions Lib/test/test_sys_settrace.py
Expand Up @@ -995,6 +995,52 @@ def func():
(5, 'line'),
(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):
"""Repeat the trace tests, but with per-line events skipped"""
Expand Down
24 changes: 17 additions & 7 deletions Python/compile.c
Expand Up @@ -1796,7 +1796,6 @@ static int
compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
int preserve_tos)
{
int loc;
switch (info->fb_type) {
case WHILE_LOOP:
case EXCEPTION_HANDLER:
Expand Down Expand Up @@ -1850,7 +1849,6 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,

case WITH:
case ASYNC_WITH:
loc = c->u->u_lineno;
SET_LOC(c, (stmt_ty)info->fb_datum);
ADDOP(c, POP_BLOCK);
if (preserve_tos) {
Expand All @@ -1865,7 +1863,10 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
ADDOP(c, YIELD_FROM);
}
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;

case HANDLER_CLEANUP:
Expand Down Expand Up @@ -3020,12 +3021,17 @@ compiler_return(struct compiler *c, stmt_ty s)
if (preserve_tos) {
VISIT(c, expr, s->v.Return.value);
} else {
/* Emit instruction with line number for expression */
/* Emit instruction with line number for return value */
if (s->v.Return.value != NULL) {
SET_LOC(c, s->v.Return.value);
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))
return 0;
if (s->v.Return.value == NULL) {
Expand All @@ -3044,6 +3050,8 @@ static int
compiler_break(struct compiler *c)
{
struct fblockinfo *loop = NULL;
/* Emit instruction with line number */
ADDOP(c, NOP);
if (!compiler_unwind_fblock_stack(c, 0, &loop)) {
return 0;
}
Expand All @@ -3062,6 +3070,8 @@ static int
compiler_continue(struct compiler *c)
{
struct fblockinfo *loop = NULL;
/* Emit instruction with line number */
ADDOP(c, NOP);
if (!compiler_unwind_fblock_stack(c, 0, &loop)) {
return 0;
}
Expand Down Expand Up @@ -4306,7 +4316,7 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
ADDOP_I(c, CALL_METHOD_KW, argsl + kwdsl);
}
else {
ADDOP_I(c, CALL_METHOD, argsl);
ADDOP_I(c, CALL_METHOD, argsl);
}
c->u->u_lineno = old_lineno;
return 1;
Expand Down Expand Up @@ -4473,7 +4483,7 @@ compiler_subkwargs(struct compiler *c, asdl_keyword_seq *keywords, Py_ssize_t be
return 1;
}

/* Used by compiler_call_helper and maybe_optimize_method_call to emit
/* Used by compiler_call_helper and maybe_optimize_method_call to emit
LOAD_CONST kw1
LOAD_CONST kw2
...
Expand All @@ -4484,7 +4494,7 @@ Returns 1 on success, 0 on error.
*/
static int
compiler_call_simple_kw_helper(struct compiler *c,
asdl_keyword_seq *keywords,
asdl_keyword_seq *keywords,
Py_ssize_t nkwelts)
{
PyObject *names;
Expand Down