Reputation: 7769
The C++17 standard revised the definitions of the order of operations for the C++ language by a rule stating, to the effect:
In every simple assignment expression E1=E2 and every compound assignment expression E1@=E2, every value computation and side-effect of E2 is sequenced before every value computation and side effect of E1
However, when compiling the following code in GCC 8.1 with -std=c++17
and -Wall
int v[] { 0,1,2,3,4,5,6,7 };
int *p0 = &v[0];
*p0++ = *p0 + 1;
cout << "v[0]: " << v[0] << endl;
I get the following warning:
main.cpp:266:8: warning: operation on 'p0' may be undefined [-Wsequence-point]
*p0++ = *p0 + 1;
~~^~
The output is:
v[0]: 1
And the question: is the warning erroneous?
Upvotes: 4
Views: 1528
Reputation: 14454
[I leave my answer below for reference but further discussion has shown that my answer below is incomplete and that its conclusion is ultimately incorrect.]
The C++17 standard (draft here), [expr.ass], indeed reads:
The right operand [of an assignment operator] is sequenced before the left operand.
This sounds as wrong to me as it does to you. @Barry dislikes your sample code so, to avoid distracting the question, I have tested alternate code:
#include <iostream>
namespace {
int a {3};
int& left()
{
std::cout << "in left () ...\n";
return ++a;
}
int right()
{
std::cout << "in right() ...\n";
return a *= 2;
}
}
int main()
{
left() = right();
std::cout << a << "\n";
return 0;
}
Output (using GCC 6.3):
in left () ...
in right() ...
8
Whether you regard the printed messages or consider the computed value of 8, it looks as though the left operand were sequenced before the right operand—which makes sense, insofar as efficient machine code
I would disagree with @Barry. You may have discovered a nontrivial problem with the standard. When you have some time, report it.
UPDATE
@SombreroChicken adds:
That's just because GCC 6.3 didn't correctly implement C++17 yet. From 7.1 and onwards it evaluates right first as seen here.
Output:
in right() ...
in left () ...
6
Upvotes: 1
Reputation: 303517
And the question: is the warning erroneous?
It depends.
Technically, the code in question is well-defined. The right-hand side is sequenced before the left-hand side in C++17, whereas before it was indeterminately sequenced. And gcc compiles the code correctly, v[0] == 1
after that assignment.
However, it is also terrible code that should not be written, so while the specific wording of the warning is erroneous, the actual spirit of the warning seems fine to me. At least, I'm not about to file a bug report about it and it doesn't seem like the kind of thing that's worth developer time to fix. YMMV.
Upvotes: 9