diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2182,7 +2182,7 @@ 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 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -663,12 +663,12 @@ 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 in { diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/include/clang/AST/TemplateName.h @@ -414,13 +414,19 @@ /// this name with DependentTemplateName). llvm::PointerIntPair 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 @@ /// 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 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4852,11 +4852,10 @@ "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(Template.getAsTemplateDecl()); + isa_and_nonnull(Template.getAsTemplateDecl()); QualType CanonType; if (!Underlying.isNull()) CanonType = getCanonicalType(Underlying); @@ -4908,7 +4907,7 @@ // 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); @@ -8971,10 +8970,9 @@ /// 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 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -9185,13 +9185,11 @@ auto QualifierOrErr = Import(QTN->getQualifier()); if (!QualifierOrErr) return QualifierOrErr.takeError(); - - if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl())) - return ToContext.getQualifiedTemplateName( - *QualifierOrErr, QTN->hasTemplateKeyword(), - cast(*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 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -80,8 +80,12 @@ 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 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1111,18 +1111,14 @@ UsingShadowDecl *FoundUsingShadow = dyn_cast(*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(FoundUsingShadow->getTargetDecl())); - Template = FoundUsingShadow ? TemplateName(FoundUsingShadow) - : TemplateName(TD); - } + assert(!FoundUsingShadow || + TD == cast(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 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -284,17 +284,13 @@ } TemplateDecl *TD = cast(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(TD)) { @@ -1006,7 +1002,7 @@ if (SS.isSet()) Name = Context.getQualifiedTemplateName(SS.getScopeRep(), /*HasTemplateKeyword*/ false, - Name.getAsTemplateDecl()); + 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 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -14715,7 +14715,7 @@ bool TemplateKW, TemplateDecl *Template) { return SemaRef.Context.getQualifiedTemplateName(SS.getScopeRep(), TemplateKW, - Template); + TemplateName(Template)); } template diff --git a/clang/unittests/AST/TemplateNameTest.cpp b/clang/unittests/AST/TemplateNameTest.cpp --- a/clang/unittests/AST/TemplateNameTest.cpp +++ b/clang/unittests/AST/TemplateNameTest.cpp @@ -58,5 +58,69 @@ "vector"); } +TEST(TemplateName, QualifiedUsingTemplate) { + std::string Code = R"cpp( + namespace std { + template struct vector {}; + } + namespace absl { using std::vector; } + + template