mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
bpo-28936: Detect lexically first syntax error first (#4097)
Lexically first global and nonlocal syntax errors at given scope should be detected first.
This commit is contained in:
parent
66c88ce30c
commit
8c83c23fa3
3 changed files with 45 additions and 27 deletions
|
@ -399,6 +399,13 @@ 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.
|
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():
|
>>> def f():
|
||||||
... x = 1
|
... x = 1
|
||||||
... global x
|
... global x
|
||||||
|
@ -406,6 +413,12 @@ Misuse of the nonlocal and global statement can lead to a few unique syntax erro
|
||||||
...
|
...
|
||||||
SyntaxError: name 'x' is assigned to before global declaration
|
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():
|
>>> def f():
|
||||||
... x = 1
|
... x = 1
|
||||||
... def g():
|
... def g():
|
||||||
|
@ -560,7 +573,6 @@ Corner-cases that used to crash:
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import unittest
|
import unittest
|
||||||
import warnings
|
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
|
|
||||||
|
@ -596,19 +608,25 @@ class SyntaxTestCase(unittest.TestCase):
|
||||||
def test_assign_del(self):
|
def test_assign_del(self):
|
||||||
self._check_error("del f()", "delete")
|
self._check_error("del f()", "delete")
|
||||||
|
|
||||||
def test_global_err_then_warn(self):
|
def test_global_param_err_first(self):
|
||||||
# Bug #763201: The SyntaxError raised for one global statement
|
|
||||||
# shouldn't be clobbered by a SyntaxWarning issued for a later one.
|
|
||||||
source = """if 1:
|
source = """if 1:
|
||||||
def error(a):
|
def error(a):
|
||||||
global a # SyntaxError
|
global a # SyntaxError
|
||||||
def warning():
|
def error2():
|
||||||
b = 1
|
b = 1
|
||||||
global b # SyntaxWarning
|
global b # SyntaxError
|
||||||
"""
|
"""
|
||||||
warnings.filterwarnings(action='ignore', category=SyntaxWarning)
|
self._check_error(source, "parameter and global", lineno=3)
|
||||||
self._check_error(source, "global")
|
|
||||||
warnings.filters.pop(0)
|
def test_nonlocal_param_err_first(self):
|
||||||
|
source = """if 1:
|
||||||
|
def error(a):
|
||||||
|
nonlocal a # SyntaxError
|
||||||
|
def error2():
|
||||||
|
b = 1
|
||||||
|
global b # SyntaxError
|
||||||
|
"""
|
||||||
|
self._check_error(source, "parameter and nonlocal", lineno=3)
|
||||||
|
|
||||||
def test_break_outside_loop(self):
|
def test_break_outside_loop(self):
|
||||||
self._check_error("break", "outside loop")
|
self._check_error("break", "outside loop")
|
||||||
|
|
|
@ -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.
|
|
@ -9,6 +9,12 @@
|
||||||
#include "structmember.h"
|
#include "structmember.h"
|
||||||
|
|
||||||
/* error strings used for warnings */
|
/* 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 \
|
#define GLOBAL_AFTER_ASSIGN \
|
||||||
"name '%U' is assigned to before global declaration"
|
"name '%U' is assigned to before global declaration"
|
||||||
|
|
||||||
|
@ -465,12 +471,6 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
|
||||||
PyObject *global)
|
PyObject *global)
|
||||||
{
|
{
|
||||||
if (flags & DEF_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) {
|
if (flags & DEF_NONLOCAL) {
|
||||||
PyErr_Format(PyExc_SyntaxError,
|
PyErr_Format(PyExc_SyntaxError,
|
||||||
"name '%U' is nonlocal and global",
|
"name '%U' is nonlocal and global",
|
||||||
|
@ -485,12 +485,6 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (flags & DEF_NONLOCAL) {
|
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) {
|
if (!bound) {
|
||||||
PyErr_Format(PyExc_SyntaxError,
|
PyErr_Format(PyExc_SyntaxError,
|
||||||
"nonlocal declaration not allowed at module level");
|
"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);
|
long cur = symtable_lookup(st, name);
|
||||||
if (cur < 0)
|
if (cur < 0)
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
if (cur & (DEF_LOCAL | USE | DEF_ANNOT)) {
|
if (cur & (DEF_PARAM | DEF_LOCAL | USE | DEF_ANNOT)) {
|
||||||
char* msg;
|
const char* msg;
|
||||||
if (cur & USE) {
|
if (cur & DEF_PARAM) {
|
||||||
|
msg = GLOBAL_PARAM;
|
||||||
|
} else if (cur & USE) {
|
||||||
msg = GLOBAL_AFTER_USE;
|
msg = GLOBAL_AFTER_USE;
|
||||||
} else if (cur & DEF_ANNOT) {
|
} else if (cur & DEF_ANNOT) {
|
||||||
msg = GLOBAL_ANNOT;
|
msg = GLOBAL_ANNOT;
|
||||||
|
@ -1315,9 +1311,11 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
|
||||||
long cur = symtable_lookup(st, name);
|
long cur = symtable_lookup(st, name);
|
||||||
if (cur < 0)
|
if (cur < 0)
|
||||||
VISIT_QUIT(st, 0);
|
VISIT_QUIT(st, 0);
|
||||||
if (cur & (DEF_LOCAL | USE | DEF_ANNOT)) {
|
if (cur & (DEF_PARAM | DEF_LOCAL | USE | DEF_ANNOT)) {
|
||||||
char* msg;
|
const char* msg;
|
||||||
if (cur & USE) {
|
if (cur & DEF_PARAM) {
|
||||||
|
msg = NONLOCAL_PARAM;
|
||||||
|
} else if (cur & USE) {
|
||||||
msg = NONLOCAL_AFTER_USE;
|
msg = NONLOCAL_AFTER_USE;
|
||||||
} else if (cur & DEF_ANNOT) {
|
} else if (cur & DEF_ANNOT) {
|
||||||
msg = NONLOCAL_ANNOT;
|
msg = NONLOCAL_ANNOT;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue