summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Coghlan <ncoghlan@gmail.com>2007-04-23 10:14:27 (GMT)
committerNick Coghlan <ncoghlan@gmail.com>2007-04-23 10:14:27 (GMT)
commit4138bfec0a189d180b7bcb89e7c8ce8a456a6b55 (patch)
treebb2b24ec1eece601a1ede4e1c09bd9e8b233c18a
parent846f1ee39004e7e00f8982928ccc166e01436a77 (diff)
downloadcpython-4138bfec0a189d180b7bcb89e7c8ce8a456a6b55.zip
cpython-4138bfec0a189d180b7bcb89e7c8ce8a456a6b55.tar.gz
cpython-4138bfec0a189d180b7bcb89e7c8ce8a456a6b55.tar.bz2
Don't crash when nonlocal is used at module level (fixes SF#1705365)
-rw-r--r--Lib/test/test_syntax.py6
-rw-r--r--Python/symtable.c15
2 files changed, 16 insertions, 5 deletions
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index b21f6cf..b5a5c5d 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -388,6 +388,12 @@ Misuse of the nonlocal statement can lead to a few unique syntax errors.
...
SyntaxError: no binding for nonlocal 'x' found
+From SF bug #1705365
+ >>> nonlocal x
+ Traceback (most recent call last):
+ ...
+ SyntaxError: nonlocal declaration not allowed at module level
+
TODO(jhylton): Figure out how to test SyntaxWarning with doctest.
## >>> def f(x):
diff --git a/Python/symtable.c b/Python/symtable.c
index 68deb0a..ca7d502 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -337,8 +337,6 @@ PyST_GetScope(PySTEntryObject *ste, PyObject *name)
block, the name is treated as global until it is assigned to; then it
is treated as a local.
- TODO(jhylton): Discuss nonlocal
-
The symbol table requires two passes to determine the scope of each name.
The first pass collects raw facts from the AST via the symtable_visit_*
functions: the name is a parameter here, the name is used but not defined
@@ -348,15 +346,17 @@ PyST_GetScope(PySTEntryObject *ste, PyObject *name)
When a function is entered during the second pass, the parent passes
the set of all name bindings visible to its children. These bindings
are used to determine if non-local variables are free or implicit globals.
- After doing the local analysis, it analyzes each of its child blocks
- using an updated set of name bindings.
+ Names which are explicitly declared nonlocal must exist in this set of
+ visible names - if they do not, a syntax error is raised. After doing
+ the local analysis, it analyzes each of its child blocks using an
+ updated set of name bindings.
The children update the free variable set. If a local variable is added to
the free variable set by the child, the variable is marked as a cell. The
function object being defined must provide runtime storage for the variable
that may outlive the function's frame. Cell variables are removed from the
free set before the analyze function returns to its parent.
-
+
During analysis, the names are:
symbols: dict mapping from symbol names to flag values (including offset scope values)
scopes: dict mapping from symbol names to scope values (no offset)
@@ -415,6 +415,11 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
PyString_AS_STRING(name));
return 0;
}
+ if (!bound) {
+ PyErr_Format(PyExc_SyntaxError,
+ "nonlocal declaration not allowed at module level");
+ return 0;
+ }
if (!PySet_Contains(bound, name)) {
PyErr_Format(PyExc_SyntaxError,
"no binding for nonlocal '%s' found",