]> granicus.if.org Git - python/commitdiff
Patch #1346214: correctly optimize away "if 0"-style stmts
authorGeorg Brandl <georg@python.org>
Sun, 4 Jun 2006 21:56:52 +0000 (21:56 +0000)
committerGeorg Brandl <georg@python.org>
Sun, 4 Jun 2006 21:56:52 +0000 (21:56 +0000)
(thanks to Neal for review)

Include/symtable.h
Lib/test/test_generators.py
Misc/NEWS
Python/compile.c
Python/symtable.c

index 222831a004926b7f7b4552660995f56802f8dcc0..1e5996dc60fb547861b91d20d6d83aff0bdcb12e 100644 (file)
@@ -39,6 +39,8 @@ typedef struct _symtable_entry {
        unsigned ste_generator : 1;   /* true if namespace is a generator */
        unsigned ste_varargs : 1;     /* true if block has varargs */
        unsigned ste_varkeywords : 1; /* true if block has varkeywords */
+       unsigned ste_returns_value : 1;  /* true if namespace uses return with
+                                           an argument */
        int ste_lineno;          /* first line of block */
        int ste_opt_lineno;      /* lineno of last exec or import * */
        int ste_tmpname;         /* counter for listcomp temp vars */
index a60a768be18cd75617c459c860b4e0ada16c05b7..a184a8be3c61e28a66c297ce6b397c8287f65ad0 100644 (file)
@@ -733,7 +733,7 @@ syntax_tests = """
 ...     yield 1
 Traceback (most recent call last):
   ..
-SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[0]>, line 2)
+SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[0]>, line 3)
 
 >>> def f():
 ...     yield 1
@@ -876,9 +876,9 @@ These are fine:
 ...         if 0:
 ...             return 3        # but *this* sucks (line 8)
 ...     if 0:
-...         yield 2             # because it's a generator
+...         yield 2             # because it's a generator (line 10)
 Traceback (most recent call last):
-SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[24]>, line 8)
+SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[24]>, line 10)
 
 This one caused a crash (see SF bug 567538):
 
index 50e7907e13279f9dd354bbebbcfcfe44b7bb8c76..f887503a9a37285149c47263c911b941fcd2d4f0 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 2.5 beta 1?
 Core and builtins
 -----------------
 
+- Patch #1346214: Statements like "if 0: suite" are now again optimized
+  away like they were in Python 2.4.
+
 - Builtin exceptions are now full-blown new-style classes instead of
   instances pretending to be classes, which speeds up exception handling
   by about 80% in comparison to 2.5a2.
index e555fec925236e9cb3d0467928d73341aa110fef..cceb2ac10fa68c1c4fea9ae2b0befc5a77279c19 100644 (file)
@@ -2148,7 +2148,7 @@ static int
 compiler_if(struct compiler *c, stmt_ty s)
 {
        basicblock *end, *next;
-
+       int constant;
        assert(s->kind == If_kind);
        end = compiler_new_block(c);
        if (end == NULL)
@@ -2156,15 +2156,27 @@ compiler_if(struct compiler *c, stmt_ty s)
        next = compiler_new_block(c);
        if (next == NULL)
            return 0;
-       VISIT(c, expr, s->v.If.test);
-       ADDOP_JREL(c, JUMP_IF_FALSE, next);
-       ADDOP(c, POP_TOP);
-       VISIT_SEQ(c, stmt, s->v.If.body);
-       ADDOP_JREL(c, JUMP_FORWARD, end);
-       compiler_use_next_block(c, next);
-       ADDOP(c, POP_TOP);
-       if (s->v.If.orelse)
-           VISIT_SEQ(c, stmt, s->v.If.orelse);
+       
+       constant = expr_constant(s->v.If.test);
+       /* constant = 0: "if 0"
+        * constant = 1: "if 1", "if 2", ...
+        * constant = -1: rest */
+       if (constant == 0) {
+               if (s->v.If.orelse)
+                       VISIT_SEQ(c, stmt, s->v.If.orelse);
+       } else if (constant == 1) {
+               VISIT_SEQ(c, stmt, s->v.If.body);
+       } else {
+               VISIT(c, expr, s->v.If.test);
+               ADDOP_JREL(c, JUMP_IF_FALSE, next);
+               ADDOP(c, POP_TOP);
+               VISIT_SEQ(c, stmt, s->v.If.body);
+               ADDOP_JREL(c, JUMP_FORWARD, end);
+               compiler_use_next_block(c, next);
+               ADDOP(c, POP_TOP);
+               if (s->v.If.orelse)
+                       VISIT_SEQ(c, stmt, s->v.If.orelse);
+       }
        compiler_use_next_block(c, end);
        return 1;
 }
@@ -2639,10 +2651,6 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
                if (c->u->u_ste->ste_type != FunctionBlock)
                        return compiler_error(c, "'return' outside function");
                if (s->v.Return.value) {
-                       if (c->u->u_ste->ste_generator) {
-                               return compiler_error(c,
-                                   "'return' with argument inside generator");
-                       }
                        VISIT(c, expr, s->v.Return.value);
                }
                else
@@ -3356,6 +3364,13 @@ expr_constant(expr_ty e)
                return PyObject_IsTrue(e->v.Num.n);
        case Str_kind:
                return PyObject_IsTrue(e->v.Str.s);
+       case Name_kind:
+               /* __debug__ is not assignable, so we can optimize
+                * it away in if and while statements */
+               if (strcmp(PyString_AS_STRING(e->v.Name.id),
+                          "__debug__") == 0)
+                          return ! Py_OptimizeFlag;
+               /* fall through */
        default:
                return -1;
        }
index 184723d5dcc18388e378906aa127df59dd468c8b..1dc2a2ea7466b04f1527ba907b125af93fa0fe7c 100644 (file)
@@ -13,6 +13,8 @@
 
 #define IMPORT_STAR_WARNING "import * only allowed at module level"
 
+#define RETURN_VAL_IN_GENERATOR \
+    "'return' with argument inside generator"
 
 /* XXX(nnorwitz): change name since static? */
 static PySTEntryObject *
@@ -66,6 +68,7 @@ PySTEntry_New(struct symtable *st, identifier name, _Py_block_ty block,
                ste->ste_nested = 1;
        ste->ste_child_free = 0;
        ste->ste_generator = 0;
+       ste->ste_returns_value = 0;
 
        if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0)
            goto fail;
@@ -944,8 +947,17 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
                break;
        }
         case Return_kind:
-               if (s->v.Return.value)
+               if (s->v.Return.value) {
                        VISIT(st, expr, s->v.Return.value);
+                       st->st_cur->ste_returns_value = 1;
+                       if (st->st_cur->ste_generator) {
+                               PyErr_SetString(PyExc_SyntaxError,
+                                       RETURN_VAL_IN_GENERATOR);
+                               PyErr_SyntaxLocation(st->st_filename,
+                                            s->lineno);
+                               return 0;
+                       }
+               }
                break;
         case Delete_kind:
                VISIT_SEQ(st, expr, s->v.Delete.targets);
@@ -1136,6 +1148,13 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
                if (e->v.Yield.value)
                        VISIT(st, expr, e->v.Yield.value);
                 st->st_cur->ste_generator = 1;
+               if (st->st_cur->ste_returns_value) {
+                       PyErr_SetString(PyExc_SyntaxError,
+                               RETURN_VAL_IN_GENERATOR);
+                       PyErr_SyntaxLocation(st->st_filename,
+                                    e->lineno);
+                       return 0;
+               }
                break;
         case Compare_kind:
                VISIT(st, expr, e->v.Compare.left);