diff --git a/clang-tools-extra/clangd/DumpAST.cpp b/clang-tools-extra/clangd/DumpAST.cpp --- a/clang-tools-extra/clangd/DumpAST.cpp +++ b/clang-tools-extra/clangd/DumpAST.cpp @@ -184,6 +184,7 @@ TEMPLATE_KIND(DependentTemplate); TEMPLATE_KIND(SubstTemplateTemplateParm); TEMPLATE_KIND(SubstTemplateTemplateParmPack); + TEMPLATE_KIND(UsingTemplate); #undef TEMPLATE_KIND } llvm_unreachable("Unhandled NameKind enum"); diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp --- a/clang-tools-extra/clangd/SemanticHighlighting.cpp +++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -762,6 +762,7 @@ case TemplateName::QualifiedTemplate: case TemplateName::SubstTemplateTemplateParm: case TemplateName::SubstTemplateTemplateParmPack: + case TemplateName::UsingTemplate: // Names that could be resolved to a TemplateDecl are handled elsewhere. break; } 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 @@ -273,6 +273,7 @@ mutable llvm::ContextualFoldingSet SubstTemplateTemplateParmPacks; + mutable llvm::FoldingSet UsingTemplateNames; /// The set of nested name specifiers. /// @@ -2189,6 +2190,9 @@ TemplateName getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, const TemplateArgument &ArgPack) const; + TemplateName getUsingTemplateName(TemplateName Underlying, + UsingShadowDecl *USD) const; + enum GetBuiltinTypeError { /// No error GE_None, 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 @@ -620,6 +620,19 @@ return TemplateName(declaration); }]>; } + +let Class = PropertyTypeCase in { + def : Property<"usingShadowDecl", UsingShadowDeclRef> { + let Read = [{ node.getAsUsingTemplateName()->getFoundDecl() }]; + } + def : Property<"underlying", TemplateName> { + let Read = [{ node.getAsUsingTemplateName()->getUnderlyingTemplate() }]; + } + def : Creator<[{ + return ctx.getUsingTemplateName(underlying, usingShadowDecl); + }]>; +} + let Class = PropertyTypeCase in { def : Property<"overloads", Array> { let Read = [{ node.getAsOverloadedTemplate()->decls() }]; 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 @@ -39,6 +39,8 @@ class TemplateArgument; class TemplateDecl; class TemplateTemplateParmDecl; +class UsingShadowDecl; +class UsingTemplateName; /// Implementation class used to describe either a set of overloaded /// template names or an already-substituted template template parameter pack. @@ -190,7 +192,8 @@ class TemplateName { using StorageType = llvm::PointerUnion; + QualifiedTemplateName *, DependentTemplateName *, + UsingTemplateName *>; StorageType Storage; @@ -224,7 +227,11 @@ /// A template template parameter pack that has been substituted for /// a template template argument pack, but has not yet been expanded into /// individual arguments. - SubstTemplateTemplateParmPack + SubstTemplateTemplateParmPack, + + /// A template name that refers to a template through a specific using + /// shadow declaration. + UsingTemplate, }; TemplateName() = default; @@ -235,6 +242,7 @@ explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage); explicit TemplateName(QualifiedTemplateName *Qual); explicit TemplateName(DependentTemplateName *Dep); + explicit TemplateName(UsingTemplateName *Using); /// Determine whether this template name is NULL. bool isNull() const; @@ -287,6 +295,9 @@ /// structure, if any. DependentTemplateName *getAsDependentTemplateName() const; + /// Retrieve the underlying using template name, if any. + UsingTemplateName *getAsUsingTemplateName() const; + TemplateName getUnderlying() const; /// Get the template name to substitute when this template name is used as a @@ -376,6 +387,42 @@ return *this; } +/// Represents a template name that refers to a template introduced by a using +/// declaration. For example, +/// +/// \code +/// using std::vector; +/// +/// vector v; +/// \endcode +/// The `vector` in \c vector is a UsingTemplateName where its underlying +/// template name is a normal template name which refers to the vector class +/// template. +class UsingTemplateName : public llvm::FoldingSetNode { + friend class ASTContext; + + TemplateName UnderlyingTN; + UsingShadowDecl *USD = nullptr; + + UsingTemplateName(TemplateName UnderlyingTN, UsingShadowDecl *USD) + : UnderlyingTN(UnderlyingTN), USD(USD) {} + +public: + /// Returns the using shadow declaration through which the underlying template + /// is introduced. + UsingShadowDecl *getFoundDecl() const { return USD; } + /// Returns the underlying template name, which refers to the a template + /// introduced by the using decl. + TemplateName getUnderlyingTemplate() const { return UnderlyingTN; } + + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, UnderlyingTN, USD); } + static void Profile(llvm::FoldingSetNodeID &ID, TemplateName Underlying, + UsingShadowDecl *USD) { + ID.AddPointer(USD); + ID.AddPointer(Underlying.getAsVoidPointer()); + } +}; + /// Represents a template name that was expressed as a /// qualified name. /// diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -317,6 +317,8 @@ void VisitTagType(const TagType *T); void VisitTemplateTypeParmType(const TemplateTypeParmType *T); void VisitAutoType(const AutoType *T); + void VisitDeducedTemplateSpecializationType( + const DeducedTemplateSpecializationType *T); void VisitTemplateSpecializationType(const TemplateSpecializationType *T); void VisitInjectedClassNameType(const InjectedClassNameType *T); void VisitObjCInterfaceType(const ObjCInterfaceType *T); 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 @@ -6125,6 +6125,10 @@ return DeclarationNameInfo(subst->getParameterPack()->getDeclName(), NameLoc); } + case TemplateName::UsingTemplate: { + return DeclarationNameInfo( + Name.getAsUsingTemplateName()->getFoundDecl()->getDeclName(), NameLoc); + } } llvm_unreachable("bad template name kind!"); @@ -6168,6 +6172,9 @@ = getCanonicalTemplateArgument(subst->getArgumentPack()); return getSubstTemplateTemplateParmPack(canonParameter, canonArgPack); } + case TemplateName::UsingTemplate: + return getCanonicalTemplateName( + Name.getAsUsingTemplateName()->getUnderlyingTemplate()); } llvm_unreachable("bad template name!"); @@ -8989,6 +8996,24 @@ return TemplateName(QTN); } +TemplateName ASTContext::getUsingTemplateName(TemplateName Underlying, + UsingShadowDecl *USD) const { + + assert(USD); + llvm::FoldingSetNodeID ID; + UsingTemplateName::Profile(ID, Underlying, USD); + + void *InsertPos = nullptr; + UsingTemplateName *T = UsingTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return TemplateName(T); + + UsingTemplateName *NewType = new (*this, alignof(UsingTemplateName)) + UsingTemplateName(Underlying, USD); + UsingTemplateNames.InsertNode(NewType, InsertPos); + return TemplateName(NewType); +} + /// Retrieve the template name that represents a dependent /// template name such as \c MetaFun::template apply. TemplateName 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 @@ -9190,6 +9190,17 @@ return ToContext.getSubstTemplateTemplateParmPack( cast(*ParamOrErr), *ArgPackOrErr); } + case TemplateName::UsingTemplate: { + auto *UTN = From.getAsUsingTemplateName(); + auto UsingOrError = Import(UTN->getFoundDecl()); + if (!UsingOrError) + return UsingOrError.takeError(); + auto UnderlyingOrError = Import(UTN->getUnderlyingTemplate()); + if (!UnderlyingOrError) + return UnderlyingOrError.takeError(); + return ToContext.getUsingTemplateName(*UnderlyingOrError, + cast(*UsingOrError)); + } } llvm_unreachable("Invalid template name kind"); diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -514,6 +514,12 @@ P2->getParameterPack()); } + case TemplateName::UsingTemplate: { + return IsStructurallyEquivalent( + Context, N1.getAsUsingTemplateName()->getUnderlyingTemplate(), + N2.getAsUsingTemplateName()->getUnderlyingTemplate()); + } + case TemplateName::Template: case TemplateName::QualifiedTemplate: case TemplateName::SubstTemplateTemplateParm: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2252,6 +2252,10 @@ Out << "_SUBSTPACK_"; break; } + case TemplateName::UsingTemplate: { + mangleType(TN.getAsUsingTemplateName()->getUnderlyingTemplate()); + break; + } } addSubstitution(TN); @@ -2383,6 +2387,12 @@ Out << "_SUBSTPACK_"; break; } + case TemplateName::UsingTemplate: { + TemplateDecl *TD = TN.getAsTemplateDecl(); + assert(TD && !isa(TD)); + mangleSourceNameWithAbiTags(TD); + break; + } } // Note: we don't pass in the template name here. We are mangling the diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -150,6 +150,7 @@ case TemplateName::DependentTemplate: case TemplateName::SubstTemplateTemplateParm: case TemplateName::SubstTemplateTemplateParmPack: + case TemplateName::UsingTemplate: break; } } diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -76,12 +76,15 @@ : Storage(Storage) {} TemplateName::TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) {} TemplateName::TemplateName(DependentTemplateName *Dep) : Storage(Dep) {} +TemplateName::TemplateName(UsingTemplateName *Using) : Storage(Using) {} bool TemplateName::isNull() const { return Storage.isNull(); } TemplateName::NameKind TemplateName::getKind() const { if (Storage.is()) return Template; + if (Storage.is()) + return UsingTemplate; if (Storage.is()) return DependentTemplate; if (Storage.is()) @@ -108,6 +111,9 @@ if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm()) return sub->getReplacement().getAsTemplateDecl(); + if (auto *UTN = getAsUsingTemplateName()) + return UTN->getUnderlyingTemplate().getAsTemplateDecl(); + return nullptr; } @@ -127,6 +133,10 @@ return nullptr; } +UsingTemplateName *TemplateName::getAsUsingTemplateName() const { + return Storage.dyn_cast(); +} + SubstTemplateTemplateParmStorage * TemplateName::getAsSubstTemplateTemplateParm() const { if (UncommonTemplateNameStorage *uncommon = @@ -261,6 +271,8 @@ OS << *SubstPack->getParameterPack(); else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) { Assumed->getDeclName().print(OS, Policy); + } else if (auto *U = getAsUsingTemplateName()) { + U->getUnderlyingTemplate().print(OS, Policy, Qualified::None); } else { OverloadedTemplateStorage *OTS = getAsOverloadedTemplate(); (*OTS->begin())->printName(OS); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -900,12 +900,17 @@ } void TextNodeDumper::VisitTemplateTemplateArgument(const TemplateArgument &TA) { + if (TA.getAsTemplate().getKind() == TemplateName::UsingTemplate) + OS << " using"; OS << " template "; TA.getAsTemplate().dump(OS); } void TextNodeDumper::VisitTemplateExpansionTemplateArgument( const TemplateArgument &TA) { + if (TA.getAsTemplateOrTemplatePattern().getKind() == + TemplateName::UsingTemplate) + OS << " using"; OS << " template expansion "; TA.getAsTemplateOrTemplatePattern().dump(OS); } @@ -1575,10 +1580,18 @@ } } +void TextNodeDumper::VisitDeducedTemplateSpecializationType( + const DeducedTemplateSpecializationType *T) { + if (T->getTemplateName().getKind() == TemplateName::UsingTemplate) + OS << " using"; +} + void TextNodeDumper::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { if (T->isTypeAlias()) OS << " alias"; + if (T->getTemplateName().getKind() == TemplateName::UsingTemplate) + OS << " using"; OS << " "; T->getTemplateName().dump(OS); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3686,7 +3686,8 @@ "Use DependentTemplateSpecializationType for dependent template-name"); assert((T.getKind() == TemplateName::Template || T.getKind() == TemplateName::SubstTemplateTemplateParm || - T.getKind() == TemplateName::SubstTemplateTemplateParmPack) && + T.getKind() == TemplateName::SubstTemplateTemplateParmPack || + T.getKind() == TemplateName::UsingTemplate) && "Unexpected template name for TemplateSpecializationType"); auto *TemplateArgs = reinterpret_cast(this + 1); 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 @@ -503,9 +503,11 @@ FoundUsingShadow = nullptr; } else if (AllowDeducedTemplate) { if (auto *TD = getAsTypeTemplateDecl(IIDecl)) { - // FIXME: TemplateName should include FoundUsingShadow sugar. - T = Context.getDeducedTemplateSpecializationType(TemplateName(TD), - QualType(), false); + TemplateName Template(TD); + if (FoundUsingShadow) + Template = Context.getUsingTemplateName(Template, FoundUsingShadow); + T = Context.getDeducedTemplateSpecializationType(Template, QualType(), + false); // Don't wrap in a further UsingType. FoundUsingShadow = nullptr; } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11023,7 +11023,9 @@ TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName(); bool TemplateMatches = Context.hasSameTemplateName(SpecifiedName, GuidedTemplate); - if (SpecifiedName.getKind() == TemplateName::Template && TemplateMatches) + if ((SpecifiedName.getKind() == TemplateName::Template || + SpecifiedName.getKind() == TemplateName::UsingTemplate) && + TemplateMatches) AcceptableReturnType = true; else { // This could still instantiate to the right type, unless we know it 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 @@ -16,6 +16,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/TemplateName.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/LangOptions.h" @@ -288,6 +289,19 @@ } else { Template = TemplateName(TD); } + // FIXME: We wrap a QualifiedTemplateName with a UsingTempalteName. + // For example: + // + // namespace ns { template class A; } + // namespace ns2 { using ns::A; } + // ns2::A a; + // + // Ideally, we want to model the "ns2::A" with a QualifiedTemplateName, + // which has an inner UsingTemplateName modelling the A found via the using + // decl. Unfortunately, QualifiedTemplate only stores the underlying + // TemplateDecl. + if (UsingShadowDecl *USD = dyn_cast(*R.begin())) + Template = Context.getUsingTemplateName(Template, USD); if (isa(TD)) { TemplateKind = TNK_Function_template; diff --git a/clang/test/AST/ast-dump-using-template.cpp b/clang/test/AST/ast-dump-using-template.cpp new file mode 100644 --- /dev/null +++ b/clang/test/AST/ast-dump-using-template.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++17 -ast-dump %s | FileCheck -strict-whitespace %s + +// Tests to verify we construct correct using template names. +// TemplateNames are not dumped, so the sugar here isn't obvious. However +// the "using" on the TemplateSpecializationTypes shows that the +// UsingTemplateName is present. +namespace ns { +template class S { + public: + S(T); +}; +} +using ns::S; + +// TemplateName in TemplateSpecializationType. +template +using A = S; +// CHECK: TypeAliasDecl +// CHECK-NEXT: `-TemplateSpecializationType {{.*}} 'S' dependent using S + +// TemplateName in TemplateArgument. +template