What bothers me a little to fill out such a bug report is that the code used is not safe when successive returns of a same function provide different arguments to a same procedure:
- Indeed, there is no constraint on the order of evaluation of the arguments passed to a procedure compared to its declaration (from the last parameter to the first or vice versa?).
- Which means that when the value returned by the function varies with each call, a precise behavior is not ensured seen from the procedure body with its received parameters.
In addition, gas and gcc/gas64 have a different behavior on this unsafe code when the function returns by reference (or by pointeur):
- For gcc/gas64, the same value is received for the different arguments,.
It is as if the arguments were actually passed by reference (or pointer) instead of by value.
Test program:
Function ReturnByVal() As Integer
Static As Integer I
I+= 1
Return I
End Function
Function ReturnByRef() Byref As Integer
Static As Integer I
I+= 1
Return I
End Function
Function ReturnByPtr() As Integer Ptr
Static As Integer I
I+= 1
Return @I
End Function
Sub Test(Byval I1 As Integer, Byval I2 As Integer, Byval I3 As Integer)
Print " First received parameter : " & I1
Print " Second received parameter : " & I2
Print " Third received parameter : " & I3
End Sub
Print "Arguments are function returns by value)
Test(ReturnByVal(), ReturnByVal(), ReturnByVal())
Print
Print "Arguments are function returns by reference)
Test(ReturnByRef(), ReturnByRef(), ReturnByRef())
Print
Print "Arguments are function returns by pointer)
Test(*ReturnByPtr(), *ReturnByPtr(), *ReturnByPtr())
Sleep
Output with gas(32):
Arguments are function returns by value)
First received parameter : 3
Second received parameter : 2
Third received parameter : 1
Arguments are function returns by reference)
First received parameter : 3
Second received parameter : 2
Third received parameter : 1
Arguments are function returns by pointer)
First received parameter : 3
Second received parameter : 2
Third received parameter : 1
Output with gcc(32/64) or gas64:
Arguments are function returns by value)
First received parameter : 3
Second received parameter : 2
Third received parameter : 1
Arguments are function returns by reference)
First received parameter : 3
Second received parameter : 3
Third received parameter : 3
Arguments are function returns by pointer)
First received parameter : 3
Second received parameter : 3
Third received parameter : 3
Discovered by dodicat.
See also the forum, from this post : https://www.freebasic.net/forum/viewtopic.php?p=304456#p304456
The calling convention (stdcall, pascal, cdecl) imposes the order of passing the parameters (in the stack) relative to the order in which they are listed in the declaration, but nothing specifically imposes that the corresponding arguments are evaluated (for passing by value) in the same order.
Otherwise, I think gas(32) is right, and it is not because the arguments provided are references that they should not still be passed by value as stipulated in the declaration.
Related: byref function result chained with additional methods
The byref result is passed as an instance parameter to the next method call; under the hood, methods have
method(this, args)as parameters, so at the very least we should expect arguments to the method to be evaluated before the method call.However, as can see in this example, all arguments are evaluated before any method call which is surely incorrect.
Execution order
Some investigation shows that this is related to how fbc tracks the list of nested arguments to calls within other calls within the AST.
So, while the arguments are evaluated ahead of the procedure call that uses them we should nonetheless like to have arguments further down the chain evaluated after method calls earlier in the chain.
Expected execution order