mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-130080: implement PEP 765 (#130087)
This commit is contained in:
parent
468a7aaeb4
commit
ffc2f1dd1c
14 changed files with 426 additions and 109 deletions
|
@ -420,16 +420,16 @@ is executed. If there is a saved exception it is re-raised at the end of the
|
||||||
:keyword:`!finally` clause. If the :keyword:`!finally` clause raises another
|
:keyword:`!finally` clause. If the :keyword:`!finally` clause raises another
|
||||||
exception, the saved exception is set as the context of the new exception.
|
exception, the saved exception is set as the context of the new exception.
|
||||||
If the :keyword:`!finally` clause executes a :keyword:`return`, :keyword:`break`
|
If the :keyword:`!finally` clause executes a :keyword:`return`, :keyword:`break`
|
||||||
or :keyword:`continue` statement, the saved exception is discarded::
|
or :keyword:`continue` statement, the saved exception is discarded. For example,
|
||||||
|
this function returns 42.
|
||||||
|
|
||||||
>>> def f():
|
.. code-block::
|
||||||
... try:
|
|
||||||
... 1/0
|
def f():
|
||||||
... finally:
|
try:
|
||||||
... return 42
|
1/0
|
||||||
...
|
finally:
|
||||||
>>> f()
|
return 42
|
||||||
42
|
|
||||||
|
|
||||||
The exception information is not available to the program during execution of
|
The exception information is not available to the program during execution of
|
||||||
the :keyword:`!finally` clause.
|
the :keyword:`!finally` clause.
|
||||||
|
@ -446,21 +446,25 @@ statement, the :keyword:`!finally` clause is also executed 'on the way out.'
|
||||||
The return value of a function is determined by the last :keyword:`return`
|
The return value of a function is determined by the last :keyword:`return`
|
||||||
statement executed. Since the :keyword:`!finally` clause always executes, a
|
statement executed. Since the :keyword:`!finally` clause always executes, a
|
||||||
:keyword:`!return` statement executed in the :keyword:`!finally` clause will
|
:keyword:`!return` statement executed in the :keyword:`!finally` clause will
|
||||||
always be the last one executed::
|
always be the last one executed. The following function returns 'finally'.
|
||||||
|
|
||||||
>>> def foo():
|
.. code-block::
|
||||||
... try:
|
|
||||||
... return 'try'
|
def foo():
|
||||||
... finally:
|
try:
|
||||||
... return 'finally'
|
return 'try'
|
||||||
...
|
finally:
|
||||||
>>> foo()
|
return 'finally'
|
||||||
'finally'
|
|
||||||
|
|
||||||
.. versionchanged:: 3.8
|
.. versionchanged:: 3.8
|
||||||
Prior to Python 3.8, a :keyword:`continue` statement was illegal in the
|
Prior to Python 3.8, a :keyword:`continue` statement was illegal in the
|
||||||
:keyword:`!finally` clause due to a problem with the implementation.
|
:keyword:`!finally` clause due to a problem with the implementation.
|
||||||
|
|
||||||
|
.. versionchanged:: next
|
||||||
|
The compiler emits a :exc:`SyntaxWarning` when a :keyword:`return`,
|
||||||
|
:keyword:`break` or :keyword:`continue` appears in a :keyword:`!finally`
|
||||||
|
block (see :pep:`765`).
|
||||||
|
|
||||||
|
|
||||||
.. _with:
|
.. _with:
|
||||||
.. _as:
|
.. _as:
|
||||||
|
|
|
@ -418,7 +418,9 @@ points discuss more complex cases when an exception occurs:
|
||||||
|
|
||||||
* If the :keyword:`!finally` clause executes a :keyword:`break`,
|
* If the :keyword:`!finally` clause executes a :keyword:`break`,
|
||||||
:keyword:`continue` or :keyword:`return` statement, exceptions are not
|
:keyword:`continue` or :keyword:`return` statement, exceptions are not
|
||||||
re-raised.
|
re-raised. This can be confusing and is therefore discouraged. From
|
||||||
|
version 3.14 the compiler emits a :exc:`SyntaxWarning` for it
|
||||||
|
(see :pep:`765`).
|
||||||
|
|
||||||
* If the :keyword:`!try` statement reaches a :keyword:`break`,
|
* If the :keyword:`!try` statement reaches a :keyword:`break`,
|
||||||
:keyword:`continue` or :keyword:`return` statement, the
|
:keyword:`continue` or :keyword:`return` statement, the
|
||||||
|
@ -430,7 +432,9 @@ points discuss more complex cases when an exception occurs:
|
||||||
statement, the returned value will be the one from the
|
statement, the returned value will be the one from the
|
||||||
:keyword:`!finally` clause's :keyword:`!return` statement, not the
|
:keyword:`!finally` clause's :keyword:`!return` statement, not the
|
||||||
value from the :keyword:`!try` clause's :keyword:`!return`
|
value from the :keyword:`!try` clause's :keyword:`!return`
|
||||||
statement.
|
statement. This can be confusing and is therefore discouraged. From
|
||||||
|
version 3.14 the compiler emits a :exc:`SyntaxWarning` for it
|
||||||
|
(see :pep:`765`).
|
||||||
|
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ Summary -- release highlights
|
||||||
* :ref:`PEP 741: Python Configuration C API <whatsnew314-pep741>`
|
* :ref:`PEP 741: Python Configuration C API <whatsnew314-pep741>`
|
||||||
* :ref:`PEP 761: Discontinuation of PGP signatures <whatsnew314-pep761>`
|
* :ref:`PEP 761: Discontinuation of PGP signatures <whatsnew314-pep761>`
|
||||||
* :ref:`A new type of interpreter <whatsnew314-tail-call>`
|
* :ref:`A new type of interpreter <whatsnew314-tail-call>`
|
||||||
|
* :ref:`PEP 765: Disallow return/break/continue that exit a finally block <whatsnew314-pep765>`
|
||||||
|
|
||||||
|
|
||||||
Incompatible changes
|
Incompatible changes
|
||||||
|
@ -370,6 +371,15 @@ Other language changes
|
||||||
The testbed can also be used to run the test suite of projects other than
|
The testbed can also be used to run the test suite of projects other than
|
||||||
CPython itself. (Contributed by Russell Keith-Magee in :gh:`127592`.)
|
CPython itself. (Contributed by Russell Keith-Magee in :gh:`127592`.)
|
||||||
|
|
||||||
|
.. _whatsnew314-pep765:
|
||||||
|
|
||||||
|
PEP 765: Disallow return/break/continue that exit a finally block
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
|
||||||
|
The compiler emits a :exc:`SyntaxWarning` when a :keyword:`return`, :keyword:`break` or
|
||||||
|
:keyword:`continue` statements appears where it exits a :keyword:`finally` block.
|
||||||
|
This change is specified in :pep:`765`.
|
||||||
|
|
||||||
New modules
|
New modules
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
|
|
@ -40,13 +40,16 @@ extern int _PyCompile_AstOptimize(
|
||||||
PyObject *filename,
|
PyObject *filename,
|
||||||
PyCompilerFlags *flags,
|
PyCompilerFlags *flags,
|
||||||
int optimize,
|
int optimize,
|
||||||
struct _arena *arena);
|
struct _arena *arena,
|
||||||
|
int syntax_check_only);
|
||||||
|
|
||||||
extern int _PyAST_Optimize(
|
extern int _PyAST_Optimize(
|
||||||
struct _mod *,
|
struct _mod *,
|
||||||
struct _arena *arena,
|
struct _arena *arena,
|
||||||
|
PyObject *filename,
|
||||||
int optimize,
|
int optimize,
|
||||||
int ff_features);
|
int ff_features,
|
||||||
|
int syntax_check_only);
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -37,6 +37,7 @@ class AllTest(unittest.TestCase):
|
||||||
(".* (module|package)", DeprecationWarning),
|
(".* (module|package)", DeprecationWarning),
|
||||||
(".* (module|package)", PendingDeprecationWarning),
|
(".* (module|package)", PendingDeprecationWarning),
|
||||||
("", ResourceWarning),
|
("", ResourceWarning),
|
||||||
|
("", SyntaxWarning),
|
||||||
quiet=True):
|
quiet=True):
|
||||||
try:
|
try:
|
||||||
exec("import %s" % modname, names)
|
exec("import %s" % modname, names)
|
||||||
|
@ -52,6 +53,7 @@ class AllTest(unittest.TestCase):
|
||||||
with warnings_helper.check_warnings(
|
with warnings_helper.check_warnings(
|
||||||
("", DeprecationWarning),
|
("", DeprecationWarning),
|
||||||
("", ResourceWarning),
|
("", ResourceWarning),
|
||||||
|
("", SyntaxWarning),
|
||||||
quiet=True):
|
quiet=True):
|
||||||
try:
|
try:
|
||||||
exec("from %s import *" % modname, names)
|
exec("from %s import *" % modname, names)
|
||||||
|
|
|
@ -820,6 +820,61 @@ class AST_Tests(unittest.TestCase):
|
||||||
r"Exceeds the limit \(\d+ digits\)"):
|
r"Exceeds the limit \(\d+ digits\)"):
|
||||||
repr(ast.Constant(value=eval(source)))
|
repr(ast.Constant(value=eval(source)))
|
||||||
|
|
||||||
|
def test_pep_765_warnings(self):
|
||||||
|
srcs = [
|
||||||
|
textwrap.dedent("""
|
||||||
|
def f():
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
return 42
|
||||||
|
"""),
|
||||||
|
textwrap.dedent("""
|
||||||
|
for x in y:
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
break
|
||||||
|
"""),
|
||||||
|
textwrap.dedent("""
|
||||||
|
for x in y:
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
continue
|
||||||
|
"""),
|
||||||
|
]
|
||||||
|
for src in srcs:
|
||||||
|
with self.assertWarnsRegex(SyntaxWarning, 'finally'):
|
||||||
|
ast.parse(src)
|
||||||
|
|
||||||
|
def test_pep_765_no_warnings(self):
|
||||||
|
srcs = [
|
||||||
|
textwrap.dedent("""
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
def f():
|
||||||
|
return 42
|
||||||
|
"""),
|
||||||
|
textwrap.dedent("""
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
for x in y:
|
||||||
|
break
|
||||||
|
"""),
|
||||||
|
textwrap.dedent("""
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
for x in y:
|
||||||
|
continue
|
||||||
|
"""),
|
||||||
|
]
|
||||||
|
for src in srcs:
|
||||||
|
ast.parse(src)
|
||||||
|
|
||||||
|
|
||||||
class CopyTests(unittest.TestCase):
|
class CopyTests(unittest.TestCase):
|
||||||
"""Test copying and pickling AST nodes."""
|
"""Test copying and pickling AST nodes."""
|
||||||
|
|
|
@ -84,7 +84,8 @@ class TestBreakContinueReturnInExceptStarBlock(unittest.TestCase):
|
||||||
if i == 2:
|
if i == 2:
|
||||||
break
|
break
|
||||||
finally:
|
finally:
|
||||||
return 0
|
pass
|
||||||
|
return 0
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,7 +118,8 @@ class TestBreakContinueReturnInExceptStarBlock(unittest.TestCase):
|
||||||
if i == 2:
|
if i == 2:
|
||||||
continue
|
continue
|
||||||
finally:
|
finally:
|
||||||
return 0
|
pass
|
||||||
|
return 0
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def test_return_in_except_star_block_invalid(self):
|
def test_return_in_except_star_block_invalid(self):
|
||||||
|
|
|
@ -858,7 +858,7 @@ Traceback (most recent call last):
|
||||||
SyntaxError: 'function call' is an illegal expression for augmented assignment
|
SyntaxError: 'function call' is an illegal expression for augmented assignment
|
||||||
|
|
||||||
|
|
||||||
Test continue in finally in weird combinations.
|
Test control flow in finally
|
||||||
|
|
||||||
continue in for loop under finally should be ok.
|
continue in for loop under finally should be ok.
|
||||||
|
|
||||||
|
@ -872,51 +872,63 @@ continue in for loop under finally should be ok.
|
||||||
>>> test()
|
>>> test()
|
||||||
9
|
9
|
||||||
|
|
||||||
continue in a finally should be ok.
|
break in for loop under finally should be ok.
|
||||||
|
|
||||||
>>> def test():
|
>>> def test():
|
||||||
... for abc in range(10):
|
... try:
|
||||||
... try:
|
... pass
|
||||||
... pass
|
... finally:
|
||||||
... finally:
|
... for abc in range(10):
|
||||||
... continue
|
... break
|
||||||
... print(abc)
|
... print(abc)
|
||||||
>>> test()
|
>>> test()
|
||||||
9
|
0
|
||||||
|
|
||||||
|
return in function under finally should be ok.
|
||||||
|
|
||||||
>>> def test():
|
>>> def test():
|
||||||
... for abc in range(10):
|
... try:
|
||||||
... try:
|
... pass
|
||||||
... pass
|
... finally:
|
||||||
... finally:
|
... def f():
|
||||||
... try:
|
... return 42
|
||||||
... continue
|
... print(f())
|
||||||
... except:
|
|
||||||
... pass
|
|
||||||
... print(abc)
|
|
||||||
>>> test()
|
>>> test()
|
||||||
9
|
42
|
||||||
|
|
||||||
|
combine for loop and function def
|
||||||
|
|
||||||
|
return in function under finally should be ok.
|
||||||
|
|
||||||
>>> def test():
|
>>> def test():
|
||||||
... for abc in range(10):
|
... try:
|
||||||
... try:
|
... pass
|
||||||
... pass
|
... finally:
|
||||||
... finally:
|
... for i in range(10):
|
||||||
... try:
|
... def f():
|
||||||
... pass
|
... return 42
|
||||||
... except:
|
... print(f())
|
||||||
... continue
|
|
||||||
... print(abc)
|
|
||||||
>>> test()
|
>>> test()
|
||||||
9
|
42
|
||||||
|
|
||||||
|
>>> def test():
|
||||||
|
... try:
|
||||||
|
... pass
|
||||||
|
... finally:
|
||||||
|
... def f():
|
||||||
|
... for i in range(10):
|
||||||
|
... return 42
|
||||||
|
... print(f())
|
||||||
|
>>> test()
|
||||||
|
42
|
||||||
|
|
||||||
A continue outside loop should not be allowed.
|
A continue outside loop should not be allowed.
|
||||||
|
|
||||||
>>> def foo():
|
>>> def foo():
|
||||||
... try:
|
... try:
|
||||||
... pass
|
|
||||||
... finally:
|
|
||||||
... continue
|
... continue
|
||||||
|
... finally:
|
||||||
|
... pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
SyntaxError: 'continue' not properly in loop
|
SyntaxError: 'continue' not properly in loop
|
||||||
|
@ -2393,7 +2405,88 @@ import unittest
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
|
|
||||||
class SyntaxTestCase(unittest.TestCase):
|
class SyntaxWarningTest(unittest.TestCase):
|
||||||
|
def check_warning(self, code, errtext, filename="<testcase>", mode="exec"):
|
||||||
|
"""Check that compiling code raises SyntaxWarning with errtext.
|
||||||
|
|
||||||
|
errtest is a regular expression that must be present in the
|
||||||
|
text of the warning raised.
|
||||||
|
"""
|
||||||
|
with self.assertWarnsRegex(SyntaxWarning, errtext):
|
||||||
|
compile(code, filename, mode)
|
||||||
|
|
||||||
|
def test_return_in_finally(self):
|
||||||
|
source = textwrap.dedent("""
|
||||||
|
def f():
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
return 42
|
||||||
|
""")
|
||||||
|
self.check_warning(source, "'return' in a 'finally' block")
|
||||||
|
|
||||||
|
source = textwrap.dedent("""
|
||||||
|
def f():
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
return 42
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
self.check_warning(source, "'return' in a 'finally' block")
|
||||||
|
|
||||||
|
source = textwrap.dedent("""
|
||||||
|
def f():
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except:
|
||||||
|
return 42
|
||||||
|
""")
|
||||||
|
self.check_warning(source, "'return' in a 'finally' block")
|
||||||
|
|
||||||
|
def test_break_and_continue_in_finally(self):
|
||||||
|
for kw in ('break', 'continue'):
|
||||||
|
|
||||||
|
source = textwrap.dedent(f"""
|
||||||
|
for abc in range(10):
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
{kw}
|
||||||
|
""")
|
||||||
|
self.check_warning(source, f"'{kw}' in a 'finally' block")
|
||||||
|
|
||||||
|
source = textwrap.dedent(f"""
|
||||||
|
for abc in range(10):
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
{kw}
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
self.check_warning(source, f"'{kw}' in a 'finally' block")
|
||||||
|
|
||||||
|
source = textwrap.dedent(f"""
|
||||||
|
for abc in range(10):
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except:
|
||||||
|
{kw}
|
||||||
|
""")
|
||||||
|
self.check_warning(source, f"'{kw}' in a 'finally' block")
|
||||||
|
|
||||||
|
|
||||||
|
class SyntaxErrorTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def _check_error(self, code, errtext,
|
def _check_error(self, code, errtext,
|
||||||
filename="<testcase>", mode="exec", subclass=None,
|
filename="<testcase>", mode="exec", subclass=None,
|
||||||
|
@ -2401,7 +2494,7 @@ class SyntaxTestCase(unittest.TestCase):
|
||||||
"""Check that compiling code raises SyntaxError with errtext.
|
"""Check that compiling code raises SyntaxError with errtext.
|
||||||
|
|
||||||
errtest is a regular expression that must be present in the
|
errtest is a regular expression that must be present in the
|
||||||
test of the exception raised. If subclass is specified it
|
text of the exception raised. If subclass is specified it
|
||||||
is the expected subclass of SyntaxError (e.g. IndentationError).
|
is the expected subclass of SyntaxError (e.g. IndentationError).
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -422,9 +422,11 @@ class UnparseTestCase(ASTTestCase):
|
||||||
self.check_ast_roundtrip(f"'''{docstring}'''")
|
self.check_ast_roundtrip(f"'''{docstring}'''")
|
||||||
|
|
||||||
def test_constant_tuples(self):
|
def test_constant_tuples(self):
|
||||||
self.check_src_roundtrip(ast.Module([ast.Constant(value=(1,))]), "(1,)")
|
locs = ast.fix_missing_locations
|
||||||
self.check_src_roundtrip(
|
self.check_src_roundtrip(
|
||||||
ast.Module([ast.Constant(value=(1, 2, 3))]), "(1, 2, 3)"
|
locs(ast.Module([ast.Expr(ast.Constant(value=(1,)))])), "(1,)")
|
||||||
|
self.check_src_roundtrip(
|
||||||
|
locs(ast.Module([ast.Expr(ast.Constant(value=(1, 2, 3)))])), "(1, 2, 3)"
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_function_type(self):
|
def test_function_type(self):
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Implement PEP 765: Disallow return/break/continue that exit a finally block.
|
172
Python/ast_opt.c
172
Python/ast_opt.c
|
@ -1,15 +1,28 @@
|
||||||
/* AST Optimizer */
|
/* AST Optimizer */
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "pycore_ast.h" // _PyAST_GetDocString()
|
#include "pycore_ast.h" // _PyAST_GetDocString()
|
||||||
|
#include "pycore_c_array.h" // _Py_CArray_EnsureCapacity()
|
||||||
#include "pycore_format.h" // F_LJUST
|
#include "pycore_format.h" // F_LJUST
|
||||||
#include "pycore_runtime.h" // _Py_STR()
|
#include "pycore_runtime.h" // _Py_STR()
|
||||||
#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString()
|
#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString()
|
||||||
#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString()
|
#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString()
|
||||||
|
|
||||||
|
|
||||||
|
/* See PEP 765 */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
bool in_finally;
|
||||||
|
bool in_funcdef;
|
||||||
|
bool in_loop;
|
||||||
|
} ControlFlowInFinallyContext;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject *filename;
|
||||||
int optimize;
|
int optimize;
|
||||||
int ff_features;
|
int ff_features;
|
||||||
|
int syntax_check_only;
|
||||||
|
|
||||||
|
_Py_c_array_t cf_finally; /* context for PEP 678 check */
|
||||||
|
int cf_finally_used;
|
||||||
} _PyASTOptimizeState;
|
} _PyASTOptimizeState;
|
||||||
|
|
||||||
#define ENTER_RECURSIVE() \
|
#define ENTER_RECURSIVE() \
|
||||||
|
@ -19,6 +32,102 @@ if (Py_EnterRecursiveCall(" during compilation")) { \
|
||||||
|
|
||||||
#define LEAVE_RECURSIVE() Py_LeaveRecursiveCall();
|
#define LEAVE_RECURSIVE() Py_LeaveRecursiveCall();
|
||||||
|
|
||||||
|
static ControlFlowInFinallyContext*
|
||||||
|
get_cf_finally_top(_PyASTOptimizeState *state)
|
||||||
|
{
|
||||||
|
int idx = state->cf_finally_used;
|
||||||
|
return ((ControlFlowInFinallyContext*)state->cf_finally.array) + idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
push_cf_context(_PyASTOptimizeState *state, stmt_ty node, bool finally, bool funcdef, bool loop)
|
||||||
|
{
|
||||||
|
if (_Py_CArray_EnsureCapacity(&state->cf_finally, state->cf_finally_used+1) < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->cf_finally_used++;
|
||||||
|
ControlFlowInFinallyContext *ctx = get_cf_finally_top(state);
|
||||||
|
|
||||||
|
ctx->in_finally = finally;
|
||||||
|
ctx->in_funcdef = funcdef;
|
||||||
|
ctx->in_loop = loop;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pop_cf_context(_PyASTOptimizeState *state)
|
||||||
|
{
|
||||||
|
assert(state->cf_finally_used > 0);
|
||||||
|
state->cf_finally_used--;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
control_flow_in_finally_warning(const char *kw, stmt_ty n, _PyASTOptimizeState *state)
|
||||||
|
{
|
||||||
|
PyObject *msg = PyUnicode_FromFormat("'%s' in a 'finally' block", kw);
|
||||||
|
if (msg == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int ret = _PyErr_EmitSyntaxWarning(msg, state->filename, n->lineno,
|
||||||
|
n->col_offset + 1, n->end_lineno,
|
||||||
|
n->end_col_offset + 1);
|
||||||
|
Py_DECREF(msg);
|
||||||
|
return ret < 0 ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
before_return(_PyASTOptimizeState *state, stmt_ty node_)
|
||||||
|
{
|
||||||
|
if (state->cf_finally_used > 0) {
|
||||||
|
ControlFlowInFinallyContext *ctx = get_cf_finally_top(state);
|
||||||
|
if (ctx->in_finally && ! ctx->in_funcdef) {
|
||||||
|
if (!control_flow_in_finally_warning("return", node_, state)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
before_loop_exit(_PyASTOptimizeState *state, stmt_ty node_, const char *kw)
|
||||||
|
{
|
||||||
|
if (state->cf_finally_used > 0) {
|
||||||
|
ControlFlowInFinallyContext *ctx = get_cf_finally_top(state);
|
||||||
|
if (ctx->in_finally && ! ctx->in_loop) {
|
||||||
|
if (!control_flow_in_finally_warning(kw, node_, state)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PUSH_CONTEXT(S, N, FINALLY, FUNCDEF, LOOP) \
|
||||||
|
if (!push_cf_context((S), (N), (FINALLY), (FUNCDEF), (LOOP))) { \
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define POP_CONTEXT(S) pop_cf_context(S)
|
||||||
|
|
||||||
|
#define BEFORE_FINALLY(S, N) PUSH_CONTEXT((S), (N), true, false, false)
|
||||||
|
#define AFTER_FINALLY(S) POP_CONTEXT(S)
|
||||||
|
#define BEFORE_FUNC_BODY(S, N) PUSH_CONTEXT((S), (N), false, true, false)
|
||||||
|
#define AFTER_FUNC_BODY(S) POP_CONTEXT(S)
|
||||||
|
#define BEFORE_LOOP_BODY(S, N) PUSH_CONTEXT((S), (N), false, false, true)
|
||||||
|
#define AFTER_LOOP_BODY(S) POP_CONTEXT(S)
|
||||||
|
|
||||||
|
#define BEFORE_RETURN(S, N) \
|
||||||
|
if (!before_return((S), (N))) { \
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BEFORE_LOOP_EXIT(S, N, KW) \
|
||||||
|
if (!before_loop_exit((S), (N), (KW))) { \
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
make_const(expr_ty node, PyObject *val, PyArena *arena)
|
make_const(expr_ty node, PyObject *val, PyArena *arena)
|
||||||
{
|
{
|
||||||
|
@ -259,6 +368,9 @@ optimize_format(expr_ty node, PyObject *fmt, asdl_expr_seq *elts, PyArena *arena
|
||||||
static int
|
static int
|
||||||
fold_binop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
|
fold_binop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
|
||||||
{
|
{
|
||||||
|
if (state->syntax_check_only) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
expr_ty lhs, rhs;
|
expr_ty lhs, rhs;
|
||||||
lhs = node->v.BinOp.left;
|
lhs = node->v.BinOp.left;
|
||||||
rhs = node->v.BinOp.right;
|
rhs = node->v.BinOp.right;
|
||||||
|
@ -304,6 +416,9 @@ make_const_tuple(asdl_expr_seq *elts)
|
||||||
static int
|
static int
|
||||||
fold_tuple(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
|
fold_tuple(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
|
||||||
{
|
{
|
||||||
|
if (state->syntax_check_only) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
PyObject *newval;
|
PyObject *newval;
|
||||||
|
|
||||||
if (node->v.Tuple.ctx != Load)
|
if (node->v.Tuple.ctx != Load)
|
||||||
|
@ -508,6 +623,9 @@ astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
|
||||||
CALL(fold_tuple, expr_ty, node_);
|
CALL(fold_tuple, expr_ty, node_);
|
||||||
break;
|
break;
|
||||||
case Name_kind:
|
case Name_kind:
|
||||||
|
if (state->syntax_check_only) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (node_->v.Name.ctx == Load &&
|
if (node_->v.Name.ctx == Load &&
|
||||||
_PyUnicode_EqualToASCIIString(node_->v.Name.id, "__debug__")) {
|
_PyUnicode_EqualToASCIIString(node_->v.Name.id, "__debug__")) {
|
||||||
LEAVE_RECURSIVE();
|
LEAVE_RECURSIVE();
|
||||||
|
@ -570,24 +688,30 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
|
||||||
{
|
{
|
||||||
ENTER_RECURSIVE();
|
ENTER_RECURSIVE();
|
||||||
switch (node_->kind) {
|
switch (node_->kind) {
|
||||||
case FunctionDef_kind:
|
case FunctionDef_kind: {
|
||||||
CALL_SEQ(astfold_type_param, type_param, node_->v.FunctionDef.type_params);
|
CALL_SEQ(astfold_type_param, type_param, node_->v.FunctionDef.type_params);
|
||||||
CALL(astfold_arguments, arguments_ty, node_->v.FunctionDef.args);
|
CALL(astfold_arguments, arguments_ty, node_->v.FunctionDef.args);
|
||||||
|
BEFORE_FUNC_BODY(state, node_);
|
||||||
CALL(astfold_body, asdl_seq, node_->v.FunctionDef.body);
|
CALL(astfold_body, asdl_seq, node_->v.FunctionDef.body);
|
||||||
|
AFTER_FUNC_BODY(state);
|
||||||
CALL_SEQ(astfold_expr, expr, node_->v.FunctionDef.decorator_list);
|
CALL_SEQ(astfold_expr, expr, node_->v.FunctionDef.decorator_list);
|
||||||
if (!(state->ff_features & CO_FUTURE_ANNOTATIONS)) {
|
if (!(state->ff_features & CO_FUTURE_ANNOTATIONS)) {
|
||||||
CALL_OPT(astfold_expr, expr_ty, node_->v.FunctionDef.returns);
|
CALL_OPT(astfold_expr, expr_ty, node_->v.FunctionDef.returns);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AsyncFunctionDef_kind:
|
}
|
||||||
|
case AsyncFunctionDef_kind: {
|
||||||
CALL_SEQ(astfold_type_param, type_param, node_->v.AsyncFunctionDef.type_params);
|
CALL_SEQ(astfold_type_param, type_param, node_->v.AsyncFunctionDef.type_params);
|
||||||
CALL(astfold_arguments, arguments_ty, node_->v.AsyncFunctionDef.args);
|
CALL(astfold_arguments, arguments_ty, node_->v.AsyncFunctionDef.args);
|
||||||
|
BEFORE_FUNC_BODY(state, node_);
|
||||||
CALL(astfold_body, asdl_seq, node_->v.AsyncFunctionDef.body);
|
CALL(astfold_body, asdl_seq, node_->v.AsyncFunctionDef.body);
|
||||||
|
AFTER_FUNC_BODY(state);
|
||||||
CALL_SEQ(astfold_expr, expr, node_->v.AsyncFunctionDef.decorator_list);
|
CALL_SEQ(astfold_expr, expr, node_->v.AsyncFunctionDef.decorator_list);
|
||||||
if (!(state->ff_features & CO_FUTURE_ANNOTATIONS)) {
|
if (!(state->ff_features & CO_FUTURE_ANNOTATIONS)) {
|
||||||
CALL_OPT(astfold_expr, expr_ty, node_->v.AsyncFunctionDef.returns);
|
CALL_OPT(astfold_expr, expr_ty, node_->v.AsyncFunctionDef.returns);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case ClassDef_kind:
|
case ClassDef_kind:
|
||||||
CALL_SEQ(astfold_type_param, type_param, node_->v.ClassDef.type_params);
|
CALL_SEQ(astfold_type_param, type_param, node_->v.ClassDef.type_params);
|
||||||
CALL_SEQ(astfold_expr, expr, node_->v.ClassDef.bases);
|
CALL_SEQ(astfold_expr, expr, node_->v.ClassDef.bases);
|
||||||
|
@ -596,6 +720,7 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
|
||||||
CALL_SEQ(astfold_expr, expr, node_->v.ClassDef.decorator_list);
|
CALL_SEQ(astfold_expr, expr, node_->v.ClassDef.decorator_list);
|
||||||
break;
|
break;
|
||||||
case Return_kind:
|
case Return_kind:
|
||||||
|
BEFORE_RETURN(state, node_);
|
||||||
CALL_OPT(astfold_expr, expr_ty, node_->v.Return.value);
|
CALL_OPT(astfold_expr, expr_ty, node_->v.Return.value);
|
||||||
break;
|
break;
|
||||||
case Delete_kind:
|
case Delete_kind:
|
||||||
|
@ -621,23 +746,32 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
|
||||||
CALL_SEQ(astfold_type_param, type_param, node_->v.TypeAlias.type_params);
|
CALL_SEQ(astfold_type_param, type_param, node_->v.TypeAlias.type_params);
|
||||||
CALL(astfold_expr, expr_ty, node_->v.TypeAlias.value);
|
CALL(astfold_expr, expr_ty, node_->v.TypeAlias.value);
|
||||||
break;
|
break;
|
||||||
case For_kind:
|
case For_kind: {
|
||||||
CALL(astfold_expr, expr_ty, node_->v.For.target);
|
CALL(astfold_expr, expr_ty, node_->v.For.target);
|
||||||
CALL(astfold_expr, expr_ty, node_->v.For.iter);
|
CALL(astfold_expr, expr_ty, node_->v.For.iter);
|
||||||
|
BEFORE_LOOP_BODY(state, node_);
|
||||||
CALL_SEQ(astfold_stmt, stmt, node_->v.For.body);
|
CALL_SEQ(astfold_stmt, stmt, node_->v.For.body);
|
||||||
|
AFTER_LOOP_BODY(state);
|
||||||
CALL_SEQ(astfold_stmt, stmt, node_->v.For.orelse);
|
CALL_SEQ(astfold_stmt, stmt, node_->v.For.orelse);
|
||||||
break;
|
break;
|
||||||
case AsyncFor_kind:
|
}
|
||||||
|
case AsyncFor_kind: {
|
||||||
CALL(astfold_expr, expr_ty, node_->v.AsyncFor.target);
|
CALL(astfold_expr, expr_ty, node_->v.AsyncFor.target);
|
||||||
CALL(astfold_expr, expr_ty, node_->v.AsyncFor.iter);
|
CALL(astfold_expr, expr_ty, node_->v.AsyncFor.iter);
|
||||||
|
BEFORE_LOOP_BODY(state, node_);
|
||||||
CALL_SEQ(astfold_stmt, stmt, node_->v.AsyncFor.body);
|
CALL_SEQ(astfold_stmt, stmt, node_->v.AsyncFor.body);
|
||||||
|
AFTER_LOOP_BODY(state);
|
||||||
CALL_SEQ(astfold_stmt, stmt, node_->v.AsyncFor.orelse);
|
CALL_SEQ(astfold_stmt, stmt, node_->v.AsyncFor.orelse);
|
||||||
break;
|
break;
|
||||||
case While_kind:
|
}
|
||||||
|
case While_kind: {
|
||||||
CALL(astfold_expr, expr_ty, node_->v.While.test);
|
CALL(astfold_expr, expr_ty, node_->v.While.test);
|
||||||
|
BEFORE_LOOP_BODY(state, node_);
|
||||||
CALL_SEQ(astfold_stmt, stmt, node_->v.While.body);
|
CALL_SEQ(astfold_stmt, stmt, node_->v.While.body);
|
||||||
|
AFTER_LOOP_BODY(state);
|
||||||
CALL_SEQ(astfold_stmt, stmt, node_->v.While.orelse);
|
CALL_SEQ(astfold_stmt, stmt, node_->v.While.orelse);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case If_kind:
|
case If_kind:
|
||||||
CALL(astfold_expr, expr_ty, node_->v.If.test);
|
CALL(astfold_expr, expr_ty, node_->v.If.test);
|
||||||
CALL_SEQ(astfold_stmt, stmt, node_->v.If.body);
|
CALL_SEQ(astfold_stmt, stmt, node_->v.If.body);
|
||||||
|
@ -655,18 +789,24 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
|
||||||
CALL_OPT(astfold_expr, expr_ty, node_->v.Raise.exc);
|
CALL_OPT(astfold_expr, expr_ty, node_->v.Raise.exc);
|
||||||
CALL_OPT(astfold_expr, expr_ty, node_->v.Raise.cause);
|
CALL_OPT(astfold_expr, expr_ty, node_->v.Raise.cause);
|
||||||
break;
|
break;
|
||||||
case Try_kind:
|
case Try_kind: {
|
||||||
CALL_SEQ(astfold_stmt, stmt, node_->v.Try.body);
|
CALL_SEQ(astfold_stmt, stmt, node_->v.Try.body);
|
||||||
CALL_SEQ(astfold_excepthandler, excepthandler, node_->v.Try.handlers);
|
CALL_SEQ(astfold_excepthandler, excepthandler, node_->v.Try.handlers);
|
||||||
CALL_SEQ(astfold_stmt, stmt, node_->v.Try.orelse);
|
CALL_SEQ(astfold_stmt, stmt, node_->v.Try.orelse);
|
||||||
|
BEFORE_FINALLY(state, node_);
|
||||||
CALL_SEQ(astfold_stmt, stmt, node_->v.Try.finalbody);
|
CALL_SEQ(astfold_stmt, stmt, node_->v.Try.finalbody);
|
||||||
|
AFTER_FINALLY(state);
|
||||||
break;
|
break;
|
||||||
case TryStar_kind:
|
}
|
||||||
|
case TryStar_kind: {
|
||||||
CALL_SEQ(astfold_stmt, stmt, node_->v.TryStar.body);
|
CALL_SEQ(astfold_stmt, stmt, node_->v.TryStar.body);
|
||||||
CALL_SEQ(astfold_excepthandler, excepthandler, node_->v.TryStar.handlers);
|
CALL_SEQ(astfold_excepthandler, excepthandler, node_->v.TryStar.handlers);
|
||||||
CALL_SEQ(astfold_stmt, stmt, node_->v.TryStar.orelse);
|
CALL_SEQ(astfold_stmt, stmt, node_->v.TryStar.orelse);
|
||||||
|
BEFORE_FINALLY(state, node_);
|
||||||
CALL_SEQ(astfold_stmt, stmt, node_->v.TryStar.finalbody);
|
CALL_SEQ(astfold_stmt, stmt, node_->v.TryStar.finalbody);
|
||||||
|
AFTER_FINALLY(state);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Assert_kind:
|
case Assert_kind:
|
||||||
CALL(astfold_expr, expr_ty, node_->v.Assert.test);
|
CALL(astfold_expr, expr_ty, node_->v.Assert.test);
|
||||||
CALL_OPT(astfold_expr, expr_ty, node_->v.Assert.msg);
|
CALL_OPT(astfold_expr, expr_ty, node_->v.Assert.msg);
|
||||||
|
@ -678,14 +818,18 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
|
||||||
CALL(astfold_expr, expr_ty, node_->v.Match.subject);
|
CALL(astfold_expr, expr_ty, node_->v.Match.subject);
|
||||||
CALL_SEQ(astfold_match_case, match_case, node_->v.Match.cases);
|
CALL_SEQ(astfold_match_case, match_case, node_->v.Match.cases);
|
||||||
break;
|
break;
|
||||||
|
case Break_kind:
|
||||||
|
BEFORE_LOOP_EXIT(state, node_, "break");
|
||||||
|
break;
|
||||||
|
case Continue_kind:
|
||||||
|
BEFORE_LOOP_EXIT(state, node_, "continue");
|
||||||
|
break;
|
||||||
// The following statements don't contain any subexpressions to be folded
|
// The following statements don't contain any subexpressions to be folded
|
||||||
case Import_kind:
|
case Import_kind:
|
||||||
case ImportFrom_kind:
|
case ImportFrom_kind:
|
||||||
case Global_kind:
|
case Global_kind:
|
||||||
case Nonlocal_kind:
|
case Nonlocal_kind:
|
||||||
case Pass_kind:
|
case Pass_kind:
|
||||||
case Break_kind:
|
|
||||||
case Continue_kind:
|
|
||||||
break;
|
break;
|
||||||
// No default case, so the compiler will emit a warning if new statement
|
// No default case, so the compiler will emit a warning if new statement
|
||||||
// kinds are added without being handled here
|
// kinds are added without being handled here
|
||||||
|
@ -828,14 +972,22 @@ astfold_type_param(type_param_ty node_, PyArena *ctx_, _PyASTOptimizeState *stat
|
||||||
#undef CALL_SEQ
|
#undef CALL_SEQ
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyAST_Optimize(mod_ty mod, PyArena *arena, int optimize, int ff_features)
|
_PyAST_Optimize(mod_ty mod, PyArena *arena, PyObject *filename, int optimize,
|
||||||
|
int ff_features, int syntax_check_only)
|
||||||
{
|
{
|
||||||
_PyASTOptimizeState state;
|
_PyASTOptimizeState state;
|
||||||
|
memset(&state, 0, sizeof(_PyASTOptimizeState));
|
||||||
|
state.filename = filename;
|
||||||
state.optimize = optimize;
|
state.optimize = optimize;
|
||||||
state.ff_features = ff_features;
|
state.ff_features = ff_features;
|
||||||
|
state.syntax_check_only = syntax_check_only;
|
||||||
|
if (_Py_CArray_Init(&state.cf_finally, sizeof(ControlFlowInFinallyContext), 20) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int ret = astfold_mod(mod, arena, &state);
|
int ret = astfold_mod(mod, arena, &state);
|
||||||
assert(ret || PyErr_Occurred());
|
assert(ret || PyErr_Occurred());
|
||||||
|
|
||||||
|
_Py_CArray_Fini(&state.cf_finally);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -833,45 +833,35 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename,
|
||||||
if (is_ast == -1)
|
if (is_ast == -1)
|
||||||
goto error;
|
goto error;
|
||||||
if (is_ast) {
|
if (is_ast) {
|
||||||
if ((flags & PyCF_OPTIMIZED_AST) == PyCF_ONLY_AST) {
|
PyArena *arena = _PyArena_New();
|
||||||
if (PyAst_CheckMode(source, compile_mode) < 0) {
|
if (arena == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & PyCF_ONLY_AST) {
|
||||||
|
mod_ty mod = PyAST_obj2mod(source, arena, compile_mode);
|
||||||
|
if (mod == NULL || !_PyAST_Validate(mod)) {
|
||||||
|
_PyArena_Free(arena);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
// return an un-optimized AST
|
int syntax_check_only = ((flags & PyCF_OPTIMIZED_AST) == PyCF_ONLY_AST); /* unoptiomized AST */
|
||||||
result = Py_NewRef(source);
|
if (_PyCompile_AstOptimize(mod, filename, &cf, optimize,
|
||||||
|
arena, syntax_check_only) < 0) {
|
||||||
|
_PyArena_Free(arena);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
result = PyAST_mod2obj(mod);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Return an optimized AST or code object
|
mod_ty mod = PyAST_obj2mod(source, arena, compile_mode);
|
||||||
|
if (mod == NULL || !_PyAST_Validate(mod)) {
|
||||||
PyArena *arena = _PyArena_New();
|
_PyArena_Free(arena);
|
||||||
if (arena == NULL) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
result = (PyObject*)_PyAST_Compile(mod, filename,
|
||||||
if (flags & PyCF_ONLY_AST) {
|
&cf, optimize, arena);
|
||||||
mod_ty mod = PyAST_obj2mod(source, arena, compile_mode);
|
|
||||||
if (mod == NULL || !_PyAST_Validate(mod)) {
|
|
||||||
_PyArena_Free(arena);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (_PyCompile_AstOptimize(mod, filename, &cf, optimize,
|
|
||||||
arena) < 0) {
|
|
||||||
_PyArena_Free(arena);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
result = PyAST_mod2obj(mod);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mod_ty mod = PyAST_obj2mod(source, arena, compile_mode);
|
|
||||||
if (mod == NULL || !_PyAST_Validate(mod)) {
|
|
||||||
_PyArena_Free(arena);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
result = (PyObject*)_PyAST_Compile(mod, filename,
|
|
||||||
&cf, optimize, arena);
|
|
||||||
}
|
|
||||||
_PyArena_Free(arena);
|
|
||||||
}
|
}
|
||||||
|
_PyArena_Free(arena);
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,7 @@ compiler_setup(compiler *c, mod_ty mod, PyObject *filename,
|
||||||
c->c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize;
|
c->c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize;
|
||||||
c->c_save_nested_seqs = false;
|
c->c_save_nested_seqs = false;
|
||||||
|
|
||||||
if (!_PyAST_Optimize(mod, arena, c->c_optimize, merged)) {
|
if (!_PyAST_Optimize(mod, arena, filename, c->c_optimize, merged, 0)) {
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
c->c_st = _PySymtable_Build(mod, filename, &c->c_future);
|
c->c_st = _PySymtable_Build(mod, filename, &c->c_future);
|
||||||
|
@ -1392,7 +1392,7 @@ _PyAST_Compile(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags,
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyCompile_AstOptimize(mod_ty mod, PyObject *filename, PyCompilerFlags *cf,
|
_PyCompile_AstOptimize(mod_ty mod, PyObject *filename, PyCompilerFlags *cf,
|
||||||
int optimize, PyArena *arena)
|
int optimize, PyArena *arena, int no_const_folding)
|
||||||
{
|
{
|
||||||
_PyFutureFeatures future;
|
_PyFutureFeatures future;
|
||||||
if (!_PyFuture_FromAST(mod, filename, &future)) {
|
if (!_PyFuture_FromAST(mod, filename, &future)) {
|
||||||
|
@ -1402,7 +1402,7 @@ _PyCompile_AstOptimize(mod_ty mod, PyObject *filename, PyCompilerFlags *cf,
|
||||||
if (optimize == -1) {
|
if (optimize == -1) {
|
||||||
optimize = _Py_GetConfig()->optimization_level;
|
optimize = _Py_GetConfig()->optimization_level;
|
||||||
}
|
}
|
||||||
if (!_PyAST_Optimize(mod, arena, optimize, flags)) {
|
if (!_PyAST_Optimize(mod, arena, filename, optimize, flags, no_const_folding)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1495,11 +1495,10 @@ Py_CompileStringObject(const char *str, PyObject *filename, int start,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (flags && (flags->cf_flags & PyCF_ONLY_AST)) {
|
if (flags && (flags->cf_flags & PyCF_ONLY_AST)) {
|
||||||
if ((flags->cf_flags & PyCF_OPTIMIZED_AST) == PyCF_OPTIMIZED_AST) {
|
int syntax_check_only = ((flags->cf_flags & PyCF_OPTIMIZED_AST) == PyCF_ONLY_AST); /* unoptiomized AST */
|
||||||
if (_PyCompile_AstOptimize(mod, filename, flags, optimize, arena) < 0) {
|
if (_PyCompile_AstOptimize(mod, filename, flags, optimize, arena, syntax_check_only) < 0) {
|
||||||
_PyArena_Free(arena);
|
_PyArena_Free(arena);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
PyObject *result = PyAST_mod2obj(mod);
|
PyObject *result = PyAST_mod2obj(mod);
|
||||||
_PyArena_Free(arena);
|
_PyArena_Free(arena);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue