Подтвердить что ты не робот

Обозначение указателя функции extern и тип предполагаемого определения

Недавно я получил код, принятый clang++, но не g++, и я хотел бы знать, какой из них правильный.

Минималистский код, воспроизводящий поведение, очень короткий и говорит сам по себе, поэтому я думаю, что объяснение было бы излишне сложным.

Вот заголовок, содержащий объявление указателя extern:

//(guards removed for simplicity) :
#include <type_traits>

using ptr_func = std::add_pointer<void()>::type;

extern ptr_func pointer;

И вот источник, реализующий необходимую остроконечную функцию:

#include "function.hh"

void foo() {}

auto pointer = &foo;

Ошибка, генерируемая gcc, такова:

g++ -c function.cc -std=c++14
function.cc:5:6: error: conflicting declaration ‘auto pointer’
 auto pointer = &foo;
      ^
In file included from function.cc:1:0:
function.hh:5:17: note: previous declaration as ‘void (* pointer)()’
 extern ptr_func pointer;
                 ^

Clang принимает этот код без каких-либо ошибок/предупреждений. И заменив определение указателя на:

decltype(foo)* pointer = &foo;

принимается gcc.

По моему мнению, clang прав, но я не уверен, поэтому мне хотелось бы знать, является ли clang слишком разрешительным или если gcc должен его принять.

4b9b3361

Ответ 1

Это определенно ошибка в gcc. Вот минимальный пример:

int foo;
extern int* ptr;
auto ptr = &foo;

Интересно, что gcc счастлив, если объявления extern и auto отменены.

Это похоже на https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60352, о котором сообщалось в прошлом году.

Соответствующее предложение [basic.link]/10:

После всех настроек типов (в течение которых typedefs (7.1.3) заменяются их определениями), типы указанные всеми объявлениями, относящимися к данной переменной или функции, должны быть идентичными, за исключением того, что объявления для объекта массива могут указывать типы массивов, которые отличаются наличием или отсутствием основного массива (8.3.4). Нарушение этого правила для идентичности типа не требует диагностики.