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. 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