Skip to content

Commit af8646c

Browse files
authored
bpo-1875: Raise SyntaxError in invalid blocks that will be optimised away (GH-13332)
Move the check for dead conditionals (if 0) to the peephole optimizer and make sure that the code block is still compiled to report any existing syntax errors within.
1 parent a8b4694 commit af8646c

File tree

4 files changed

+33
-9
lines changed

4 files changed

+33
-9
lines changed

Lib/test/test_syntax.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,20 @@ def error2():
696696
def test_break_outside_loop(self):
697697
self._check_error("break", "outside loop")
698698

699+
def test_yield_outside_function(self):
700+
self._check_error("if 0: yield", "outside function")
701+
self._check_error("class C:\n if 0: yield", "outside function")
702+
703+
def test_return_outside_function(self):
704+
self._check_error("if 0: return", "outside function")
705+
self._check_error("class C:\n if 0: return", "outside function")
706+
707+
def test_break_outside_loop(self):
708+
self._check_error("if 0: break", "outside loop")
709+
710+
def test_continue_outside_loop(self):
711+
self._check_error("if 0: continue", "not properly in loop")
712+
699713
def test_unexpected_indent(self):
700714
self._check_error("foo()\n bar()\n", "unexpected indent",
701715
subclass=IndentationError)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
A :exc:`SyntaxError` is now raised if a code blocks that will be optimized
2+
away (e.g. if conditions that are always false) contains syntax errors.
3+
Patch by Pablo Galindo.

Python/compile.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2546,13 +2546,12 @@ compiler_if(struct compiler *c, stmt_ty s)
25462546
return 0;
25472547

25482548
constant = expr_constant(s->v.If.test);
2549-
/* constant = 0: "if 0"
2549+
/* constant = 0: "if 0" Leave the optimizations to
2550+
* the pephole optimizer to check for syntax errors
2551+
* in the block.
25502552
* constant = 1: "if 1", "if 2", ...
25512553
* constant = -1: rest */
2552-
if (constant == 0) {
2553-
if (s->v.If.orelse)
2554-
VISIT_SEQ(c, stmt, s->v.If.orelse);
2555-
} else if (constant == 1) {
2554+
if (constant == 1) {
25562555
VISIT_SEQ(c, stmt, s->v.If.body);
25572556
} else {
25582557
if (asdl_seq_LEN(s->v.If.orelse)) {

Python/peephole.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -302,11 +302,19 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
302302
case LOAD_CONST:
303303
cumlc = lastlc + 1;
304304
if (nextop != POP_JUMP_IF_FALSE ||
305-
!ISBASICBLOCK(blocks, op_start, i + 1) ||
306-
!PyObject_IsTrue(PyList_GET_ITEM(consts, get_arg(codestr, i))))
305+
!ISBASICBLOCK(blocks, op_start, i + 1)) {
307306
break;
308-
fill_nops(codestr, op_start, nexti + 1);
309-
cumlc = 0;
307+
}
308+
PyObject* cnt = PyList_GET_ITEM(consts, get_arg(codestr, i));
309+
int is_true = PyObject_IsTrue(cnt);
310+
if (is_true == 1) {
311+
fill_nops(codestr, op_start, nexti + 1);
312+
cumlc = 0;
313+
} else if (is_true == 0) {
314+
h = get_arg(codestr, nexti) / sizeof(_Py_CODEUNIT);
315+
tgt = find_op(codestr, codelen, h);
316+
fill_nops(codestr, op_start, tgt);
317+
}
310318
break;
311319

312320
/* Try to fold tuples of constants.

0 commit comments

Comments
 (0)