Author: Haojian Wu Date: 2022-04-21T10:53:23+02:00 New Revision: 1234b1c6d8113d50beef5801be607ad1d502b2f7
URL: https://github.com/llvm/llvm-project/commit/1234b1c6d8113d50beef5801be607ad1d502b2f7 DIFF: https://github.com/llvm/llvm-project/commit/1234b1c6d8113d50beef5801be607ad1d502b2f7.diff LOG: [AST] Support template declaration found through using-decl for QualifiedTemplateName. This is a followup of https://reviews.llvm.org/D123127, adding support for the QualifiedTemplateName. Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D123775 Added: Modified: clang/include/clang/AST/ASTContext.h clang/include/clang/AST/PropertiesBase.td clang/include/clang/AST/TemplateName.h clang/lib/AST/ASTContext.cpp clang/lib/AST/ASTImporter.cpp clang/lib/AST/QualTypeNames.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/TreeTransform.h clang/unittests/AST/TemplateNameTest.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 9e10571740de4..03d6a0fbe6eea 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2182,7 +2182,7 @@ class ASTContext : public RefCountedBase<ASTContext> { TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, - TemplateDecl *Template) const; + TemplateName Template) const; TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, const IdentifierInfo *Name) const; diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index 0ab18b6d59c3d..559f29edcf0fe 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -663,12 +663,12 @@ let Class = PropertyTypeCase<TemplateName, "QualifiedTemplate"> in { def : Property<"hasTemplateKeyword", Bool> { let Read = [{ qtn->hasTemplateKeyword() }]; } - def : Property<"declaration", TemplateDeclRef> { - let Read = [{ qtn->getTemplateDecl() }]; + def : Property<"underlyingTemplateName", TemplateName> { + let Read = [{ qtn->getUnderlyingTemplate() }]; } def : Creator<[{ return ctx.getQualifiedTemplateName(qualifier, hasTemplateKeyword, - declaration); + underlyingTemplateName); }]>; } let Class = PropertyTypeCase<TemplateName, "DependentTemplate"> in { diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h index 1bd86b0bdcf11..b6f4332830c8f 100644 --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/include/clang/AST/TemplateName.h @@ -414,13 +414,19 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { /// this name with DependentTemplateName). llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier; - /// The template declaration or set of overloaded function templates - /// that this qualified name refers to. - TemplateDecl *Template; + /// The underlying template name, it is either + /// 1) a Template -- a template declaration that this qualified name refers + /// to. + /// 2) or a UsingTemplate -- a template declaration introduced by a + /// using-shadow declaration. + TemplateName UnderlyingTemplate; QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, - TemplateDecl *Template) - : Qualifier(NNS, TemplateKeyword? 1 : 0), Template(Template) {} + TemplateName Template) + : Qualifier(NNS, TemplateKeyword ? 1 : 0), UnderlyingTemplate(Template) { + assert(UnderlyingTemplate.getKind() == TemplateName::Template || + UnderlyingTemplate.getKind() == TemplateName::UsingTemplate); + } public: /// Return the nested name specifier that qualifies this name. @@ -430,19 +436,25 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { /// keyword. bool hasTemplateKeyword() const { return Qualifier.getInt(); } + /// Return the underlying template name. + TemplateName getUnderlyingTemplate() const { return UnderlyingTemplate; } + /// The template declaration to which this qualified name /// refers. - TemplateDecl *getTemplateDecl() const { return Template; } + /// FIXME: remove this and use getUnderlyingTemplate() instead. + TemplateDecl *getTemplateDecl() const { + return UnderlyingTemplate.getAsTemplateDecl(); + } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getQualifier(), hasTemplateKeyword(), getTemplateDecl()); + Profile(ID, getQualifier(), hasTemplateKeyword(), UnderlyingTemplate); } static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, - bool TemplateKeyword, TemplateDecl *Template) { + bool TemplateKeyword, TemplateName TN) { ID.AddPointer(NNS); ID.AddBoolean(TemplateKeyword); - ID.AddPointer(Template); + ID.AddPointer(TN.getAsVoidPointer()); } }; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index dacc4f3ae855e..eb8d53a20012b 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4859,11 +4859,10 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, "No dependent template names here!"); // Look through qualified template names. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Template = TemplateName(QTN->getTemplateDecl()); + Template = QTN->getUnderlyingTemplate(); bool IsTypeAlias = - Template.getAsTemplateDecl() && - isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl()); + isa_and_nonnull<TypeAliasTemplateDecl>(Template.getAsTemplateDecl()); QualType CanonType; if (!Underlying.isNull()) CanonType = getCanonicalType(Underlying); @@ -4915,7 +4914,7 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( // Look through qualified template names. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Template = TemplateName(QTN->getTemplateDecl()); + Template = TemplateName(QTN->getUnderlyingTemplate()); // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); @@ -8978,10 +8977,9 @@ TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const { /// Retrieve the template name that represents a qualified /// template name such as \c std::vector. -TemplateName -ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, - bool TemplateKeyword, - TemplateDecl *Template) const { +TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, + bool TemplateKeyword, + TemplateName Template) const { assert(NNS && "Missing nested-name-specifier in qualified template name"); // FIXME: Canonicalization? diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 319f39b43264c..537ccc22ed050 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -9185,13 +9185,11 @@ Expected<TemplateName> ASTImporter::Import(TemplateName From) { auto QualifierOrErr = Import(QTN->getQualifier()); if (!QualifierOrErr) return QualifierOrErr.takeError(); - - if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl())) - return ToContext.getQualifiedTemplateName( - *QualifierOrErr, QTN->hasTemplateKeyword(), - cast<TemplateDecl>(*ToTemplateOrErr)); - else - return ToTemplateOrErr.takeError(); + auto TNOrErr = Import(QTN->getUnderlyingTemplate()); + if (!TNOrErr) + return TNOrErr.takeError(); + return ToContext.getQualifiedTemplateName( + *QualifierOrErr, QTN->hasTemplateKeyword(), *TNOrErr); } case TemplateName::DependentTemplate: { diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index 561757b1ba645..26aaa96a1dc68 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -80,8 +80,12 @@ static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, Ctx, ArgTDecl, true, WithGlobalNsPrefix); } if (NNS) { - TName = Ctx.getQualifiedTemplateName(NNS, - /*TemplateKeyword=*/false, ArgTDecl); + TemplateName UnderlyingTN(ArgTDecl); + if (UsingShadowDecl *USD = TName.getAsUsingShadowDecl()) + UnderlyingTN = TemplateName(USD); + TName = + Ctx.getQualifiedTemplateName(NNS, + /*TemplateKeyword=*/false, UnderlyingTN); Changed = true; } return Changed; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index a854de6479781..250a553c414ea 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1114,18 +1114,14 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, UsingShadowDecl *FoundUsingShadow = dyn_cast<UsingShadowDecl>(*Result.begin()); - - if (SS.isNotEmpty()) { - // FIXME: support using shadow-declaration in qualified template name. - Template = - Context.getQualifiedTemplateName(SS.getScopeRep(), - /*TemplateKeyword=*/false, TD); - } else { - assert(!FoundUsingShadow || - TD == cast<TemplateDecl>(FoundUsingShadow->getTargetDecl())); - Template = FoundUsingShadow ? TemplateName(FoundUsingShadow) - : TemplateName(TD); - } + assert(!FoundUsingShadow || + TD == cast<TemplateDecl>(FoundUsingShadow->getTargetDecl())); + Template = + FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD); + if (SS.isNotEmpty()) + Template = Context.getQualifiedTemplateName(SS.getScopeRep(), + /*TemplateKeyword=*/false, + Template); } else { // All results were non-template functions. This is a function template // name. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index e7195edc9a268..4a42969c34d3f 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -284,17 +284,13 @@ TemplateNameKind Sema::isTemplateName(Scope *S, } TemplateDecl *TD = cast<TemplateDecl>(D); - + Template = + FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD); + assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD); if (SS.isSet() && !SS.isInvalid()) { NestedNameSpecifier *Qualifier = SS.getScopeRep(); - // FIXME: store the using TemplateName in QualifiedTemplateName if - // the TD is referred via a using-declaration. - Template = - Context.getQualifiedTemplateName(Qualifier, hasTemplateKeyword, TD); - } else { - Template = - FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD); - assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD); + Template = Context.getQualifiedTemplateName(Qualifier, hasTemplateKeyword, + Template); } if (isa<FunctionTemplateDecl>(TD)) { @@ -1005,8 +1001,8 @@ ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) { TemplateName Name = DTST.getTypePtr()->getTemplateName(); if (SS.isSet()) Name = Context.getQualifiedTemplateName(SS.getScopeRep(), - /*HasTemplateKeyword*/ false, - Name.getAsTemplateDecl()); + /*HasTemplateKeyword=*/false, + Name); ParsedTemplateArgument Result(SS, TemplateTy::make(Name), DTST.getTemplateNameLoc()); if (EllipsisLoc.isValid()) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 5eff7cfd7a253..282163cf4c923 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -14714,7 +14714,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, bool TemplateKW, TemplateDecl *Template) { return SemaRef.Context.getQualifiedTemplateName(SS.getScopeRep(), TemplateKW, - Template); + TemplateName(Template)); } template<typename Derived> diff --git a/clang/unittests/AST/TemplateNameTest.cpp b/clang/unittests/AST/TemplateNameTest.cpp index 30986920ce28e..5844af6cc957f 100644 --- a/clang/unittests/AST/TemplateNameTest.cpp +++ b/clang/unittests/AST/TemplateNameTest.cpp @@ -58,5 +58,69 @@ TEST(TemplateName, PrintUsingTemplate) { "vector"); } +TEST(TemplateName, QualifiedUsingTemplate) { + std::string Code = R"cpp( + namespace std { + template <typename> struct vector {}; + } + namespace absl { using std::vector; } + + template<template <typename> class T> class X; + + using A = X<absl::vector>; // QualifiedTemplateName in a template argument. + )cpp"; + auto AST = tooling::buildASTFromCode(Code); + // Match the template argument absl::vector in X<absl::vector>. + auto Matcher = templateArgumentLoc().bind("id"); + auto MatchResults = match(Matcher, AST->getASTContext()); + const auto *TAL = MatchResults.front().getNodeAs<TemplateArgumentLoc>("id"); + ASSERT_TRUE(TAL); + TemplateName TN = TAL->getArgument().getAsTemplate(); + EXPECT_EQ(TN.getKind(), TemplateName::QualifiedTemplate); + const auto *QTN = TN.getAsQualifiedTemplateName(); + // Verify that we have the Using template name in the QualifiedTemplateName. + const auto *USD = QTN->getUnderlyingTemplate().getAsUsingShadowDecl(); + EXPECT_TRUE(USD); + EXPECT_EQ(USD->getTargetDecl(), TN.getAsTemplateDecl()); +} + +TEST(TemplateName, UsingTemplate) { + auto AST = tooling::buildASTFromCode(R"cpp( + namespace std { + template <typename T> struct vector { vector(T); }; + } + namespace absl { using std::vector; } + // The "absl::vector<int>" is an elaborated TemplateSpecializationType with + // an inner Using TemplateName (not a Qualified TemplateName, the qualifiers + // are rather part of the ElaboratedType)! + absl::vector<int> v(123); + )cpp"); + auto Matcher = elaboratedTypeLoc( + hasNamedTypeLoc(loc(templateSpecializationType().bind("id")))); + auto MatchResults = match(Matcher, AST->getASTContext()); + const auto *TST = + MatchResults.front().getNodeAs<TemplateSpecializationType>("id"); + ASSERT_TRUE(TST); + EXPECT_EQ(TST->getTemplateName().getKind(), TemplateName::UsingTemplate); + + AST = tooling::buildASTFromCodeWithArgs(R"cpp( + namespace std { + template <typename T> struct vector { vector(T); }; + } + namespace absl { using std::vector; } + // Similiar to the TemplateSpecializationType, absl::vector is an elaborated + // DeducedTemplateSpecializationType with an inner Using TemplateName! + absl::vector DTST(123); + )cpp", + {"-std=c++17"}); + Matcher = elaboratedTypeLoc( + hasNamedTypeLoc(loc(deducedTemplateSpecializationType().bind("id")))); + MatchResults = match(Matcher, AST->getASTContext()); + const auto *DTST = + MatchResults.front().getNodeAs<DeducedTemplateSpecializationType>("id"); + ASSERT_TRUE(DTST); + EXPECT_EQ(DTST->getTemplateName().getKind(), TemplateName::UsingTemplate); +} + } // namespace } // namespace clang _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits