Skip to content

Commit bc94cf7

Browse files
authored
gh-122245: move checks for writes and shadowing of __debug__ to symtable (#122246)
1 parent 2c42e13 commit bc94cf7

File tree

5 files changed

+173
-83
lines changed

5 files changed

+173
-83
lines changed

Doc/whatsnew/3.14.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ Other Language Changes
8080
command line option. For example, ``python -O -c 'assert await 1'``
8181
now produces a :exc:`SyntaxError`. (Contributed by Jelle Zijlstra in :gh:`121637`.)
8282

83+
* Writes to ``__debug__`` are now detected even if the code is optimized
84+
away by the :option:`-O` command line option. For example,
85+
``python -O -c 'assert (__debug__ := 1)'`` now produces a
86+
:exc:`SyntaxError`. (Contributed by Irit Katriel in :gh:`122245`.)
87+
8388
* Added class methods :meth:`float.from_number` and :meth:`complex.from_number`
8489
to convert a number to :class:`float` or :class:`complex` type correspondingly.
8590
They raise an error if the argument is a string.

Lib/test/test_syntax.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@
5959
Traceback (most recent call last):
6060
SyntaxError: cannot assign to __debug__
6161
62+
>>> def __debug__(): pass
63+
Traceback (most recent call last):
64+
SyntaxError: cannot assign to __debug__
65+
66+
>>> async def __debug__(): pass
67+
Traceback (most recent call last):
68+
SyntaxError: cannot assign to __debug__
69+
70+
>>> class __debug__: pass
71+
Traceback (most recent call last):
72+
SyntaxError: cannot assign to __debug__
73+
6274
>>> del __debug__
6375
Traceback (most recent call last):
6476
SyntaxError: cannot delete __debug__
@@ -786,6 +798,9 @@
786798
>>> __debug__: int
787799
Traceback (most recent call last):
788800
SyntaxError: cannot assign to __debug__
801+
>>> x.__debug__: int
802+
Traceback (most recent call last):
803+
SyntaxError: cannot assign to __debug__
789804
>>> f(a=)
790805
Traceback (most recent call last):
791806
SyntaxError: expected argument value expression
@@ -1182,6 +1197,24 @@
11821197
Traceback (most recent call last):
11831198
SyntaxError: expected ':'
11841199
1200+
>>> match x:
1201+
... case a, __debug__, b:
1202+
... pass
1203+
Traceback (most recent call last):
1204+
SyntaxError: cannot assign to __debug__
1205+
1206+
>>> match x:
1207+
... case a, b, *__debug__:
1208+
... pass
1209+
Traceback (most recent call last):
1210+
SyntaxError: cannot assign to __debug__
1211+
1212+
>>> match x:
1213+
... case Foo(a, __debug__=1, b=2):
1214+
... pass
1215+
Traceback (most recent call last):
1216+
SyntaxError: cannot assign to __debug__
1217+
11851218
>>> if x = 3:
11861219
... pass
11871220
Traceback (most recent call last):
@@ -1275,6 +1308,15 @@
12751308
Traceback (most recent call last):
12761309
SyntaxError: expected 'except' or 'finally' block
12771310
1311+
Custom error message for __debug__ as exception variable
1312+
1313+
>>> try:
1314+
... pass
1315+
... except TypeError as __debug__:
1316+
... pass
1317+
Traceback (most recent call last):
1318+
SyntaxError: cannot assign to __debug__
1319+
12781320
Custom error message for try block mixing except and except*
12791321
12801322
>>> try:
@@ -1522,6 +1564,19 @@
15221564
Traceback (most recent call last):
15231565
IndentationError: expected an indented block after class definition on line 1
15241566
1567+
>>> class C(__debug__=42): ...
1568+
Traceback (most recent call last):
1569+
SyntaxError: cannot assign to __debug__
1570+
1571+
>>> class Meta(type):
1572+
... def __new__(*args, **kwargs):
1573+
... pass
1574+
1575+
>>> class C(metaclass=Meta, __debug__=42):
1576+
... pass
1577+
Traceback (most recent call last):
1578+
SyntaxError: cannot assign to __debug__
1579+
15251580
>>> match something:
15261581
... pass
15271582
Traceback (most recent call last):
@@ -1708,6 +1763,26 @@
17081763
Traceback (most recent call last):
17091764
SyntaxError: Did you mean to use 'from ... import ...' instead?
17101765
1766+
>>> import __debug__
1767+
Traceback (most recent call last):
1768+
SyntaxError: cannot assign to __debug__
1769+
1770+
>>> import a as __debug__
1771+
Traceback (most recent call last):
1772+
SyntaxError: cannot assign to __debug__
1773+
1774+
>>> import a.b.c as __debug__
1775+
Traceback (most recent call last):
1776+
SyntaxError: cannot assign to __debug__
1777+
1778+
>>> from a import __debug__
1779+
Traceback (most recent call last):
1780+
SyntaxError: cannot assign to __debug__
1781+
1782+
>>> from a import b as __debug__
1783+
Traceback (most recent call last):
1784+
SyntaxError: cannot assign to __debug__
1785+
17111786
# Check that we dont raise the "trailing comma" error if there is more
17121787
# input to the left of the valid part that we parsed.
17131788
@@ -2186,6 +2261,10 @@ def f(x: *b)
21862261
...
21872262
SyntaxError: yield expression cannot be used within a type alias
21882263
2264+
>>> type __debug__ = int
2265+
Traceback (most recent call last):
2266+
SyntaxError: cannot assign to __debug__
2267+
21892268
>>> class A[T]((x := 3)): ...
21902269
Traceback (most recent call last):
21912270
...
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Detection of writes to ``__debug__`` is moved from the compiler's codegen
2+
stage to the symtable. This means that these errors now detected even in
3+
code that is optimized away before codegen (such as assertions with the
4+
:option:`-O` command line option.)

Python/compile.c

Lines changed: 0 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1954,55 +1954,6 @@ compiler_default_arguments(struct compiler *c, location loc,
19541954
return funcflags;
19551955
}
19561956

1957-
static bool
1958-
forbidden_name(struct compiler *c, location loc, identifier name,
1959-
expr_context_ty ctx)
1960-
{
1961-
if (ctx == Store && _PyUnicode_EqualToASCIIString(name, "__debug__")) {
1962-
compiler_error(c, loc, "cannot assign to __debug__");
1963-
return true;
1964-
}
1965-
if (ctx == Del && _PyUnicode_EqualToASCIIString(name, "__debug__")) {
1966-
compiler_error(c, loc, "cannot delete __debug__");
1967-
return true;
1968-
}
1969-
return false;
1970-
}
1971-
1972-
static int
1973-
compiler_check_debug_one_arg(struct compiler *c, arg_ty arg)
1974-
{
1975-
if (arg != NULL) {
1976-
if (forbidden_name(c, LOC(arg), arg->arg, Store)) {
1977-
return ERROR;
1978-
}
1979-
}
1980-
return SUCCESS;
1981-
}
1982-
1983-
static int
1984-
compiler_check_debug_args_seq(struct compiler *c, asdl_arg_seq *args)
1985-
{
1986-
if (args != NULL) {
1987-
for (Py_ssize_t i = 0, n = asdl_seq_LEN(args); i < n; i++) {
1988-
RETURN_IF_ERROR(
1989-
compiler_check_debug_one_arg(c, asdl_seq_GET(args, i)));
1990-
}
1991-
}
1992-
return SUCCESS;
1993-
}
1994-
1995-
static int
1996-
compiler_check_debug_args(struct compiler *c, arguments_ty args)
1997-
{
1998-
RETURN_IF_ERROR(compiler_check_debug_args_seq(c, args->posonlyargs));
1999-
RETURN_IF_ERROR(compiler_check_debug_args_seq(c, args->args));
2000-
RETURN_IF_ERROR(compiler_check_debug_one_arg(c, args->vararg));
2001-
RETURN_IF_ERROR(compiler_check_debug_args_seq(c, args->kwonlyargs));
2002-
RETURN_IF_ERROR(compiler_check_debug_one_arg(c, args->kwarg));
2003-
return SUCCESS;
2004-
}
2005-
20061957
static int
20071958
wrap_in_stopiteration_handler(struct compiler *c)
20081959
{
@@ -2267,7 +2218,6 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
22672218
type_params = s->v.FunctionDef.type_params;
22682219
}
22692220

2270-
RETURN_IF_ERROR(compiler_check_debug_args(c, args));
22712221
RETURN_IF_ERROR(compiler_decorators(c, decos));
22722222

22732223
firstlineno = s->lineno;
@@ -2910,8 +2860,6 @@ compiler_lambda(struct compiler *c, expr_ty e)
29102860
arguments_ty args = e->v.Lambda.args;
29112861
assert(e->kind == Lambda_kind);
29122862

2913-
RETURN_IF_ERROR(compiler_check_debug_args(c, args));
2914-
29152863
location loc = LOC(e);
29162864
funcflags = compiler_default_arguments(c, loc, args);
29172865
if (funcflags == -1) {
@@ -4086,10 +4034,6 @@ compiler_nameop(struct compiler *c, location loc,
40864034
!_PyUnicode_EqualToASCIIString(name, "True") &&
40874035
!_PyUnicode_EqualToASCIIString(name, "False"));
40884036

4089-
if (forbidden_name(c, loc, name, ctx)) {
4090-
return ERROR;
4091-
}
4092-
40934037
mangled = compiler_maybe_mangle(c, name);
40944038
if (!mangled) {
40954039
return ERROR;
@@ -4878,10 +4822,6 @@ validate_keywords(struct compiler *c, asdl_keyword_seq *keywords)
48784822
if (key->arg == NULL) {
48794823
continue;
48804824
}
4881-
location loc = LOC(key);
4882-
if (forbidden_name(c, loc, key->arg, Store)) {
4883-
return ERROR;
4884-
}
48854825
for (Py_ssize_t j = i + 1; j < nkeywords; j++) {
48864826
keyword_ty other = ((keyword_ty)asdl_seq_GET(keywords, j));
48874827
if (other->arg && !PyUnicode_Compare(key->arg, other->arg)) {
@@ -6135,9 +6075,6 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
61356075
ADDOP_NAME(c, loc, LOAD_ATTR, e->v.Attribute.attr, names);
61366076
break;
61376077
case Store:
6138-
if (forbidden_name(c, loc, e->v.Attribute.attr, e->v.Attribute.ctx)) {
6139-
return ERROR;
6140-
}
61416078
ADDOP_NAME(c, loc, STORE_ATTR, e->v.Attribute.attr, names);
61426079
break;
61436080
case Del:
@@ -6331,9 +6268,6 @@ compiler_annassign(struct compiler *c, stmt_ty s)
63316268
}
63326269
switch (targ->kind) {
63336270
case Name_kind:
6334-
if (forbidden_name(c, loc, targ->v.Name.id, Store)) {
6335-
return ERROR;
6336-
}
63376271
/* If we have a simple name in a module or class, store annotation. */
63386272
if (s->v.AnnAssign.simple &&
63396273
(c->u->u_scope_type == COMPILER_SCOPE_MODULE ||
@@ -6365,9 +6299,6 @@ compiler_annassign(struct compiler *c, stmt_ty s)
63656299
}
63666300
break;
63676301
case Attribute_kind:
6368-
if (forbidden_name(c, loc, targ->v.Attribute.attr, Store)) {
6369-
return ERROR;
6370-
}
63716302
if (!s->v.AnnAssign.value &&
63726303
check_ann_expr(c, targ->v.Attribute.value) < 0) {
63736304
return ERROR;
@@ -6631,9 +6562,6 @@ pattern_helper_store_name(struct compiler *c, location loc,
66316562
ADDOP(c, loc, POP_TOP);
66326563
return SUCCESS;
66336564
}
6634-
if (forbidden_name(c, loc, n, Store)) {
6635-
return ERROR;
6636-
}
66376565
// Can't assign to the same name twice:
66386566
int duplicate = PySequence_Contains(pc->stores, n);
66396567
RETURN_IF_ERROR(duplicate);
@@ -6791,10 +6719,6 @@ validate_kwd_attrs(struct compiler *c, asdl_identifier_seq *attrs, asdl_pattern_
67916719
Py_ssize_t nattrs = asdl_seq_LEN(attrs);
67926720
for (Py_ssize_t i = 0; i < nattrs; i++) {
67936721
identifier attr = ((identifier)asdl_seq_GET(attrs, i));
6794-
location loc = LOC((pattern_ty) asdl_seq_GET(patterns, i));
6795-
if (forbidden_name(c, loc, attr, Store)) {
6796-
return ERROR;
6797-
}
67986722
for (Py_ssize_t j = i + 1; j < nattrs; j++) {
67996723
identifier other = ((identifier)asdl_seq_GET(attrs, j));
68006724
if (!PyUnicode_Compare(attr, other)) {

0 commit comments

Comments
 (0)