]> granicus.if.org Git - python/commitdiff
Fix for SF bug 1569998: break permitted inside try.
authorJeremy Hylton <jeremy@alum.mit.edu>
Wed, 4 Oct 2006 02:24:52 +0000 (02:24 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Wed, 4 Oct 2006 02:24:52 +0000 (02:24 +0000)
The compiler was checking that there was something on the fblock
stack, but not that there was a loop on the stack.  Fixed that and
added a test for the specific syntax error.

Bug fix candidate.

Lib/test/test_syntax.py
Python/compile.c

index 692ba57a3eae5ca85af94bbe4290a1192918ad04..814303291907c733b2f8f75e7f7e0619e4752b89 100644 (file)
@@ -322,6 +322,20 @@ This is essentially a continue in a finally which should not be allowed.
       ...
     SyntaxError: 'continue' not supported inside 'finally' clause (<doctest test.test_syntax[41]>, line 8)
 
+There is one test for a break that is not in a loop.  The compiler
+uses a single data structure to keep track of try-finally and loops,
+so we need to be sure that a break is actually inside a loop.  If it
+isn't, there should be a syntax error.
+
+   >>> try:
+   ...     print 1
+   ...     break
+   ...     print 2
+   ... finally:
+   ...     print 3
+   Traceback (most recent call last):
+     ...
+   SyntaxError: 'break' outside loop (<doctest test.test_syntax[42]>, line 3)
 """
 
 import re
index a03de0d663a9ad47b30d70c46b0b4bc612908aa9..374cf1c4ef5457d50d77c8d75ff696f7dd85d3c4 100644 (file)
@@ -187,6 +187,8 @@ static int compiler_push_fblock(struct compiler *, enum fblocktype,
                                basicblock *);
 static void compiler_pop_fblock(struct compiler *, enum fblocktype,
                                basicblock *);
+/* Returns true if there is a loop on the fblock stack. */
+static int compiler_in_loop(struct compiler *);
 
 static int inplace_binop(struct compiler *, operator_ty);
 static int expr_constant(expr_ty e);
@@ -2157,7 +2159,7 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
        case Pass_kind:
                break;
        case Break_kind:
-               if (!c->u->u_nfblocks)
+                if (!compiler_in_loop(c))
                        return compiler_error(c, "'break' outside loop");
                ADDOP(c, BREAK_LOOP);
                break;
@@ -3147,6 +3149,16 @@ compiler_pop_fblock(struct compiler *c, enum fblocktype t, basicblock *b)
        assert(u->u_fblock[u->u_nfblocks].fb_block == b);
 }
 
+static int
+compiler_in_loop(struct compiler *c) {
+        int i;
+        struct compiler_unit *u = c->u;
+        for (i = 0; i < u->u_nfblocks; ++i) {
+                if (u->u_fblock[i].fb_type == LOOP)
+                        return 1;
+        }
+        return 0;
+}
 /* Raises a SyntaxError and returns 0.
    If something goes wrong, a different exception may be raised.
 */