r354091 - Fix implementation of [temp.local]p4.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 15 09:56:12 PST 2019
On Thu, 14 Feb 2019, 18:35 Francis Visoiu Mistrih via cfe-commits, <
cfe-commits at 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 at 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 at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20190215/4cb3ddb1/attachment-0001.html>
More information about the cfe-commits
mailing list