Fix GH-22256: Preserve frameless argument order#22766
Conversation
|
I'm fairly certain that we consider the evaluation order of arguments to be undefined, just like languages like C etc. |
|
Argument evaluation order is undefined, but I think this case is slightly different. A regular call snapshots the earlier CV argument before the later assignment, while the frameless path keeps the CV live until the handler runs and therefore sees the mutated value. The result changes only because the call was optimized into a frameless call. Since frameless calls should be transparent to userland, I still think matching regular call behavior here is worth fixing. |
|
That's at the cost of performance. |
|
I see the performance concern, but I checked the documented behavior and function arguments seem to be a specific exception here. The manual says arguments are evaluated from left to right, and the language spec says there is a sequence point after each argument: |
Frameless calls keep CV arguments in their original slots until the handler runs. If a later argument changes one of those CVs, the handler sees the new value instead of the value from when the earlier argument was evaluated.
Copy earlier CV arguments before compiling a later expression that may have side effects. The common variable, literal, and constant argument paths remain unchanged.
This happens before the frameless opcode runs, so the
__toString()re-entry protection proposed in #21815 does not cover it.Includes tests for assignment, increment, and mutation through a nested call.
Fixes GH-22256