Part of C++ DR 39: a class member lookup is not ambiguous if it finds the
authorRichard Smith <richard@metafoo.co.uk>
Thu, 26 Nov 2020 01:00:23 +0000 (17:00 -0800)
committerRichard Smith <richard@metafoo.co.uk>
Thu, 26 Nov 2020 01:03:11 +0000 (17:03 -0800)
same type in multiple base classes.

Not even if the type is introduced by distinct declarations (for
example, two typedef declarations, or a typedef and a class definition).

clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaLookup.cpp
clang/test/CXX/drs/dr3xx.cpp
clang/test/CXX/temp/temp.res/temp.local/p3.cpp
clang/test/SemaCXX/member-name-lookup.cpp
clang/test/SemaTemplate/dependent-base-classes.cpp
clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp
clang/test/SemaTemplate/temp.cpp
clang/test/SemaTemplate/typename-specifier-4.cpp
clang/www/cxx_dr_status.html

index 2e47930..f2b2b1d 100644 (file)
@@ -8640,6 +8640,8 @@ def err_ambiguous_member_multiple_subobjects : Error<
 def err_ambiguous_member_multiple_subobject_types : Error<
   "member %0 found in multiple base classes of different types">;
 def note_ambiguous_member_found : Note<"member found by ambiguous name lookup">;
+def note_ambiguous_member_type_found : Note<
+  "member type %0 found by ambiguous name lookup">;
 def err_ambiguous_reference : Error<"reference to %0 is ambiguous">;
 def note_ambiguous_candidate : Note<"candidate found by name lookup is %q0">;
 def err_ambiguous_tag_hiding : Error<"a type named %0 is hidden by a "
index 9a1312a..16dd8f5 100644 (file)
@@ -2228,11 +2228,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
 
   // Determine whether two sets of members contain the same members, as
   // required by C++ [class.member.lookup]p6.
-  auto HasSameDeclarations = [IDNS,
-                              TemplateNameLookup](DeclContextLookupResult A,
-                                                  DeclContextLookupResult B) {
+  auto HasSameDeclarations = [&](DeclContextLookupResult A,
+                                 DeclContextLookupResult B) {
     using Iterator = DeclContextLookupResult::iterator;
-    using Result = const Decl *;
+    using Result = const void *;
 
     auto Next = [&](Iterator &It, Iterator End) -> Result {
       while (It != End) {
@@ -2252,14 +2251,15 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
           if (auto *TD = getAsTemplateNameDecl(ND))
             ND = TD;
 
-        // FIXME: Per C++ [class.member.lookup]p3:
-        //   type declarations (including injected-class-names are replaced by the
-        //   types they designate
-        // So two different typedef declarations with the same name from two
-        // different base classes declaring the same type do not introduce an
-        // ambiguity.
+        // C++ [class.member.lookup]p3:
+        //   type declarations (including injected-class-names) are replaced by
+        //   the types they designate
+        if (const TypeDecl *TD = dyn_cast<TypeDecl>(ND->getUnderlyingDecl())) {
+          QualType T = Context.getTypeDeclType(TD);
+          return T.getCanonicalType().getAsOpaquePtr();
+        }
 
-        return cast<NamedDecl>(ND->getUnderlyingDecl()->getCanonicalDecl());
+        return ND->getUnderlyingDecl()->getCanonicalDecl();
       }
       return nullptr;
     };
@@ -2509,13 +2509,23 @@ void Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
       << Name << LookupRange;
 
     CXXBasePaths *Paths = Result.getBasePaths();
-    std::set<Decl *> DeclsPrinted;
+    std::set<const NamedDecl *> DeclsPrinted;
     for (CXXBasePaths::paths_iterator Path = Paths->begin(),
                                       PathEnd = Paths->end();
          Path != PathEnd; ++Path) {
-      Decl *D = Path->Decls.front();
-      if (DeclsPrinted.insert(D).second)
-        Diag(D->getLocation(), diag::note_ambiguous_member_found);
+      const NamedDecl *D = Path->Decls.front();
+      if (!D->isInIdentifierNamespace(Result.getIdentifierNamespace()))
+        continue;
+      if (DeclsPrinted.insert(D).second) {
+        if (const auto *TD = dyn_cast<TypedefNameDecl>(D->getUnderlyingDecl()))
+          Diag(D->getLocation(), diag::note_ambiguous_member_type_found)
+              << TD->getUnderlyingType();
+        else if (const auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl()))
+          Diag(D->getLocation(), diag::note_ambiguous_member_type_found)
+              << Context.getTypeDeclType(TD);
+        else
+          Diag(D->getLocation(), diag::note_ambiguous_member_found);
+      }
     }
     break;
   }
index cec9acf..06aa885 100644 (file)
@@ -137,13 +137,17 @@ namespace dr305 { // dr305: no
 #endif
 }
 
-namespace dr306 { // dr306: no
-  // FIXME: dup 39
-  // FIXME: This should be accepted.
-  struct A { struct B {}; }; // expected-note 2{{member}}
-  struct C { typedef A::B B; }; // expected-note {{member}}
+namespace dr306 { // dr306: dup 39
+  struct A { struct B {}; };
+  struct C { typedef A::B B; };
   struct D : A, A::B, C {};
-  D::B b; // expected-error {{found in multiple base classes of different types}}
+  D::B b;
+
+  struct X {}; // expected-note {{member type 'dr306::X' found}}
+  template<typename T> struct Y { typedef T X; }; // expected-note {{member type 'const dr306::X' found}}
+  template<typename T> struct Z : X, Y<T> {};
+  Z<X>::X zx;
+  Z<const X>::X zcx; // expected-error {{member 'X' found in multiple base classes of different types}}
 }
 
 // dr307: na
index 63c40fb..ac03c72 100644 (file)
@@ -1,6 +1,8 @@
 // RUN: %clang_cc1 -verify %s
 
-template <class T> struct Base { // expected-note 4 {{member found by ambiguous name lookup}}
+template <class T> struct Base {
+  // expected-note@-1 2{{member type 'Base<int>' found by ambiguous name lookup}}
+  // expected-note@-2 2{{member type 'Base<char>' found by ambiguous name lookup}}
   static void f();
 }; 
 
index 0149169..cfd00b3 100644 (file)
@@ -20,14 +20,14 @@ struct B : A {
 
   enum E2 { enumerator2 };
 
-  enum E3 { enumerator3 }; // expected-note 2{{member found by ambiguous name lookup}}
+  enum E3 { enumerator3 }; // expected-note 2{{member type 'B::E3' found by ambiguous name lookup}}
 };
 
 struct C : A {
   int c; // expected-note 2{{member found by ambiguous name lookup}}
   int d; // expected-note 2{{member found by ambiguous name lookup}}
 
-  enum E3 { enumerator3_2 }; // expected-note 2{{member found by ambiguous name lookup}}
+  enum E3 { enumerator3_2 }; // expected-note 2{{member type 'C::E3' found by ambiguous name lookup}}
 };
 
 struct D : B, C {
@@ -71,14 +71,14 @@ struct B2 : virtual A {
 
   enum E2 { enumerator2 };
 
-  enum E3 { enumerator3 }; // expected-note 2 {{member found by ambiguous name lookup}}
+  enum E3 { enumerator3 }; // expected-note 2 {{member type 'B2::E3' found by ambiguous name lookup}}
 };
 
 struct C2 : virtual A {
   int c;
   int d; // expected-note 2{{member found by ambiguous name lookup}}
 
-  enum E3 { enumerator3_2 }; // expected-note 2{{member found by ambiguous name lookup}}
+  enum E3 { enumerator3_2 }; // expected-note 2{{member type 'C2::E3' found by ambiguous name lookup}}
 };
 
 struct D2 : B2, C2 { 
@@ -132,11 +132,11 @@ void G::test_virtual_lookup() {
 
 
 struct HasMemberType1 {
-  struct type { }; // expected-note{{member found by ambiguous name lookup}}
+  struct type { }; // expected-note{{member type 'HasMemberType1::type' found by ambiguous name lookup}}
 };
 
 struct HasMemberType2 {
-  struct type { }; // expected-note{{member found by ambiguous name lookup}}
+  struct type { }; // expected-note{{member type 'HasMemberType2::type' found by ambiguous name lookup}}
 };
 
 struct HasAnotherMemberType : HasMemberType1, HasMemberType2 { 
index f8f36b2..09f475f 100644 (file)
@@ -64,11 +64,11 @@ namespace PR6031 {
 namespace Ambig {
   template<typename T>
   struct Base1 {
-    typedef int type; // expected-note{{member found by ambiguous name lookup}}
+    typedef int type; // expected-note{{member type 'int' found by ambiguous name lookup}}
   };
 
   struct Base2 {
-    typedef float type; // expected-note{{member found by ambiguous name lookup}}
+    typedef float type; // expected-note{{member type 'float' found by ambiguous name lookup}}
   };
 
   template<typename T>
index cb49717..14e4386 100644 (file)
@@ -304,8 +304,8 @@ static_assert(sizeof(B<int>) == sizeof(A<int>::NameFromBase), "");
 }
 
 namespace two_types_in_base {
-template <typename T> struct A { typedef T NameFromBase; }; // expected-note {{member found by ambiguous name lookup}}
-template <typename T> struct B { struct NameFromBase { T m; }; }; // expected-note {{member found by ambiguous name lookup}}
+template <typename T> struct A { typedef T NameFromBase; }; // expected-note {{member type 'int' found by ambiguous name lookup}}
+template <typename T> struct B { struct NameFromBase { T m; }; }; // expected-note {{member type 'two_types_in_base::B<int>::NameFromBase' found by ambiguous name lookup}}
 template <typename T> struct C : A<T>, B<T> {
   NameFromBase m; // expected-error {{member 'NameFromBase' found in multiple base classes of different types}} expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
 };
index a8a2dae..ae0f017 100644 (file)
@@ -8,8 +8,8 @@ namespace test0 {
 
 // PR7252
 namespace test1 {
-  namespace A { template<typename T> struct Base { typedef T t; }; } // expected-note 3{{member}}
-  namespace B { template<typename T> struct Base { typedef T t; }; } // expected-note {{member found}}
+  namespace A { template<typename T> struct Base { typedef T t; }; } // expected-note {{member type 'test1::A::Base<char>' found}} expected-note 2{{declared here}}
+  namespace B { template<typename T> struct Base { typedef T t; }; } // expected-note {{member type 'test1::B::Base<int>' found}}
 
   template<typename T> struct Derived : A::Base<char>, B::Base<int> {
     typename Derived::Base<float>::t x; // expected-error {{found in multiple base classes of different types}}
index 2856c99..7aa2b8d 100644 (file)
@@ -107,8 +107,8 @@ namespace PR6268 {
 }
 
 namespace PR6463 {
-  struct B { typedef int type; }; // expected-note 2{{member found by ambiguous name lookup}}
-  struct C { typedef int type; }; // expected-note 2{{member found by ambiguous name lookup}}
+  struct B { typedef int type; }; // expected-note 2{{member type 'int' found by ambiguous name lookup}}
+  struct C { typedef const int type; }; // expected-note 2{{member type 'const int' found by ambiguous name lookup}}
 
   template<typename T>
   struct A : B, C { 
index 89e4fe0..f7e4e98 100755 (executable)
@@ -1877,7 +1877,7 @@ of class templates</td>
     <td><a href="https://wg21.link/cwg306">306</a></td>
     <td>CD1</td>
     <td>Ambiguity by class name injection</td>
-    <td class="none" align="center">No</td>
+    <td class="none" align="center">Duplicate of <a href="#39">39</a></td>
   </tr>
   <tr id="307">
     <td><a href="https://wg21.link/cwg307">307</a></td>