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