diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -584,8 +584,72 @@ def test_kwargs_last(self): self._check_error("int(base=10, '2')", "non-keyword arg") + +class TryExceptTargetDel(unittest.TestCase): + + def _check_syntax_warning(self, code, filename="", mode="exec"): + # for prefix in ['if 1:', 'def f():']: <- only works inside functions + for prefix in ['def f():']: + with self.subTest(prefix=prefix): + with self.assertWarns(SyntaxWarning): + compile(prefix+code, filename, mode) + + def _check_ok(self, code, filename="", mode="exec"): + for prefix in ['if 1:', 'def f():']: + with support.check_warnings() as w: + compile(code, filename, mode) + self.assertEqual(len(w.warnings), 0, + 'no warning should have been triggered here') + + def test_good1(self): + source = """if 1: + def good(): + exc = None + try: + bar(int(sys.argv[1])) + except KeyError as e: + print('ke') + exc = e + except ValueError as e: + print('ve') + exc = e + print(exc) + """ + self._check_ok(source) + + def test_good2(self): + source = """if 1: + def good(): + try: + pass + except KeyError as e: + pass + e = 15 + """ + self._check_ok(source) + + def test_bad1(self): + source = """ + e = None + try: + pass + except KeyError as e: + pass + """ + self._check_syntax_warning(source) + + def test_bad2(self): + source = """ + try: + e = None + except KeyError as e: + pass + """ + self._check_syntax_warning(source) + + def test_main(): - support.run_unittest(SyntaxTestCase) + support.run_unittest(SyntaxTestCase, TryExceptTargetDel) from test import test_syntax support.run_doctest(test_syntax, verbosity=True) diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -2093,11 +2093,14 @@ Of course, parts are not generated if Vi or Ei is not present. */ +static PyObject * +dict_keys_inorder(PyObject *, int ); static int compiler_try_except(struct compiler *c, stmt_ty s) { basicblock *body, *orelse, *except, *end; int i, n; + PyObject *locals; body = compiler_new_block(c); except = compiler_new_block(c); @@ -2115,17 +2118,20 @@ ADDOP_JREL(c, JUMP_FORWARD, orelse); n = asdl_seq_LEN(s->v.Try.handlers); compiler_use_next_block(c, except); + locals = dict_keys_inorder(c->u->u_varnames, 0); for (i = 0; i < n; i++) { excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET( s->v.Try.handlers, i); - if (!handler->v.ExceptHandler.type && i < n-1) + if (!handler->v.ExceptHandler.type && i < n-1) { + Py_DECREF(locals); return compiler_error(c, "default 'except:' must be last"); + } c->u->u_lineno_set = 0; c->u->u_lineno = handler->lineno; c->u->u_col_offset = handler->col_offset; except = compiler_new_block(c); if (except == NULL) - return 0; + goto except_error; if (handler->v.ExceptHandler.type) { ADDOP(c, DUP_TOP); VISIT(c, expr, handler->v.ExceptHandler.type); @@ -2134,12 +2140,21 @@ } ADDOP(c, POP_TOP); if (handler->v.ExceptHandler.name) { + if (PySequence_Contains(locals, handler->v.ExceptHandler.name) == 1) { + PyObject *msg; + msg = PyUnicode_FromFormat( + "name %R is already defined but implicitly deleted after " + "end of except clause", handler->v.ExceptHandler.name); + PyErr_WarnExplicit(PyExc_SyntaxWarning, PyObject_REPR(msg), + c->c_filename, c->u->u_lineno, NULL, NULL); + Py_DECREF(msg); + } basicblock *cleanup_end, *cleanup_body; cleanup_end = compiler_new_block(c); cleanup_body = compiler_new_block(c); if (!(cleanup_end || cleanup_body)) - return 0; + goto except_error; compiler_nameop(c, handler->v.ExceptHandler.name, Store); ADDOP(c, POP_TOP); @@ -2159,7 +2174,7 @@ ADDOP_JREL(c, SETUP_FINALLY, cleanup_end); compiler_use_next_block(c, cleanup_body); if (!compiler_push_fblock(c, FINALLY_TRY, cleanup_body)) - return 0; + goto except_error; /* second # body */ VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body); @@ -2171,7 +2186,7 @@ ADDOP_O(c, LOAD_CONST, Py_None, consts); compiler_use_next_block(c, cleanup_end); if (!compiler_push_fblock(c, FINALLY_END, cleanup_end)) - return 0; + goto except_error; /* name = None */ ADDOP_O(c, LOAD_CONST, Py_None, consts); @@ -2188,13 +2203,13 @@ cleanup_body = compiler_new_block(c); if (!cleanup_body) - return 0; + goto except_error; ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); compiler_use_next_block(c, cleanup_body); if (!compiler_push_fblock(c, FINALLY_TRY, cleanup_body)) - return 0; + goto except_error; VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body); ADDOP(c, POP_EXCEPT); compiler_pop_fblock(c, FINALLY_TRY, cleanup_body); @@ -2202,11 +2217,16 @@ ADDOP_JREL(c, JUMP_FORWARD, end); compiler_use_next_block(c, except); } + Py_DECREF(locals); ADDOP(c, END_FINALLY); compiler_use_next_block(c, orelse); VISIT_SEQ(c, stmt, s->v.Try.orelse); compiler_use_next_block(c, end); return 1; + +except_error: + Py_DECREF(locals); + return 0; } static int