diff options
author | Irit Katriel <1055913+iritkatriel@users.noreply.github.com> | 2024-01-12 15:38:09 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-12 15:38:09 (GMT) |
commit | 8aa0088ea2422ed6b95076fe48a13df7562a4355 (patch) | |
tree | 162f0c87500bf9e24b3786719af9ea9f4c95e545 | |
parent | e02c15b3f13d9d83032ada72c6773f8a3b2d34dc (diff) | |
download | cpython-8aa0088ea2422ed6b95076fe48a13df7562a4355.zip cpython-8aa0088ea2422ed6b95076fe48a13df7562a4355.tar.gz cpython-8aa0088ea2422ed6b95076fe48a13df7562a4355.tar.bz2 |
gh-107901: duplicate blocks with no lineno that have an eval break and multiple predecessors (#113950)
-rw-r--r-- | Lib/test/test_compile.py | 15 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst | 1 | ||||
-rw-r--r-- | Python/flowgraph.c | 32 |
3 files changed, 38 insertions, 10 deletions
diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 45fd309..50629b2 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1098,6 +1098,21 @@ class TestSpecifics(unittest.TestCase): code_lines = self.get_code_lines(test.__code__) self.assertEqual(expected_lines, code_lines) + def test_line_number_synthetic_jump_multiple_predecessors(self): + def f(): + for x in it: + try: + if C1: + yield 2 + except OSError: + pass + + # Ensure that all JUMP_BACKWARDs have line number + code = f.__code__ + for inst in dis.Bytecode(code): + if inst.opname == 'JUMP_BACKWARD': + self.assertIsNotNone(inst.positions.lineno) + def test_lineno_of_backward_jump(self): # Issue gh-107901 def f(): diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst b/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst new file mode 100644 index 0000000..ce59ef5 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst @@ -0,0 +1 @@ +Compiler duplicates basic blocks that have an eval breaker check, no line number, and multiple predecessors. diff --git a/Python/flowgraph.c b/Python/flowgraph.c index dad9457..4778f89 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -316,6 +316,16 @@ basicblock_exits_scope(const basicblock *b) { return last && IS_SCOPE_EXIT_OPCODE(last->i_opcode); } +static inline int +basicblock_has_eval_break(const basicblock *b) { + for (int i = 0; i < b->b_iused; i++) { + if (OPCODE_HAS_EVAL_BREAK(b->b_instr[i].i_opcode)) { + return true; + } + } + return false; +} + static bool cfg_builder_current_block_is_terminated(cfg_builder *g) { @@ -2246,16 +2256,18 @@ convert_pseudo_ops(basicblock *entryblock) } static inline bool -is_exit_without_lineno(basicblock *b) { - if (!basicblock_exits_scope(b)) { - return false; - } - for (int i = 0; i < b->b_iused; i++) { - if (b->b_instr[i].i_loc.lineno >= 0) { - return false; +is_exit_or_eval_check_without_lineno(basicblock *b) { + if (basicblock_exits_scope(b) || basicblock_has_eval_break(b)) { + for (int i = 0; i < b->b_iused; i++) { + if (b->b_instr[i].i_loc.lineno >= 0) { + return false; + } } + return true; + } + else { + return false; } - return true; } @@ -2283,7 +2295,7 @@ duplicate_exits_without_lineno(cfg_builder *g) } if (is_jump(last)) { basicblock *target = next_nonempty_block(last->i_target); - if (is_exit_without_lineno(target) && target->b_predecessors > 1) { + if (is_exit_or_eval_check_without_lineno(target) && target->b_predecessors > 1) { basicblock *new_target = copy_basicblock(g, target); if (new_target == NULL) { return ERROR; @@ -2303,7 +2315,7 @@ duplicate_exits_without_lineno(cfg_builder *g) * fall through, and thus can only have a single predecessor */ for (basicblock *b = entryblock; b != NULL; b = b->b_next) { if (BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_iused > 0) { - if (is_exit_without_lineno(b->b_next)) { + if (is_exit_or_eval_check_without_lineno(b->b_next)) { cfg_instr *last = basicblock_last_instr(b); assert(last != NULL); b->b_next->b_instr[0].i_loc = last->i_loc; |