diff options
author | Pablo Galindo <Pablogsal@gmail.com> | 2019-07-15 09:15:01 (GMT) |
---|---|---|
committer | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2019-07-15 09:15:01 (GMT) |
commit | 18c5f9d44dde37c0fae5585a604c6027825252d2 (patch) | |
tree | 5646a1af289769cc336aa9b4c8441dca80f43ff1 /Python | |
parent | cd6e83b4810549c308ab2d7315dbab526e35ccf6 (diff) | |
download | cpython-18c5f9d44dde37c0fae5585a604c6027825252d2.zip cpython-18c5f9d44dde37c0fae5585a604c6027825252d2.tar.gz cpython-18c5f9d44dde37c0fae5585a604c6027825252d2.tar.bz2 |
bpo-37500: Make sure dead code does not generate bytecode but also detect syntax errors (GH-14612)
https://bugs.python.org/issue37500
Add a new field to the compiler structure that allows to be configured
so no bytecode is emitted. In this way is possible to detect errors by
walking the nodes while preserving optimizations.
https://bugs.python.org/issue37500
Diffstat (limited to 'Python')
-rw-r--r-- | Python/compile.c | 69 |
1 files changed, 64 insertions, 5 deletions
diff --git a/Python/compile.c b/Python/compile.c index 9cce8ae..0336959 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -161,6 +161,11 @@ struct compiler { int c_optimize; /* optimization level */ int c_interactive; /* true if in interactive mode */ int c_nestlevel; + int c_do_not_emit_bytecode; /* The compiler won't emit any bytecode + if this value is different from zero. + This can be used to temporarily visit + nodes without emitting bytecode to + check only errors. */ PyObject *c_const_cache; /* Python dict holding all constants, including names tuple */ @@ -340,6 +345,7 @@ PyAST_CompileObject(mod_ty mod, PyObject *filename, PyCompilerFlags *flags, c.c_flags = flags; c.c_optimize = (optimize == -1) ? config->optimization_level : optimize; c.c_nestlevel = 0; + c.c_do_not_emit_bytecode = 0; if (!_PyAST_Optimize(mod, arena, c.c_optimize)) { goto finally; @@ -1152,6 +1158,9 @@ compiler_addop(struct compiler *c, int opcode) struct instr *i; int off; assert(!HAS_ARG(opcode)); + if (c->c_do_not_emit_bytecode) { + return 1; + } off = compiler_next_instr(c, c->u->u_curblock); if (off < 0) return 0; @@ -1305,6 +1314,10 @@ merge_consts_recursive(struct compiler *c, PyObject *o) static Py_ssize_t compiler_add_const(struct compiler *c, PyObject *o) { + if (c->c_do_not_emit_bytecode) { + return 0; + } + PyObject *key = merge_consts_recursive(c, o); if (key == NULL) { return -1; @@ -1318,6 +1331,10 @@ compiler_add_const(struct compiler *c, PyObject *o) static int compiler_addop_load_const(struct compiler *c, PyObject *o) { + if (c->c_do_not_emit_bytecode) { + return 1; + } + Py_ssize_t arg = compiler_add_const(c, o); if (arg < 0) return 0; @@ -1328,6 +1345,10 @@ static int compiler_addop_o(struct compiler *c, int opcode, PyObject *dict, PyObject *o) { + if (c->c_do_not_emit_bytecode) { + return 1; + } + Py_ssize_t arg = compiler_add_o(c, dict, o); if (arg < 0) return 0; @@ -1339,6 +1360,11 @@ compiler_addop_name(struct compiler *c, int opcode, PyObject *dict, PyObject *o) { Py_ssize_t arg; + + if (c->c_do_not_emit_bytecode) { + return 1; + } + PyObject *mangled = _Py_Mangle(c->u->u_private, o); if (!mangled) return 0; @@ -1359,6 +1385,10 @@ compiler_addop_i(struct compiler *c, int opcode, Py_ssize_t oparg) struct instr *i; int off; + if (c->c_do_not_emit_bytecode) { + return 1; + } + /* oparg value is unsigned, but a signed C int is usually used to store it in the C code (like Python/ceval.c). @@ -1385,6 +1415,10 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute) struct instr *i; int off; + if (c->c_do_not_emit_bytecode) { + return 1; + } + assert(HAS_ARG(opcode)); assert(b != NULL); off = compiler_next_instr(c, c->u->u_curblock); @@ -1519,6 +1553,17 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute) } \ } +/* These macros allows to check only for errors and not emmit bytecode + * while visiting nodes. +*/ + +#define BEGIN_DO_NOT_EMIT_BYTECODE { \ + c->c_do_not_emit_bytecode++; + +#define END_DO_NOT_EMIT_BYTECODE \ + c->c_do_not_emit_bytecode--; \ +} + /* Search if variable annotations are present statically in a block. */ static int @@ -2546,13 +2591,23 @@ compiler_if(struct compiler *c, stmt_ty s) return 0; constant = expr_constant(s->v.If.test); - /* constant = 0: "if 0" Leave the optimizations to - * the pephole optimizer to check for syntax errors - * in the block. + /* constant = 0: "if 0" * constant = 1: "if 1", "if 2", ... * constant = -1: rest */ - if (constant == 1) { + if (constant == 0) { + BEGIN_DO_NOT_EMIT_BYTECODE + VISIT_SEQ(c, stmt, s->v.If.body); + END_DO_NOT_EMIT_BYTECODE + if (s->v.If.orelse) { + VISIT_SEQ(c, stmt, s->v.If.orelse); + } + } else if (constant == 1) { VISIT_SEQ(c, stmt, s->v.If.body); + if (s->v.If.orelse) { + BEGIN_DO_NOT_EMIT_BYTECODE + VISIT_SEQ(c, stmt, s->v.If.orelse); + END_DO_NOT_EMIT_BYTECODE + } } else { if (asdl_seq_LEN(s->v.If.orelse)) { next = compiler_new_block(c); @@ -2662,8 +2717,12 @@ compiler_while(struct compiler *c, stmt_ty s) int constant = expr_constant(s->v.While.test); if (constant == 0) { - if (s->v.While.orelse) + BEGIN_DO_NOT_EMIT_BYTECODE + VISIT_SEQ(c, stmt, s->v.While.body); + END_DO_NOT_EMIT_BYTECODE + if (s->v.While.orelse) { VISIT_SEQ(c, stmt, s->v.While.orelse); + } return 1; } loop = compiler_new_block(c); |