mirror of https://github.com/python/cpython
Patch #1346214: correctly optimize away "if 0"-style stmts
(thanks to Neal for review)
This commit is contained in:
parent
9f16760666
commit
ddbaa660d3
|
@ -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 */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue