Думаю, я действительно спрашиваю: является ли псевдоним «транзитивным»? Если компилятор знает, что A может быть псевдонимом B, а B может быть псевдонимом C, то, конечно же, он должен помнить, что A, следовательно, может быть псевдонимом C. Возможно, эта «очевидная» транзитивная логика не требуется?
Пример, для наглядности. Самый интересный для меня пример проблемы со строгим псевдонимом:
// g++ -fstrict-aliasing -std=c++11 -O2
#include <iostream>
union
{
int i;
short s;
} u;
int * i = &u.i;
int main()
{
u.i = 1; // line 1
*i += 1; // line 2
short & s = u.s;
s += 100; // line 3
std::cout
<< " *i\t" << *i << std::endl // prints 2
<< "u.i\t" << u.i << std::endl // prints 101
;
return 0;
}
g++ 5.3.0 на x86_64 (но не clang 3.5.0) дает приведенный выше вывод, где *i
и u.i
дают разные числа. Но они должны давать точно такое же число, потому что i
определяется как int * i = &u.i;
, а i
не изменяется.
У меня есть теория: при «предсказании» значения u.i
компилятор спрашивает, какие строки могут повлиять на содержимое u.i
. Это включает в себя строку 1, очевидно. И строка 2, потому что int*
может быть псевдонимом int
члена союза. И строка 3 также, потому что все, что может повлиять на одного члена союза (u.s
), может повлиять на другого члена того же союза. Но при прогнозировании *i
он не понимает, что строка 3 может повлиять на int
lvalue в *i
.
Эта теория кажется разумной?
Я нахожу этот пример забавным, потому что в нем нет кастинга. Мне удалось нарушить строгое сглаживание при любом приведении.