Skip to content

Commit dcb338e

Browse files
bpo-38640: Allow break and continue in always false while loops (GH-16992)
(cherry picked from commit 6c3e66a) Co-authored-by: Pablo Galindo <[email protected]>
1 parent 1d2862a commit dcb338e

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
@@ -2736,7 +2736,15 @@ compiler_while(struct compiler *c, stmt_ty s)
27362736

27372737
if (constant == 0) {
27382738
BEGIN_DO_NOT_EMIT_BYTECODE
2739+
// Push a dummy block so the VISIT_SEQ knows that we are
2740+
// inside a while loop so it can correctly evaluate syntax
2741+
// errors.
2742+
if (!compiler_push_fblock(c, WHILE_LOOP, NULL, NULL)) {
2743+
return 0;
2744+
}
27392745
VISIT_SEQ(c, stmt, s->v.While.body);
2746+
// Remove the dummy block now that is not needed.
2747+
compiler_pop_fblock(c, WHILE_LOOP, NULL);
27402748
END_DO_NOT_EMIT_BYTECODE
27412749
if (s->v.While.orelse) {
27422750
VISIT_SEQ(c, stmt, s->v.While.orelse);

0 commit comments

Comments
 (0)