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,16 @@ def : Property<"hasTemplateKeyword", Bool> { let Read = [{ qtn->hasTemplateKeyword() }]; } - def : Property<"declaration", TemplateDeclRef> { + def : Property<"templateDecl", TemplateDeclRef> { let Read = [{ qtn->getTemplateDecl() }]; } + def : Property<"usingShadowDecl", UsingShadowDeclRef> { + let Read = [{ qtn->getUsingShadowDecl() }]; + } def : Creator<[{ return ctx.getQualifiedTemplateName(qualifier, hasTemplateKeyword, - declaration); + usingShadowDecl ? TemplateName(usingShadowDecl) : + TemplateName(templateDecl)); }]>; } 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,16 @@ /// 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 TemplateName -- a template declaration or set of overloaded + // function templates that this qualified name refers to. + // 2) or a UsingTemplate TemplateName -- 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) {} public: /// Return the nested name specifier that qualifies this name. @@ -432,17 +435,25 @@ /// The template declaration to which this qualified name /// refers. - TemplateDecl *getTemplateDecl() const { return Template; } + TemplateDecl *getTemplateDecl() const { + return UnderlyingTemplate.getAsTemplateDecl(); + } + + /// If the underlying template declaration is found through a using-shadow + /// declaration, returns the using-shadow declaration. + UsingShadowDecl *getUsingShadowDecl() const { + return UnderlyingTemplate.getAsUsingShadowDecl(); + } 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 @@ -4851,12 +4851,15 @@ assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); // Look through qualified template names. - if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Template = TemplateName(QTN->getTemplateDecl()); + if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) { + if (UsingShadowDecl *USD = QTN->getUsingShadowDecl()) + Template = TemplateName(USD); + else + Template = TemplateName(QTN->getTemplateDecl()); + } bool IsTypeAlias = - Template.getAsTemplateDecl() && - isa(Template.getAsTemplateDecl()); + isa_and_nonnull(Template.getAsTemplateDecl()); QualType CanonType; if (!Underlying.isNull()) CanonType = getCanonicalType(Underlying); @@ -4907,8 +4910,12 @@ "No dependent template names here!"); // Look through qualified template names. - if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Template = TemplateName(QTN->getTemplateDecl()); + if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) { + if (UsingShadowDecl *USD = QTN->getUsingShadowDecl()) + Template = TemplateName(USD); + else + Template = TemplateName(QTN->getTemplateDecl()); + } // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); @@ -8971,15 +8978,15 @@ /// 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? llvm::FoldingSetNodeID ID; - QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template); + QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, + TemplateName(Template)); void *InsertPos = nullptr; QualifiedTemplateName *QTN = 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,11 +9185,19 @@ auto QualifierOrErr = Import(QTN->getQualifier()); if (!QualifierOrErr) return QualifierOrErr.takeError(); + if (UsingShadowDecl *USD = QTN->getUsingShadowDecl()) { + if (ExpectedDecl ToUSDOrErr = Import(USD)) + return ToContext.getQualifiedTemplateName( + *QualifierOrErr, QTN->hasTemplateKeyword(), + TemplateName(cast(*ToUSDOrErr))); + else + return ToUSDOrErr.takeError(); + } if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl())) return ToContext.getQualifiedTemplateName( *QualifierOrErr, QTN->hasTemplateKeyword(), - cast(*ToTemplateOrErr)); + TemplateName(cast(*ToTemplateOrErr))); else return ToTemplateOrErr.takeError(); } 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 @@ -14714,7 +14714,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,66 @@ "vector"); } +TEST(TemplateName, QualifiedUsingTemplate) { + std::string Code = R"cpp( + namespace std { + template struct vector {}; + } + namespace absl { using std::vector; } + + template