Only eliminate jumps to successor block if jump is unconditional. (GH-24417)

* Prevents elimination of the sole test of a value in statements like:
   if x or True: ...
This commit is contained in:
Mark Shannon 2021-02-02 14:59:15 +00:00 committed by GitHub
parent 9eb11a139f
commit 802b645e81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 17 deletions

View file

@ -354,6 +354,22 @@ def test_real_and_imag(self):
self.assertIs(type(False.real), int)
self.assertIs(type(False.imag), int)
def test_bool_called_at_least_once(self):
class X:
def __init__(self):
self.count = 0
def __bool__(self):
self.count += 1
return True
def f(x):
if x or True:
pass
x = X()
f(x)
self.assertGreaterEqual(x.count, 1)
def test_main():
support.run_unittest(BoolTest)

View file

@ -6586,27 +6586,14 @@ optimize_cfg(struct assembler *a, PyObject *consts)
for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) {
if (b->b_iused > 0) {
struct instr *b_last_instr = &b->b_instr[b->b_iused - 1];
if (b_last_instr->i_opcode == POP_JUMP_IF_FALSE ||
b_last_instr->i_opcode == POP_JUMP_IF_TRUE ||
b_last_instr->i_opcode == JUMP_ABSOLUTE ||
if (b_last_instr->i_opcode == JUMP_ABSOLUTE ||
b_last_instr->i_opcode == JUMP_FORWARD) {
if (b_last_instr->i_target == b->b_next) {
assert(b->b_next->b_iused);
b->b_nofallthrough = 0;
switch(b_last_instr->i_opcode) {
case POP_JUMP_IF_FALSE:
case POP_JUMP_IF_TRUE:
b_last_instr->i_opcode = POP_TOP;
b_last_instr->i_target = NULL;
b_last_instr->i_oparg = 0;
break;
case JUMP_ABSOLUTE:
case JUMP_FORWARD:
b_last_instr->i_opcode = NOP;
clean_basic_block(b, -1);
maybe_empty_blocks = 1;
break;
}
b_last_instr->i_opcode = NOP;
clean_basic_block(b, -1);
maybe_empty_blocks = 1;
}
}
}