I have a case where a friend casts a non-base class object of type "Base" to a class type object "Derived", where "Derived" is a derived class of "Base" and only adds functions, but no data. In the below code, I did add a data member x
to the derived class
struct A {
int a;
};
struct B : A {
// int x;
int x;
};
A a;
int g(B *b) {
a.a = 10;
b->a++;
return a.a;
}
With strict alias analysis on, GCC (also Clang) always returns 10
, and not 11
, because b
can never point to a
in a well-defined code. However, if I remove B::x
(as is actually the case in the code of my friend), GCC's output assembler code does not optimize the return access of a.a
and reloads the value from memory. So the code of my friend that calls g
"works" on GCC (as he intended) even though I think it still has undefined behavior
g((B*)&a);
So in essentially the same two cases, GCC optimizes one case and doesn't optimize the other case. Is it because b
can then legally point to a
? Or is it because GCC just wants to not break real-world code?
I tested the answer that states
If you remove B::x, then B meets the requirements in 9p7 for a standard-layout class and the access becomes perfectly well-defined because the two types are layout-compatible, 9.2p17.
With two layout compatible enums
enum A : int { X, Y };
enum B : int { Z };
A a;
int g(B *b) {
a = Y;
*b = Z;
return a;
}
The assembler output for g
returns 1
, not 0
, even though A
and B
are layout compatible (7.2p8).
So my further question is (quoting an answer): "two classes with exactly the same layout may be considered "almost the same" and they are left out of the optimization.". Can someone provide a proof of this for GCC or Clang?