-2

If I understand the C++17 standard correctly then function arguments should be indeterminately sequenced (P0145R3). Please consider the following testcase:

#include <stdio.h>
void foo(int a, int b, int c) { printf("%d %d %d\n", a, b, c); }
int main() {
  int i = 0;
  foo(++i, ++i, ++i);
}

clang warns incorrectly:

warning: multiple unsequenced modifications to 'i' [-Wunsequenced]

and prints: 1 2 3

gcc also warns:

warning: operation on ‘i’ may be undefined [-Wsequence-point]

and prints: 3 3 3

Which output is correct?

octoploid
  • 635
  • 3
  • 7
  • 6
    Undefined behavior. Thus, anything goes and they are both "correct" – Jonas Apr 03 '17 at 12:59
  • 1
    Isn't the implementation vendor specific as the standard states that argument evaluation order is unspecified? So both are valid according to the standard – EdChum Apr 03 '17 at 12:59
  • 2
    If they're indeterminately sequenced wouldn't either be "correct"? That's kind of what undefined behavior means. Everything in your question states the same. – Dave Newton Apr 03 '17 at 13:00
  • (And what makes the clang warning incorrect? It's telling you exactly what you stated is the behavior.) – Dave Newton Apr 03 '17 at 13:02
  • 1
    Well, P0145 says that function call arguments are indeterminately sequenced. So any permutation of "1 2 3" seems valid. – octoploid Apr 03 '17 at 13:04
  • @DaveNewton "Indeterminately sequenced" != "undefined behaviour". – sepp2k Apr 03 '17 at 13:05
  • @Someprogrammerdude The linked question doesn't address the changes in C++17 at all, so I wouldn't consider it a duplicate. – sepp2k Apr 03 '17 at 13:07
  • @sepp2k Then how about http://stackoverflow.com/questions/38501587/what-are-the-evaluation-order-guarantees-introduced-by-c17? Which basically says that the argument evaluation order is still unspecified. – Some programmer dude Apr 03 '17 at 13:09
  • @sepp2k In general, no, but in this case, I'd argue it does, since you cannot rely on evaluation order. Since you can't rely on the order, the behavior is undefined. – Dave Newton Apr 03 '17 at 13:12
  • @DaveNewton The difference between unspecified and undefined, is that undefined may cause the program to go complete bananas, crash & burn, launch random computer games etc. Whereas unspecified means that the program behaves deterministically but you can't assume anything about the order. – Lundin Apr 03 '17 at 13:57
  • @Lundin Fair enough-I should use the terms properly. My bad. – Dave Newton Apr 03 '17 at 13:59

1 Answers1

0

The initialization of the function parameters is unsequenced as per a note in C++17 5.2.2/4:

When a function is called, each parameter (8.3.5) shall be initialized (8.5, 12.8, 12.1) with its corresponding argument. [ Note: Such initializations are indeterminately sequenced with respect to each other (1.9) — end note ]

Meaning that even if the function arguments are guaranteed to be evaluated left-to-right (which I can't find any info about in C++17 draft), the initialization of the arguments is still indeterminately sequenced.

Meaning that for example, if your parameters all call the same copy constructor, which in turn modifies a global/static resource, your program has unspecified behavior:

static int f;

Foo::Foo (const Foo& foo)
  : x(f++)
{}

...

void func (Foo a, Foo b, Foo c)
{
  std::cout << a.x << b.x << c.x;  // unspecified output
}

A good compiler will give a warning upon spotting reliance on unspecified behavior = deterministic but undocumented behavior, which you can't assume anything about.

Lundin
  • 155,020
  • 33
  • 213
  • 341
  • Then both warnings are bogus and clang's output is right (any other permutation of 1,2,3 would also be correct). – octoploid Apr 03 '17 at 13:45
  • 2
    Your answer says "unsequenced", but your quote says "indeterminately sequenced". Those are very different: indeterminately sequenced is still sequenced and so free of undefined behavior (it's just unspecified as you then correctly say) – Cubbi Apr 03 '17 at 15:19