summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorNick Coghlan <ncoghlan@gmail.com>2020-11-07 12:35:17 (GMT)
committerGitHub <noreply@github.com>2020-11-07 12:35:17 (GMT)
commit8805a4dad201473599416b2c265802b8885f69b8 (patch)
tree5d1c8947ac9733025aaa1cb58b62625ac4a6736f /Python
parentee2549c2ba8bae00f2b2fea8a39c6dfbd1d06520 (diff)
downloadcpython-8805a4dad201473599416b2c265802b8885f69b8.zip
cpython-8805a4dad201473599416b2c265802b8885f69b8.tar.gz
cpython-8805a4dad201473599416b2c265802b8885f69b8.tar.bz2
bpo-42282: Fold constants inside named expressions (GH-23190)
* The AST optimiser wasn't descending into named expressions, so any constant subexpressions weren't being folded at compile time * Remove "default:" clauses inside the AST optimiser code to reduce the risk of similar bugs passing unnoticed in future compiler changes
Diffstat (limited to 'Python')
-rw-r--r--Python/ast_opt.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/Python/ast_opt.c b/Python/ast_opt.c
index 22ca6f2..8c958ca 100644
--- a/Python/ast_opt.c
+++ b/Python/ast_opt.c
@@ -7,6 +7,8 @@
static int
make_const(expr_ty node, PyObject *val, PyArena *arena)
{
+ // Even if no new value was calculated, make_const may still
+ // need to clear an error (e.g. for division by zero)
if (val == NULL) {
if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
return 0;
@@ -49,7 +51,7 @@ fold_unaryop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
of !=. Detecting such cases doesn't seem worthwhile.
Python uses </> for 'is subset'/'is superset' operations on sets.
They don't satisfy not folding laws. */
- int op = asdl_seq_GET(arg->v.Compare.ops, 0);
+ cmpop_ty op = asdl_seq_GET(arg->v.Compare.ops, 0);
switch (op) {
case Is:
op = IsNot;
@@ -63,8 +65,17 @@ fold_unaryop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
case NotIn:
op = In;
break;
- default:
- op = 0;
+ // The remaining comparison operators can't be safely inverted
+ case Eq:
+ case NotEq:
+ case Lt:
+ case LtE:
+ case Gt:
+ case GtE:
+ op = 0; // The AST enums leave "0" free as an "unused" marker
+ break;
+ // No default case, so the compiler will emit a warning if new
+ // comparison operators are added without being handled here
}
if (op) {
asdl_seq_SET(arg->v.Compare.ops, 0, op);
@@ -224,7 +235,7 @@ fold_binop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
PyObject *lv = lhs->v.Constant.value;
PyObject *rv = rhs->v.Constant.value;
- PyObject *newval;
+ PyObject *newval = NULL;
switch (node->v.BinOp.op) {
case Add:
@@ -263,8 +274,11 @@ fold_binop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state)
case BitAnd:
newval = PyNumber_And(lv, rv);
break;
- default: // Unknown operator
+ // No builtin constants implement the following operators
+ case MatMult:
return 1;
+ // No default case, so the compiler will emit a warning if new binary
+ // operators are added without being handled here
}
return make_const(node, newval, arena);
@@ -457,8 +471,11 @@ astfold_mod(mod_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
case Expression_kind:
CALL(astfold_expr, expr_ty, node_->v.Expression.body);
break;
- default:
+ // The following top level nodes don't participate in constant folding
+ case FunctionType_kind:
break;
+ // No default case, so the compiler will emit a warning if new top level
+ // compilation nodes are added without being handled here
}
return 1;
}
@@ -567,8 +584,14 @@ astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
return make_const(node_, PyBool_FromLong(!state->optimize), ctx_);
}
break;
- default:
+ case NamedExpr_kind:
+ CALL(astfold_expr, expr_ty, node_->v.NamedExpr.value);
+ break;
+ case Constant_kind:
+ // Already a constant, nothing further to do
break;
+ // No default case, so the compiler will emit a warning if new expression
+ // kinds are added without being handled here
}
return 1;
}
@@ -686,8 +709,17 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
case Expr_kind:
CALL(astfold_expr, expr_ty, node_->v.Expr.value);
break;
- default:
- break;
+ // The following statements don't contain any subexpressions to be folded
+ case Import_kind:
+ case ImportFrom_kind:
+ case Global_kind:
+ case Nonlocal_kind:
+ case Pass_kind:
+ case Break_kind:
+ case Continue_kind:
+ break;
+ // No default case, so the compiler will emit a warning if new statement
+ // kinds are added without being handled here
}
return 1;
}
@@ -700,8 +732,8 @@ astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, _PyASTOptimizeState
CALL_OPT(astfold_expr, expr_ty, node_->v.ExceptHandler.type);
CALL_SEQ(astfold_stmt, stmt, node_->v.ExceptHandler.body);
break;
- default:
- break;
+ // No default case, so the compiler will emit a warning if new handler
+ // kinds are added without being handled here
}
return 1;
}