-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
bpo-37500: Make sure dead code does not generate bytecode but also detect syntax errors #14612
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
23efd8e
b58ad27
b314b72
b47c977
0662108
d6ffa31
169ce59
58322a5
125c278
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 { \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
instead of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will update the PR soon. |
||
c->c_do_not_emit_bytecode++; | ||
|
||
#define END_DO_NOT_EMIT_BYTECODE \ | ||
c->c_do_not_emit_bytecode--; \ | ||
} | ||
pablogsal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/* 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) { | ||
pablogsal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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) { | ||
pablogsal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
VISIT_SEQ(c, stmt, s->v.While.orelse); | ||
} | ||
return 1; | ||
} | ||
loop = compiler_new_block(c); | ||
|
Uh oh!
There was an error while loading. Please reload this page.