Kaydet (Commit) ddbaa660 authored tarafından Georg Brandl's avatar Georg Brandl

Patch #1346214: correctly optimize away "if 0"-style stmts

(thanks to Neal for review)
üst 9f167606
...@@ -39,6 +39,8 @@ typedef struct _symtable_entry { ...@@ -39,6 +39,8 @@ typedef struct _symtable_entry {
unsigned ste_generator : 1; /* true if namespace is a generator */ unsigned ste_generator : 1; /* true if namespace is a generator */
unsigned ste_varargs : 1; /* true if block has varargs */ unsigned ste_varargs : 1; /* true if block has varargs */
unsigned ste_varkeywords : 1; /* true if block has varkeywords */ 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_lineno; /* first line of block */
int ste_opt_lineno; /* lineno of last exec or import * */ int ste_opt_lineno; /* lineno of last exec or import * */
int ste_tmpname; /* counter for listcomp temp vars */ int ste_tmpname; /* counter for listcomp temp vars */
......
...@@ -733,7 +733,7 @@ syntax_tests = """ ...@@ -733,7 +733,7 @@ syntax_tests = """
... yield 1 ... yield 1
Traceback (most recent call last): 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(): >>> def f():
... yield 1 ... yield 1
...@@ -876,9 +876,9 @@ These are fine: ...@@ -876,9 +876,9 @@ These are fine:
... if 0: ... if 0:
... return 3 # but *this* sucks (line 8) ... return 3 # but *this* sucks (line 8)
... if 0: ... if 0:
... yield 2 # because it's a generator ... yield 2 # because it's a generator (line 10)
Traceback (most recent call last): 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): This one caused a crash (see SF bug 567538):
......
...@@ -12,6 +12,9 @@ What's New in Python 2.5 beta 1? ...@@ -12,6 +12,9 @@ What's New in Python 2.5 beta 1?
Core and builtins 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 - Builtin exceptions are now full-blown new-style classes instead of
instances pretending to be classes, which speeds up exception handling instances pretending to be classes, which speeds up exception handling
by about 80% in comparison to 2.5a2. by about 80% in comparison to 2.5a2.
......
...@@ -2148,7 +2148,7 @@ static int ...@@ -2148,7 +2148,7 @@ static int
compiler_if(struct compiler *c, stmt_ty s) compiler_if(struct compiler *c, stmt_ty s)
{ {
basicblock *end, *next; basicblock *end, *next;
int constant;
assert(s->kind == If_kind); assert(s->kind == If_kind);
end = compiler_new_block(c); end = compiler_new_block(c);
if (end == NULL) if (end == NULL)
...@@ -2156,15 +2156,27 @@ compiler_if(struct compiler *c, stmt_ty s) ...@@ -2156,15 +2156,27 @@ compiler_if(struct compiler *c, stmt_ty s)
next = compiler_new_block(c); next = compiler_new_block(c);
if (next == NULL) if (next == NULL)
return 0; return 0;
VISIT(c, expr, s->v.If.test);
ADDOP_JREL(c, JUMP_IF_FALSE, next); constant = expr_constant(s->v.If.test);
ADDOP(c, POP_TOP); /* constant = 0: "if 0"
VISIT_SEQ(c, stmt, s->v.If.body); * constant = 1: "if 1", "if 2", ...
ADDOP_JREL(c, JUMP_FORWARD, end); * constant = -1: rest */
compiler_use_next_block(c, next); if (constant == 0) {
ADDOP(c, POP_TOP); if (s->v.If.orelse)
if (s->v.If.orelse) VISIT_SEQ(c, stmt, 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); compiler_use_next_block(c, end);
return 1; return 1;
} }
...@@ -2639,10 +2651,6 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) ...@@ -2639,10 +2651,6 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
if (c->u->u_ste->ste_type != FunctionBlock) if (c->u->u_ste->ste_type != FunctionBlock)
return compiler_error(c, "'return' outside function"); return compiler_error(c, "'return' outside function");
if (s->v.Return.value) { 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); VISIT(c, expr, s->v.Return.value);
} }
else else
...@@ -3356,6 +3364,13 @@ expr_constant(expr_ty e) ...@@ -3356,6 +3364,13 @@ expr_constant(expr_ty e)
return PyObject_IsTrue(e->v.Num.n); return PyObject_IsTrue(e->v.Num.n);
case Str_kind: case Str_kind:
return PyObject_IsTrue(e->v.Str.s); 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: default:
return -1; return -1;
} }
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#define IMPORT_STAR_WARNING "import * only allowed at module level" #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? */ /* XXX(nnorwitz): change name since static? */
static PySTEntryObject * static PySTEntryObject *
...@@ -66,6 +68,7 @@ PySTEntry_New(struct symtable *st, identifier name, _Py_block_ty block, ...@@ -66,6 +68,7 @@ PySTEntry_New(struct symtable *st, identifier name, _Py_block_ty block,
ste->ste_nested = 1; ste->ste_nested = 1;
ste->ste_child_free = 0; ste->ste_child_free = 0;
ste->ste_generator = 0; ste->ste_generator = 0;
ste->ste_returns_value = 0;
if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0) if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0)
goto fail; goto fail;
...@@ -944,8 +947,17 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) ...@@ -944,8 +947,17 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
break; break;
} }
case Return_kind: case Return_kind:
if (s->v.Return.value) if (s->v.Return.value) {
VISIT(st, expr, 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; break;
case Delete_kind: case Delete_kind:
VISIT_SEQ(st, expr, s->v.Delete.targets); VISIT_SEQ(st, expr, s->v.Delete.targets);
...@@ -1136,6 +1148,13 @@ symtable_visit_expr(struct symtable *st, expr_ty e) ...@@ -1136,6 +1148,13 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
if (e->v.Yield.value) if (e->v.Yield.value)
VISIT(st, expr, e->v.Yield.value); VISIT(st, expr, e->v.Yield.value);
st->st_cur->ste_generator = 1; 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; break;
case Compare_kind: case Compare_kind:
VISIT(st, expr, e->v.Compare.left); VISIT(st, expr, e->v.Compare.left);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment