Skip to content

Commit 68499c1

Browse files
iritkatrielaisk
authored andcommitted
pythongh-107901: duplicate blocks with no lineno that have an eval break and multiple predecessors (python#113950)
1 parent 42f449d commit 68499c1

File tree

3 files changed

+38
-10
lines changed

3 files changed

+38
-10
lines changed

Lib/test/test_compile.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,21 @@ async def test(aseq):
10981098
code_lines = self.get_code_lines(test.__code__)
10991099
self.assertEqual(expected_lines, code_lines)
11001100

1101+
def test_line_number_synthetic_jump_multiple_predecessors(self):
1102+
def f():
1103+
for x in it:
1104+
try:
1105+
if C1:
1106+
yield 2
1107+
except OSError:
1108+
pass
1109+
1110+
# Ensure that all JUMP_BACKWARDs have line number
1111+
code = f.__code__
1112+
for inst in dis.Bytecode(code):
1113+
if inst.opname == 'JUMP_BACKWARD':
1114+
self.assertIsNotNone(inst.positions.lineno)
1115+
11011116
def test_lineno_of_backward_jump(self):
11021117
# Issue gh-107901
11031118
def f():
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Compiler duplicates basic blocks that have an eval breaker check, no line number, and multiple predecessors.

Python/flowgraph.c

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,16 @@ basicblock_exits_scope(const basicblock *b) {
316316
return last && IS_SCOPE_EXIT_OPCODE(last->i_opcode);
317317
}
318318

319+
static inline int
320+
basicblock_has_eval_break(const basicblock *b) {
321+
for (int i = 0; i < b->b_iused; i++) {
322+
if (OPCODE_HAS_EVAL_BREAK(b->b_instr[i].i_opcode)) {
323+
return true;
324+
}
325+
}
326+
return false;
327+
}
328+
319329
static bool
320330
cfg_builder_current_block_is_terminated(cfg_builder *g)
321331
{
@@ -2246,16 +2256,18 @@ convert_pseudo_ops(basicblock *entryblock)
22462256
}
22472257

22482258
static inline bool
2249-
is_exit_without_lineno(basicblock *b) {
2250-
if (!basicblock_exits_scope(b)) {
2251-
return false;
2252-
}
2253-
for (int i = 0; i < b->b_iused; i++) {
2254-
if (b->b_instr[i].i_loc.lineno >= 0) {
2255-
return false;
2259+
is_exit_or_eval_check_without_lineno(basicblock *b) {
2260+
if (basicblock_exits_scope(b) || basicblock_has_eval_break(b)) {
2261+
for (int i = 0; i < b->b_iused; i++) {
2262+
if (b->b_instr[i].i_loc.lineno >= 0) {
2263+
return false;
2264+
}
22562265
}
2266+
return true;
2267+
}
2268+
else {
2269+
return false;
22572270
}
2258-
return true;
22592271
}
22602272

22612273

@@ -2283,7 +2295,7 @@ duplicate_exits_without_lineno(cfg_builder *g)
22832295
}
22842296
if (is_jump(last)) {
22852297
basicblock *target = next_nonempty_block(last->i_target);
2286-
if (is_exit_without_lineno(target) && target->b_predecessors > 1) {
2298+
if (is_exit_or_eval_check_without_lineno(target) && target->b_predecessors > 1) {
22872299
basicblock *new_target = copy_basicblock(g, target);
22882300
if (new_target == NULL) {
22892301
return ERROR;
@@ -2303,7 +2315,7 @@ duplicate_exits_without_lineno(cfg_builder *g)
23032315
* fall through, and thus can only have a single predecessor */
23042316
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
23052317
if (BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_iused > 0) {
2306-
if (is_exit_without_lineno(b->b_next)) {
2318+
if (is_exit_or_eval_check_without_lineno(b->b_next)) {
23072319
cfg_instr *last = basicblock_last_instr(b);
23082320
assert(last != NULL);
23092321
b->b_next->b_instr[0].i_loc = last->i_loc;

0 commit comments

Comments
 (0)