This code
struct Inner{
    Inner();
    ~Inner();
};
struct Outer {
    using Inner = ::Inner;
};
Outer::Inner::Inner()
{
    //
}
Outer::Inner::~Inner()
{
    //
}
is compiled by GCC up to the latest as of today (14.2) but is rejected by clang since version 11 (accepted by clang 10).
It's strange (to me) that only the destructor is rejected.
Which compiler is right? Can somebody cite chapter and verse from the standard?
Per C++23 DIS [basic.lookup.qual.general]/41:
If a qualified name Q follows a
~: … its nested-name-specifier N shall nominate a type. If N has another nested-name-specifier S, Q is looked up as if its lookup context were that nominated by S.
Inner after ~ in Outer::Inner::~Inner is looked up in Outer, which finds type alias. But per [class.dtor]/1, destructor declaration shall use injected-class-name after ~:
its declarator shall be a function declarator … where … the id-expression has one of the following forms … nested-name-specifier
~class-name and the class-name is the injected-class-name of the class nominated by the nested-name-specifier
P.S. Without preceding ~, the lookup is performed as usual, in the context associated with nested-name-specifier N. So, in the constructor declaration, the second Inner is looked up in the context nominated by Outer::Inner, which is the class scope of struct Inner, finds injected-class-name, and the constructor declaration is valid
in a qualified-id of the form:
nested-name-specifieropt class-name
::~class-namethe second class-name is looked up in the same scope as the first
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With