mirror of https://github.com/python/cpython.git
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_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 @@
|
||||||
... 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 @@
|
||||||
... 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?
|
||||||
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
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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 @@
|
||||||
|
|
||||||
#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,
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue