Ошибка компиляции при определении функции-члена, но только в GCC

Следующая программа компилируется без ошибок с помощью MSVS, clang и GCC:

class A;

namespace Y {
    using ::A;
    class A {};
}

int main() {}

Теперь давайте определим функцию-член. Теперь он все еще компилируется с помощью MSVS и clang, но не с GCC:

class A;

namespace Y {
    using ::A;
    class A { void f() {} };
}

int main() {}

GCC дает следующее сообщение об ошибке:

  • prog.cc:5:22: error: определение 'void A:: f()' не находится в пространстве имен, в котором содержится 'A' [-fpermissive]

Почему? Это ошибка в GCC?

Если вторая версия программы нарушает правило стандарта С++, какое правило это нарушает и почему MSVS и clang не дают диагностическое сообщение для этого нарушения?

Это случай двусмысленности стандарта С++?

Из сообщения об ошибке похоже, что GCC неправильно считает, что у нас есть нарушение следующего правила:

  • http://eel.is/c++draft/class.mfct#2 "Определение функции-члена, которое появляется за пределами определения класса, должно появиться в области пространства имен, охватывающей определение класса."

У нас нет нарушения этого правила, поскольку определение функции-члена находится внутри определения класса. Моя теория состоит в том, что GCC смешивает класс декларации A; в глобальном пространстве имен с классом определения класса A {...} в пространстве имен Y. Я думаю, что у нас есть ошибка в GCC.

С GCC они объявляют одну и ту же сущность. Это можно увидеть, заметив, что в первой версии программы можно использовать:: A как полный тип в основном при компиляции с GCC. То же самое для MSVS. Вместе с Clang они объявляют разные сущности. Эта разница может быть вызвана двусмысленностью в стандарте С++. Независимо от такой двусмысленности мы явно не нарушаем http://eel.is/c++draft/class.mfct#2. Это правило очень ясно.

Связанный вопрос: Объявление класса в той же области, что и с использованием компиляций декларации в GCC, но не MSVS

Ответ 1

Обе эти программы плохо сформированы в соответствии со стандартом С++. Это происходит по той же причине, что и в связанном с этим вопросе:

Объявление класса в той же области, что и при использовании компиляции объявлений в GCC, но не в MSVS

Все компиляторы должны давать ошибку компиляции в обоих случаях: Таким образом, это указывает на ошибку в MSVS, clang и GCC.

Ошибка в clang подтверждена и исправлена: https://llvm.org/bugs/show_bug.cgi?id=24030

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