diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index c756d43a3cf3b8..8a6eb1ad97bed7 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -990,6 +990,20 @@ async def test(aseq): code_lines = self.get_code_lines(test.__code__) self.assertEqual(expected_lines, code_lines) + def test_lineno_of_backward_jump(self): + # Issue gh-107901 + def f(): + for i in x: + if y: + pass + + linenos = list(inst.positions.lineno + for inst in dis.get_instructions(f.__code__) + if inst.opname == 'JUMP_BACKWARD') + + self.assertTrue(len(linenos) > 0) + self.assertTrue(all(l is not None for l in linenos)) + def test_big_dict_literal(self): # The compiler has a flushing point in "compiler_dict" that calls compiles # a portion of the dictionary literal when the loop that iterates over the items diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 6a0a2d92796703..f3b4080c290c5a 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -146,12 +146,13 @@ def bug708901(): %3d PRECALL 2 CALL 2 GET_ITER - >> FOR_ITER 2 (to 40) + >> FOR_ITER 3 (to 42) STORE_FAST 0 (res) -%3d JUMP_BACKWARD 3 (to 34) +%3d NOP -%3d >> LOAD_CONST 0 (None) +%3d JUMP_BACKWARD 4 (to 34) + >> LOAD_CONST 0 (None) RETURN_VALUE """ % (bug708901.__code__.co_firstlineno, bug708901.__code__.co_firstlineno + 1, @@ -622,9 +623,9 @@ def loop_test(): 34 PRECALL_PYFUNC 1 38 CALL_PY_WITH_DEFAULTS 1 48 POP_TOP - 50 JUMP_BACKWARD_QUICK 18 (to 16) -%3d >> 52 LOAD_CONST 0 (None) +%3d 50 JUMP_BACKWARD_QUICK 18 (to 16) + >> 52 LOAD_CONST 0 (None) 54 RETURN_VALUE """ % (loop_test.__code__.co_firstlineno, loop_test.__code__.co_firstlineno + 1, @@ -1434,7 +1435,7 @@ def _prepare_test_cases(): Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=2, argval=96, argrepr='to 96', offset=90, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=92, starts_line=8, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=128, argrepr='to 128', offset=94, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=33, argval=32, argrepr='to 32', offset=96, starts_line=7, is_jump_target=True, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=33, argval=32, argrepr='to 32', offset=96, starts_line=3, is_jump_target=True, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=98, starts_line=10, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=110, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None), diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 96242bb260a612..c14807c4631959 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -130,9 +130,11 @@ def no_pop_tops(): # 0 (3, 'line'), (6, 'line'), (2, 'line'), + (2, 'line'), (3, 'line'), (4, 'line'), (2, 'line'), + (2, 'line'), (2, 'return')] def no_pop_blocks(): @@ -299,7 +301,7 @@ def generator_example(): (-4, 'exception'), (-1, 'line'), (-1, 'return')] + - [(5, 'line'), (6, 'line')] * 10 + + [(5, 'line'), (6, 'line'), (5, 'line')] * 10 + [(5, 'line'), (5, 'return')]) @@ -451,8 +453,10 @@ def for_example(): (1, 'line'), (2, 'line'), (1, 'line'), + (1, 'line'), (2, 'line'), (1, 'line'), + (1, 'line'), (1, 'return')]) def while_example(): @@ -641,6 +645,7 @@ async def f(): (1, 'line'), (-1, 'call'), (-2, 'line'), + (-2, 'line'), (-1, 'line'), (-1, 'return'), (1, 'exception'), @@ -648,6 +653,7 @@ async def f(): (1, 'line'), (-1, 'call'), (-2, 'line'), + (-2, 'line'), (-1, 'line'), (-1, 'return'), (1, 'exception'), @@ -655,6 +661,7 @@ async def f(): (1, 'line'), (-1, 'call'), (-2, 'line'), + (-2, 'line'), (-2, 'return'), (1, 'exception'), (1, 'return'), @@ -765,14 +772,20 @@ def func(): (2, 'line'), (3, 'line'), (2, 'line'), + (2, 'line'), (3, 'line'), (2, 'line'), + (2, 'line'), + (1, 'line'), (1, 'line'), (2, 'line'), (3, 'line'), (2, 'line'), + (2, 'line'), (3, 'line'), (2, 'line'), + (2, 'line'), + (1, 'line'), (1, 'line'), (4, 'line'), (4, 'return')]) @@ -830,6 +843,7 @@ def func(): (8, 'line'), (10, 'line'), (3, 'line'), + (3, 'line'), (4, 'line'), (5, 'line'), (6, 'line'), @@ -866,6 +880,7 @@ def func(): (8, 'line'), (10, 'line'), (3, 'line'), + (3, 'line'), (4, 'line'), (5, 'line'), (6, 'line'), @@ -1242,6 +1257,7 @@ def func(): (-2, 'line'), (-2, 'return'), (1, 'line'), + (1, 'line'), (2, 'line'), (-8, 'call'), (-7, 'line'), @@ -1253,6 +1269,7 @@ def func(): (-2, 'line'), (-2, 'return'), (1, 'line'), + (1, 'line'), (1, 'return')]) def test_no_tracing_of_named_except_cleanup(self): @@ -1551,6 +1568,7 @@ def func(): (-2, 'line'), (-2, 'return'), (4, 'line'), + (2, 'line'), (1, 'line'), (-2, 'call'), (-2, 'return'), diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py index fad2b3b8379ffc..b757f97ec0432b 100644 --- a/Lib/test/test_trace.py +++ b/Lib/test/test_trace.py @@ -147,7 +147,7 @@ def test_traced_func_loop(self): firstlineno = get_firstlineno(traced_func_loop) expected = { (self.my_py_filename, firstlineno + 1): 1, - (self.my_py_filename, firstlineno + 2): 6, + (self.my_py_filename, firstlineno + 2): 11, (self.my_py_filename, firstlineno + 3): 5, (self.my_py_filename, firstlineno + 4): 1, } @@ -172,10 +172,10 @@ def test_trace_func_generator(self): firstlineno_gen = get_firstlineno(traced_func_generator) expected = { (self.my_py_filename, firstlineno_calling + 1): 1, - (self.my_py_filename, firstlineno_calling + 2): 11, + (self.my_py_filename, firstlineno_calling + 2): 21, (self.my_py_filename, firstlineno_calling + 3): 10, (self.my_py_filename, firstlineno_gen + 1): 1, - (self.my_py_filename, firstlineno_gen + 2): 11, + (self.my_py_filename, firstlineno_gen + 2): 21, (self.my_py_filename, firstlineno_gen + 3): 10, } self.assertEqual(self.tracer.results().counts, expected) @@ -246,7 +246,7 @@ def test_exec_counts(self): firstlineno = get_firstlineno(traced_func_loop) expected = { (self.my_py_filename, firstlineno + 1): 1, - (self.my_py_filename, firstlineno + 2): 6, + (self.my_py_filename, firstlineno + 2): 11, (self.my_py_filename, firstlineno + 3): 5, (self.my_py_filename, firstlineno + 4): 1, } diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-22-18-38-45.gh-107901.XgXVgU.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-22-18-38-45.gh-107901.XgXVgU.rst new file mode 100644 index 00000000000000..112e093736dd5d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-22-18-38-45.gh-107901.XgXVgU.rst @@ -0,0 +1 @@ +Fix missing line number on :opcode:`JUMP_BACKWARD` at the end of a for loop. diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 0b658000d44658..b26a2e545cf424 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -28,7 +28,7 @@ unsigned char M_test_frozenmain[] = { 107,101,121,169,0,243,0,0,0,0,250,18,116,101,115,116, 95,102,114,111,122,101,110,109,97,105,110,46,112,121,250,8, 60,109,111,100,117,108,101,62,114,18,0,0,0,1,0,0, - 0,115,156,0,0,0,240,3,1,1,1,240,8,0,1,11, + 0,115,158,0,0,0,240,3,1,1,1,240,8,0,1,11, 128,10,128,10,128,10,216,0,24,208,0,24,208,0,24,208, 0,24,224,0,5,128,5,208,6,26,209,0,27,212,0,27, 208,0,27,216,0,5,128,5,128,106,144,35,148,40,209,0, @@ -37,6 +37,6 @@ unsigned char M_test_frozenmain[] = { 12,2,240,0,7,1,42,240,0,7,1,42,128,67,240,14, 0,5,10,128,69,208,10,40,144,67,208,10,40,208,10,40, 152,54,160,35,156,59,208,10,40,208,10,40,209,4,41,212, - 4,41,208,4,41,208,4,41,240,15,7,1,42,240,0,7, - 1,42,114,16,0,0,0, + 4,41,208,4,41,240,15,6,12,2,240,0,7,1,42,240, + 0,7,1,42,114,16,0,0,0, }; diff --git a/Python/compile.c b/Python/compile.c index 558df3fca653ea..e0cba41c1d7d3d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -3123,7 +3123,7 @@ compiler_for(struct compiler *c, stmt_ty s) VISIT(c, expr, s->v.For.target); VISIT_SEQ(c, stmt, s->v.For.body); /* Mark jump as artificial */ - UNSET_LOC(c); + SET_LOC(c, s->v.For.iter); ADDOP_JUMP(c, JUMP, start); compiler_use_next_block(c, cleanup);