summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>2024-01-12 15:38:09 (GMT)
committerGitHub <noreply@github.com>2024-01-12 15:38:09 (GMT)
commit8aa0088ea2422ed6b95076fe48a13df7562a4355 (patch)
tree162f0c87500bf9e24b3786719af9ea9f4c95e545
parente02c15b3f13d9d83032ada72c6773f8a3b2d34dc (diff)
downloadcpython-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.py15
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst1
-rw-r--r--Python/flowgraph.c32
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;