Skip to content

Commit 6c3e66a

Browse files
authored
bpo-38640: Allow break and continue in always false while loops (GH-16992)
1 parent 24c6258 commit 6c3e66a

File tree

3 files changed

+29
-0
lines changed

3 files changed

+29
-0
lines changed

Lib/test/test_compile.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,24 @@ def unused_block_while_else():
731731
self.assertEqual(None, opcodes[0].argval)
732732
self.assertEqual('RETURN_VALUE', opcodes[1].opname)
733733

734+
def test_false_while_loop(self):
735+
def break_in_while():
736+
while False:
737+
break
738+
739+
def continue_in_while():
740+
while False:
741+
continue
742+
743+
funcs = [break_in_while, continue_in_while]
744+
745+
# Check that we did not raise but we also don't generate bytecode
746+
for func in funcs:
747+
opcodes = list(dis.get_instructions(func))
748+
self.assertEqual(2, len(opcodes))
749+
self.assertEqual('LOAD_CONST', opcodes[0].opname)
750+
self.assertEqual(None, opcodes[0].argval)
751+
self.assertEqual('RETURN_VALUE', opcodes[1].opname)
734752

735753
class TestExpressionStackSize(unittest.TestCase):
736754
# These tests check that the computed stack size for a code object
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed a bug in the compiler that was causing to raise in the presence of
2+
break statements and continue statements inside always false while loops.
3+
Patch by Pablo Galindo.

Python/compile.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2738,7 +2738,15 @@ compiler_while(struct compiler *c, stmt_ty s)
27382738

27392739
if (constant == 0) {
27402740
BEGIN_DO_NOT_EMIT_BYTECODE
2741+
// Push a dummy block so the VISIT_SEQ knows that we are
2742+
// inside a while loop so it can correctly evaluate syntax
2743+
// errors.
2744+
if (!compiler_push_fblock(c, WHILE_LOOP, NULL, NULL)) {
2745+
return 0;
2746+
}
27412747
VISIT_SEQ(c, stmt, s->v.While.body);
2748+
// Remove the dummy block now that is not needed.
2749+
compiler_pop_fblock(c, WHILE_LOOP, NULL);
27422750
END_DO_NOT_EMIT_BYTECODE
27432751
if (s->v.While.orelse) {
27442752
VISIT_SEQ(c, stmt, s->v.While.orelse);

0 commit comments

Comments
 (0)