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).
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 "
// 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) {
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;
};
<< 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;
}
#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
// 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();
};
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 {
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 {
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 {
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>
}
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}}
};
// 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}}
}
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 {
<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>