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?
 
     
    