From f8395cc42d7360a375e41f65b298539c3bd55f20 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 12 Jul 2024 17:52:39 -0700 Subject: [PATCH 1/8] Fix await itself --- Lib/test/test_builtin.py | 11 +++++++---- Python/compile.c | 14 ++++---------- Python/symtable.c | 32 +++++++++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 5818e96d61f480..41ff6b579ca45f 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -426,6 +426,7 @@ async def arange(n): yield i modes = ('single', 'exec') + optimizations = (-1, 0, 1, 2) code_samples = [ '''a = await asyncio.sleep(0, result=1)''', '''async for i in arange(1): @@ -438,20 +439,22 @@ async def arange(n): '''a = [x async for x in arange(2) async for x in arange(2)][1]''', '''a = [x async for x in (x async for x in arange(5))][1]''', '''a, = [1 for x in {x async for x in arange(1)}]''', - '''a = [await asyncio.sleep(0, x) async for x in arange(2)][1]''' + '''a = [await asyncio.sleep(0, x) async for x in arange(2)][1]''', + '''assert not await asyncio.sleep(0); a = 1''', ] policy = maybe_get_event_loop_policy() try: - for mode, code_sample in product(modes, code_samples): + for mode, code_sample, optimize in product(modes, code_samples, optimizations): source = dedent(code_sample) with self.assertRaises( SyntaxError, msg=f"source={source} mode={mode}"): - compile(source, '?', mode) + compile(source, '?', mode, optimize=optimize) co = compile(source, '?', mode, - flags=ast.PyCF_ALLOW_TOP_LEVEL_AWAIT) + flags=ast.PyCF_ALLOW_TOP_LEVEL_AWAIT, + optimize=optimize) self.assertEqual(co.co_flags & CO_COROUTINE, CO_COROUTINE, msg=f"source={source} mode={mode}") diff --git a/Python/compile.c b/Python/compile.c index 4190b141324b38..36ef197153a57e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -6130,16 +6130,10 @@ compiler_visit_expr(struct compiler *c, expr_ty e) ADD_YIELD_FROM(c, loc, 0); break; case Await_kind: - if (!IS_TOP_LEVEL_AWAIT(c)){ - if (!_PyST_IsFunctionLike(SYMTABLE_ENTRY(c))) { - return compiler_error(c, loc, "'await' outside function"); - } - - if (c->u->u_scope_type != COMPILER_SCOPE_ASYNC_FUNCTION && - c->u->u_scope_type != COMPILER_SCOPE_COMPREHENSION) { - return compiler_error(c, loc, "'await' outside async function"); - } - } + assert(IS_TOP_LEVEL_AWAIT(c) || (_PyST_IsFunctionLike(SYMTABLE_ENTRY(c)) && ( + c->u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION || + c->u->u_scope_type == COMPILER_SCOPE_COMPREHENSION + ))); VISIT(c, expr, e->v.Await.value); ADDOP_I(c, loc, GET_AWAITABLE, 0); diff --git a/Python/symtable.c b/Python/symtable.c index 10103dbc2582a2..73063492e4dad0 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1660,12 +1660,18 @@ check_import_from(struct symtable *st, stmt_ty s) return 1; } +static bool +allows_top_level_await(struct symtable* st) +{ + return (st->st_future->ff_features & PyCF_ALLOW_TOP_LEVEL_AWAIT) + && st->st_cur->ste_type == ModuleBlock; +} + + static void maybe_set_ste_coroutine_for_module(struct symtable *st, stmt_ty s) { - if ((st->st_future->ff_features & PyCF_ALLOW_TOP_LEVEL_AWAIT) && - (st->st_cur->ste_type == ModuleBlock)) - { + if (allows_top_level_await(st)) { st->st_cur->ste_coroutine = 1; } } @@ -2185,6 +2191,7 @@ symtable_handle_namedexpr(struct symtable *st, expr_ty e) return 1; } + static int symtable_visit_expr(struct symtable *st, expr_ty e) { @@ -2279,6 +2286,25 @@ symtable_visit_expr(struct symtable *st, expr_ty e) if (!symtable_raise_if_annotation_block(st, "await expression", e)) { VISIT_QUIT(st, 0); } + if (!allows_top_level_await(st)) { + if (!_PyST_IsFunctionLike(st->st_cur)) { + PyErr_SetString(PyExc_SyntaxError, + "'await' outside function"); + SET_ERROR_LOCATION(st->st_filename, LOCATION(e)); + VISIT_QUIT(st, 0); + } + bool is_async_def = ( + st->st_cur->ste_type == FunctionBlock && + st->st_cur->ste_coroutine + ); + if (!is_async_def && st->st_cur->ste_comprehension != NoComprehension) { + PyErr_SetString(PyExc_SyntaxError, + "'await' outside async function"); + SET_ERROR_LOCATION(st->st_filename, LOCATION(e)); + VISIT_QUIT(st, 0); + + } + } VISIT(st, expr, e->v.Await.value); st->st_cur->ste_coroutine = 1; break; From 8160c6cad166db775a603eb817486b129ca3198f Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 12 Jul 2024 17:54:38 -0700 Subject: [PATCH 2/8] fix typo --- Python/symtable.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Python/symtable.c b/Python/symtable.c index 73063492e4dad0..457d749eb3748a 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -70,10 +70,10 @@ #define DUPLICATE_TYPE_PARAM \ "duplicate type parameter '%U'" -#define ASYNC_WITH_OUTISDE_ASYNC_FUNC \ +#define ASYNC_WITH_OUTSIDE_ASYNC_FUNC \ "'async with' outside async function" -#define ASYNC_FOR_OUTISDE_ASYNC_FUNC \ +#define ASYNC_FOR_OUTSIDE_ASYNC_FUNC \ "'async for' outside async function" #define LOCATION(x) SRC_LOCATION_FROM_AST(x) @@ -2060,7 +2060,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) } case AsyncWith_kind: maybe_set_ste_coroutine_for_module(st, s); - if (!symtable_raise_if_not_coroutine(st, ASYNC_WITH_OUTISDE_ASYNC_FUNC, LOCATION(s))) { + if (!symtable_raise_if_not_coroutine(st, ASYNC_WITH_OUTSIDE_ASYNC_FUNC, LOCATION(s))) { VISIT_QUIT(st, 0); } VISIT_SEQ(st, withitem, s->v.AsyncWith.items); @@ -2068,7 +2068,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) break; case AsyncFor_kind: maybe_set_ste_coroutine_for_module(st, s); - if (!symtable_raise_if_not_coroutine(st, ASYNC_FOR_OUTISDE_ASYNC_FUNC, LOCATION(s))) { + if (!symtable_raise_if_not_coroutine(st, ASYNC_FOR_OUTSIDE_ASYNC_FUNC, LOCATION(s))) { VISIT_QUIT(st, 0); } VISIT(st, expr, s->v.AsyncFor.target); From 1a39f45bd53bf6b8186076748202692fb72a2bd2 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 12 Jul 2024 17:58:26 -0700 Subject: [PATCH 3/8] more tests --- Lib/test/test_builtin.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 41ff6b579ca45f..5001910eb9b98f 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -16,6 +16,7 @@ import random import re import sys +import textwrap import traceback import types import typing @@ -440,7 +441,29 @@ async def arange(n): '''a = [x async for x in (x async for x in arange(5))][1]''', '''a, = [1 for x in {x async for x in arange(1)}]''', '''a = [await asyncio.sleep(0, x) async for x in arange(2)][1]''', + # gh-121637: Make sure we correctly handle the case where the + # async code is optimized away '''assert not await asyncio.sleep(0); a = 1''', + '''assert [x async for x in arange(1)]; a = 1''', + '''assert (x async for x in arange(1)); a = 1''', + '''assert {x async for x in arange(1)}; a = 1''', + '''assert {x: x async for x in arange(1)}; a = 1''', + textwrap.dedent( + ''' + if __debug__: + async with asyncio.Lock() as l: + pass + a = 1 + ''' + ), + textwrap.dedent( + ''' + if __debug__: + async for x in arange(2): + pass + a = 1 + ''' + ), ] policy = maybe_get_event_loop_policy() try: From 9a7ce67271cfc8507ca30ba98d776326fb59319d Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 12 Jul 2024 18:21:54 -0700 Subject: [PATCH 4/8] News, more fixes --- Doc/whatsnew/3.14.rst | 4 ++ Lib/test/test_builtin.py | 56 +++++++++---------- ...-07-12-18-18-44.gh-issue-121297.67VE7b.rst | 4 ++ Python/compile.c | 17 ++---- Python/symtable.c | 9 +++ 5 files changed, 50 insertions(+), 40 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-07-12-18-18-44.gh-issue-121297.67VE7b.rst diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index da9b45cd8e58b3..cf4c23fa5b2267 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -75,6 +75,10 @@ New Features Other Language Changes ====================== +* Incorrect usage of :keyword:`await` and asynchronous comprehensions + is now detected even if the code is optimized away by the :option:`-O` + command line option. For example, ``python -O -c 'assert await 1'`` + now produces a syntax error. (Contributed by Jelle Zijlstra in :gh:`121637`.) New Modules diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 5001910eb9b98f..d777853cc5a563 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -413,7 +413,7 @@ def test_compile_top_level_await_no_coro(self): "socket.accept is broken" ) def test_compile_top_level_await(self): - """Test whether code some top level await can be compiled. + """Test whether code with top level await can be compiled. Make sure it compiles only with the PyCF_ALLOW_TOP_LEVEL_AWAIT flag set, and make sure the generated code object has the CO_COROUTINE flag @@ -445,53 +445,51 @@ async def arange(n): # async code is optimized away '''assert not await asyncio.sleep(0); a = 1''', '''assert [x async for x in arange(1)]; a = 1''', - '''assert (x async for x in arange(1)); a = 1''', '''assert {x async for x in arange(1)}; a = 1''', '''assert {x: x async for x in arange(1)}; a = 1''', textwrap.dedent( ''' - if __debug__: + if (a := 1) and __debug__: async with asyncio.Lock() as l: pass - a = 1 ''' ), textwrap.dedent( ''' - if __debug__: + if (a := 1) and __debug__: async for x in arange(2): pass - a = 1 ''' ), ] policy = maybe_get_event_loop_policy() try: for mode, code_sample, optimize in product(modes, code_samples, optimizations): - source = dedent(code_sample) - with self.assertRaises( - SyntaxError, msg=f"source={source} mode={mode}"): - compile(source, '?', mode, optimize=optimize) + with self.subTest(mode=mode, code_sample=code_sample, optimize=optimize): + source = dedent(code_sample) + with self.assertRaises( + SyntaxError, msg=f"source={source} mode={mode}"): + compile(source, '?', mode, optimize=optimize) - co = compile(source, - '?', - mode, - flags=ast.PyCF_ALLOW_TOP_LEVEL_AWAIT, - optimize=optimize) - - self.assertEqual(co.co_flags & CO_COROUTINE, CO_COROUTINE, - msg=f"source={source} mode={mode}") - - # test we can create and advance a function type - globals_ = {'asyncio': asyncio, 'a': 0, 'arange': arange} - async_f = FunctionType(co, globals_) - asyncio.run(async_f()) - self.assertEqual(globals_['a'], 1) - - # test we can await-eval, - globals_ = {'asyncio': asyncio, 'a': 0, 'arange': arange} - asyncio.run(eval(co, globals_)) - self.assertEqual(globals_['a'], 1) + co = compile(source, + '?', + mode, + flags=ast.PyCF_ALLOW_TOP_LEVEL_AWAIT, + optimize=optimize) + + self.assertEqual(co.co_flags & CO_COROUTINE, CO_COROUTINE, + msg=f"source={source} mode={mode}") + + # test we can create and advance a function type + globals_ = {'asyncio': asyncio, 'a': 0, 'arange': arange} + async_f = FunctionType(co, globals_) + asyncio.run(async_f()) + self.assertEqual(globals_['a'], 1) + + # test we can await-eval, + globals_ = {'asyncio': asyncio, 'a': 0, 'arange': arange} + asyncio.run(eval(co, globals_)) + self.assertEqual(globals_['a'], 1) finally: asyncio.set_event_loop_policy(policy) diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-12-18-18-44.gh-issue-121297.67VE7b.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-12-18-18-44.gh-issue-121297.67VE7b.rst new file mode 100644 index 00000000000000..b9e8f8409a0772 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-07-12-18-18-44.gh-issue-121297.67VE7b.rst @@ -0,0 +1,4 @@ +Previously, incorrect usage of :keyword:`await` or asynchronous +comprehensions in code removed by the :option:`-O` option was not flagged by +the Python compiler. Now, such codew raises :exc:`SyntaxError`. Patch by +Jelle Zijlstra. diff --git a/Python/compile.c b/Python/compile.c index 36ef197153a57e..bae19be5d96079 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5674,7 +5674,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, goto error; } int is_inlined = entry->ste_comp_inlined; - int is_async_generator = entry->ste_coroutine; + int is_async_comprehension = entry->ste_coroutine; location loc = LOC(e); @@ -5696,15 +5696,10 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, } Py_CLEAR(entry); - if (is_async_generator && type != COMP_GENEXP && - scope_type != COMPILER_SCOPE_ASYNC_FUNCTION && - scope_type != COMPILER_SCOPE_COMPREHENSION && - !is_top_level_await) - { - compiler_error(c, loc, "asynchronous comprehension outside of " - "an asynchronous function"); - goto error_in_scope; - } + assert (!is_async_comprehension || type == COMP_GENEXP + || scope_type == COMPILER_SCOPE_ASYNC_FUNCTION + || scope_type == COMPILER_SCOPE_COMPREHENSION + || is_top_level_await); if (type != COMP_GENEXP) { int op; @@ -5769,7 +5764,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, ADDOP_I(c, loc, CALL, 0); - if (is_async_generator && type != COMP_GENEXP) { + if (is_async_comprehension && type != COMP_GENEXP) { ADDOP_I(c, loc, GET_AWAITABLE, 0); ADDOP_LOAD_CONST(c, loc, Py_None); ADD_YIELD_FROM(c, loc, 1); diff --git a/Python/symtable.c b/Python/symtable.c index 457d749eb3748a..2f9e06348d11de 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -2824,6 +2824,15 @@ symtable_handle_comprehension(struct symtable *st, expr_ty e, if (!symtable_exit_block(st)) { return 0; } + if (is_async && + !(st->st_cur->ste_type == FunctionBlock && st->st_cur->ste_coroutine) && + st->st_cur->ste_comprehension == NoComprehension && + !allows_top_level_await(st)) { + PyErr_SetString(PyExc_SyntaxError, "asynchronous comprehension outside of " + "an asynchronous function"); + SET_ERROR_LOCATION(st->st_filename, LOCATION(e)); + return 0; + } if (is_async) { st->st_cur->ste_coroutine = 1; } From e226b5670e2f215f3dd394faba6acf8a804a1b54 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 12 Jul 2024 18:40:49 -0700 Subject: [PATCH 5/8] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/whatsnew/3.14.rst | 2 +- .../2024-07-12-18-18-44.gh-issue-121297.67VE7b.rst | 2 +- Python/compile.c | 9 +++++---- Python/symtable.c | 11 +++++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index cf4c23fa5b2267..29f63a45d8fa31 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -78,7 +78,7 @@ Other Language Changes * Incorrect usage of :keyword:`await` and asynchronous comprehensions is now detected even if the code is optimized away by the :option:`-O` command line option. For example, ``python -O -c 'assert await 1'`` - now produces a syntax error. (Contributed by Jelle Zijlstra in :gh:`121637`.) + now produces a :exc:`SyntaxError`. (Contributed by Jelle Zijlstra in :gh:`121637`.) New Modules diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-12-18-18-44.gh-issue-121297.67VE7b.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-12-18-18-44.gh-issue-121297.67VE7b.rst index b9e8f8409a0772..25aae6c8c5cb10 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2024-07-12-18-18-44.gh-issue-121297.67VE7b.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2024-07-12-18-18-44.gh-issue-121297.67VE7b.rst @@ -1,4 +1,4 @@ Previously, incorrect usage of :keyword:`await` or asynchronous comprehensions in code removed by the :option:`-O` option was not flagged by -the Python compiler. Now, such codew raises :exc:`SyntaxError`. Patch by +the Python compiler. Now, such code raises :exc:`SyntaxError`. Patch by Jelle Zijlstra. diff --git a/Python/compile.c b/Python/compile.c index bae19be5d96079..6a57fa08c0c1d8 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5696,10 +5696,11 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, } Py_CLEAR(entry); - assert (!is_async_comprehension || type == COMP_GENEXP - || scope_type == COMPILER_SCOPE_ASYNC_FUNCTION - || scope_type == COMPILER_SCOPE_COMPREHENSION - || is_top_level_await); + assert (!is_async_comprehension || + type == COMP_GENEXP || + scope_type == COMPILER_SCOPE_ASYNC_FUNCTION || + scope_type == COMPILER_SCOPE_COMPREHENSION || + is_top_level_await); if (type != COMP_GENEXP) { int op; diff --git a/Python/symtable.c b/Python/symtable.c index 2f9e06348d11de..167435eef56b5c 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1661,10 +1661,10 @@ check_import_from(struct symtable *st, stmt_ty s) } static bool -allows_top_level_await(struct symtable* st) +allows_top_level_await(struct symtable *st) { - return (st->st_future->ff_features & PyCF_ALLOW_TOP_LEVEL_AWAIT) - && st->st_cur->ste_type == ModuleBlock; + return (st->st_future->ff_features & PyCF_ALLOW_TOP_LEVEL_AWAIT) && + st->st_cur->ste_type == ModuleBlock; } @@ -2191,7 +2191,6 @@ symtable_handle_namedexpr(struct symtable *st, expr_ty e) return 1; } - static int symtable_visit_expr(struct symtable *st, expr_ty e) { @@ -2302,7 +2301,6 @@ symtable_visit_expr(struct symtable *st, expr_ty e) "'await' outside async function"); SET_ERROR_LOCATION(st->st_filename, LOCATION(e)); VISIT_QUIT(st, 0); - } } VISIT(st, expr, e->v.Await.value); @@ -2827,7 +2825,8 @@ symtable_handle_comprehension(struct symtable *st, expr_ty e, if (is_async && !(st->st_cur->ste_type == FunctionBlock && st->st_cur->ste_coroutine) && st->st_cur->ste_comprehension == NoComprehension && - !allows_top_level_await(st)) { + !allows_top_level_await(st)) + { PyErr_SetString(PyExc_SyntaxError, "asynchronous comprehension outside of " "an asynchronous function"); SET_ERROR_LOCATION(st->st_filename, LOCATION(e)); From 07d5488c0238ab9344c4b47de6609b8f1d819d43 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 12 Jul 2024 18:43:22 -0700 Subject: [PATCH 6/8] not not no but no --- Python/symtable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/symtable.c b/Python/symtable.c index 167435eef56b5c..4fc98647b29d1a 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -2296,7 +2296,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e) st->st_cur->ste_type == FunctionBlock && st->st_cur->ste_coroutine ); - if (!is_async_def && st->st_cur->ste_comprehension != NoComprehension) { + if (!is_async_def && st->st_cur->ste_comprehension == NoComprehension) { PyErr_SetString(PyExc_SyntaxError, "'await' outside async function"); SET_ERROR_LOCATION(st->st_filename, LOCATION(e)); From 456ea0446741b8d85a163658da93c2e33ca585ce Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 22 Jul 2024 07:22:23 -0700 Subject: [PATCH 7/8] Code review tweaks --- Lib/test/test_builtin.py | 25 +++++++++++-------------- Python/compile.c | 5 +++-- Python/symtable.c | 10 ++++------ 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index d777853cc5a563..d289972cc54beb 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -447,20 +447,16 @@ async def arange(n): '''assert [x async for x in arange(1)]; a = 1''', '''assert {x async for x in arange(1)}; a = 1''', '''assert {x: x async for x in arange(1)}; a = 1''', - textwrap.dedent( - ''' - if (a := 1) and __debug__: - async with asyncio.Lock() as l: - pass - ''' - ), - textwrap.dedent( - ''' - if (a := 1) and __debug__: - async for x in arange(2): - pass - ''' - ), + ''' + if (a := 1) and __debug__: + async with asyncio.Lock() as l: + pass + ''', + ''' + if (a := 1) and __debug__: + async for x in arange(2): + pass + ''', ] policy = maybe_get_event_loop_policy() try: @@ -2427,6 +2423,7 @@ def child(wpipe): def test_input_tty(self): # Test input() functionality when wired to a tty (the code path # is different and invokes GNU readline if available). + return self.check_input_tty("prompt", b"quux") def skip_if_readline(self): diff --git a/Python/compile.c b/Python/compile.c index 4ce69eaa8f04b4..a05c2ec453a7d3 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5667,8 +5667,10 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, PyCodeObject *co = NULL; inlined_comprehension_state inline_state = {NULL, NULL, NULL, NO_LABEL, NO_LABEL}; comprehension_ty outermost; +#ifndef NDEBUG int scope_type = c->u->u_scope_type; int is_top_level_await = IS_TOP_LEVEL_AWAIT(c); +#endif PySTEntryObject *entry = _PySymtable_Lookup(SYMTABLE(c), (void *)e); if (entry == NULL) { goto error; @@ -5689,8 +5691,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, } else { if (compiler_enter_scope(c, name, COMPILER_SCOPE_COMPREHENSION, - (void *)e, e->lineno, NULL) < 0) - { + (void *)e, e->lineno, NULL) < 0) { goto error; } } diff --git a/Python/symtable.c b/Python/symtable.c index 4fc98647b29d1a..c4508cac7f5928 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -82,6 +82,8 @@ PyErr_RangedSyntaxLocationObject((FNAME), \ (L).lineno, (L).col_offset + 1, (L).end_lineno, (L).end_col_offset + 1) +#define IS_ASYNC_DEF(st) ((st)->st_cur->ste_type == FunctionBlock && (st)->st_cur->ste_coroutine) + static PySTEntryObject * ste_new(struct symtable *st, identifier name, _Py_block_ty block, void *key, _Py_SourceLocation loc) @@ -2292,11 +2294,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e) SET_ERROR_LOCATION(st->st_filename, LOCATION(e)); VISIT_QUIT(st, 0); } - bool is_async_def = ( - st->st_cur->ste_type == FunctionBlock && - st->st_cur->ste_coroutine - ); - if (!is_async_def && st->st_cur->ste_comprehension == NoComprehension) { + if (!IS_ASYNC_DEF(st) && st->st_cur->ste_comprehension == NoComprehension) { PyErr_SetString(PyExc_SyntaxError, "'await' outside async function"); SET_ERROR_LOCATION(st->st_filename, LOCATION(e)); @@ -2823,7 +2821,7 @@ symtable_handle_comprehension(struct symtable *st, expr_ty e, return 0; } if (is_async && - !(st->st_cur->ste_type == FunctionBlock && st->st_cur->ste_coroutine) && + !IS_ASYNC_DEF(st) && st->st_cur->ste_comprehension == NoComprehension && !allows_top_level_await(st)) { From e9c25cd64dc5051783a04272ea184f091c1f5473 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 22 Jul 2024 07:52:49 -0700 Subject: [PATCH 8/8] Update Lib/test/test_builtin.py --- Lib/test/test_builtin.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index d289972cc54beb..c6a563cc90fec4 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -2423,7 +2423,6 @@ def child(wpipe): def test_input_tty(self): # Test input() functionality when wired to a tty (the code path # is different and invokes GNU readline if available). - return self.check_input_tty("prompt", b"quux") def skip_if_readline(self):