Skip to content

Commit 2f2aa69

Browse files
committed
[clang] Preserve Qualifiers and type sugar in TemplateNames
This patch improves the preservation of qualifiers and loss of type sugar in TemplateNames. This problem is analogous to https://reviews.llvm.org/D112374 and this patch takes a very similar approach to that patch, except the impact here is much lesser. When a TemplateName was written bare, without qualifications, we wouldn't produce a QualifiedTemplate which could be used to disambiguate it from a Canonical TemplateName. This had effects in the TemplateName printer, which had workarounds to deal with this, and wouldn't print the TemplateName as-written in most situations. There are also some related fixes to help preserve this type sugar along the way into diagnostics, so that this patch can be properly tested. - Fix dropping the template keyword. - Fix type deduction to preserve sugar in TST TemplateNames.
1 parent fabcce0 commit 2f2aa69

File tree

55 files changed

+316
-240
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+316
-240
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,8 @@ Bug Fixes to AST Handling
819819
- Clang now properly preserves ``FoundDecls`` within a ``ConceptReference``. (#GH82628)
820820
- The presence of the ``typename`` keyword is now stored in ``TemplateTemplateParmDecl``.
821821
- Fixed malformed AST generated for anonymous union access in templates. (#GH90842)
822+
- Improved preservation of qualifiers and sugar in `TemplateNames`, including
823+
template keyword.
822824

823825
Miscellaneous Bug Fixes
824826
^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/TemplateName.h

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ class TemplateName {
332332
/// unexpanded parameter pack (for C++0x variadic templates).
333333
bool containsUnexpandedParameterPack() const;
334334

335-
enum class Qualified { None, AsWritten, Fully };
335+
enum class Qualified { None, AsWritten };
336336
/// Print the template name.
337337
///
338338
/// \param OS the output stream to which the template name will be
@@ -417,17 +417,18 @@ inline TemplateName TemplateName::getUnderlying() const {
417417
return *this;
418418
}
419419

420-
/// Represents a template name that was expressed as a
421-
/// qualified name.
420+
/// Represents a template name as written in source code.
422421
///
423-
/// This kind of template name refers to a template name that was
422+
/// This kind of template name may refer to a template name that was
424423
/// preceded by a nested name specifier, e.g., \c std::vector. Here,
425424
/// the nested name specifier is "std::" and the template name is the
426-
/// declaration for "vector". The QualifiedTemplateName class is only
427-
/// used to provide "sugar" for template names that were expressed
428-
/// with a qualified name, and has no semantic meaning. In this
429-
/// manner, it is to TemplateName what ElaboratedType is to Type,
430-
/// providing extra syntactic sugar for downstream clients.
425+
/// declaration for "vector". It may also have been written with the
426+
/// 'template' keyword. The QualifiedTemplateName class is only
427+
/// used to provide "sugar" for template names, so that they can
428+
/// be differentiated from canonical template names. and has no
429+
/// semantic meaning. In this manner, it is to TemplateName what
430+
/// ElaboratedType is to Type, providing extra syntactic sugar
431+
/// for downstream clients.
431432
class QualifiedTemplateName : public llvm::FoldingSetNode {
432433
friend class ASTContext;
433434

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8988,6 +8988,9 @@ class Sema final : public SemaBase {
89888988
const TemplateArgumentListInfo *TemplateArgs);
89898989

89908990
void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc);
8991+
void diagnoseMissingTemplateArguments(const CXXScopeSpec &SS,
8992+
bool TemplateKeyword, TemplateDecl *TD,
8993+
SourceLocation Loc);
89918994

89928995
ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS,
89938996
SourceLocation TemplateKWLoc, LookupResult &R,

clang/lib/AST/ASTContext.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5006,9 +5006,6 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
50065006
QualType Underlying) const {
50075007
assert(!Template.getAsDependentTemplateName() &&
50085008
"No dependent template names here!");
5009-
// Look through qualified template names.
5010-
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
5011-
Template = QTN->getUnderlyingTemplate();
50125009

50135010
const auto *TD = Template.getAsTemplateDecl();
50145011
bool IsTypeAlias = TD && TD->isTypeAlias();
@@ -5044,10 +5041,6 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
50445041
assert(!Template.getAsDependentTemplateName() &&
50455042
"No dependent template names here!");
50465043

5047-
// Look through qualified template names.
5048-
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
5049-
Template = TemplateName(QTN->getUnderlyingTemplate());
5050-
50515044
// Build the canonical template specialization type.
50525045
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
50535046
bool AnyNonCanonArgs = false;
@@ -5262,10 +5255,12 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) {
52625255
Arg = TemplateArgument(E);
52635256
} else {
52645257
auto *TTP = cast<TemplateTemplateParmDecl>(Param);
5258+
TemplateName Name = getQualifiedTemplateName(
5259+
nullptr, /*TemplateKeyword=*/false, TemplateName(TTP));
52655260
if (TTP->isParameterPack())
5266-
Arg = TemplateArgument(TemplateName(TTP), std::optional<unsigned>());
5261+
Arg = TemplateArgument(Name, std::optional<unsigned>());
52675262
else
5268-
Arg = TemplateArgument(TemplateName(TTP));
5263+
Arg = TemplateArgument(Name);
52695264
}
52705265

52715266
if (Param->isTemplateParameterPack())
@@ -9304,7 +9299,8 @@ TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const {
93049299
TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
93059300
bool TemplateKeyword,
93069301
TemplateName Template) const {
9307-
assert(NNS && "Missing nested-name-specifier in qualified template name");
9302+
assert(Template.getKind() == TemplateName::Template ||
9303+
Template.getKind() == TemplateName::UsingTemplate);
93089304

93099305
// FIXME: Canonicalization?
93109306
llvm::FoldingSetNodeID ID;

clang/lib/AST/DeclTemplate.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -627,9 +627,10 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
627627
TemplateParameterList *Params = getTemplateParameters();
628628
SmallVector<TemplateArgument, 16> TemplateArgs;
629629
Context.getInjectedTemplateArgs(Params, TemplateArgs);
630-
CommonPtr->InjectedClassNameType
631-
= Context.getTemplateSpecializationType(TemplateName(this),
632-
TemplateArgs);
630+
TemplateName Name = Context.getQualifiedTemplateName(
631+
/*NNS=*/nullptr, /*TemplateKeyword=*/false, TemplateName(this));
632+
CommonPtr->InjectedClassNameType =
633+
Context.getTemplateSpecializationType(Name, TemplateArgs);
633634
return CommonPtr->InjectedClassNameType;
634635
}
635636

clang/lib/AST/ODRHash.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,17 @@ void ODRHash::AddTemplateName(TemplateName Name) {
146146
case TemplateName::Template:
147147
AddDecl(Name.getAsTemplateDecl());
148148
break;
149+
case TemplateName::QualifiedTemplate: {
150+
QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName();
151+
if (NestedNameSpecifier *NNS = QTN->getQualifier())
152+
AddNestedNameSpecifier(NNS);
153+
AddBoolean(QTN->hasTemplateKeyword());
154+
AddTemplateName(QTN->getUnderlyingTemplate());
155+
break;
156+
}
149157
// TODO: Support these cases.
150158
case TemplateName::OverloadedTemplate:
151159
case TemplateName::AssumedTemplate:
152-
case TemplateName::QualifiedTemplate:
153160
case TemplateName::DependentTemplate:
154161
case TemplateName::SubstTemplateTemplateParm:
155162
case TemplateName::SubstTemplateTemplateParmPack:

clang/lib/AST/TemplateBase.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out,
552552
const auto *TTP = cast<TemplateTemplateParmDecl>(TD);
553553
Out << "template-parameter-" << TTP->getDepth() << "-" << TTP->getIndex();
554554
} else {
555-
TN.print(Out, Policy, TemplateName::Qualified::Fully);
555+
TN.print(Out, Policy);
556556
}
557557
break;
558558
}

clang/lib/AST/TemplateName.cpp

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,8 @@ TemplateNameDependence TemplateName::getDependence() const {
235235
auto D = TemplateNameDependence::None;
236236
switch (getKind()) {
237237
case TemplateName::NameKind::QualifiedTemplate:
238-
D |= toTemplateNameDependence(
239-
getAsQualifiedTemplateName()->getQualifier()->getDependence());
238+
if (NestedNameSpecifier *NNS = getAsQualifiedTemplateName()->getQualifier())
239+
D |= toTemplateNameDependence(NNS->getDependence());
240240
break;
241241
case TemplateName::NameKind::DependentTemplate:
242242
D |= toTemplateNameDependence(
@@ -292,9 +292,8 @@ void TemplateName::Profile(llvm::FoldingSetNodeID &ID) {
292292

293293
void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
294294
Qualified Qual) const {
295-
auto Kind = getKind();
296-
TemplateDecl *Template = nullptr;
297-
if (Kind == TemplateName::Template || Kind == TemplateName::UsingTemplate) {
295+
if (NameKind Kind = getKind();
296+
Kind == TemplateName::Template || Kind == TemplateName::UsingTemplate) {
298297
// After `namespace ns { using std::vector }`, what is the fully-qualified
299298
// name of the UsingTemplateName `vector` within ns?
300299
//
@@ -304,46 +303,43 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
304303
// Similar to the UsingType behavior, using declarations are used to import
305304
// names more often than to export them, thus using the original name is
306305
// most useful in this case.
307-
Template = getAsTemplateDecl();
308-
}
309-
310-
if (Template)
311-
if (Policy.CleanUglifiedParameters &&
312-
isa<TemplateTemplateParmDecl>(Template) && Template->getIdentifier())
313-
OS << Template->getIdentifier()->deuglifiedName();
314-
else if (Qual == Qualified::Fully &&
315-
getDependence() !=
316-
TemplateNameDependenceScope::DependentInstantiation)
317-
Template->printQualifiedName(OS, Policy);
318-
else
306+
TemplateDecl *Template = getAsTemplateDecl();
307+
if (Qual == Qualified::None)
319308
OS << *Template;
320-
else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
321-
if (Qual == Qualified::Fully &&
322-
getDependence() !=
323-
TemplateNameDependenceScope::DependentInstantiation) {
324-
QTN->getUnderlyingTemplate().getAsTemplateDecl()->printQualifiedName(
325-
OS, Policy);
326-
return;
327-
}
328-
if (Qual == Qualified::AsWritten)
329-
QTN->getQualifier()->print(OS, Policy);
309+
else
310+
Template->printQualifiedName(OS, Policy);
311+
} else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
312+
if (NestedNameSpecifier *NNS = QTN->getQualifier();
313+
Qual != Qualified::None && NNS)
314+
NNS->print(OS, Policy);
330315
if (QTN->hasTemplateKeyword())
331316
OS << "template ";
332-
OS << *QTN->getUnderlyingTemplate().getAsTemplateDecl();
317+
318+
TemplateName Underlying = QTN->getUnderlyingTemplate();
319+
assert(Underlying.getKind() == TemplateName::Template ||
320+
Underlying.getKind() == TemplateName::UsingTemplate);
321+
322+
TemplateDecl *UTD = Underlying.getAsTemplateDecl();
323+
if (IdentifierInfo *II = UTD->getIdentifier();
324+
Policy.CleanUglifiedParameters && II &&
325+
isa<TemplateTemplateParmDecl>(UTD))
326+
OS << II->deuglifiedName();
327+
else
328+
OS << *UTD;
333329
} else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
334-
if (Qual == Qualified::AsWritten && DTN->getQualifier())
335-
DTN->getQualifier()->print(OS, Policy);
330+
if (NestedNameSpecifier *NNS = DTN->getQualifier())
331+
NNS->print(OS, Policy);
336332
OS << "template ";
337333

338334
if (DTN->isIdentifier())
339335
OS << DTN->getIdentifier()->getName();
340336
else
341337
OS << "operator " << getOperatorSpelling(DTN->getOperator());
342-
} else if (SubstTemplateTemplateParmStorage *subst
343-
= getAsSubstTemplateTemplateParm()) {
338+
} else if (SubstTemplateTemplateParmStorage *subst =
339+
getAsSubstTemplateTemplateParm()) {
344340
subst->getReplacement().print(OS, Policy, Qual);
345-
} else if (SubstTemplateTemplateParmPackStorage *SubstPack
346-
= getAsSubstTemplateTemplateParmPack())
341+
} else if (SubstTemplateTemplateParmPackStorage *SubstPack =
342+
getAsSubstTemplateTemplateParmPack())
347343
OS << *SubstPack->getParameterPack();
348344
else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) {
349345
Assumed->getDeclName().print(OS, Policy);

clang/lib/AST/TextNodeDumper.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1989,15 +1989,15 @@ void TextNodeDumper::VisitAutoType(const AutoType *T) {
19891989

19901990
void TextNodeDumper::VisitDeducedTemplateSpecializationType(
19911991
const DeducedTemplateSpecializationType *T) {
1992-
if (T->getTemplateName().getKind() == TemplateName::UsingTemplate)
1992+
if (T->getTemplateName().getAsUsingShadowDecl())
19931993
OS << " using";
19941994
}
19951995

19961996
void TextNodeDumper::VisitTemplateSpecializationType(
19971997
const TemplateSpecializationType *T) {
19981998
if (T->isTypeAlias())
19991999
OS << " alias";
2000-
if (T->getTemplateName().getKind() == TemplateName::UsingTemplate)
2000+
if (T->getTemplateName().getAsUsingShadowDecl())
20012001
OS << " using";
20022002
OS << " ";
20032003
T->getTemplateName().dump(OS);

clang/lib/AST/Type.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4251,7 +4251,8 @@ TemplateSpecializationType::TemplateSpecializationType(
42514251
assert((T.getKind() == TemplateName::Template ||
42524252
T.getKind() == TemplateName::SubstTemplateTemplateParm ||
42534253
T.getKind() == TemplateName::SubstTemplateTemplateParmPack ||
4254-
T.getKind() == TemplateName::UsingTemplate) &&
4254+
T.getKind() == TemplateName::UsingTemplate ||
4255+
T.getKind() == TemplateName::QualifiedTemplate) &&
42554256
"Unexpected template name for TemplateSpecializationType");
42564257

42574258
auto *TemplateArgs = reinterpret_cast<TemplateArgument *>(this + 1);

clang/lib/AST/TypePrinter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,14 +1586,14 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T,
15861586
IncludeStrongLifetimeRAII Strong(Policy);
15871587

15881588
TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl();
1589-
// FIXME: Null TD never excercised in test suite.
1589+
// FIXME: Null TD never exercised in test suite.
15901590
if (FullyQualify && TD) {
15911591
if (!Policy.SuppressScope)
15921592
AppendScope(TD->getDeclContext(), OS, TD->getDeclName());
15931593

15941594
OS << TD->getName();
15951595
} else {
1596-
T->getTemplateName().print(OS, Policy);
1596+
T->getTemplateName().print(OS, Policy, TemplateName::Qualified::None);
15971597
}
15981598

15991599
DefaultTemplateArgsPolicyRAII TemplateArgs(Policy);

clang/lib/Sema/SemaDecl.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -538,8 +538,9 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
538538
} else if (AllowDeducedTemplate) {
539539
if (auto *TD = getAsTypeTemplateDecl(IIDecl)) {
540540
assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD);
541-
TemplateName Template =
542-
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
541+
TemplateName Template = Context.getQualifiedTemplateName(
542+
SS ? SS->getScopeRep() : nullptr, /*TemplateKeyword=*/false,
543+
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD));
543544
T = Context.getDeducedTemplateSpecializationType(Template, QualType(),
544545
false);
545546
// Don't wrap in a further UsingType.
@@ -1137,12 +1138,10 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
11371138
dyn_cast<UsingShadowDecl>(*Result.begin());
11381139
assert(!FoundUsingShadow ||
11391140
TD == cast<TemplateDecl>(FoundUsingShadow->getTargetDecl()));
1140-
Template =
1141-
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
1142-
if (SS.isNotEmpty())
1143-
Template = Context.getQualifiedTemplateName(SS.getScopeRep(),
1144-
/*TemplateKeyword=*/false,
1145-
Template);
1141+
Template = Context.getQualifiedTemplateName(
1142+
SS.getScopeRep(),
1143+
/*TemplateKeyword=*/false,
1144+
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD));
11461145
} else {
11471146
// All results were non-template functions. This is a function template
11481147
// name.

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11547,12 +11547,12 @@ bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
1154711547
TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
1154811548
bool TemplateMatches =
1154911549
Context.hasSameTemplateName(SpecifiedName, GuidedTemplate);
11550-
auto TKind = SpecifiedName.getKind();
11551-
// A Using TemplateName can't actually be valid (either it's qualified, or
11552-
// we're in the wrong scope). But we have diagnosed these problems
11553-
// already.
11554-
bool SimplyWritten = TKind == TemplateName::Template ||
11555-
TKind == TemplateName::UsingTemplate;
11550+
11551+
const QualifiedTemplateName *Qualifiers =
11552+
SpecifiedName.getAsQualifiedTemplateName();
11553+
assert(Qualifiers && "expected QualifiedTemplate");
11554+
bool SimplyWritten = !Qualifiers->hasTemplateKeyword() &&
11555+
Qualifiers->getQualifier() == nullptr;
1155611556
if (SimplyWritten && TemplateMatches)
1155711557
AcceptableReturnType = true;
1155811558
else {

clang/lib/Sema/SemaExpr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3284,10 +3284,10 @@ ExprResult Sema::BuildDeclarationNameExpr(
32843284
return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {});
32853285
}
32863286

3287-
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
3287+
if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {
32883288
// Specifically diagnose references to class templates that are missing
32893289
// a template argument list.
3290-
diagnoseMissingTemplateArguments(TemplateName(Template), Loc);
3290+
diagnoseMissingTemplateArguments(SS, /*TemplateKeyword=*/false, TD, Loc);
32913291
return ExprError();
32923292
}
32933293

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
11941194

11951195
if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
11961196
if (!TemplateArgs) {
1197-
diagnoseMissingTemplateArguments(TemplateName(VarTempl), MemberLoc);
1197+
diagnoseMissingTemplateArguments(
1198+
SS, /*TemplateKeyword=*/TemplateKWLoc.isValid(), VarTempl, MemberLoc);
11981199
return ExprError();
11991200
}
12001201

0 commit comments

Comments
 (0)