[clang] 1234b1c - [AST] Support template declaration found through using-decl for QualifiedTemplateName.

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 21 01:53:35 PDT 2022


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


        


More information about the cfe-commits mailing list