Skip to content

Commit e9e82b3

Browse files
committed
Fix incorrect match default branch optimization
Fixes GH-11134
1 parent 725f136 commit e9e82b3

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

Zend/Optimizer/dfa_pass.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,11 +1001,23 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa)
10011001
|| (opline->opcode == ZEND_MATCH && (type == IS_LONG || type == IS_STRING));
10021002

10031003
if (!correct_type) {
1004-
removed_ops++;
1005-
MAKE_NOP(opline);
1006-
opline->extended_value = 0;
1007-
take_successor_ex(ssa, block_num, block, block->successors[block->successors_count - 1]);
1008-
goto optimize_nop;
1004+
if (opline->opcode != ZEND_MATCH) {
1005+
removed_ops++;
1006+
MAKE_NOP(opline);
1007+
opline->extended_value = 0;
1008+
take_successor_ex(ssa, block_num, block, block->successors[block->successors_count - 1]);
1009+
goto optimize_nop;
1010+
} else {
1011+
/* Match doesn't have a fallback chain, so we need to we can jump directly to the default branch. */
1012+
uint32_t target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
1013+
opline->opcode = ZEND_JMP;
1014+
opline->extended_value = 0;
1015+
SET_UNUSED(opline->op1);
1016+
ZEND_SET_OP_JMP_ADDR(opline, opline->op1, op_array->opcodes + target);
1017+
SET_UNUSED(opline->op2);
1018+
take_successor_ex(ssa, block_num, block, ssa->cfg.map[target]);
1019+
goto optimize_jmp;
1020+
}
10091021
} else {
10101022
HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant));
10111023
zval *jmp_zv = type == IS_LONG

Zend/tests/match/gh11134.phpt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GH-11134: Incorrect match optimization
3+
--FILE--
4+
<?php
5+
6+
function testMatch() {
7+
return match ($unset ?? null) {
8+
'foo' => 'foo',
9+
'bar' => 'bar',
10+
default => 'baz',
11+
};
12+
}
13+
14+
function testSwitch() {
15+
switch ($unset ?? null) {
16+
case 'foo': return 'foo';
17+
case 'bar': return 'bar';
18+
default: return 'baz';
19+
}
20+
}
21+
22+
var_dump(testMatch());
23+
var_dump(testSwitch());
24+
25+
?>
26+
--EXPECT--
27+
string(3) "baz"
28+
string(3) "baz"

0 commit comments

Comments
 (0)