GH-123044: Give the POP_TOP after a case test a location in the body, not the pattern. (GH-130627)

This commit is contained in:
Mark Shannon 2025-03-10 17:31:16 +00:00 committed by GitHub
parent 91d6db7ee0
commit be046ee6e0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 52 additions and 6 deletions

View file

@ -58,6 +58,7 @@ typedef struct {
.end_col_offset = (n)->end_col_offset }
static const _Py_SourceLocation NO_LOCATION = {-1, -1, -1, -1};
static const _Py_SourceLocation NEXT_LOCATION = {-2, -2, -2, -2};
/* __future__ information */
typedef struct {

View file

@ -1681,6 +1681,35 @@ class TestBranchAndJumpEvents(CheckEvents):
('branch left', 'func', 12, 12)])
def test_match(self):
def func(v=1):
x = 0
for v in range(4):
match v:
case 1:
x += 1
case 2:
x += 2
case _:
x += 3
return x
self.check_events(func, recorders = BRANCHES_RECORDERS, expected = [
('branch left', 'func', 2, 2),
('branch right', 'func', 4, 6),
('branch right', 'func', 6, 8),
('branch left', 'func', 2, 2),
('branch left', 'func', 4, 5),
('branch left', 'func', 2, 2),
('branch right', 'func', 4, 6),
('branch left', 'func', 6, 7),
('branch left', 'func', 2, 2),
('branch right', 'func', 4, 6),
('branch right', 'func', 6, 8),
('branch right', 'func', 2, 10)])
class TestBranchConsistency(MonitoringTestBase, unittest.TestCase):
def check_branches(self, run_func, test_func=None, tool=TEST_TOOL, recorders=BRANCH_OFFSET_RECORDERS):

View file

@ -0,0 +1,2 @@
Make sure that the location of branch targets in ``match`` cases is in the
body, not the pattern.

View file

@ -291,6 +291,7 @@ write_location_info_entry(struct assembler* a, location loc, int isize)
RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, len*2));
}
if (loc.lineno < 0) {
assert(loc.lineno == NO_LOCATION.lineno);
write_location_info_none(a, isize);
return SUCCESS;
}
@ -341,6 +342,18 @@ assemble_location_info(struct assembler *a, instr_sequence *instrs,
{
a->a_lineno = firstlineno;
location loc = NO_LOCATION;
for (int i = instrs->s_used-1; i >= 0; i--) {
instruction *instr = &instrs->s_instrs[i];
if (same_location(instr->i_loc, NEXT_LOCATION)) {
if (IS_TERMINATOR_OPCODE(instr->i_opcode)) {
instr->i_loc = NO_LOCATION;
}
else {
assert(i < instrs->s_used-1);
instr->i_loc = instr[1].i_loc;
}
}
}
int size = 0;
for (int i = 0; i < instrs->s_used; i++) {
instruction *instr = &instrs->s_instrs[i];

View file

@ -6124,7 +6124,8 @@ codegen_match_inner(compiler *c, stmt_ty s, pattern_context *pc)
}
// Success! Pop the subject off, we're done with it:
if (i != cases - has_default - 1) {
ADDOP(c, LOC(m->pattern), POP_TOP);
/* Use the next location to give better locations for branch events */
ADDOP(c, NEXT_LOCATION, POP_TOP);
}
VISIT_SEQ(c, stmt, m->body);
ADDOP_JUMP(c, NO_LOCATION, JUMP, end);

View file

@ -1078,8 +1078,8 @@ basicblock_remove_redundant_nops(basicblock *bb) {
location next_loc = NO_LOCATION;
for (int next_i=0; next_i < next->b_iused; next_i++) {
cfg_instr *instr = &next->b_instr[next_i];
if (instr->i_opcode == NOP && instr->i_loc.lineno == NO_LOCATION.lineno) {
/* Skip over NOPs without location, they will be removed */
if (instr->i_opcode == NOP && instr->i_loc.lineno < 0) {
/* Skip over NOPs without a location, they will be removed */
continue;
}
next_loc = instr->i_loc;
@ -2976,7 +2976,7 @@ propagate_line_numbers(basicblock *entryblock) {
location prev_location = NO_LOCATION;
for (int i = 0; i < b->b_iused; i++) {
if (b->b_instr[i].i_loc.lineno < 0) {
if (b->b_instr[i].i_loc.lineno == NO_LOCATION.lineno) {
b->b_instr[i].i_loc = prev_location;
}
else {
@ -2985,7 +2985,7 @@ propagate_line_numbers(basicblock *entryblock) {
}
if (BB_HAS_FALLTHROUGH(b) && b->b_next->b_predecessors == 1) {
if (b->b_next->b_iused > 0) {
if (b->b_next->b_instr[0].i_loc.lineno < 0) {
if (b->b_next->b_instr[0].i_loc.lineno == NO_LOCATION.lineno) {
b->b_next->b_instr[0].i_loc = prev_location;
}
}
@ -2993,7 +2993,7 @@ propagate_line_numbers(basicblock *entryblock) {
if (is_jump(last)) {
basicblock *target = last->i_target;
if (target->b_predecessors == 1) {
if (target->b_instr[0].i_loc.lineno < 0) {
if (target->b_instr[0].i_loc.lineno == NO_LOCATION.lineno) {
target->b_instr[0].i_loc = prev_location;
}
}