diff options
author | Georg Brandl <georg@python.org> | 2006-06-04 21:56:52 (GMT) |
---|---|---|
committer | Georg Brandl <georg@python.org> | 2006-06-04 21:56:52 (GMT) |
commit | ddbaa660d3b64a71b4ac9eab64b1bb944ca1276b (patch) | |
tree | ff4255db178f608511fbc29f1410241bef74a109 | |
parent | 9f167606665c186179bf362d4227e722731cd1b9 (diff) | |
download | cpython-ddbaa660d3b64a71b4ac9eab64b1bb944ca1276b.zip cpython-ddbaa660d3b64a71b4ac9eab64b1bb944ca1276b.tar.gz cpython-ddbaa660d3b64a71b4ac9eab64b1bb944ca1276b.tar.bz2 |
Patch #1346214: correctly optimize away "if 0"-style stmts
(thanks to Neal for review)
-rw-r--r-- | Include/symtable.h | 2 | ||||
-rw-r--r-- | Lib/test/test_generators.py | 6 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Python/compile.c | 43 | ||||
-rw-r--r-- | Python/symtable.c | 21 |
5 files changed, 57 insertions, 18 deletions
diff --git a/Include/symtable.h b/Include/symtable.h index 222831a..1e5996d 100644 --- a/Include/symtable.h +++ b/Include/symtable.h @@ -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 */ diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index a60a768..a184a8b 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -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): @@ -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. diff --git a/Python/compile.c b/Python/compile.c index e555fec..cceb2ac 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -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; } diff --git a/Python/symtable.c b/Python/symtable.c index 184723d..1dc2a2e 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -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); |