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