Skip to content

Commit 85ed171

Browse files
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. (cherry picked from commit af8646c) Co-authored-by: Pablo Galindo <[email protected]>
1 parent 9470404 commit 85ed171

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
@@ -650,6 +650,20 @@ def error2():
650650
def test_break_outside_loop(self):
651651
self._check_error("break", "outside loop")
652652

653+
def test_yield_outside_function(self):
654+
self._check_error("if 0: yield", "outside function")
655+
self._check_error("class C:\n if 0: yield", "outside function")
656+
657+
def test_return_outside_function(self):
658+
self._check_error("if 0: return", "outside function")
659+
self._check_error("class C:\n if 0: return", "outside function")
660+
661+
def test_break_outside_loop(self):
662+
self._check_error("if 0: break", "outside loop")
663+
664+
def test_continue_outside_loop(self):
665+
self._check_error("if 0: continue", "not properly in loop")
666+
653667
def test_unexpected_indent(self):
654668
self._check_error("foo()\n bar()\n", "unexpected indent",
655669
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
@@ -2301,13 +2301,12 @@ compiler_if(struct compiler *c, stmt_ty s)
23012301
return 0;
23022302

23032303
constant = expr_constant(s->v.If.test);
2304-
/* constant = 0: "if 0"
2304+
/* constant = 0: "if 0" Leave the optimizations to
2305+
* the pephole optimizer to check for syntax errors
2306+
* in the block.
23052307
* constant = 1: "if 1", "if 2", ...
23062308
* constant = -1: rest */
2307-
if (constant == 0) {
2308-
if (s->v.If.orelse)
2309-
VISIT_SEQ(c, stmt, s->v.If.orelse);
2310-
} else if (constant == 1) {
2309+
if (constant == 1) {
23112310
VISIT_SEQ(c, stmt, s->v.If.body);
23122311
} else {
23132312
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
@@ -304,11 +304,19 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
304304
case LOAD_CONST:
305305
cumlc = lastlc + 1;
306306
if (nextop != POP_JUMP_IF_FALSE ||
307-
!ISBASICBLOCK(blocks, op_start, i + 1) ||
308-
!PyObject_IsTrue(PyList_GET_ITEM(consts, get_arg(codestr, i))))
307+
!ISBASICBLOCK(blocks, op_start, i + 1)) {
309308
break;
310-
fill_nops(codestr, op_start, nexti + 1);
311-
cumlc = 0;
309+
}
310+
PyObject* cnt = PyList_GET_ITEM(consts, get_arg(codestr, i));
311+
int is_true = PyObject_IsTrue(cnt);
312+
if (is_true == 1) {
313+
fill_nops(codestr, op_start, nexti + 1);
314+
cumlc = 0;
315+
} else if (is_true == 0) {
316+
h = get_arg(codestr, nexti) / sizeof(_Py_CODEUNIT);
317+
tgt = find_op(codestr, codelen, h);
318+
fill_nops(codestr, op_start, tgt);
319+
}
312320
break;
313321

314322
/* Try to fold tuples of constants.

0 commit comments

Comments
 (0)