Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are these evaluations in the calling function that are not specifically sequenced before the body of the called function?

[intro.execution]/15 contains these statements in page 11 of N4140 (emphasis is mine):

When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function. [ Note: Value computations and side effects associated with different argument expressions are unsequenced. —end note ] Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.9

9) In other words, function executions do not interleave with each other.

I'm wondering what are these evaluations in the calling function that are not specifically sequenced before the execution of the body of the called function?


* Edit * I claim both answers in the question "sequence before" and "Every evaluation in the calling function" in C++ have nothing whatsoever to do with my question. Please read my question and the answers given therein. See also my comment to the answer given below by @CoryKramer.


* Edit 2 * This is probably the answer to my question. See Proposed Resolution number 3 in DR 1949:

Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function For each function invocation F, for every evaluation A that occurs within F and every evaluation B that does not occur within F but is evaluated on the same thread and as part of the same signal handler (if any), either A is sequenced before B or B is sequenced before A.9 [Note: if A and B would not otherwise be sequenced then they are indeterminately sequenced. —end note]

like image 570
Belloc Avatar asked Jan 18 '16 17:01

Belloc


2 Answers

If you have two functions that return int

int Foo();
int Bar();

Then you have some calling function

void SomeFunction(int x, int y);

Then the calling code looks like

SomeFunction(Foo(), Bar());

They are saying the execution order of Foo and Bar is indeterminant.

like image 191
Cory Kramer Avatar answered Nov 10 '22 01:11

Cory Kramer


The answer by CoryKramer is entirely correct but perhaps insufficiently elaborated. The clarification in DR 1949 is not relevant.

The key is paragraph 13 of §1.9: which defines the relation "sequenced before" as a partial order, and provides four possibilites for two evaluations A and B:

  1. A is sequenced before B

  2. B is sequenced before A

  3. One of (1) or (2) holds, but the standard does not specify which. In this case, we say that A and B are indeterminately sequenced.

  4. Neither (1) nor (2) holds. In this case, we say that A and B are unsequenced.

There is a difference between indeterminately sequenced and unsequenced, and it is this difference which is addressed in paragraph 15. Paragraph 15 commences with the general rule (emphasis added):

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

The consequence of that is that in the function call

f(argument1, argument2);

the evaluations argument1 and argument2 are unsequenced. That makes the following undefined behaviour:

f(i++, i++);

But suppose we had:

int incr(int& i) { return i++; }

and we instead wrote:

f(incr(i), incr(i));

If we applied the general rule, then this would also be undefined behaviour, with exactly the same argument: the two evaluations are unsequenced, so the evaluations of the bodies of the two function calls are unsequenced, and we end up with two unsequenced modifications of the same variable.

But this is really not desirable, as it would lead to chaos. [It should be noted that the above example is brutally simplified; the two functions might be completely different and the common variable might not be named. In particular, as a common case, the two functions might both send output to std::cout, thus performing a mutable operation on the same shared object (std::cout itself).]

So an explicit exception is made for function calls: the body of a function evaluation is always sequenced with respect to sub-expressions of the expression which contains the function call. So in

f(incr1(i), incr2(i));

because these are function calls, the evaluation of the bodies of incr1 and incr2 are indeterminately sequenced, not unsequenced, and since both orders result in i being incremented twice, the value of i at the end of the evaluation of the argument list is well-defined. Furthermore, the actual arguments passed to f are unspecified, not undefined; either the first or the second will be greater, but they will not be equal.

That exception doesn't apply to the evaluation of the calls themselves, only to the evaluation of the bodies of the called function. So f(g(i++), h(i++)) is still undefined behaviour, because the evaluation of the two subexpressions i++ are not part of the evaluation of the body of either function.

Two side issues

  1. Paragraph 15 also extends this exception to function calls which are the result of the semantics of the language, including operator overrides, with the interesting result that

     f(i++, i++);
    

    is unspecified rather than undefined if i is an instance of an object with an operator++(int) override. Similarly,

     f(std::cout << 'a', std::cout << 'b');
    

    will cause either ab or ba to be sent to std::cout (it is unspecified which), but is not undefined behaviour.

  2. The point of DR 1949 is that "sequenced after" has never been formally defined. So rather than saying "A is sequenced either before or after B", the more precise formulation is "either A is sequenced before B or B is sequenced before A". You could achieve the same logical effect by formally defining "A is sequenced after B" as "B is sequenced before A". DR 1949 does both.

like image 38
rici Avatar answered Nov 10 '22 00:11

rici