[Python-checkins] cpython: Issue #27999: Make "global after use" a SyntaxError, and ditto for nonlocal.

guido.van.rossum python-checkins at python.org
Fri Sep 9 12:53:18 EDT 2016


https://hg.python.org/cpython/rev/804b71d43c85
changeset:   103415:804b71d43c85
user:        Guido van Rossum <guido at dropbox.com>
date:        Fri Sep 09 09:36:26 2016 -0700
summary:
  Issue #27999: Make "global after use" a SyntaxError, and ditto for nonlocal.
Patch by Ivan Levkivskyi.

files:
  Doc/reference/simple_stmts.rst |    5 +-
  Lib/test/test_syntax.py        |   18 +++-
  Misc/NEWS                      |    3 +
  Python/symtable.c              |  104 +++++++-------------
  4 files changed, 59 insertions(+), 71 deletions(-)


diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst
--- a/Doc/reference/simple_stmts.rst
+++ b/Doc/reference/simple_stmts.rst
@@ -903,11 +903,12 @@
 
 Names listed in a :keyword:`global` statement must not be defined as formal
 parameters or in a :keyword:`for` loop control target, :keyword:`class`
-definition, function definition, or :keyword:`import` statement.
+definition, function definition, :keyword:`import` statement, or variable
+annotation.
 
 .. impl-detail::
 
-   The current implementation does not enforce the two restrictions, but
+   The current implementation does not enforce some of these restriction, but
    programs should not abuse this freedom, as future implementations may enforce
    them or silently change the meaning of the program.
 
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
@@ -366,7 +366,23 @@
      ...
    SyntaxError: too many statically nested blocks
 
-Misuse of the nonlocal statement can lead to a few unique syntax errors.
+Misuse of the nonlocal and global statement can lead to a few unique syntax errors.
+
+   >>> def f():
+   ...     x = 1
+   ...     global x
+   Traceback (most recent call last):
+     ...
+   SyntaxError: name 'x' is assigned to before global declaration
+
+   >>> def f():
+   ...     x = 1
+   ...     def g():
+   ...         print(x)
+   ...         nonlocal x
+   Traceback (most recent call last):
+     ...
+   SyntaxError: name 'x' is used prior to nonlocal declaration
 
    >>> def f(x):
    ...     nonlocal x
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
 Core and Builtins
 -----------------
 
+- Issue #27999: Make "global after use" a SyntaxError, and ditto for nonlocal.
+  Patch by Ivan Levkivskyi.
+
 - Issue #28003: Implement PEP 525 -- Asynchronous Generators.
 
 - Issue #27985: Implement PEP 526 -- Syntax for Variable Annotations.
diff --git a/Python/symtable.c b/Python/symtable.c
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -6,16 +6,22 @@
 
 /* error strings used for warnings */
 #define GLOBAL_AFTER_ASSIGN \
-"name '%.400s' is assigned to before global declaration"
+"name '%U' is assigned to before global declaration"
 
 #define NONLOCAL_AFTER_ASSIGN \
-"name '%.400s' is assigned to before nonlocal declaration"
+"name '%U' is assigned to before nonlocal declaration"
 
 #define GLOBAL_AFTER_USE \
-"name '%.400s' is used prior to global declaration"
+"name '%U' is used prior to global declaration"
 
 #define NONLOCAL_AFTER_USE \
-"name '%.400s' is used prior to nonlocal declaration"
+"name '%U' is used prior to nonlocal declaration"
+
+#define GLOBAL_ANNOT \
+"annotated name '%U' can't be global"
+
+#define NONLOCAL_ANNOT \
+"annotated name '%U' can't be nonlocal"
 
 #define IMPORT_STAR_WARNING "import * only allowed at module level"
 
@@ -161,7 +167,6 @@
 };
 
 static int symtable_analyze(struct symtable *st);
-static int symtable_warn(struct symtable *st, const char *msg, int lineno);
 static int symtable_enter_block(struct symtable *st, identifier name,
                                 _Py_block_ty block, void *ast, int lineno,
                                 int col_offset);
@@ -907,27 +912,6 @@
     return r;
 }
 
-
-static int
-symtable_warn(struct symtable *st, const char *msg, int lineno)
-{
-    PyObject *message = PyUnicode_FromString(msg);
-    if (message == NULL)
-        return 0;
-    if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, message, st->st_filename,
-                                 lineno, NULL, NULL) < 0)     {
-        Py_DECREF(message);
-        if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
-            PyErr_SetString(PyExc_SyntaxError, msg);
-            PyErr_SyntaxLocationObject(st->st_filename, st->st_cur->ste_lineno,
-                                       st->st_cur->ste_col_offset);
-        }
-        return 0;
-    }
-    Py_DECREF(message);
-    return 1;
-}
-
 /* symtable_enter_block() gets a reference via ste_new.
    This reference is released when the block is exited, via the DECREF
    in symtable_exit_block().
@@ -1212,9 +1196,8 @@
             if ((cur & (DEF_GLOBAL | DEF_NONLOCAL))
                 && s->v.AnnAssign.simple) {
                 PyErr_Format(PyExc_SyntaxError,
-                             "annotated name '%U' can't be %s",
-                             e_name->v.Name.id,
-                             cur & DEF_GLOBAL ? "global" : "nonlocal");
+                             cur & DEF_GLOBAL ? GLOBAL_ANNOT : NONLOCAL_ANNOT,
+                             e_name->v.Name.id);
                 PyErr_SyntaxLocationObject(st->st_filename,
                                            s->lineno,
                                            s->col_offset);
@@ -1297,31 +1280,24 @@
             long cur = symtable_lookup(st, name);
             if (cur < 0)
                 VISIT_QUIT(st, 0);
-            if (cur & DEF_ANNOT) {
+            if (cur & (DEF_LOCAL | USE | DEF_ANNOT)) {
+                char* msg;
+                if (cur & DEF_ANNOT) {
+                    msg = GLOBAL_ANNOT;
+                }
+                if (cur & DEF_LOCAL) {
+                    msg = GLOBAL_AFTER_ASSIGN;
+                }
+                else {
+                    msg = GLOBAL_AFTER_USE;
+                }
                 PyErr_Format(PyExc_SyntaxError,
-                             "annotated name '%U' can't be global",
-                             name);
+                             msg, name);
                 PyErr_SyntaxLocationObject(st->st_filename,
                                            s->lineno,
                                            s->col_offset);
                 VISIT_QUIT(st, 0);
             }
-            if (cur & (DEF_LOCAL | USE)) {
-                char buf[256];
-                char *c_name = _PyUnicode_AsString(name);
-                if (!c_name)
-                    return 0;
-                if (cur & DEF_LOCAL)
-                    PyOS_snprintf(buf, sizeof(buf),
-                                  GLOBAL_AFTER_ASSIGN,
-                                  c_name);
-                else
-                    PyOS_snprintf(buf, sizeof(buf),
-                                  GLOBAL_AFTER_USE,
-                                  c_name);
-                if (!symtable_warn(st, buf, s->lineno))
-                    VISIT_QUIT(st, 0);
-            }
             if (!symtable_add_def(st, name, DEF_GLOBAL))
                 VISIT_QUIT(st, 0);
             if (!symtable_record_directive(st, name, s))
@@ -1337,31 +1313,23 @@
             long cur = symtable_lookup(st, name);
             if (cur < 0)
                 VISIT_QUIT(st, 0);
-            if (cur & DEF_ANNOT) {
-                PyErr_Format(PyExc_SyntaxError,
-                             "annotated name '%U' can't be nonlocal",
-                             name);
+            if (cur & (DEF_LOCAL | USE | DEF_ANNOT)) {
+                char* msg;
+                if (cur & DEF_ANNOT) {
+                    msg = NONLOCAL_ANNOT;
+                }
+                if (cur & DEF_LOCAL) {
+                    msg = NONLOCAL_AFTER_ASSIGN;
+                }
+                else {
+                    msg = NONLOCAL_AFTER_USE;
+                }
+                PyErr_Format(PyExc_SyntaxError, msg, name);
                 PyErr_SyntaxLocationObject(st->st_filename,
                                            s->lineno,
                                            s->col_offset);
                 VISIT_QUIT(st, 0);
             }
-            if (cur & (DEF_LOCAL | USE)) {
-                char buf[256];
-                char *c_name = _PyUnicode_AsString(name);
-                if (!c_name)
-                    return 0;
-                if (cur & DEF_LOCAL)
-                    PyOS_snprintf(buf, sizeof(buf),
-                                  NONLOCAL_AFTER_ASSIGN,
-                                  c_name);
-                else
-                    PyOS_snprintf(buf, sizeof(buf),
-                                  NONLOCAL_AFTER_USE,
-                                  c_name);
-                if (!symtable_warn(st, buf, s->lineno))
-                    VISIT_QUIT(st, 0);
-            }
             if (!symtable_add_def(st, name, DEF_NONLOCAL))
                 VISIT_QUIT(st, 0);
             if (!symtable_record_directive(st, name, s))

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list