6
votes

Consider a example in the standard

Example

template<class T> struct A {
  typedef int M;
  struct B {
    typedef void M;
    struct C;
  };
};

template<class T> struct A<T>::B::C : A<T> {
  M m;                          // OK, A<T>​::​M
};

The comment says M refer to A<T>::M, I doubt with this, because of these rules:

temp.dep#3

In the definition of a class or class template, the scope of a dependent base class is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

That means a name in the scope of dependent base class is never be considered during unqualified name lookup.

Name M is an unqualified name. Hence M declared in A<T> is not considered.

Then according to the rule for unqualified name lookup, that is:

basic.lookup.unqual#8

For the members of a class X, a name used in a member function body, in a default argument, in a noexcept-specifier, in the brace-or-equal-initializer of a non-static data member, or in the definition of a class member outside of the definition of X, following the member's declarator-id32, shall be declared in one of the following ways:

  • if X is a nested class of class Y, shall be a member of Y, or shall be a member of a base class of Y (this lookup applies in turn to Y's enclosing classes, starting with the innermost enclosing class)

Since C is a nested class of B, Hence I think lookup shall be began at B, then A, due to there's a name M in the scope of B, hence the lookup shall be stoped.

In all the cases listed in [basic.lookup.unqual], the scopes are searched for a declaration in the order listed in each of the respective categories; name lookup ends as soon as a declaration is found for the name. If no declaration is found, the program is ill-formed.

So, according to these rules, the name M within A<T>::B::C shall refer to B::M.

The outcome is here.

GCC agreed what the standard said, however clang reported an error and denoted that the type M is void. The outcome of clang consistent with my analysis. According to these reasons, I agree clang is right. So, I wonder is it a defect? Or what something I misunderstand ?

1

1 Answers

5
votes

According to C++ Defect Report Support in Clang, currently (2020-07-06) Clang does not implement the resolution of CWG591, where the paragraph with the definition of dependent base class and the Example you cite in the question was added.