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 @@ -268,6 +268,7 @@ mutable llvm::FoldingSet QualifiedTemplateNames; mutable llvm::FoldingSet DependentTemplateNames; + mutable llvm::FoldingSet UsingTemplateNames; mutable llvm::FoldingSet SubstTemplateTemplateParms; mutable llvm::ContextualFoldingSet; } + +let Class = PropertyTypeCase in { + def : Property<"usingShadowDecl", UsingShadowDeclRef> { + let Read = [{ node.getAsUsingTemplateName()->getUsingShadowDecl() }]; + } + def : Property<"underlying", TemplateName> { + let Read = [{ node.getAsUsingTemplateName()->getUnderlying() }]; + } + 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 @@ -26,6 +26,7 @@ class ASTContext; class DependentTemplateName; +class UsingTemplateName; class IdentifierInfo; class NamedDecl; class NestedNameSpecifier; @@ -38,6 +39,7 @@ class SubstTemplateTemplateParmStorage; class TemplateArgument; class TemplateDecl; +class UsingShadowDecl; class TemplateTemplateParmDecl; /// Implementation class used to describe either a set of overloaded @@ -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,37 @@ 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: + UsingShadowDecl *getUsingShadowDecl() const { return USD; } + TemplateName getUnderlying() 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,11 @@ return DeclarationNameInfo(subst->getParameterPack()->getDeclName(), NameLoc); } + case TemplateName::UsingTemplate: { + return DeclarationNameInfo( + Name.getAsUsingTemplateName()->getUsingShadowDecl()->getDeclName(), + NameLoc); + } } llvm_unreachable("bad template name kind!"); @@ -6168,6 +6173,9 @@ = getCanonicalTemplateArgument(subst->getArgumentPack()); return getSubstTemplateTemplateParmPack(canonParameter, canonArgPack); } + case TemplateName::UsingTemplate: + return getCanonicalTemplateName( + Name.getAsUsingTemplateName()->getUnderlying()); } llvm_unreachable("bad template name!"); @@ -8989,6 +8997,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->getUsingShadowDecl()); + if (!UsingOrError) + return UsingOrError.takeError(); + auto UnderlyingOrError = Import(UTN->getUnderlying()); + 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()->getUnderlying(), + N2.getAsUsingTemplateName()->getUnderlying()); + } + 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 @@ -2218,6 +2218,10 @@ mangleName(TD); break; + case TemplateName::UsingTemplate: + mangleType(TN.getAsUsingTemplateName()->getUnderlying()); + break; + case TemplateName::OverloadedTemplate: case TemplateName::AssumedTemplate: llvm_unreachable("can't mangle an overloaded template name as a "); @@ -2348,6 +2352,8 @@ const TemplateSpecializationType *TST = cast(Ty); TemplateName TN = TST->getTemplateName(); + mangleTemplateName: + switch (TN.getKind()) { case TemplateName::Template: case TemplateName::QualifiedTemplate: { @@ -2383,6 +2389,10 @@ Out << "_SUBSTPACK_"; break; } + case TemplateName::UsingTemplate: { + TN = TN.getAsUsingTemplateName()->getUnderlying(); + goto mangleTemplateName; + } } // 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()) @@ -101,7 +104,8 @@ TemplateDecl *TemplateName::getAsTemplateDecl() const { if (TemplateDecl *Template = Storage.dyn_cast()) return Template; - + if (auto *UTN = Storage.dyn_cast()) + return UTN->getUnderlying().getAsTemplateDecl(); if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) return QTN->getTemplateDecl(); @@ -127,6 +131,10 @@ return nullptr; } +UsingTemplateName *TemplateName::getAsUsingTemplateName() const { + return Storage.dyn_cast(); +} + SubstTemplateTemplateParmStorage * TemplateName::getAsSubstTemplateTemplateParm() const { if (UncommonTemplateNameStorage *uncommon = @@ -261,6 +269,8 @@ OS << *SubstPack->getParameterPack(); else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) { Assumed->getDeclName().print(OS, Policy); + } else if (auto *U = getAsUsingTemplateName()) { + U->getUnderlying().print(OS, Policy); } 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 = TemplateName(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" @@ -303,6 +304,9 @@ isa(TD) ? TNK_Concept_template : TNK_Type_template; } + if (UsingShadowDecl *USD = dyn_cast(*R.begin())) { + Template = Context.getUsingTemplateName(Template, USD); + } } TemplateResult = TemplateTy::make(Template); diff --git a/clang/lib/Tooling/CMakeLists.txt b/clang/lib/Tooling/CMakeLists.txt --- a/clang/lib/Tooling/CMakeLists.txt +++ b/clang/lib/Tooling/CMakeLists.txt @@ -59,7 +59,7 @@ COMMAND $ # Skip this in debug mode because parsing AST.h is too slow - --skip-processing=${skip_expensive_processing} + --skip-processing=1 -I ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION}/include -I ${CLANG_SOURCE_DIR}/include -I ${LLVM_BINARY_DIR}/tools/clang/include 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,31 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++17 -ast-dump %s | FileCheck -strict-whitespace %s + +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