https://github.com/python/cpython/commit/8aa0088ea2422ed6b95076fe48a13df7562a4355
commit: 8aa0088ea2422ed6b95076fe48a13df7562a4355
branch: main
author: Irit Katriel <[email protected]>
committer: iritkatriel <[email protected]>
date: 2024-01-12T15:38:09Z
summary:

gh-107901: duplicate blocks with no lineno that have an eval break and multiple 
predecessors (#113950)

files:
A Misc/NEWS.d/next/Core and 
Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst
M Lib/test/test_compile.py
M Python/flowgraph.c

diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
index 45fd30987760cb..50629b22822245 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -1098,6 +1098,21 @@ async def test(aseq):
         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 00000000000000..ce59ef55b5ee60
--- /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 dad945761a4a58..4778f89e19b143 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;

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to