Различные результаты между gcc и clang при компиляции довольно простой программы С++ 11

Я пытаюсь понять, отличается ли поведение gcc против clang от вывода этой простой программы С++ 11 из-за ошибки в clang (Xcode 5.0.2, OS X 10.8.5). Код выглядит следующим образом:

#include <iostream>

int main() {


    int matrix[][3]{{1,2,3}, {4,5,6}, {7,8,9}};
    auto dyn_matrix = new int[3][3]{{1,2,3}, {4,5,6}, {7,8,9}};

    std::cout << matrix[0][1] << std::endl;
    std::cout << dyn_matrix[0][1] << std::endl;

    return 0;   
}

Как показано, я пытаюсь использовать единую инициализацию для инициализации многомерного массива анонимного (соответственно названного) размера 3x3. При компиляции с gcc 4.7 из MacPorts получается ожидаемый результат:

$g++-mp-4.7 -std=c++11 dyn_matrix.cpp -o dyn_matrix 
$ ./dyn_matrix
2
2
$

И наоборот, в случае использования clang вывод:

$ clang++ -std=c++11 -stdlib=libc++ dyn_matrix.cpp -o dyn_matrix_clang
$ ./dyn_matrix_clang 
2
4
$  

В этом случае результат (по-видимому) неправильный. clang --version сообщает:

Apple LLVM version 5.0 (clang-500.2.75) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix

Кто виноват? меня, gcc или clang?

ОБНОВЛЕНИЕ 11 декабря 2013 г. Ошибка должна быть исправлена ​​в r196995. К сожалению, мы все еще не знаем, сколько времени потребуется, прежде чем Apple обновит версию clang, поставляемую с Xcode.

ОБНОВЛЕНИЕ 9 ДЕКАБРЯ 2013 ГОДА: Я отправил отчет об ошибке на платформе bugzilla LLVM. Это действительно признано ошибкой, в настоящее время рассматривается патч, см. http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20131209/095099.html.

Спасибо.

Ответ 1

Обновление: Благодаря Фейсалу Вали и Ричарду Смиту эта ошибка была исправлена ​​в Clang ToT; см. тестовый файл, введенный коммитом.


Согласно §8.5.1 [dcl.init.aggr], похоже, что Clang ошибочен:

11/Брекеты могут быть удалены в списке инициализаторов следующим образом. Если список инициализаторов начинается с левой фигурной скобки, то последующий разделенный запятыми список инициализатор-предложений инициализирует элементы субагрегата; ошибочно, чтобы было больше предложений инициализатора, чем членов. Если, однако, список инициализаторов для субагрегата не начинается с левой скобки, тогда для инициализации членов субагрегата берутся только достаточные предложения инициализатора из списка; любые оставшиеся условия инициализации оставляются для инициализации следующего члена агрегата, членом которого является текущий субагрегат. [Пример:

float y[4][3] = {
    { 1, 3, 5 },
    { 2, 4, 6 },
    { 3, 5, 7 },
};

- это полностью фиксированная инициализация: 1, 3 и 5 инициализируют первую строку массива y[0], а именно y[0][0], y[0][1] и y[0][2]. Аналогично, следующие две строки инициализируют y[1] и y[2]. Инициализатор заканчивается раньше, и поэтому элементы y[3] инициализируются так, как если бы они были явно инициализированы выражением формы float(), то есть инициализированы с помощью 0.0. В следующем примере скобки в списке инициализаторов устранены; однако список инициализаторов имеет тот же эффект, что и полностью скопированный список инициализаторов вышеприведенного примера,

float y[4][3] = {
    1, 3, 5, 2, 4, 6, 3, 5, 7
};

Инициализатор для y начинается с левой скобки, но для y[0] нет, поэтому используются три элемента из списка. Аналогично, следующие три последовательно выполняются для y[1] и y[2]. -end пример]

Я думаю, что это применимо из-за §5.3.4 [expr.new]:

15/Новое выражение, создающее объект типа T, инициализирует этот объект следующим образом:

  • Если новый инициализатор опущен, объект инициализируется по умолчанию (§8.5); если инициализация не выполняется, объект имеет неопределенное значение.
  • В противном случае новый-инициализатор интерпретируется в соответствии с правилами инициализации §8.5 для прямой инициализации.