Part of C++ DR 39: a class member lookup is not ambiguous if it finds the
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).
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 2e47930..f2b2b1d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8640,6 +8640,8 @@
 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 "
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 9a1312a..16dd8f5 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2228,11 +2228,10 @@
 
   // 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 @@
           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 @@
       << 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;
   }
diff --git a/clang/test/CXX/drs/dr3xx.cpp b/clang/test/CXX/drs/dr3xx.cpp
index cec9acf..06aa885 100644
--- a/clang/test/CXX/drs/dr3xx.cpp
+++ b/clang/test/CXX/drs/dr3xx.cpp
@@ -137,13 +137,17 @@
 #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
diff --git a/clang/test/CXX/temp/temp.res/temp.local/p3.cpp b/clang/test/CXX/temp/temp.res/temp.local/p3.cpp
index 63c40fb..ac03c72 100644
--- a/clang/test/CXX/temp/temp.res/temp.local/p3.cpp
+++ b/clang/test/CXX/temp/temp.res/temp.local/p3.cpp
@@ -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();
 }; 
 
diff --git a/clang/test/SemaCXX/member-name-lookup.cpp b/clang/test/SemaCXX/member-name-lookup.cpp
index 0149169..cfd00b3 100644
--- a/clang/test/SemaCXX/member-name-lookup.cpp
+++ b/clang/test/SemaCXX/member-name-lookup.cpp
@@ -20,14 +20,14 @@
 
   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 @@
 
   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 @@
 
 
 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 { 
diff --git a/clang/test/SemaTemplate/dependent-base-classes.cpp b/clang/test/SemaTemplate/dependent-base-classes.cpp
index f8f36b2..09f475f 100644
--- a/clang/test/SemaTemplate/dependent-base-classes.cpp
+++ b/clang/test/SemaTemplate/dependent-base-classes.cpp
@@ -64,11 +64,11 @@
 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>
diff --git a/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp
index cb49717..14e4386 100644
--- a/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp
+++ b/clang/test/SemaTemplate/ms-lookup-template-base-classes.cpp
@@ -304,8 +304,8 @@
 }
 
 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}}
 };
diff --git a/clang/test/SemaTemplate/temp.cpp b/clang/test/SemaTemplate/temp.cpp
index a8a2dae..ae0f017 100644
--- a/clang/test/SemaTemplate/temp.cpp
+++ b/clang/test/SemaTemplate/temp.cpp
@@ -8,8 +8,8 @@
 
 // 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}}
diff --git a/clang/test/SemaTemplate/typename-specifier-4.cpp b/clang/test/SemaTemplate/typename-specifier-4.cpp
index 2856c99..7aa2b8d 100644
--- a/clang/test/SemaTemplate/typename-specifier-4.cpp
+++ b/clang/test/SemaTemplate/typename-specifier-4.cpp
@@ -107,8 +107,8 @@
 }
 
 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 { 
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 89e4fe0..f7e4e98 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -1877,7 +1877,7 @@
     <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>