summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_syntax.py36
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2017-10-23-23-39-26.bpo-28936.C288Jh.rst2
-rw-r--r--Python/symtable.c34
3 files changed, 45 insertions, 27 deletions
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index 7ce3d75..5d36581 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -400,12 +400,25 @@ build. The number of blocks must be greater than CO_MAXBLOCKS. SF #1565514
Misuse of the nonlocal and global statement can lead to a few unique syntax errors.
>>> def f():
+ ... print(x)
+ ... global x
+ Traceback (most recent call last):
+ ...
+ SyntaxError: name 'x' is used prior to global declaration
+
+ >>> def f():
... x = 1
... global x
Traceback (most recent call last):
...
SyntaxError: name 'x' is assigned to before global declaration
+ >>> def f(x):
+ ... global x
+ Traceback (most recent call last):
+ ...
+ SyntaxError: name 'x' is parameter and global
+
>>> def f():
... x = 1
... def g():
@@ -560,7 +573,6 @@ Corner-cases that used to crash:
import re
import unittest
-import warnings
from test import support
@@ -596,19 +608,25 @@ class SyntaxTestCase(unittest.TestCase):
def test_assign_del(self):
self._check_error("del f()", "delete")
- def test_global_err_then_warn(self):
- # Bug #763201: The SyntaxError raised for one global statement
- # shouldn't be clobbered by a SyntaxWarning issued for a later one.
+ def test_global_param_err_first(self):
source = """if 1:
def error(a):
global a # SyntaxError
- def warning():
+ def error2():
+ b = 1
+ global b # SyntaxError
+ """
+ self._check_error(source, "parameter and global", lineno=3)
+
+ def test_nonlocal_param_err_first(self):
+ source = """if 1:
+ def error(a):
+ nonlocal a # SyntaxError
+ def error2():
b = 1
- global b # SyntaxWarning
+ global b # SyntaxError
"""
- warnings.filterwarnings(action='ignore', category=SyntaxWarning)
- self._check_error(source, "global")
- warnings.filters.pop(0)
+ self._check_error(source, "parameter and nonlocal", lineno=3)
def test_break_outside_loop(self):
self._check_error("break", "outside loop")
diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-10-23-23-39-26.bpo-28936.C288Jh.rst b/Misc/NEWS.d/next/Core and Builtins/2017-10-23-23-39-26.bpo-28936.C288Jh.rst
new file mode 100644
index 0000000..8ebdf32
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2017-10-23-23-39-26.bpo-28936.C288Jh.rst
@@ -0,0 +1,2 @@
+Ensure that lexically first syntax error involving a parameter and ``global``
+or ``nonlocal`` is detected first at a given scope. Patch by Ivan Levkivskyi.
diff --git a/Python/symtable.c b/Python/symtable.c
index 2658b91..55815c9 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -9,6 +9,12 @@
#include "structmember.h"
/* error strings used for warnings */
+#define GLOBAL_PARAM \
+"name '%U' is parameter and global"
+
+#define NONLOCAL_PARAM \
+"name '%U' is parameter and nonlocal"
+
#define GLOBAL_AFTER_ASSIGN \
"name '%U' is assigned to before global declaration"
@@ -465,12 +471,6 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
PyObject *global)
{
if (flags & DEF_GLOBAL) {
- if (flags & DEF_PARAM) {
- PyErr_Format(PyExc_SyntaxError,
- "name '%U' is parameter and global",
- name);
- return error_at_directive(ste, name);
- }
if (flags & DEF_NONLOCAL) {
PyErr_Format(PyExc_SyntaxError,
"name '%U' is nonlocal and global",
@@ -485,12 +485,6 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
return 1;
}
if (flags & DEF_NONLOCAL) {
- if (flags & DEF_PARAM) {
- PyErr_Format(PyExc_SyntaxError,
- "name '%U' is parameter and nonlocal",
- name);
- return error_at_directive(ste, name);
- }
if (!bound) {
PyErr_Format(PyExc_SyntaxError,
"nonlocal declaration not allowed at module level");
@@ -1284,9 +1278,11 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
long cur = symtable_lookup(st, name);
if (cur < 0)
VISIT_QUIT(st, 0);
- if (cur & (DEF_LOCAL | USE | DEF_ANNOT)) {
- char* msg;
- if (cur & USE) {
+ if (cur & (DEF_PARAM | DEF_LOCAL | USE | DEF_ANNOT)) {
+ const char* msg;
+ if (cur & DEF_PARAM) {
+ msg = GLOBAL_PARAM;
+ } else if (cur & USE) {
msg = GLOBAL_AFTER_USE;
} else if (cur & DEF_ANNOT) {
msg = GLOBAL_ANNOT;
@@ -1315,9 +1311,11 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
long cur = symtable_lookup(st, name);
if (cur < 0)
VISIT_QUIT(st, 0);
- if (cur & (DEF_LOCAL | USE | DEF_ANNOT)) {
- char* msg;
- if (cur & USE) {
+ if (cur & (DEF_PARAM | DEF_LOCAL | USE | DEF_ANNOT)) {
+ const char* msg;
+ if (cur & DEF_PARAM) {
+ msg = NONLOCAL_PARAM;
+ } else if (cur & USE) {
msg = NONLOCAL_AFTER_USE;
} else if (cur & DEF_ANNOT) {
msg = NONLOCAL_ANNOT;