Order of evaluation - aka hidden undefined behaviours.
Timon Gehr
timon.gehr at gmx.ch
Wed Sep 26 04:54:37 PDT 2012
On 09/26/2012 12:13 PM, Don Clugston wrote:
> On 26/09/12 01:31, H. S. Teoh wrote:
>> On Wed, Sep 26, 2012 at 01:10:00AM +0200, Timon Gehr wrote:
>>> On 09/26/2012 12:58 AM, Iain Buclaw wrote:
>> [...]
>>>> string abc;
>>>>
>>>> float[] A()
>>>> {
>>>> abc ~= "A";
>>>> return [];
>>>> }
>>>>
>>>> float[] B()
>>>> {
>>>> abc ~= "B";
>>>> return [];
>>>> }
>>>>
>>>> float[] C()
>>>> {
>>>> abc ~= "C";
>>>> return [];
>>>> }
>>>>
>>>> void main()
>>>> {
>>>> A()[] = B()[] + C()[];
>>>> assert(abc == "???");
>>>> }
>>>> ----
>>>>
>>>> Without cheating, I invite people to have a good guess what 'abc' is
>>>> equal to, but just to narrow it down.
>>>>
>>>> 1) It isn't "ABC".
>>>> 2) On x86/x86_64, it isn't "ACB".
>>>> 3) On everything else, it's the reverse of what you'd expect on
>>>> x86/x86_64.
>>>>
>>>> The problem here is that the array operation A[] = B[] + C[] gets
>>>> transformed into an extern(C) call. And because there's no strict
>>>> rules
>>>> in place over the order of which it's parameters are evaluated, it
>>>> could
>>>> go either way (LTR, or RTL).
>>>>
>>>> Serious note: This test is bogus as this and similar other failing
>>>> tests
>>>> on non-x86 platforms are not at all obvious to the users who get
>>>> issues.
>>>> So what are we to do about it?
>> [...]
>>> As far as my understanding of the issue goes, the correct answer is
>>> "ABC", and compilers that do not produce "ABC" are buggy.
>>>
>>> The solution is to transform the code to code that evaluates the
>>> arguments to the extern(C) call in the correct order and eg. stores
>>> them in temporaries before passing them on.
>> [...]
>>
>> Shouldn't it be BCA? I'd expect the assignment operation to take place
>> last, so the corresponding expression should be evaluated last.
>
> I expected "BCA" too. Left associative expressions evaluated
> left-to-right, right associative expressions evaluated right-to-left.
>
I don't think that makes any sense. Why would that be the case?
a = b = c;
=>
a.opAssign(b.opAssign(c));
foo() ^^ bar() ^^ qux()
=>
pow(foo(), pow(bar(), qux()));
More information about the Digitalmars-d
mailing list