Skip to content

Commit 1234b1c

Browse files
committed
[AST] Support template declaration found through using-decl for QualifiedTemplateName.
This is a followup of https://reviews.llvm.org/D123127, adding support for the QualifiedTemplateName. Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D123775
1 parent 8988254 commit 1234b1c

File tree

10 files changed

+122
-54
lines changed

10 files changed

+122
-54
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2182,7 +2182,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
21822182

21832183
TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS,
21842184
bool TemplateKeyword,
2185-
TemplateDecl *Template) const;
2185+
TemplateName Template) const;
21862186

21872187
TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
21882188
const IdentifierInfo *Name) const;

clang/include/clang/AST/PropertiesBase.td

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -663,12 +663,12 @@ let Class = PropertyTypeCase<TemplateName, "QualifiedTemplate"> in {
663663
def : Property<"hasTemplateKeyword", Bool> {
664664
let Read = [{ qtn->hasTemplateKeyword() }];
665665
}
666-
def : Property<"declaration", TemplateDeclRef> {
667-
let Read = [{ qtn->getTemplateDecl() }];
666+
def : Property<"underlyingTemplateName", TemplateName> {
667+
let Read = [{ qtn->getUnderlyingTemplate() }];
668668
}
669669
def : Creator<[{
670670
return ctx.getQualifiedTemplateName(qualifier, hasTemplateKeyword,
671-
declaration);
671+
underlyingTemplateName);
672672
}]>;
673673
}
674674
let Class = PropertyTypeCase<TemplateName, "DependentTemplate"> in {

clang/include/clang/AST/TemplateName.h

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -414,13 +414,19 @@ class QualifiedTemplateName : public llvm::FoldingSetNode {
414414
/// this name with DependentTemplateName).
415415
llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier;
416416

417-
/// The template declaration or set of overloaded function templates
418-
/// that this qualified name refers to.
419-
TemplateDecl *Template;
417+
/// The underlying template name, it is either
418+
/// 1) a Template -- a template declaration that this qualified name refers
419+
/// to.
420+
/// 2) or a UsingTemplate -- a template declaration introduced by a
421+
/// using-shadow declaration.
422+
TemplateName UnderlyingTemplate;
420423

421424
QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword,
422-
TemplateDecl *Template)
423-
: Qualifier(NNS, TemplateKeyword? 1 : 0), Template(Template) {}
425+
TemplateName Template)
426+
: Qualifier(NNS, TemplateKeyword ? 1 : 0), UnderlyingTemplate(Template) {
427+
assert(UnderlyingTemplate.getKind() == TemplateName::Template ||
428+
UnderlyingTemplate.getKind() == TemplateName::UsingTemplate);
429+
}
424430

425431
public:
426432
/// Return the nested name specifier that qualifies this name.
@@ -430,19 +436,25 @@ class QualifiedTemplateName : public llvm::FoldingSetNode {
430436
/// keyword.
431437
bool hasTemplateKeyword() const { return Qualifier.getInt(); }
432438

439+
/// Return the underlying template name.
440+
TemplateName getUnderlyingTemplate() const { return UnderlyingTemplate; }
441+
433442
/// The template declaration to which this qualified name
434443
/// refers.
435-
TemplateDecl *getTemplateDecl() const { return Template; }
444+
/// FIXME: remove this and use getUnderlyingTemplate() instead.
445+
TemplateDecl *getTemplateDecl() const {
446+
return UnderlyingTemplate.getAsTemplateDecl();
447+
}
436448

437449
void Profile(llvm::FoldingSetNodeID &ID) {
438-
Profile(ID, getQualifier(), hasTemplateKeyword(), getTemplateDecl());
450+
Profile(ID, getQualifier(), hasTemplateKeyword(), UnderlyingTemplate);
439451
}
440452

441453
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
442-
bool TemplateKeyword, TemplateDecl *Template) {
454+
bool TemplateKeyword, TemplateName TN) {
443455
ID.AddPointer(NNS);
444456
ID.AddBoolean(TemplateKeyword);
445-
ID.AddPointer(Template);
457+
ID.AddPointer(TN.getAsVoidPointer());
446458
}
447459
};
448460

clang/lib/AST/ASTContext.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4859,11 +4859,10 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
48594859
"No dependent template names here!");
48604860
// Look through qualified template names.
48614861
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
4862-
Template = TemplateName(QTN->getTemplateDecl());
4862+
Template = QTN->getUnderlyingTemplate();
48634863

48644864
bool IsTypeAlias =
4865-
Template.getAsTemplateDecl() &&
4866-
isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
4865+
isa_and_nonnull<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
48674866
QualType CanonType;
48684867
if (!Underlying.isNull())
48694868
CanonType = getCanonicalType(Underlying);
@@ -4915,7 +4914,7 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
49154914

49164915
// Look through qualified template names.
49174916
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
4918-
Template = TemplateName(QTN->getTemplateDecl());
4917+
Template = TemplateName(QTN->getUnderlyingTemplate());
49194918

49204919
// Build the canonical template specialization type.
49214920
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
@@ -8978,10 +8977,9 @@ TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const {
89788977

89798978
/// Retrieve the template name that represents a qualified
89808979
/// template name such as \c std::vector.
8981-
TemplateName
8982-
ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
8983-
bool TemplateKeyword,
8984-
TemplateDecl *Template) const {
8980+
TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
8981+
bool TemplateKeyword,
8982+
TemplateName Template) const {
89858983
assert(NNS && "Missing nested-name-specifier in qualified template name");
89868984

89878985
// FIXME: Canonicalization?

clang/lib/AST/ASTImporter.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9185,13 +9185,11 @@ Expected<TemplateName> ASTImporter::Import(TemplateName From) {
91859185
auto QualifierOrErr = Import(QTN->getQualifier());
91869186
if (!QualifierOrErr)
91879187
return QualifierOrErr.takeError();
9188-
9189-
if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl()))
9190-
return ToContext.getQualifiedTemplateName(
9191-
*QualifierOrErr, QTN->hasTemplateKeyword(),
9192-
cast<TemplateDecl>(*ToTemplateOrErr));
9193-
else
9194-
return ToTemplateOrErr.takeError();
9188+
auto TNOrErr = Import(QTN->getUnderlyingTemplate());
9189+
if (!TNOrErr)
9190+
return TNOrErr.takeError();
9191+
return ToContext.getQualifiedTemplateName(
9192+
*QualifierOrErr, QTN->hasTemplateKeyword(), *TNOrErr);
91959193
}
91969194

91979195
case TemplateName::DependentTemplate: {

clang/lib/AST/QualTypeNames.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,12 @@ static bool getFullyQualifiedTemplateName(const ASTContext &Ctx,
8080
Ctx, ArgTDecl, true, WithGlobalNsPrefix);
8181
}
8282
if (NNS) {
83-
TName = Ctx.getQualifiedTemplateName(NNS,
84-
/*TemplateKeyword=*/false, ArgTDecl);
83+
TemplateName UnderlyingTN(ArgTDecl);
84+
if (UsingShadowDecl *USD = TName.getAsUsingShadowDecl())
85+
UnderlyingTN = TemplateName(USD);
86+
TName =
87+
Ctx.getQualifiedTemplateName(NNS,
88+
/*TemplateKeyword=*/false, UnderlyingTN);
8589
Changed = true;
8690
}
8791
return Changed;

clang/lib/Sema/SemaDecl.cpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,18 +1114,14 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
11141114

11151115
UsingShadowDecl *FoundUsingShadow =
11161116
dyn_cast<UsingShadowDecl>(*Result.begin());
1117-
1118-
if (SS.isNotEmpty()) {
1119-
// FIXME: support using shadow-declaration in qualified template name.
1120-
Template =
1121-
Context.getQualifiedTemplateName(SS.getScopeRep(),
1122-
/*TemplateKeyword=*/false, TD);
1123-
} else {
1124-
assert(!FoundUsingShadow ||
1125-
TD == cast<TemplateDecl>(FoundUsingShadow->getTargetDecl()));
1126-
Template = FoundUsingShadow ? TemplateName(FoundUsingShadow)
1127-
: TemplateName(TD);
1128-
}
1117+
assert(!FoundUsingShadow ||
1118+
TD == cast<TemplateDecl>(FoundUsingShadow->getTargetDecl()));
1119+
Template =
1120+
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
1121+
if (SS.isNotEmpty())
1122+
Template = Context.getQualifiedTemplateName(SS.getScopeRep(),
1123+
/*TemplateKeyword=*/false,
1124+
Template);
11291125
} else {
11301126
// All results were non-template functions. This is a function template
11311127
// name.

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -284,17 +284,13 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
284284
}
285285

286286
TemplateDecl *TD = cast<TemplateDecl>(D);
287-
287+
Template =
288+
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
289+
assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD);
288290
if (SS.isSet() && !SS.isInvalid()) {
289291
NestedNameSpecifier *Qualifier = SS.getScopeRep();
290-
// FIXME: store the using TemplateName in QualifiedTemplateName if
291-
// the TD is referred via a using-declaration.
292-
Template =
293-
Context.getQualifiedTemplateName(Qualifier, hasTemplateKeyword, TD);
294-
} else {
295-
Template =
296-
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
297-
assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD);
292+
Template = Context.getQualifiedTemplateName(Qualifier, hasTemplateKeyword,
293+
Template);
298294
}
299295

300296
if (isa<FunctionTemplateDecl>(TD)) {
@@ -1005,8 +1001,8 @@ ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) {
10051001
TemplateName Name = DTST.getTypePtr()->getTemplateName();
10061002
if (SS.isSet())
10071003
Name = Context.getQualifiedTemplateName(SS.getScopeRep(),
1008-
/*HasTemplateKeyword*/ false,
1009-
Name.getAsTemplateDecl());
1004+
/*HasTemplateKeyword=*/false,
1005+
Name);
10101006
ParsedTemplateArgument Result(SS, TemplateTy::make(Name),
10111007
DTST.getTemplateNameLoc());
10121008
if (EllipsisLoc.isValid())

clang/lib/Sema/TreeTransform.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14714,7 +14714,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
1471414714
bool TemplateKW,
1471514715
TemplateDecl *Template) {
1471614716
return SemaRef.Context.getQualifiedTemplateName(SS.getScopeRep(), TemplateKW,
14717-
Template);
14717+
TemplateName(Template));
1471814718
}
1471914719

1472014720
template<typename Derived>

clang/unittests/AST/TemplateNameTest.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,69 @@ TEST(TemplateName, PrintUsingTemplate) {
5858
"vector");
5959
}
6060

61+
TEST(TemplateName, QualifiedUsingTemplate) {
62+
std::string Code = R"cpp(
63+
namespace std {
64+
template <typename> struct vector {};
65+
}
66+
namespace absl { using std::vector; }
67+
68+
template<template <typename> class T> class X;
69+
70+
using A = X<absl::vector>; // QualifiedTemplateName in a template argument.
71+
)cpp";
72+
auto AST = tooling::buildASTFromCode(Code);
73+
// Match the template argument absl::vector in X<absl::vector>.
74+
auto Matcher = templateArgumentLoc().bind("id");
75+
auto MatchResults = match(Matcher, AST->getASTContext());
76+
const auto *TAL = MatchResults.front().getNodeAs<TemplateArgumentLoc>("id");
77+
ASSERT_TRUE(TAL);
78+
TemplateName TN = TAL->getArgument().getAsTemplate();
79+
EXPECT_EQ(TN.getKind(), TemplateName::QualifiedTemplate);
80+
const auto *QTN = TN.getAsQualifiedTemplateName();
81+
// Verify that we have the Using template name in the QualifiedTemplateName.
82+
const auto *USD = QTN->getUnderlyingTemplate().getAsUsingShadowDecl();
83+
EXPECT_TRUE(USD);
84+
EXPECT_EQ(USD->getTargetDecl(), TN.getAsTemplateDecl());
85+
}
86+
87+
TEST(TemplateName, UsingTemplate) {
88+
auto AST = tooling::buildASTFromCode(R"cpp(
89+
namespace std {
90+
template <typename T> struct vector { vector(T); };
91+
}
92+
namespace absl { using std::vector; }
93+
// The "absl::vector<int>" is an elaborated TemplateSpecializationType with
94+
// an inner Using TemplateName (not a Qualified TemplateName, the qualifiers
95+
// are rather part of the ElaboratedType)!
96+
absl::vector<int> v(123);
97+
)cpp");
98+
auto Matcher = elaboratedTypeLoc(
99+
hasNamedTypeLoc(loc(templateSpecializationType().bind("id"))));
100+
auto MatchResults = match(Matcher, AST->getASTContext());
101+
const auto *TST =
102+
MatchResults.front().getNodeAs<TemplateSpecializationType>("id");
103+
ASSERT_TRUE(TST);
104+
EXPECT_EQ(TST->getTemplateName().getKind(), TemplateName::UsingTemplate);
105+
106+
AST = tooling::buildASTFromCodeWithArgs(R"cpp(
107+
namespace std {
108+
template <typename T> struct vector { vector(T); };
109+
}
110+
namespace absl { using std::vector; }
111+
// Similiar to the TemplateSpecializationType, absl::vector is an elaborated
112+
// DeducedTemplateSpecializationType with an inner Using TemplateName!
113+
absl::vector DTST(123);
114+
)cpp",
115+
{"-std=c++17"});
116+
Matcher = elaboratedTypeLoc(
117+
hasNamedTypeLoc(loc(deducedTemplateSpecializationType().bind("id"))));
118+
MatchResults = match(Matcher, AST->getASTContext());
119+
const auto *DTST =
120+
MatchResults.front().getNodeAs<DeducedTemplateSpecializationType>("id");
121+
ASSERT_TRUE(DTST);
122+
EXPECT_EQ(DTST->getTemplateName().getKind(), TemplateName::UsingTemplate);
123+
}
124+
61125
} // namespace
62126
} // namespace clang

0 commit comments

Comments
 (0)