]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-38640: Allow break and continue in always false while loops (GH-16992)
authorPablo Galindo <Pablogsal@gmail.com>
Wed, 30 Oct 2019 11:53:26 +0000 (11:53 +0000)
committerGitHub <noreply@github.com>
Wed, 30 Oct 2019 11:53:26 +0000 (11:53 +0000)
Lib/test/test_compile.py
Misc/NEWS.d/next/Core and Builtins/2019-10-30-11-25-25.bpo-38640.4sAFh5.rst [new file with mode: 0644]
Python/compile.c

index 9d77f7af05d6fd02ffb73abe0e8009d77412aceb..566ca27fca893da74b8f678479b9a8ca0a98ccb5 100644 (file)
@@ -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 (file)
index 0000000..d99db3c
--- /dev/null
@@ -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.
index 3b2188e6e74386b58b7dd8250e162365a1c0c927..f26ad3c775255155215eb93f5028eef2c7d85a9a 100644 (file)
@@ -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);