Thanks to visit codestin.com
Credit goes to github.com

Skip to content

bpo-42246: Make sure that line number is correct after a return, as required by PEP 626 #23495

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

Merged

Conversation

markshannon
Copy link
Member

@markshannon markshannon commented Nov 24, 2020

This PR ensures that f_lineno can be correctly computed after a return, by ensuring that all compiler generated return instructions
have a line number.

Any block that has no line numbers and has only one predecessor can inherit the line number from its predecessor.
Any block ending in a return has no successors, and thus can be safely duplicated.

By duplicating all blocks that end in a return, but have no line number, those blocks will have only one predecessor and thus can inherit its predecessor's line number, meaning that all implicit returns now have a line number.

For example,

2. if cond:
3.     a

currently compiles to:

  2           0 LOAD_FAST                0 (cond)
              2 POP_JUMP_IF_FALSE        8

  3           4 LOAD_GLOBAL              0 (a)
              6 POP_TOP
None    >>    8 LOAD_CONST               0 (None)
             10 RETURN_VALUE

with this PR it compiles to:

  2           0 LOAD_FAST                0 (cond)
              2 POP_JUMP_IF_FALSE       12

  3           4 LOAD_GLOBAL              0 (a)
              6 POP_TOP
              8 LOAD_CONST               0 (None)
             10 RETURN_VALUE

  2     >>   12 LOAD_CONST               0 (None)
             14 RETURN_VALUE

which is equivalent, but produces the correct line number when not cond.

https://bugs.python.org/issue42246

@markshannon markshannon force-pushed the correct_lineno_after_return_or_raise branch from 63c5fa2 to b142622 Compare November 25, 2020 11:14
Copy link
Member

@gpshead gpshead left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM though it'd be a good idea to have more eyeballs than just mine on this. 👍

@markshannon
Copy link
Member Author

@pablogsal would you mind taking a quick look at this?

@pablogsal
Copy link
Member

@pablogsal would you mind taking a quick look at this?

Yep, will review this today

Python/compile.c Outdated
Comment on lines 6509 to 6512
static int
is_exit_without_lineno(basicblock *b) {
return b->b_exit && b->b_instr[0].i_lineno < 0;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static int
is_exit_without_lineno(basicblock *b) {
return b->b_exit && b->b_instr[0].i_lineno < 0;
}
static inline int
is_exit_without_lineno(basicblock *b) {
return b->b_exit && b->b_instr[0].i_lineno < 0;
}

Python/compile.c Outdated
if (result == NULL) {
return NULL;
}
for(int i = 0; i < block->b_iused; i++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for(int i = 0; i < block->b_iused; i++) {
for (int i = 0; i < block->b_iused; i++) {

Python/compile.c Outdated
}
}
return 0;
}


static int
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static int
static inline int

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've deleted the function and inlined its body of the function. It was only used in once place.

@@ -2747,6 +2770,7 @@ compiler_for(struct compiler *c, stmt_ty s)
ADDOP(c, GET_ITER);
compiler_use_next_block(c, start);
ADDOP_JUMP(c, FOR_ITER, cleanup);
compiler_use_next_block(c, body);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed? To repeat the "body" if there is an implicit return? If so, could you add an example to the test?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python/compile.c Outdated
*/
for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) {
if (b->b_iused > 0 && is_jump(&b->b_instr[b->b_iused-1])) {
switch(b->b_instr[b->b_iused-1].i_opcode) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
switch(b->b_instr[b->b_iused-1].i_opcode) {
switch (b->b_instr[b->b_iused-1].i_opcode) {

@pablogsal
Copy link
Member

LGTM in general but I left some minor suggestions

@markshannon markshannon merged commit 5977a79 into python:master Dec 2, 2020
@markshannon markshannon deleted the correct_lineno_after_return_or_raise branch December 2, 2020 13:31
adorilson pushed a commit to adorilson/cpython that referenced this pull request Mar 13, 2021
…equired by PEP 626 (pythonGH-23495)

Make sure that line number is correct after a return, as defined by PEP 626.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants