File: astcompiler-fix

package info (click to toggle)
pypy3 7.3.20%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 212,628 kB
  • sloc: python: 2,101,020; ansic: 540,684; sh: 21,462; asm: 14,419; cpp: 4,451; makefile: 4,209; objc: 761; xml: 530; exp: 499; javascript: 314; pascal: 244; lisp: 45; csh: 12; awk: 4
file content (100 lines) | stat: -rw-r--r-- 4,618 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
From: CF Bolz-Tereick <cfbolz@gmx.de>
Date: Mon, 25 Aug 2025 16:35:49 +0200
Subject: gh-5328: be more careful in duplicate_exits_without_lineno

there's still a case where I didn't manage to find a unit test yet,
trying to see whether the buildbot shows one

Bug-Debian: https://bugs.debian.org/1119266
Bug-Upstream: https://github.com/pypy/pypy/issues/5328
Origin: upstream, 0b47638bbde129c521ce486f0357c74e5e1deed3
---
 pypy/interpreter/astcompiler/assemble.py           | 20 +++++++++++++++++---
 pypy/interpreter/astcompiler/test/test_compiler.py | 19 ++++++++++++++++++-
 2 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py
index 2e7596f..42f4513 100644
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -829,7 +829,9 @@ class PythonCodeMaker(ast.ASTVisitor):
 
                 # if it's an unconditional jump, duplicate it
                 if op.opcode in (ops.JUMP_FORWARD, ops.JUMP_ABSOLUTE):
+                    assert block.cant_add_instructions
                     block.instructions.pop()
+                    block.cant_add_instructions = False
                     j -= 1
                     target.marked -= 2 # one fewer incoming links
                     for instr in target.instructions:
@@ -840,18 +842,30 @@ class PythonCodeMaker(ast.ASTVisitor):
                         if copy.jump:
                             copy.jump.marked += 2
                         block.emit_instr(copy)
+                    if target.next_block and not block.cant_add_instructions:
+                        print "missing test! please report a bug about the astcompiler", self.name
+                        assert 0
+                        instr = Instruction(ops.JUMP_ABSOLUTE, position_info=self.position_info)
+                        instr.jump = target.next_block
+                        block.emit_instr(instr)
+                        target.next_block.marked += 2
+
                 elif (target.marked >> 1) > 1:
                     # copy the block, it has more than one predecessor
                     target.marked -= 2 # one fewer incoming links for old target
                     newtarget = target.copy()
                     newtarget.marked = 1 << 1 # new target has one incoming link
                     newtarget.instructions[0].position_info = op.position_info
-                    # maintain marked correctly:
-                    if newtarget.next_block:
-                        newtarget.next_block.marked += 2
                     for copied_op in newtarget.instructions:
                         if copied_op.jump:
                             copied_op.jump.marked += 2
+                    # deal with fall-through of copied target block - rare, but
+                    # see test_if_call_or_call_bug
+                    if target.next_block and not newtarget.cant_add_instructions:
+                        instr = Instruction(ops.JUMP_ABSOLUTE, position_info=self.position_info)
+                        instr.jump = target.next_block
+                        target.next_block.marked += 2
+                        newtarget.emit_instr(instr)
                     op.jump = newtarget
                     blocks.append(newtarget)
 
diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py
index 7843c31..17efbe1 100644
--- a/pypy/interpreter/astcompiler/test/test_compiler.py
+++ b/pypy/interpreter/astcompiler/test/test_compiler.py
@@ -2401,7 +2401,16 @@ match x:
     @pytest.mark.xfail
     def test_if_call_or_call_bug(self):
         # used to crash
-        compile_with_astcompiler("def func_if_call_or_call():\n    if a: f1() or g1()\n", 'exec', self.space)
+        compile_with_astcompiler("""
+def func_if_call_or_call():
+    if a:
+        (f1() or
+        g1())""", 'exec', self.space)
+        compile_with_astcompiler("""
+def func_if_call_and_call():
+    if a:
+        (f1() and
+        g1())""", 'exec', self.space)
 
 class TestLinenoChanges310(object):
     def get_line_numbers(self, source, expected, function=False):
@@ -2627,6 +2636,14 @@ def withreturn():
         )
         """, [3, 0, 1])
 
+    def test_or_with_implicit_return(self):
+        code = self.get_line_numbers("""
+def or_with_implicit_return():
+    if a:
+        (g
+         or
+         h)""", [1, 2, 4, 1, 2], function=True)
+
 class TestErrorPositions(BaseTestCompiler):
     def test_import_star_in_function_position(self):
         src = "def f(): from _ import *"