Index: clang/include/clang/Sema/Lookup.h =================================================================== --- clang/include/clang/Sema/Lookup.h +++ clang/include/clang/Sema/Lookup.h @@ -148,20 +148,22 @@ : SemaPtr(&SemaRef), NameInfo(NameInfo), LookupKind(LookupKind), Redecl(Redecl != Sema::NotForRedeclaration), ExternalRedecl(Redecl == Sema::ForExternalRedeclaration), - Diagnose(Redecl == Sema::NotForRedeclaration) { + DiagnoseAccess(Redecl == Sema::NotForRedeclaration), + DiagnoseAmbiguous(Redecl == Sema::NotForRedeclaration) { configure(); } // TODO: consider whether this constructor should be restricted to take // as input a const IdentifierInfo* (instead of Name), // forcing other cases towards the constructor taking a DNInfo. - LookupResult(Sema &SemaRef, DeclarationName Name, - SourceLocation NameLoc, Sema::LookupNameKind LookupKind, + LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc, + Sema::LookupNameKind LookupKind, Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) : SemaPtr(&SemaRef), NameInfo(Name, NameLoc), LookupKind(LookupKind), Redecl(Redecl != Sema::NotForRedeclaration), ExternalRedecl(Redecl == Sema::ForExternalRedeclaration), - Diagnose(Redecl == Sema::NotForRedeclaration) { + DiagnoseAccess(Redecl == Sema::NotForRedeclaration), + DiagnoseAmbiguous(Redecl == Sema::NotForRedeclaration) { configure(); } @@ -192,12 +194,14 @@ Redecl(std::move(Other.Redecl)), ExternalRedecl(std::move(Other.ExternalRedecl)), HideTags(std::move(Other.HideTags)), - Diagnose(std::move(Other.Diagnose)), + DiagnoseAccess(std::move(Other.DiagnoseAccess)), + DiagnoseAmbiguous(std::move(Other.DiagnoseAmbiguous)), AllowHidden(std::move(Other.AllowHidden)), Shadowed(std::move(Other.Shadowed)), TemplateNameLookup(std::move(Other.TemplateNameLookup)) { Other.Paths = nullptr; - Other.Diagnose = false; + Other.DiagnoseAccess = false; + Other.DiagnoseAmbiguous = false; } LookupResult &operator=(LookupResult &&Other) { @@ -215,17 +219,22 @@ Redecl = std::move(Other.Redecl); ExternalRedecl = std::move(Other.ExternalRedecl); HideTags = std::move(Other.HideTags); - Diagnose = std::move(Other.Diagnose); + DiagnoseAccess = std::move(Other.DiagnoseAccess); + DiagnoseAmbiguous = std::move(Other.DiagnoseAmbiguous); AllowHidden = std::move(Other.AllowHidden); Shadowed = std::move(Other.Shadowed); TemplateNameLookup = std::move(Other.TemplateNameLookup); Other.Paths = nullptr; - Other.Diagnose = false; + Other.DiagnoseAccess = false; + Other.DiagnoseAmbiguous = false; return *this; } ~LookupResult() { - if (Diagnose) diagnose(); + if (DiagnoseAccess) + diagnoseAccess(); + if (DiagnoseAmbiguous) + diagnoseAmbiguous(); if (Paths) deletePaths(Paths); } @@ -607,13 +616,19 @@ /// Suppress the diagnostics that would normally fire because of this /// lookup. This happens during (e.g.) redeclaration lookups. void suppressDiagnostics() { - Diagnose = false; + DiagnoseAccess = false; + DiagnoseAmbiguous = false; } - /// Determines whether this lookup is suppressing diagnostics. - bool isSuppressingDiagnostics() const { - return !Diagnose; - } + /// Suppress the diagnostics that would normally fire because of this + /// lookup due to access control violations. + void suppressAccessDiagnostics() { DiagnoseAccess = false; } + + /// Determines whether this lookup is suppressing access control diagnostics. + bool isSuppressingAccessDiagnostics() const { return !DiagnoseAccess; } + + /// Determines whether this lookup is suppressing ambiguous lookup diagnostics. + bool isSuppressingAmbiguousDiagnostics() const { return !DiagnoseAmbiguous; } /// Sets a 'context' source range. void setContextRange(SourceRange SR) { @@ -726,11 +741,14 @@ } private: - void diagnose() { + void diagnoseAccess() { + if (isClassLookup() && getSema().getLangOpts().AccessControl) + getSema().CheckLookupAccess(*this); + } + + void diagnoseAmbiguous() { if (isAmbiguous()) getSema().DiagnoseAmbiguousLookup(*this); - else if (isClassLookup() && getSema().getLangOpts().AccessControl) - getSema().CheckLookupAccess(*this); } void setAmbiguous(AmbiguityKind AK) { @@ -776,7 +794,8 @@ /// are present bool HideTags = true; - bool Diagnose = false; + bool DiagnoseAccess = false; + bool DiagnoseAmbiguous = false; /// True if we should allow hidden declarations to be 'visible'. bool AllowHidden = false; Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -14927,7 +14927,7 @@ const auto *Record = Object.get()->getType()->castAs(); LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName); LookupQualifiedName(R, Record->getDecl()); - R.suppressDiagnostics(); + R.suppressAccessDiagnostics(); for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -593,7 +593,7 @@ // postfix-expression and does not name a class template, the name // found in the class of the object expression is used, otherwise FoundOuter.clear(); - } else if (!Found.isSuppressingDiagnostics()) { + } else if (!Found.isSuppressingAmbiguousDiagnostics()) { // - if the name found is a class template, it must refer to the same // entity as the one found in the class of the object expression, // otherwise the program is ill-formed. Index: clang/test/CXX/class.derived/class.member.lookup/gh22413.cpp =================================================================== --- /dev/null +++ clang/test/CXX/class.derived/class.member.lookup/gh22413.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +struct A { + void operator()(int); // expected-note {{member found by ambiguous name lookup}} + void f(int); // expected-note {{member found by ambiguous name lookup}} +}; +struct B { + void operator()(); // expected-note {{member found by ambiguous name lookup}} + void f() {} // expected-note {{member found by ambiguous name lookup}} +}; + +struct C : A, B {}; + +int f() { + C c; + c(); // expected-error {{member 'operator()' found in multiple base classes of different types}} + c.f(10); //expected-error {{member 'f' found in multiple base classes of different types}} + return 0; +} Index: clang/test/CXX/class.derived/class.member.lookup/p11.cpp =================================================================== --- /dev/null +++ clang/test/CXX/class.derived/class.member.lookup/p11.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +struct B1 { + void f(); + static void f(int); + int i; // expected-note 2{{member found by ambiguous name lookup}} +}; +struct B2 { + void f(double); +}; +struct I1: B1 { }; +struct I2: B1 { }; + +struct D: I1, I2, B2 { + using B1::f; + using B2::f; + void g() { + f(); // expected-error {{ambiguous conversion from derived class 'D' to base class 'B1'}} + f(0); // ok + f(0.0); // ok + // FIXME next line should be well-formed + int B1::* mpB1 = &D::i; // expected-error {{non-static member 'i' found in multiple base-class subobjects of type 'B1'}} + int D::* mpD = &D::i; // expected-error {{non-static member 'i' found in multiple base-class subobjects of type 'B1'}} + } +};