Given the following code:
struct Tag {};
struct X {
// Tag t; // if not commented it shouldn't be pointer-interconvertible
int k;
};
int fn(const X& x, int& p) {
int i = x.k;
p = 2;
return i + x.k;
}
The generated code is:
fn(X const&, int&):
mov eax, DWORD PTR [rdi]
mov DWORD PTR [rsi], 2
add eax, DWORD PTR [rdi]
ret
Here the compiler assumes aliasing.
If member t is not present, the types X and int are pointer-interconvertible. As so, the compiler must generate code as if the references could alias.
But if member t is present, they should no longer be pointer-interconvertible and code for the non-aliased case should be generated. But in both cases the code is identical except the relative address of member k.
The assembler:
fn(X const&, int&):
mov eax, DWORD PTR [rdi+4]
mov DWORD PTR [rsi], 2
add eax, DWORD PTR [rdi+4]
ret
As an counter-example
template<typename T>
struct X {int k; };
int fn(X<struct A>& x, X<struct B>& p) {
int i = x.k;
p.k = 2;
return i + x.k;
}
in the above version the generated code assumes no aliasing, but the types are pointer-interconvertible.
fn(X<A>&, X<B>&):
mov eax, DWORD PTR [rdi]
mov DWORD PTR [rsi], 2
add eax, eax
ret
Can anyone explain this?
Here
X::kisint,pis a reference toint.pcan be a reference tox.k.On the other hand, here:
X<struct A>andX<struct B>are distinct types. There is no way to havexandpor parts of it refer to the same object.Then nothing changes. Sloppy speaking, you need a reference/pointer to get potential aliasing. For example
Here
b.gandacan point to the sameG(note that this is the case no matter ifbis passed by value, reference or pointer). In your example..... the only references are
xandp. They refer to objects of different types, aka different objects.