<div dir="auto"><div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, 14 Feb 2019, 18:35 Francis Visoiu Mistrih via cfe-commits, <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space">Hi Richard,<div><br></div><div>This seems to now emit an error when building the sanitizer tests: <a href="http://green.lab.llvm.org/green/job/clang-stage1-configure-RA/53965/consoleFull" target="_blank" rel="noreferrer">http://green.lab.llvm.org/green/job/clang-stage1-configure-RA/53965/consoleFull</a>.</div><div><br></div><div>I managed to reproduce it locally and when reverting your commit the error goes away.</div><div><br></div><div>I am not sure if the error is in the sanitizer test’s code or actually a compiler error. Can you please take a look?</div></div></blockquote></div></div><div dir="auto"><br></div><div dir="auto">It's an error in the sanitizer test's code.</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><div>Thanks,</div><div><br></div><div>-- </div><div>Francis<br><div><br><blockquote type="cite"><div>On Feb 14, 2019, at 4:29 PM, Richard Smith via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" target="_blank" rel="noreferrer">cfe-commits@lists.llvm.org</a>> wrote:</div><br class="m_-7096614929714390344Apple-interchange-newline"><div><div>Author: rsmith<br>Date: Thu Feb 14 16:29:04 2019<br>New Revision: 354091<br><br>URL: <a href="http://llvm.org/viewvc/llvm-project?rev=354091&view=rev" target="_blank" rel="noreferrer">http://llvm.org/viewvc/llvm-project?rev=354091&view=rev</a><br>Log:<br>Fix implementation of [temp.local]p4.<br><br>When a template-name is looked up, we need to give injected-class-name<br>declarations of class templates special treatment, as they denote a<br>template rather than a type.<br><br>Previously we achieved this by applying a filter to the lookup results<br>after completing name lookup, but that is incorrect in various ways, not<br>least of which is that it lost all information about access and how<br>members were named, and the filtering caused us to generally lose<br>all ambiguity errors between templates and non-templates.<br><br>We now preserve the lookup results exactly, and the few places that need<br>to map from a declaration found by name lookup into a declaration of a<br>template do so explicitly. Deduplication of repeated lookup results of<br>the same injected-class-name declaration is done by name lookup instead<br>of after the fact.<br><br>Modified:<br> cfe/trunk/include/clang/Sema/Lookup.h<br> cfe/trunk/include/clang/Sema/Sema.h<br> cfe/trunk/lib/Sema/SemaDecl.cpp<br> cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br> cfe/trunk/lib/Sema/SemaLookup.cpp<br> cfe/trunk/lib/Sema/SemaTemplate.cpp<br> cfe/trunk/test/CXX/class.access/p4.cpp<br> cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp<br> cfe/trunk/test/SemaTemplate/temp.cpp<br><br>Modified: cfe/trunk/include/clang/Sema/Lookup.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Lookup.h?rev=354091&r1=354090&r2=354091&view=diff" target="_blank" rel="noreferrer">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Lookup.h?rev=354091&r1=354090&r2=354091&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/Sema/Lookup.h (original)<br>+++ cfe/trunk/include/clang/Sema/Lookup.h Thu Feb 14 16:29:04 2019<br>@@ -172,7 +172,8 @@ public:<br> : SemaPtr(Other.SemaPtr), NameInfo(Other.NameInfo),<br> LookupKind(Other.LookupKind), IDNS(Other.IDNS), Redecl(Other.Redecl),<br> ExternalRedecl(Other.ExternalRedecl), HideTags(Other.HideTags),<br>- AllowHidden(Other.AllowHidden) {}<br>+ AllowHidden(Other.AllowHidden),<br>+ TemplateNameLookup(Other.TemplateNameLookup) {}<br><br> // FIXME: Remove these deleted methods once the default build includes<br> // -Wdeprecated.<br>@@ -193,7 +194,8 @@ public:<br> HideTags(std::move(Other.HideTags)),<br> Diagnose(std::move(Other.Diagnose)),<br> AllowHidden(std::move(Other.AllowHidden)),<br>- Shadowed(std::move(Other.Shadowed)) {<br>+ Shadowed(std::move(Other.Shadowed)),<br>+ TemplateNameLookup(std::move(Other.TemplateNameLookup)) {<br> Other.Paths = nullptr;<br> Other.Diagnose = false;<br> }<br>@@ -216,6 +218,7 @@ public:<br> Diagnose = std::move(Other.Diagnose);<br> AllowHidden = std::move(Other.AllowHidden);<br> Shadowed = std::move(Other.Shadowed);<br>+ TemplateNameLookup = std::move(Other.TemplateNameLookup);<br> Other.Paths = nullptr;<br> Other.Diagnose = false;<br> return *this;<br>@@ -286,6 +289,15 @@ public:<br> HideTags = Hide;<br> }<br><br>+ /// Sets whether this is a template-name lookup. For template-name lookups,<br>+ /// injected-class-names are treated as naming a template rather than a<br>+ /// template specialization.<br>+ void setTemplateNameLookup(bool TemplateName) {<br>+ TemplateNameLookup = TemplateName;<br>+ }<br>+<br>+ bool isTemplateNameLookup() const { return TemplateNameLookup; }<br>+<br> bool isAmbiguous() const {<br> return getResultKind() == Ambiguous;<br> }<br>@@ -739,6 +751,9 @@ private:<br> /// declaration that we skipped. This only happens when \c LookupKind<br> /// is \c LookupRedeclarationWithLinkage.<br> bool Shadowed = false;<br>+<br>+ /// True if we're looking up a template-name.<br>+ bool TemplateNameLookup = false;<br> };<br><br> /// Consumes visible declarations found when searching for<br><br>Modified: cfe/trunk/include/clang/Sema/Sema.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=354091&r1=354090&r2=354091&view=diff" target="_blank" rel="noreferrer">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=354091&r1=354090&r2=354091&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/Sema/Sema.h (original)<br>+++ cfe/trunk/include/clang/Sema/Sema.h Thu Feb 14 16:29:04 2019<br>@@ -6212,9 +6212,21 @@ public:<br> // C++ Templates [C++ 14]<br> //<br> void FilterAcceptableTemplateNames(LookupResult &R,<br>- bool AllowFunctionTemplates = true);<br>+ bool AllowFunctionTemplates = true,<br>+ bool AllowDependent = true);<br> bool hasAnyAcceptableTemplateNames(LookupResult &R,<br>- bool AllowFunctionTemplates = true);<br>+ bool AllowFunctionTemplates = true,<br>+ bool AllowDependent = true);<br>+ /// Try to interpret the lookup result D as a template-name.<br>+ ///<br>+ /// \param D A declaration found by name lookup.<br>+ /// \param AllowFunctionTemplates Whether function templates should be<br>+ /// considered valid results.<br>+ /// \param AllowDependent Whether unresolved using declarations (that might<br>+ /// name templates) should be considered valid results.<br>+ NamedDecl *getAsTemplateNameDecl(NamedDecl *D,<br>+ bool AllowFunctionTemplates = true,<br>+ bool AllowDependent = true);<br><br> bool LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,<br> QualType ObjectType, bool EnteringContext,<br><br>Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=354091&r1=354090&r2=354091&view=diff" target="_blank" rel="noreferrer">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=354091&r1=354090&r2=354091&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Feb 14 16:29:04 2019<br>@@ -1017,7 +1017,8 @@ Corrected:<br><br> case LookupResult::Ambiguous:<br> if (getLangOpts().CPlusPlus && <a href="http://NextToken.is" target="_blank" rel="noreferrer">NextToken.is</a>(tok::less) &&<br>- hasAnyAcceptableTemplateNames(Result)) {<br>+ hasAnyAcceptableTemplateNames(Result, /*AllowFunctionTemplates=*/true,<br>+ /*AllowDependent=*/false)) {<br> // C++ [temp.local]p3:<br> // A lookup that finds an injected-class-name (10.2) can result in an<br> // ambiguity in certain cases (for example, if it is found in more than<br>@@ -1041,7 +1042,9 @@ Corrected:<br> }<br><br> if (getLangOpts().CPlusPlus && <a href="http://NextToken.is" target="_blank" rel="noreferrer">NextToken.is</a>(tok::less) &&<br>- (IsFilteredTemplateName || hasAnyAcceptableTemplateNames(Result))) {<br>+ (IsFilteredTemplateName ||<br>+ hasAnyAcceptableTemplateNames(Result, /*AllowFunctionTemplates=*/true,<br>+ /*AllowDependent=*/false))) {<br> // C++ [temp.names]p3:<br> // After name lookup (3.4) finds that a name is a template-name or that<br> // an operator-function-id or a literal- operator-id refers to a set of<br>@@ -1060,15 +1063,16 @@ Corrected:<br> Template = Context.getOverloadedTemplateName(Result.begin(),<br> Result.end());<br> } else {<br>- TemplateDecl *TD<br>- = cast<TemplateDecl>((*Result.begin())->getUnderlyingDecl());<br>+ auto *TD = cast<TemplateDecl>(getAsTemplateNameDecl(<br>+ *Result.begin(), /*AllowFunctionTemplates=*/true,<br>+ /*AllowDependent=*/false));<br> IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);<br> IsVarTemplate = isa<VarTemplateDecl>(TD);<br><br> if (SS.isSet() && !SS.isInvalid())<br>- Template = Context.getQualifiedTemplateName(SS.getScopeRep(),<br>- /*TemplateKeyword=*/false,<br>- TD);<br>+ Template =<br>+ Context.getQualifiedTemplateName(SS.getScopeRep(),<br>+ /*TemplateKeyword=*/false, TD);<br> else<br> Template = TemplateName(TD);<br> }<br><br>Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=354091&r1=354090&r2=354091&view=diff" target="_blank" rel="noreferrer">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=354091&r1=354090&r2=354091&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Feb 14 16:29:04 2019<br>@@ -1128,7 +1128,6 @@ static bool checkTupleLikeDecomposition(<br> }<br> }<br> }<br>- S.FilterAcceptableTemplateNames(MemberGet);<br> }<br><br> unsigned I = 0;<br><br>Modified: cfe/trunk/lib/Sema/SemaLookup.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=354091&r1=354090&r2=354091&view=diff" target="_blank" rel="noreferrer">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=354091&r1=354090&r2=354091&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaLookup.cpp Thu Feb 14 16:29:04 2019<br>@@ -2172,11 +2172,27 @@ bool Sema::LookupQualifiedName(LookupRes<br> DeclContext::lookup_iterator FirstD = FirstPath->Decls.begin();<br> DeclContext::lookup_iterator CurrentD = Path->Decls.begin();<br><br>+ // Get the decl that we should use for deduplicating this lookup.<br>+ auto GetRepresentativeDecl = [&](NamedDecl *D) -> Decl * {<br>+ // C++ [temp.local]p3:<br>+ // A lookup that finds an injected-class-name (10.2) can result in<br>+ // an ambiguity in certain cases (for example, if it is found in<br>+ // more than one base class). If all of the injected-class-names<br>+ // that are found refer to specializations of the same class<br>+ // template, and if the name is used as a template-name, the<br>+ // reference refers to the class template itself and not a<br>+ // specialization thereof, and is not ambiguous.<br>+ if (R.isTemplateNameLookup())<br>+ if (auto *TD = getAsTemplateNameDecl(D))<br>+ D = TD;<br>+ return D->getUnderlyingDecl()->getCanonicalDecl();<br>+ };<br>+<br> while (FirstD != FirstPath->Decls.end() &&<br> CurrentD != Path->Decls.end()) {<br>- if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() !=<br>- (*CurrentD)->getUnderlyingDecl()->getCanonicalDecl())<br>- break;<br>+ if (GetRepresentativeDecl(*FirstD) !=<br>+ GetRepresentativeDecl(*CurrentD))<br>+ break;<br><br> ++FirstD;<br> ++CurrentD;<br><br>Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=354091&r1=354090&r2=354091&view=diff" target="_blank" rel="noreferrer">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=354091&r1=354090&r2=354091&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Feb 14 16:29:04 2019<br>@@ -66,17 +66,20 @@ static Expr *clang::formAssociatedConstr<br><br> /// Determine whether the declaration found is acceptable as the name<br> /// of a template and, if so, return that template declaration. Otherwise,<br>-/// returns NULL.<br>-static NamedDecl *isAcceptableTemplateName(ASTContext &Context,<br>- NamedDecl *Orig,<br>- bool AllowFunctionTemplates) {<br>- NamedDecl *D = Orig->getUnderlyingDecl();<br>+/// returns null.<br>+///<br>+/// Note that this may return an UnresolvedUsingValueDecl if AllowDependent<br>+/// is true. In all other cases it will return a TemplateDecl (or null).<br>+NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D,<br>+ bool AllowFunctionTemplates,<br>+ bool AllowDependent) {<br>+ D = D->getUnderlyingDecl();<br><br> if (isa<TemplateDecl>(D)) {<br> if (!AllowFunctionTemplates && isa<FunctionTemplateDecl>(D))<br> return nullptr;<br><br>- return Orig;<br>+ return D;<br> }<br><br> if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {<br>@@ -107,54 +110,29 @@ static NamedDecl *isAcceptableTemplateNa<br> // 'using Dependent::foo;' can resolve to a template name.<br> // 'using typename Dependent::foo;' cannot (not even if 'foo' is an<br> // injected-class-name).<br>- if (isa<UnresolvedUsingValueDecl>(D))<br>+ if (AllowDependent && isa<UnresolvedUsingValueDecl>(D))<br> return D;<br><br> return nullptr;<br> }<br><br> void Sema::FilterAcceptableTemplateNames(LookupResult &R,<br>- bool AllowFunctionTemplates) {<br>- // The set of class templates we've already seen.<br>- llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates;<br>+ bool AllowFunctionTemplates,<br>+ bool AllowDependent) {<br> LookupResult::Filter filter = R.makeFilter();<br> while (filter.hasNext()) {<br> NamedDecl *Orig = filter.next();<br>- NamedDecl *Repl = isAcceptableTemplateName(Context, Orig,<br>- AllowFunctionTemplates);<br>- if (!Repl)<br>+ if (!getAsTemplateNameDecl(Orig, AllowFunctionTemplates, AllowDependent))<br> filter.erase();<br>- else if (Repl != Orig) {<br>-<br>- // C++ [temp.local]p3:<br>- // A lookup that finds an injected-class-name (10.2) can result in an<br>- // ambiguity in certain cases (for example, if it is found in more than<br>- // one base class). If all of the injected-class-names that are found<br>- // refer to specializations of the same class template, and if the name<br>- // is used as a template-name, the reference refers to the class<br>- // template itself and not a specialization thereof, and is not<br>- // ambiguous.<br>- if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl))<br>- if (!ClassTemplates.insert(ClassTmpl).second) {<br>- filter.erase();<br>- continue;<br>- }<br>-<br>- // FIXME: we promote access to public here as a workaround to<br>- // the fact that LookupResult doesn't let us remember that we<br>- // found this template through a particular injected class name,<br>- // which means we end up doing nasty things to the invariants.<br>- // Pretending that access is public is *much* safer.<br>- filter.replace(Repl, AS_public);<br>- }<br> }<br> filter.done();<br> }<br><br> bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R,<br>- bool AllowFunctionTemplates) {<br>+ bool AllowFunctionTemplates,<br>+ bool AllowDependent) {<br> for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I)<br>- if (isAcceptableTemplateName(Context, *I, AllowFunctionTemplates))<br>+ if (getAsTemplateNameDecl(*I, AllowFunctionTemplates, AllowDependent))<br> return true;<br><br> return false;<br>@@ -198,20 +176,45 @@ TemplateNameKind Sema::isTemplateName(Sc<br> MemberOfUnknownSpecialization))<br> return TNK_Non_template;<br> if (R.empty()) return TNK_Non_template;<br>+<br>+ NamedDecl *D = nullptr;<br> if (R.isAmbiguous()) {<br>- // Suppress diagnostics; we'll redo this lookup later.<br>- R.suppressDiagnostics();<br>+ // If we got an ambiguity involving a non-function template, treat this<br>+ // as a template name, and pick an arbitrary template for error recovery.<br>+ bool AnyFunctionTemplates = false;<br>+ for (NamedDecl *FoundD : R) {<br>+ if (NamedDecl *FoundTemplate = getAsTemplateNameDecl(FoundD)) {<br>+ if (isa<FunctionTemplateDecl>(FoundTemplate))<br>+ AnyFunctionTemplates = true;<br>+ else {<br>+ D = FoundTemplate;<br>+ break;<br>+ }<br>+ }<br>+ }<br><br>- // FIXME: we might have ambiguous templates, in which case we<br>- // should at least parse them properly!<br>- return TNK_Non_template;<br>+ // If we didn't find any templates at all, this isn't a template name.<br>+ // Leave the ambiguity for a later lookup to diagnose.<br>+ if (!D && !AnyFunctionTemplates) {<br>+ R.suppressDiagnostics();<br>+ return TNK_Non_template;<br>+ }<br>+<br>+ // If the only templates were function templates, filter out the rest.<br>+ // We'll diagnose the ambiguity later.<br>+ if (!D)<br>+ FilterAcceptableTemplateNames(R);<br> }<br><br>+ // At this point, we have either picked a single template name declaration D<br>+ // or we have a non-empty set of results R containing either one template name<br>+ // declaration or a set of function templates.<br>+<br> TemplateName Template;<br> TemplateNameKind TemplateKind;<br><br> unsigned ResultCount = R.end() - R.begin();<br>- if (ResultCount > 1) {<br>+ if (!D && ResultCount > 1) {<br> // We assume that we'll preserve the qualifier from a function<br> // template name in other ways.<br> Template = Context.getOverloadedTemplateName(R.begin(), R.end());<br>@@ -219,12 +222,19 @@ TemplateNameKind Sema::isTemplateName(Sc<br><br> // We'll do this lookup again later.<br> R.suppressDiagnostics();<br>- } else if (isa<UnresolvedUsingValueDecl>((*R.begin())->getUnderlyingDecl())) {<br>- // We don't yet know whether this is a template-name or not.<br>- MemberOfUnknownSpecialization = true;<br>- return TNK_Non_template;<br> } else {<br>- TemplateDecl *TD = cast<TemplateDecl>((*R.begin())->getUnderlyingDecl());<br>+ if (!D) {<br>+ D = getAsTemplateNameDecl(*R.begin());<br>+ assert(D && "unambiguous result is not a template name");<br>+ }<br>+<br>+ if (isa<UnresolvedUsingValueDecl>(D)) {<br>+ // We don't yet know whether this is a template-name or not.<br>+ MemberOfUnknownSpecialization = true;<br>+ return TNK_Non_template;<br>+ }<br>+<br>+ TemplateDecl *TD = cast<TemplateDecl>(D);<br><br> if (SS.isSet() && !SS.isInvalid()) {<br> NestedNameSpecifier *Qualifier = SS.getScopeRep();<br>@@ -316,6 +326,8 @@ bool Sema::LookupTemplateName(LookupResu<br> bool EnteringContext,<br> bool &MemberOfUnknownSpecialization,<br> SourceLocation TemplateKWLoc) {<br>+ Found.setTemplateNameLookup(true);<br>+<br> // Determine where to perform name lookup<br> MemberOfUnknownSpecialization = false;<br> DeclContext *LookupCtx = nullptr;<br>@@ -390,6 +402,9 @@ bool Sema::LookupTemplateName(LookupResu<br> IsDependent |= Found.wasNotFoundInCurrentInstantiation();<br> }<br><br>+ if (Found.isAmbiguous())<br>+ return false;<br>+<br> if (Found.empty() && !IsDependent) {<br> // If we did not find any names, attempt to correct any typos.<br> DeclarationName Name = Found.getLookupName();<br>@@ -407,7 +422,9 @@ bool Sema::LookupTemplateName(LookupResu<br> if (auto *ND = Corrected.getFoundDecl())<br> Found.addDecl(ND);<br> FilterAcceptableTemplateNames(Found);<br>- if (!Found.empty()) {<br>+ if (Found.isAmbiguous()) {<br>+ Found.clear();<br>+ } else if (!Found.empty()) {<br> if (LookupCtx) {<br> std::string CorrectedStr(Corrected.getAsString(getLangOpts()));<br> bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&<br>@@ -457,14 +474,19 @@ bool Sema::LookupTemplateName(LookupResu<br> // Note: C++11 does not perform this second lookup.<br> LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(),<br> LookupOrdinaryName);<br>+ FoundOuter.setTemplateNameLookup(true);<br> LookupName(FoundOuter, S);<br>+ // FIXME: We silently accept an ambiguous lookup here, in violation of<br>+ // [basic.lookup]/1.<br> FilterAcceptableTemplateNames(FoundOuter, /*AllowFunctionTemplates=*/false);<br><br>+ NamedDecl *OuterTemplate;<br> if (FoundOuter.empty()) {<br> // - if the name is not found, the name found in the class of the<br> // object expression is used, otherwise<br>- } else if (!FoundOuter.getAsSingle<ClassTemplateDecl>() ||<br>- FoundOuter.isAmbiguous()) {<br>+ } else if (FoundOuter.isAmbiguous() || !FoundOuter.isSingleResult() ||<br>+ !(OuterTemplate =<br>+ getAsTemplateNameDecl(FoundOuter.getFoundDecl()))) {<br> // - if the name is found in the context of the entire<br> // postfix-expression and does not name a class template, the name<br> // found in the class of the object expression is used, otherwise<br>@@ -474,8 +496,8 @@ bool Sema::LookupTemplateName(LookupResu<br> // entity as the one found in the class of the object expression,<br> // otherwise the program is ill-formed.<br> if (!Found.isSingleResult() ||<br>- Found.getFoundDecl()->getCanonicalDecl()<br>- != FoundOuter.getFoundDecl()->getCanonicalDecl()) {<br>+ getAsTemplateNameDecl(Found.getFoundDecl())->getCanonicalDecl() !=<br>+ OuterTemplate->getCanonicalDecl()) {<br> Diag(Found.getNameLoc(),<br> diag::ext_nested_name_member_ref_lookup_ambiguous)<br> << Found.getLookupName()<br>@@ -545,7 +567,8 @@ void Sema::diagnoseExprIntendedAsTemplat<br><br> // Try to correct the name by looking for templates and C++ named casts.<br> struct TemplateCandidateFilter : CorrectionCandidateCallback {<br>- TemplateCandidateFilter() {<br>+ Sema &S;<br>+ TemplateCandidateFilter(Sema &S) : S(S) {<br> WantTypeSpecifiers = false;<br> WantExpressionKeywords = false;<br> WantRemainingKeywords = false;<br>@@ -553,7 +576,7 @@ void Sema::diagnoseExprIntendedAsTemplat<br> };<br> bool ValidateCandidate(const TypoCorrection &Candidate) override {<br> if (auto *ND = Candidate.getCorrectionDecl())<br>- return isAcceptableTemplateName(ND->getASTContext(), ND, true);<br>+ return S.getAsTemplateNameDecl(ND);<br> return Candidate.isKeyword();<br> }<br> };<br>@@ -561,12 +584,11 @@ void Sema::diagnoseExprIntendedAsTemplat<br> DeclarationName Name = NameInfo.getName();<br> if (TypoCorrection Corrected =<br> CorrectTypo(NameInfo, LookupKind, S, &SS,<br>- llvm::make_unique<TemplateCandidateFilter>(),<br>+ llvm::make_unique<TemplateCandidateFilter>(*this),<br> CTK_ErrorRecovery, LookupCtx)) {<br> auto *ND = Corrected.getFoundDecl();<br> if (ND)<br>- ND = isAcceptableTemplateName(Context, ND,<br>- /*AllowFunctionTemplates*/ true);<br>+ ND = getAsTemplateNameDecl(ND);<br> if (ND || Corrected.isKeyword()) {<br> if (LookupCtx) {<br> std::string CorrectedStr(Corrected.getAsString(getLangOpts()));<br>@@ -4262,7 +4284,7 @@ TemplateNameKind Sema::ActOnDependentTem<br> LookupOrdinaryName);<br> bool MOUS;<br> if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext,<br>- MOUS, TemplateKWLoc))<br>+ MOUS, TemplateKWLoc) && !R.isAmbiguous())<br> Diag(Name.getBeginLoc(), diag::err_no_member)<br> << DNI.getName() << LookupCtx << SS.getRange();<br> return TNK_Non_template;<br><br>Modified: cfe/trunk/test/CXX/class.access/p4.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/p4.cpp?rev=354091&r1=354090&r2=354091&view=diff" target="_blank" rel="noreferrer">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/p4.cpp?rev=354091&r1=354090&r2=354091&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/CXX/class.access/p4.cpp (original)<br>+++ cfe/trunk/test/CXX/class.access/p4.cpp Thu Feb 14 16:29:04 2019<br>@@ -514,16 +514,12 @@ namespace test17 {<br> }<br><br> namespace test18 {<br>- template <class T> class A {};<br>- class B : A<int> {<br>+ template <class T> class A {}; // expected-note {{member is declared here}}<br>+ class B : A<int> { // expected-note {{constrained by implicitly private inheritance here}}<br> A<int> member;<br> };<br>-<br>- // FIXME: this access to A should be forbidden (because C++ is dumb),<br>- // but LookupResult can't express the necessary information to do<br>- // the check, so we aggressively suppress access control.<br> class C : B {<br>- A<int> member;<br>+ A<int> member; // expected-error {{'A' is a private member of 'test18::A<int>'}}<br> };<br> }<br><br><br>Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp?rev=354091&r1=354090&r2=354091&view=diff" target="_blank" rel="noreferrer">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp?rev=354091&r1=354090&r2=354091&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp (original)<br>+++ cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp Thu Feb 14 16:29:04 2019<br>@@ -380,10 +380,10 @@ template <class T> struct A {<br> namespace test18 {<br> namespace ns1 { template <class T> struct foo {}; } // expected-note{{candidate ignored: not a function template}}<br> namespace ns2 { void foo() {} } // expected-note{{candidate ignored: not a function template}}<br>-using ns1::foo;<br>-using ns2::foo;<br>+using ns1::foo; // expected-note {{found by name lookup}}<br>+using ns2::foo; // expected-note {{found by name lookup}}<br><br> template <class T> class A {<br>- friend void foo<T>() {} // expected-error{{no candidate function template was found for dependent friend function template specialization}}<br>+ friend void foo<T>() {} // expected-error {{ambiguous}} expected-error{{no candidate function template was found for dependent friend function template specialization}}<br> };<br> }<br><br>Modified: cfe/trunk/test/SemaTemplate/temp.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp.cpp?rev=354091&r1=354090&r2=354091&view=diff" target="_blank" rel="noreferrer">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp.cpp?rev=354091&r1=354090&r2=354091&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/SemaTemplate/temp.cpp (original)<br>+++ cfe/trunk/test/SemaTemplate/temp.cpp Thu Feb 14 16:29:04 2019<br>@@ -8,12 +8,43 @@ namespace test0 {<br><br> // PR7252<br> namespace test1 {<br>- namespace A { template<typename T> struct Base { typedef T t; }; } // expected-note {{member found}}<br>+ namespace A { template<typename T> struct Base { typedef T t; }; } // expected-note 3{{member}}<br> namespace B { template<typename T> struct Base { typedef T t; }; } // expected-note {{member found}}<br><br> template<typename T> struct Derived : A::Base<char>, B::Base<int> {<br>- // FIXME: the syntax error here is unfortunate<br>- typename Derived::Base<float>::t x; // expected-error {{found in multiple base classes of different types}} \<br>- // expected-error {{expected member name or ';'}}<br>+ typename Derived::Base<float>::t x; // expected-error {{found in multiple base classes of different types}}<br> };<br>+<br>+ class X : A::Base<int> {}; // expected-note 2{{private}}<br>+ class Y : A::Base<float> {};<br>+ struct Z : A::Base<double> {};<br>+ struct Use1 : X, Y {<br>+ Base<double> b1; // expected-error {{private}}<br>+ Use1::Base<double> b2; // expected-error {{private}}<br>+ };<br>+ struct Use2 : Z, Y {<br>+ Base<double> b1;<br>+ Use2::Base<double> b2;<br>+ };<br>+ struct Use3 : X, Z {<br>+ Base<double> b1;<br>+ Use3::Base<double> b2;<br>+ };<br>+}<br>+<br>+namespace test2 {<br>+ struct A { static int x; }; // expected-note 4{{member}}<br>+ struct B { template<typename T> static T x(); }; // expected-note 4{{member}}<br>+ struct C { template<typename T> struct x {}; }; // expected-note 3{{member}}<br>+ struct D { template<typename T> static T x(); }; // expected-note {{member}}<br>+<br>+ template<typename ...T> struct X : T... {};<br>+<br>+ void f() {<br>+ X<A, B>::x<int>(); // expected-error {{found in multiple base classes of different types}}<br>+ X<A, C>::x<int>(); // expected-error {{found in multiple base classes of different types}}<br>+ X<B, C>::x<int>(); // expected-error {{found in multiple base classes of different types}}<br>+ X<A, B, C>::x<int>(); // expected-error {{found in multiple base classes of different types}}<br>+ X<A, B, D>::x<int>(); // expected-error {{found in multiple base classes of different types}}<br>+ }<br> }<br><br><br>_______________________________________________<br>cfe-commits mailing list<br><a href="mailto:cfe-commits@lists.llvm.org" target="_blank" rel="noreferrer">cfe-commits@lists.llvm.org</a><br><a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" target="_blank" rel="noreferrer">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br></div></div></blockquote></div><br></div></div>_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank" rel="noreferrer">cfe-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div></div></div>