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/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,16 @@ return TemplateName(declaration); }]>; } + +let Class = PropertyTypeCase in { + def : Property<"foundDecl", UsingShadowDeclRef> { + let Read = [{ node.getAsUsingShadowDecl() }]; + } + def : Creator<[{ + return TemplateName(foundDecl); + }]>; +} + 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 @@ -25,6 +25,7 @@ namespace clang { class ASTContext; +class Decl; class DependentTemplateName; class IdentifierInfo; class NamedDecl; @@ -39,6 +40,7 @@ class TemplateArgument; class TemplateDecl; class TemplateTemplateParmDecl; +class UsingShadowDecl; /// Implementation class used to describe either a set of overloaded /// template names or an already-substituted template template parameter pack. @@ -188,8 +190,12 @@ /// specifier in the typedef. "apply" is a nested template, and can /// only be understood in the context of class TemplateName { + // NameDecl is either a TemplateDecl or a UsingShadowDecl depending on the + // NameKind. + // !! There is no free low bits in 32-bit builds to discriminate more than 4 + // pointer types in PointerUnion. using StorageType = - llvm::PointerUnion; StorageType Storage; @@ -224,7 +230,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 declaration found through a + /// specific using shadow declaration. + UsingTemplate, }; TemplateName() = default; @@ -235,6 +245,7 @@ explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage); explicit TemplateName(QualifiedTemplateName *Qual); explicit TemplateName(DependentTemplateName *Dep); + explicit TemplateName(UsingShadowDecl *Using); /// Determine whether this template name is NULL. bool isNull() const; @@ -287,6 +298,10 @@ /// structure, if any. DependentTemplateName *getAsDependentTemplateName() const; + /// Retrieve the using shadow declaration through which the underlying + /// template declaration is introduced, if any. + UsingShadowDecl *getAsUsingShadowDecl() const; + TemplateName getUnderlying() const; /// Get the template name to substitute when this template name is used as a 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,9 @@ return DeclarationNameInfo(subst->getParameterPack()->getDeclName(), NameLoc); } + case TemplateName::UsingTemplate: + return DeclarationNameInfo(Name.getAsUsingShadowDecl()->getDeclName(), + NameLoc); } llvm_unreachable("bad template name kind!"); @@ -6133,6 +6136,7 @@ TemplateName ASTContext::getCanonicalTemplateName(const TemplateName &Name) const { switch (Name.getKind()) { + case TemplateName::UsingTemplate: case TemplateName::QualifiedTemplate: case TemplateName::Template: { TemplateDecl *Template = Name.getAsTemplateDecl(); 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 @@ -9240,6 +9240,12 @@ return ToContext.getSubstTemplateTemplateParmPack( cast(*ParamOrErr), *ArgPackOrErr); } + case TemplateName::UsingTemplate: { + auto UsingOrError = Import(From.getAsUsingShadowDecl()); + if (!UsingOrError) + return UsingOrError.takeError(); + return TemplateName(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 @@ -517,6 +517,7 @@ case TemplateName::Template: case TemplateName::QualifiedTemplate: case TemplateName::SubstTemplateTemplateParm: + case TemplateName::UsingTemplate: // It is sufficient to check value of getAsTemplateDecl. break; 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 @@ -2207,6 +2207,7 @@ TD = TN.getAsQualifiedTemplateName()->getTemplateDecl(); goto HaveDecl; + case TemplateName::UsingTemplate: case TemplateName::Template: TD = TN.getAsTemplateDecl(); goto HaveDecl; @@ -2383,6 +2384,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 @@ -13,6 +13,7 @@ #include "clang/AST/TemplateName.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DependenceFlags.h" #include "clang/AST/NestedNameSpecifier.h" @@ -76,12 +77,18 @@ : Storage(Storage) {} TemplateName::TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) {} TemplateName::TemplateName(DependentTemplateName *Dep) : Storage(Dep) {} +TemplateName::TemplateName(UsingShadowDecl *Using) : Storage(Using) {} bool TemplateName::isNull() const { return Storage.isNull(); } TemplateName::NameKind TemplateName::getKind() const { - if (Storage.is()) + if (auto *ND = Storage.dyn_cast()) { + if (isa(ND)) + return UsingTemplate; + assert(isa(ND)); return Template; + } + if (Storage.is()) return DependentTemplate; if (Storage.is()) @@ -99,8 +106,13 @@ } TemplateDecl *TemplateName::getAsTemplateDecl() const { - if (TemplateDecl *Template = Storage.dyn_cast()) - return Template; + if (Decl *TemplateOrUsing = Storage.dyn_cast()) { + if (UsingShadowDecl *USD = dyn_cast(TemplateOrUsing)) + return cast(USD->getTargetDecl()); + + assert(isa(TemplateOrUsing)); + return cast(TemplateOrUsing); + } if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) return QTN->getTemplateDecl(); @@ -108,6 +120,9 @@ if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm()) return sub->getReplacement().getAsTemplateDecl(); + if (UsingShadowDecl *USD = getAsUsingShadowDecl()) + return cast(USD->getTargetDecl()); + return nullptr; } @@ -153,6 +168,13 @@ return Storage.dyn_cast(); } +UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const { + if (Decl *D = Storage.dyn_cast()) + if (UsingShadowDecl *USD = dyn_cast(D)) + return USD; + return nullptr; +} + TemplateName TemplateName::getNameToSubstitute() const { TemplateDecl *Decl = getAsTemplateDecl(); @@ -222,7 +244,22 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, Qualified Qual) const { - if (TemplateDecl *Template = Storage.dyn_cast()) + auto Kind = getKind(); + TemplateDecl *Template = nullptr; + if (Kind == TemplateName::Template || Kind == TemplateName::UsingTemplate) { + // After `namespace ns { using std::vector }`, what is the fully-qualified + // name of the UsingTemplateName `vector` within ns? + // + // - ns::vector (the qualified name of the using-shadow decl) + // - std::vector (the qualified name of the underlying template decl) + // + // Similar to the UsingType behavior, using declarations are used to import + // names more often than to export them, thus using the original name is + // most useful in this case. + Template = getAsTemplateDecl(); + } + + if (Template) if (Policy.CleanUglifiedParameters && isa(Template) && Template->getIdentifier()) OS << Template->getIdentifier()->deuglifiedName(); @@ -262,6 +299,7 @@ else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) { Assumed->getDeclName().print(OS, Policy); } else { + assert(getKind() == TemplateName::OverloadedTemplate); 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 @@ -504,9 +504,11 @@ FoundUsingShadow = nullptr; } else if (AllowDeducedTemplate) { if (auto *TD = getAsTypeTemplateDecl(IIDecl)) { - // FIXME: TemplateName should include FoundUsingShadow sugar. - T = Context.getDeducedTemplateSpecializationType(TemplateName(TD), - QualType(), false); + assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD); + TemplateName Template = + FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD); + T = Context.getDeducedTemplateSpecializationType(Template, QualType(), + false); // Don't wrap in a further UsingType. FoundUsingShadow = nullptr; } @@ -1107,12 +1109,20 @@ IsFunctionTemplate = isa(TD); IsVarTemplate = isa(TD); - if (SS.isNotEmpty()) + 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 - Template = TemplateName(TD); + } else { + assert(!FoundUsingShadow || + TD == cast(FoundUsingShadow->getTargetDecl())); + Template = FoundUsingShadow ? TemplateName(FoundUsingShadow) + : TemplateName(TD); + } } else { // All results were non-template functions. This is a function template // name. 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,6 +11023,8 @@ TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName(); bool TemplateMatches = Context.hasSameTemplateName(SpecifiedName, GuidedTemplate); + // FIXME: We should consider other template kinds (using, qualified), + // otherwise we will emit bogus diagnostics. if (SpecifiedName.getKind() == TemplateName::Template && TemplateMatches) AcceptableReturnType = true; else { 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 @@ -11,11 +11,13 @@ #include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #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" @@ -223,6 +225,7 @@ return TNK_Non_template; NamedDecl *D = nullptr; + UsingShadowDecl *FoundUsingShadow = dyn_cast(*R.begin()); if (R.isAmbiguous()) { // If we got an ambiguity involving a non-function template, treat this // as a template name, and pick an arbitrary template for error recovery. @@ -233,6 +236,7 @@ AnyFunctionTemplates = true; else { D = FoundTemplate; + FoundUsingShadow = dyn_cast(FoundD); break; } } @@ -283,10 +287,14 @@ if (SS.isSet() && !SS.isInvalid()) { NestedNameSpecifier *Qualifier = SS.getScopeRep(); - Template = Context.getQualifiedTemplateName(Qualifier, - hasTemplateKeyword, TD); + // FIXME: store the using TemplateName in QualifiedTemplateName if + // the TD is referred via a using-declaration. + Template = + Context.getQualifiedTemplateName(Qualifier, hasTemplateKeyword, TD); } else { - Template = TemplateName(TD); + Template = + FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD); + assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD); } if (isa(TD)) { 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