From 97069e5d5ba6c17a309c0814c387b1e722756400 Mon Sep 17 00:00:00 2001 From: Alessio Giacobbe Date: Fri, 28 Aug 2026 17:53:20 +0200 Subject: [PATCH] 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. --- src/Parser/UnaryExpressionTrait.php | 8 +++++ .../compiler/operator/unary-minus-nested.phpt | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/compiler/operator/unary-minus-nested.phpt diff --git a/src/Parser/UnaryExpressionTrait.php b/src/Parser/UnaryExpressionTrait.php index e273551d..c4a92e6a 100644 --- a/src/Parser/UnaryExpressionTrait.php +++ b/src/Parser/UnaryExpressionTrait.php @@ -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; } diff --git a/tests/compiler/operator/unary-minus-nested.phpt b/tests/compiler/operator/unary-minus-nested.phpt new file mode 100644 index 00000000..b9f988ad --- /dev/null +++ b/tests/compiler/operator/unary-minus-nested.phpt @@ -0,0 +1,35 @@ +--TEST-- +Nested unary minus must not emit the C++ pre-decrement token +--FILE-- + +--EXPECT-- +5 +5 +7 +1.5 +9 +-3