]> granicus.if.org Git - python/commitdiff
Issue #27999: Make "global after use" a SyntaxError, and ditto for nonlocal.
authorGuido van Rossum <guido@dropbox.com>
Fri, 9 Sep 2016 16:36:26 +0000 (09:36 -0700)
committerGuido van Rossum <guido@dropbox.com>
Fri, 9 Sep 2016 16:36:26 +0000 (09:36 -0700)
Patch by Ivan Levkivskyi.

Doc/reference/simple_stmts.rst
Lib/test/test_syntax.py
Misc/NEWS
Python/symtable.c

index 197327259d3722585c2c66a72920c143c98cd1e0..6aafa7258f1690f731550fa02bd29e9eded617e9 100644 (file)
@@ -903,11 +903,12 @@ block textually preceding that :keyword:`global` statement.
 
 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.
 
index f47bdf96723ee8db18674e1fc7a3c6c9453e1b5f..80e36fd46e56cac9dcf85670be9f6353e3caf93b 100644 (file)
@@ -366,7 +366,23 @@ build.  The number of blocks must be greater than CO_MAXBLOCKS.  SF #1565514
      ...
    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
index 478259ae4a0da9b840c63189f0fd744a36a3b1b0..cd2f022f8deb9b67ceca24d17c6b3ca32d05947e 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 3.6.0 beta 1
 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.
index e55813feb5318483cdb6f350e0f99d8505e88f77..9325dc170f6bda79b333c59e33f887fa37f28702 100644 (file)
@@ -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 @@ PyTypeObject PySTEntry_Type = {
 };
 
 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 @@ symtable_analyze(struct symtable *st)
     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 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
             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 @@ 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_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 @@ 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_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))