From 6c3e66a34b95fff07df0ad5086104dd637a091ce Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 30 Oct 2019 11:53:26 +0000 Subject: bpo-38640: Allow break and continue in always false while loops (GH-16992) --- Lib/test/test_compile.py | 18 ++++++++++++++++++ .../2019-10-30-11-25-25.bpo-38640.4sAFh5.rst | 3 +++ Python/compile.c | 8 ++++++++ 3 files changed, 29 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-10-30-11-25-25.bpo-38640.4sAFh5.rst diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 9d77f7a..566ca27 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -731,6 +731,24 @@ if 1: self.assertEqual(None, opcodes[0].argval) self.assertEqual('RETURN_VALUE', opcodes[1].opname) + def test_false_while_loop(self): + def break_in_while(): + while False: + break + + def continue_in_while(): + while False: + continue + + funcs = [break_in_while, continue_in_while] + + # Check that we did not raise but we also don't generate bytecode + for func in funcs: + opcodes = list(dis.get_instructions(func)) + self.assertEqual(2, len(opcodes)) + self.assertEqual('LOAD_CONST', opcodes[0].opname) + self.assertEqual(None, opcodes[0].argval) + self.assertEqual('RETURN_VALUE', opcodes[1].opname) class TestExpressionStackSize(unittest.TestCase): # These tests check that the computed stack size for a code object diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-10-30-11-25-25.bpo-38640.4sAFh5.rst b/Misc/NEWS.d/next/Core and Builtins/2019-10-30-11-25-25.bpo-38640.4sAFh5.rst new file mode 100644 index 0000000..d99db3c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-10-30-11-25-25.bpo-38640.4sAFh5.rst @@ -0,0 +1,3 @@ +Fixed a bug in the compiler that was causing to raise in the presence of +break statements and continue statements inside always false while loops. +Patch by Pablo Galindo. diff --git a/Python/compile.c b/Python/compile.c index 3b2188e..f26ad3c 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2738,7 +2738,15 @@ compiler_while(struct compiler *c, stmt_ty s) if (constant == 0) { BEGIN_DO_NOT_EMIT_BYTECODE + // Push a dummy block so the VISIT_SEQ knows that we are + // inside a while loop so it can correctly evaluate syntax + // errors. + if (!compiler_push_fblock(c, WHILE_LOOP, NULL, NULL)) { + return 0; + } VISIT_SEQ(c, stmt, s->v.While.body); + // Remove the dummy block now that is not needed. + compiler_pop_fblock(c, WHILE_LOOP, NULL); END_DO_NOT_EMIT_BYTECODE if (s->v.While.orelse) { VISIT_SEQ(c, stmt, s->v.While.orelse); -- cgit v0.12