fix(parser): parenthesize unary minus operand to avoid C++ pre-decrement

parseUnaryMinus emitted '-' . $code without guarding against an operand
that itself starts with '-', pasting into the C++ pre-decrement token:
`- -$x` compiled to `--x`. On a php::Var operand the generated
translation unit fails to build ("expression is not assignable"); on a
native int operand it builds and silently decrements: a function
`(int $x) => - -$x` returned 8 for input 9.

Parenthesize the operand exactly when its emitted code starts with '-'
(a nested unary minus or a negative literal), so plain literals keep
their compact form (`-7L`). Binary operands are already self-wrapped in
parentheses, and unary plus needs no change since it returns the
operand unchanged.
master
Alessio Giacobbe 2 days ago
parent b493ac79c5
commit 97069e5d5b
No known key found for this signature in database
  1. 8
      src/Parser/UnaryExpressionTrait.php
  2. 35
      tests/compiler/operator/unary-minus-nested.phpt

@ -125,6 +125,14 @@ trait UnaryExpressionTrait
}
$code = $this->parseExprAsValue($expr->expr);
// An operand that already starts with `-` (a nested unary minus, a
// negative literal) would paste into the C++ pre-decrement token:
// `- -$a` -> `--a`. Parenthesize exactly then, so plain literals
// keep their compact `-7L` form.
if (str_starts_with($code, '-')) {
return '-(' . $code . ')';
}
return '-' . $code;
}

@ -0,0 +1,35 @@
--TEST--
Nested unary minus must not emit the C++ pre-decrement token
--FILE--
<?php
function negNative(int $x): int
{
return - -$x;
}
function main(): void
{
$a = 5;
$b = - -$a;
echo $b, "\n";
echo $a, "\n";
$c = -(-7);
echo $c, "\n";
$f = 1.5;
$g = - -$f;
echo $g, "\n";
echo negNative(9), "\n";
echo - -(-3), "\n";
}
?>
--EXPECT--
5
5
7
1.5
9
-3
Loading…
Cancel
Save