-
-
Notifications
You must be signed in to change notification settings - Fork 34.2k
bpo-1875, bpo-32477: Raise SyntaxError in invalid blocks that will be optimized away. #14116
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
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 |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| A :exc:`SyntaxError` is now always raised if a code blocks that will be | ||
| optimized away (e.g. if conditions that are always false) contains syntax | ||
| errors. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -200,7 +200,6 @@ static int compiler_slice(struct compiler *, expr_ty); | |
|
|
||
| static int inplace_binop(operator_ty); | ||
| static int are_all_items_const(asdl_seq *, Py_ssize_t, Py_ssize_t); | ||
| static int expr_constant(expr_ty); | ||
|
|
||
| static int compiler_with(struct compiler *, stmt_ty, int); | ||
| static int compiler_async_with(struct compiler *, stmt_ty, int); | ||
|
|
@@ -2555,10 +2554,22 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) | |
| /* fallback to general implementation */ | ||
| break; | ||
| } | ||
| default: | ||
| default: { | ||
| if (e->kind == Constant_kind) { | ||
|
Member
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. Shouldn't this be it's on case in the previous switch? (case Constant_kind: )
Member
Author
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. Good point! |
||
| int is_true = PyObject_IsTrue(e->v.Constant.value); | ||
| if (is_true < 0) { | ||
| return 0; | ||
| } | ||
| if (is_true == cond) { | ||
| ADDOP_JABS(c, JUMP_ABSOLUTE, next); | ||
| NEXT_BLOCK(c); | ||
| } | ||
| return 1; | ||
| } | ||
| /* fallback to general implementation */ | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| /* general implementation */ | ||
| VISIT(c, expr, e); | ||
|
|
@@ -2646,48 +2657,24 @@ static int | |
| compiler_if(struct compiler *c, stmt_ty s) | ||
| { | ||
| basicblock *end, *next; | ||
| int constant; | ||
| assert(s->kind == If_kind); | ||
| end = compiler_new_block(c); | ||
| next = end = compiler_new_block(c); | ||
| if (end == NULL) | ||
| return 0; | ||
|
|
||
| constant = expr_constant(s->v.If.test); | ||
| /* constant = 0: "if 0" | ||
| * constant = 1: "if 1", "if 2", ... | ||
| * constant = -1: rest */ | ||
| if (constant == 0) { | ||
| BEGIN_DO_NOT_EMIT_BYTECODE | ||
|
Member
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. You can remove this macro and the attribute in the compiler struct if is not used anymore |
||
| 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); | ||
| if (next == NULL) | ||
| return 0; | ||
| } | ||
| else { | ||
| next = end; | ||
| } | ||
| if (!compiler_jump_if(c, s->v.If.test, next, 0)) { | ||
| if (asdl_seq_LEN(s->v.If.orelse)) { | ||
| next = compiler_new_block(c); | ||
| if (next == NULL) | ||
pablogsal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return 0; | ||
| } | ||
| VISIT_SEQ(c, stmt, s->v.If.body); | ||
| if (asdl_seq_LEN(s->v.If.orelse)) { | ||
| ADDOP_JREL(c, JUMP_FORWARD, end); | ||
| compiler_use_next_block(c, next); | ||
| VISIT_SEQ(c, stmt, s->v.If.orelse); | ||
| } | ||
| } | ||
| if (!compiler_jump_if(c, s->v.If.test, next, 0)) { | ||
| return 0; | ||
| } | ||
| VISIT_SEQ(c, stmt, s->v.If.body); | ||
| if (asdl_seq_LEN(s->v.If.orelse)) { | ||
| ADDOP_JREL(c, JUMP_FORWARD, end); | ||
| compiler_use_next_block(c, next); | ||
| VISIT_SEQ(c, stmt, s->v.If.orelse); | ||
| } | ||
| compiler_use_next_block(c, end); | ||
| return 1; | ||
|
|
@@ -2777,59 +2764,32 @@ compiler_async_for(struct compiler *c, stmt_ty s) | |
| static int | ||
| compiler_while(struct compiler *c, stmt_ty s) | ||
| { | ||
| basicblock *loop, *orelse, *end, *anchor = NULL; | ||
| int constant = expr_constant(s->v.While.test); | ||
| basicblock *loop, *orelse = NULL, *end, *anchor; | ||
|
|
||
| if (constant == 0) { | ||
| BEGIN_DO_NOT_EMIT_BYTECODE | ||
| // Push a dummy block so the VISIT_SEQ knows that we are | ||
| // inside a while loop so it can correctly evaluate syntax | ||
| // errors. | ||
| if (!compiler_push_fblock(c, WHILE_LOOP, NULL, NULL, NULL)) { | ||
| return 0; | ||
| } | ||
| VISIT_SEQ(c, stmt, s->v.While.body); | ||
| // Remove the dummy block now that is not needed. | ||
| compiler_pop_fblock(c, WHILE_LOOP, NULL); | ||
| 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); | ||
| end = compiler_new_block(c); | ||
| if (constant == -1) { | ||
| anchor = compiler_new_block(c); | ||
| if (anchor == NULL) | ||
| return 0; | ||
| } | ||
| if (loop == NULL || end == NULL) | ||
| anchor = compiler_new_block(c); | ||
| if (loop == NULL || end == NULL || anchor == NULL) | ||
pablogsal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return 0; | ||
| if (s->v.While.orelse) { | ||
| orelse = compiler_new_block(c); | ||
| if (orelse == NULL) | ||
| return 0; | ||
| } | ||
| else | ||
| orelse = NULL; | ||
|
|
||
| compiler_use_next_block(c, loop); | ||
| if (!compiler_push_fblock(c, WHILE_LOOP, loop, end, NULL)) | ||
| return 0; | ||
| if (constant == -1) { | ||
| if (!compiler_jump_if(c, s->v.While.test, anchor, 0)) | ||
| return 0; | ||
| } | ||
| if (!compiler_jump_if(c, s->v.While.test, anchor, 0)) | ||
pablogsal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return 0; | ||
| VISIT_SEQ(c, stmt, s->v.While.body); | ||
| ADDOP_JABS(c, JUMP_ABSOLUTE, loop); | ||
|
|
||
| /* XXX should the two POP instructions be in a separate block | ||
| if there is no else clause ? | ||
| */ | ||
|
|
||
| if (constant == -1) | ||
| compiler_use_next_block(c, anchor); | ||
| compiler_use_next_block(c, anchor); | ||
| compiler_pop_fblock(c, WHILE_LOOP, loop); | ||
|
|
||
| if (orelse != NULL) /* what if orelse is just pass? */ | ||
|
|
@@ -4669,21 +4629,6 @@ compiler_visit_keyword(struct compiler *c, keyword_ty k) | |
| return 1; | ||
| } | ||
|
|
||
| /* Test whether expression is constant. For constants, report | ||
| whether they are true or false. | ||
|
|
||
| Return values: 1 for true, 0 for false, -1 for non-constant. | ||
| */ | ||
|
|
||
| static int | ||
| expr_constant(expr_ty e) | ||
| { | ||
| if (e->kind == Constant_kind) { | ||
| return PyObject_IsTrue(e->v.Constant.value); | ||
| } | ||
| return -1; | ||
| } | ||
|
|
||
| static int | ||
| compiler_with_except_finish(struct compiler *c) { | ||
| basicblock *exit; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'if code blocks' or 'if a code block'