clang 22.0.0git
TemplateName.cpp
Go to the documentation of this file.
1//===- TemplateName.cpp - C++ Template Name Representation ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the TemplateName interface and subclasses.
10//
11//===----------------------------------------------------------------------===//
12
14#include "clang/AST/Decl.h"
15#include "clang/AST/DeclBase.h"
16#include "clang/AST/DeclCXX.h"
23#include "clang/Basic/LLVM.h"
26#include "llvm/ADT/ArrayRef.h"
27#include "llvm/ADT/FoldingSet.h"
28#include "llvm/Support/Compiler.h"
29#include "llvm/Support/raw_ostream.h"
30#include <cassert>
31#include <optional>
32#include <string>
33
34using namespace clang;
35
36DeducedTemplateStorage::DeducedTemplateStorage(TemplateName Underlying,
37 const DefaultArguments &DefArgs)
38 : UncommonTemplateNameStorage(Deduced, /*Index=*/DefArgs.StartPos,
39 DefArgs.Args.size()),
40 Underlying(Underlying) {
41 llvm::copy(DefArgs.Args, reinterpret_cast<TemplateArgument *>(this + 1));
42}
43
44void DeducedTemplateStorage::Profile(llvm::FoldingSetNodeID &ID,
45 const ASTContext &Context) const {
46 Profile(ID, Context, Underlying, getDefaultArguments());
47}
48
49void DeducedTemplateStorage::Profile(llvm::FoldingSetNodeID &ID,
50 const ASTContext &Context,
51 TemplateName Underlying,
52 const DefaultArguments &DefArgs) {
53 Underlying.Profile(ID);
54 ID.AddInteger(DefArgs.StartPos);
55 ID.AddInteger(DefArgs.Args.size());
56 for (const TemplateArgument &Arg : DefArgs.Args)
57 Arg.Profile(ID, Context);
58}
59
64
70
76
77void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID) {
78 Profile(ID, Replacement, getAssociatedDecl(), getIndex(), getPackIndex(),
79 getFinal());
80}
81
83 llvm::FoldingSetNodeID &ID, TemplateName Replacement, Decl *AssociatedDecl,
84 unsigned Index, UnsignedOrNone PackIndex, bool Final) {
85 Replacement.Profile(ID);
86 ID.AddPointer(AssociatedDecl);
87 ID.AddInteger(Index);
88 ID.AddInteger(PackIndex.toInternalRepresentation());
89 ID.AddBoolean(Final);
90}
91
93 ArrayRef<TemplateArgument> ArgPack, Decl *AssociatedDecl, unsigned Index,
94 bool Final)
96 ArgPack.size()),
97 Arguments(ArgPack.data()), AssociatedDeclAndFinal(AssociatedDecl, Final) {
98 assert(AssociatedDecl != nullptr);
99}
100
101void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID,
102 ASTContext &Context) {
104 getFinal());
105}
106
108 return AssociatedDeclAndFinal.getPointer();
109}
110
112 return AssociatedDeclAndFinal.getInt();
113}
114
116 llvm::FoldingSetNodeID &ID, ASTContext &Context,
117 const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index,
118 bool Final) {
119 ArgPack.Profile(ID, Context);
120 ID.AddPointer(AssociatedDecl);
121 ID.AddInteger(Index);
122 ID.AddBoolean(Final);
123}
124
126 const IdentifierInfo *II)
127 : PtrOrOp(reinterpret_cast<uintptr_t>(II)) {
128 static_assert(NUM_OVERLOADED_OPERATORS <= 4096,
129 "NUM_OVERLOADED_OPERATORS is too large");
130 assert(II);
131 assert(getIdentifier() == II);
132}
135 : PtrOrOp(-uintptr_t(OOK)) {
136 assert(OOK != OO_None);
137 assert(getOperator() == OOK);
138}
139
140void IdentifierOrOverloadedOperator::Profile(llvm::FoldingSetNodeID &ID) const {
141 if (auto *Identifier = getIdentifier()) {
142 ID.AddBoolean(false);
143 ID.AddPointer(Identifier);
144 } else {
145 ID.AddBoolean(true);
146 ID.AddInteger(getOperator());
147 }
148}
149
151 Storage = StorageType::getFromOpaqueValue(Ptr);
152}
153
156 : Storage(Storage) {}
158 : Storage(Storage) {}
167 : Storage(Deduced) {}
168
169bool TemplateName::isNull() const { return Storage.isNull(); }
170
172 if (auto *ND = dyn_cast<Decl *>(Storage)) {
173 if (isa<UsingShadowDecl>(ND))
174 return UsingTemplate;
175 assert(isa<TemplateDecl>(ND));
176 return Template;
177 }
178
179 if (isa<DependentTemplateName *>(Storage))
180 return DependentTemplate;
181 if (isa<QualifiedTemplateName *>(Storage))
182 return QualifiedTemplate;
183
186 if (uncommon->getAsOverloadedStorage())
187 return OverloadedTemplate;
188 if (uncommon->getAsAssumedTemplateName())
189 return AssumedTemplate;
190 if (uncommon->getAsSubstTemplateTemplateParm())
192 if (uncommon->getAsDeducedTemplateName())
193 return DeducedTemplate;
194
195 assert(uncommon->getAsSubstTemplateTemplateParmPack() != nullptr);
197}
198
200 TemplateName Name = *this;
201 while (std::optional<TemplateName> UnderlyingOrNone =
202 Name.desugar(IgnoreDeduced))
203 Name = *UnderlyingOrNone;
204
205 if (!IgnoreDeduced)
206 assert(Name.getAsDeducedTemplateName() == nullptr &&
207 "Unexpected canonical DeducedTemplateName; Did you mean to use "
208 "getTemplateDeclAndDefaultArgs instead?");
209
210 return cast_if_present<TemplateDecl>(
211 dyn_cast_if_present<Decl *>(Name.Storage));
212}
213
214std::pair<TemplateName, DefaultArguments>
216 DefaultArguments DefArgs;
217 for (TemplateName Name = *this; /**/; /**/) {
219 assert(!DefArgs && "multiple default args?");
220 DefArgs = DTS->getDefaultArguments();
221 if (TemplateDecl *TD = DTS->getUnderlying().getAsTemplateDecl();
222 TD && DefArgs)
223 assert(DefArgs.StartPos + DefArgs.Args.size() <=
224 TD->getTemplateParameters()->size());
225 Name = DTS->getUnderlying();
226 }
227 if (std::optional<TemplateName> UnderlyingOrNone =
228 Name.desugar(/*IgnoreDeduced=*/false)) {
229 Name = *UnderlyingOrNone;
230 continue;
231 }
232 return {Name, DefArgs};
233 }
234}
235
236std::optional<TemplateName> TemplateName::desugar(bool IgnoreDeduced) const {
237 if (Decl *D = dyn_cast_if_present<Decl *>(Storage)) {
238 if (auto *USD = dyn_cast<UsingShadowDecl>(D))
239 return TemplateName(USD->getTargetDecl());
240 return std::nullopt;
241 }
243 return QTN->getUnderlyingTemplate();
245 return S->getReplacement();
246 if (IgnoreDeduced)
248 return S->getUnderlying();
249 return std::nullopt;
250}
251
253 if (UncommonTemplateNameStorage *Uncommon =
254 Storage.dyn_cast<UncommonTemplateNameStorage *>())
255 return Uncommon->getAsOverloadedStorage();
256
257 return nullptr;
258}
259
261 if (UncommonTemplateNameStorage *Uncommon =
262 Storage.dyn_cast<UncommonTemplateNameStorage *>())
263 return Uncommon->getAsAssumedTemplateName();
264
265 return nullptr;
266}
267
270 if (UncommonTemplateNameStorage *uncommon =
271 dyn_cast_if_present<UncommonTemplateNameStorage *>(Storage))
272 return uncommon->getAsSubstTemplateTemplateParm();
273
274 return nullptr;
275}
276
279 if (UncommonTemplateNameStorage *Uncommon =
280 Storage.dyn_cast<UncommonTemplateNameStorage *>())
281 return Uncommon->getAsSubstTemplateTemplateParmPack();
282
283 return nullptr;
284}
285
287 return dyn_cast_if_present<QualifiedTemplateName *>(Storage);
288}
289
293
294std::tuple<NestedNameSpecifier, bool>
296 for (std::optional<TemplateName> Cur = *this; Cur;
297 Cur = Cur->desugar(/*IgnoreDeduced=*/true)) {
298 if (DependentTemplateName *N = Cur->getAsDependentTemplateName())
299 return {N->getQualifier(), N->hasTemplateKeyword()};
300 if (QualifiedTemplateName *N = Cur->getAsQualifiedTemplateName())
301 return {N->getQualifier(), N->hasTemplateKeyword()};
302 if (Cur->getAsSubstTemplateTemplateParm() ||
303 Cur->getAsSubstTemplateTemplateParmPack())
304 break;
305 }
306 return {std::nullopt, false};
307}
308
310 if (Decl *D = Storage.dyn_cast<Decl *>())
311 if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D))
312 return USD;
314 return QTN->getUnderlyingTemplate().getAsUsingShadowDecl();
315 return nullptr;
316}
317
320 bool HasTemplateKeyword)
321 : Qualifier(Qualifier, HasTemplateKeyword), Name(Name) {
322 assert((!Qualifier || Qualifier.isDependent()) &&
323 "Qualifier must be dependent");
324}
325
326TemplateNameDependence DependentTemplateStorage::getDependence() const {
328 TemplateNameDependence::DependentInstantiation;
329}
330
332 const PrintingPolicy &Policy) const {
333 getQualifier().print(OS, Policy);
334
335 if (hasTemplateKeyword())
336 OS << "template ";
337
339 if (const IdentifierInfo *II = Name.getIdentifier())
340 OS << II->getName();
341 else
342 OS << "operator " << getOperatorSpelling(Name.getOperator());
343}
344
346 if (UncommonTemplateNameStorage *Uncommon =
347 dyn_cast_if_present<UncommonTemplateNameStorage *>(Storage))
348 return Uncommon->getAsDeducedTemplateName();
349
350 return nullptr;
351}
352
353TemplateNameDependence TemplateName::getDependence() const {
354 switch (getKind()) {
358 auto D = TemplateNameDependence::None;
359 if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Template)) {
360 D |= TemplateNameDependence::DependentInstantiation;
361 if (TTP->isParameterPack())
362 D |= TemplateNameDependence::UnexpandedPack;
363 }
364 // FIXME: Hack, getDeclContext() can be null if Template is still
365 // initializing due to PCH reading, so we check it before using it.
366 // Should probably modify TemplateSpecializationType to allow constructing
367 // it without the isDependent() checking.
368 if (Template->getDeclContext() &&
369 Template->getDeclContext()->isDependentContext())
370 D |= TemplateNameDependence::DependentInstantiation;
371 return D;
372 }
375 TemplateNameDependence D = S->getUnderlyingTemplate().getDependence();
377 return D;
378 }
382 TemplateNameDependence::DependentInstantiation;
383 }
386 return S->getReplacement().getDependence();
387 }
389 return TemplateNameDependence::UnexpandedPack |
390 TemplateNameDependence::DependentInstantiation;
393 TemplateNameDependence D = DTS->getUnderlying().getDependence();
394 for (const TemplateArgument &Arg : DTS->getDefaultArguments().Args)
395 D |= toTemplateNameDependence(Arg.getDependence());
396 return D;
397 }
399 return TemplateNameDependence::DependentInstantiation;
401 llvm_unreachable("overloaded templates shouldn't survive to here.");
402 }
403 llvm_unreachable("Unknown TemplateName kind");
404}
405
407 return getDependence() & TemplateNameDependence::Dependent;
408}
409
411 return getDependence() & TemplateNameDependence::Instantiation;
412}
413
415 return getDependence() & TemplateNameDependence::UnexpandedPack;
416}
417
418void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
419 Qualified Qual) const {
420 auto handleAnonymousTTP = [&](TemplateDecl *TD, raw_ostream &OS) {
421 if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(TD);
422 TTP && (Policy.PrintAsCanonical || TTP->getIdentifier() == nullptr)) {
423 OS << "template-parameter-" << TTP->getDepth() << "-" << TTP->getIndex();
424 return true;
425 }
426 return false;
427 };
428 if (NameKind Kind = getKind();
430 // After `namespace ns { using std::vector }`, what is the fully-qualified
431 // name of the UsingTemplateName `vector` within ns?
432 //
433 // - ns::vector (the qualified name of the using-shadow decl)
434 // - std::vector (the qualified name of the underlying template decl)
435 //
436 // Similar to the UsingType behavior, using declarations are used to import
437 // names more often than to export them, thus using the original name is
438 // most useful in this case.
440 if (Policy.PrintAsCanonical)
441 Template = cast<TemplateDecl>(Template->getCanonicalDecl());
442 if (handleAnonymousTTP(Template, OS))
443 return;
445 Policy.SuppressScope) {
446 if (IdentifierInfo *II = Template->getIdentifier();
447 Policy.CleanUglifiedParameters && II &&
449 OS << II->deuglifiedName();
450 else
451 OS << *Template;
452 } else {
453 PrintingPolicy NestedNamePolicy = Policy;
454 NestedNamePolicy.SuppressUnwrittenScope = true;
455 Template->printQualifiedName(OS, NestedNamePolicy);
456 }
458 if (Policy.PrintAsCanonical) {
459 QTN->getUnderlyingTemplate().print(OS, Policy, Qual);
460 return;
461 }
462 if (Qual != Qualified::None)
463 QTN->getQualifier().print(OS, Policy);
464 if (QTN->hasTemplateKeyword())
465 OS << "template ";
466
467 TemplateName Underlying = QTN->getUnderlyingTemplate();
468 assert(Underlying.getKind() == TemplateName::Template ||
469 Underlying.getKind() == TemplateName::UsingTemplate);
470
471 TemplateDecl *UTD = Underlying.getAsTemplateDecl();
472
473 if (handleAnonymousTTP(UTD, OS))
474 return;
475
476 OS << *UTD;
478 DTN->print(OS, Policy);
479 } else if (SubstTemplateTemplateParmStorage *subst =
481 subst->getReplacement().print(OS, Policy, Qual);
482 } else if (SubstTemplateTemplateParmPackStorage *SubstPack =
484 OS << *SubstPack->getParameterPack();
485 else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) {
486 Assumed->getDeclName().print(OS, Policy);
487 } else if (DeducedTemplateStorage *Deduced = getAsDeducedTemplateName()) {
488 Deduced->getUnderlying().print(OS, Policy);
489 DefaultArguments DefArgs = Deduced->getDefaultArguments();
490 OS << ":" << DefArgs.StartPos;
491 printTemplateArgumentList(OS, DefArgs.Args, Policy);
492 } else {
495 (*OTS->begin())->printName(OS, Policy);
496 }
497}
498
500 TemplateName N) {
501 std::string NameStr;
502 llvm::raw_string_ostream OS(NameStr);
503 LangOptions LO;
504 LO.CPlusPlus = true;
505 LO.Bool = true;
506 OS << '\'';
507 N.print(OS, PrintingPolicy(LO));
508 OS << '\'';
509 return DB << NameStr;
510}
Defines the Diagnostic-related interfaces.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::LangOptions interface.
Defines an enumeration for C++ overloaded operators.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
A structure for storing the information associated with a name that has been assumed to be a template...
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
TemplateName getUnderlying() const
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const
DefaultArguments getDefaultArguments() const
void print(raw_ostream &OS, const PrintingPolicy &Policy) const
IdentifierOrOverloadedOperator getName() const
NestedNameSpecifier getQualifier() const
Return the nested name specifier that qualifies this name.
DependentTemplateStorage(NestedNameSpecifier Qualifier, IdentifierOrOverloadedOperator Name, bool HasTemplateKeyword)
TemplateNameDependence getDependence() const
bool hasTemplateKeyword() const
Was this template name was preceeded by the template keyword?
One of these records is kept for each identifier that is lexed.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
void print(raw_ostream &OS, const PrintingPolicy &Policy, bool ResolveTemplateArguments=false, bool PrintFinalScopeResOp=true) const
Print this nested name specifier to the given output stream.
NestedNameSpecifierDependence getDependence() const
A structure for storing the information associated with an overloaded template name.
Represents a template name as written in source code.
NestedNameSpecifier getQualifier() const
Return the nested name specifier that qualifies this name.
TemplateName getUnderlyingTemplate() const
Return the underlying template name.
The streaming interface shared between DiagnosticBuilder and PartialDiagnostic.
A structure for storing an already-substituted template template parameter pack.
Decl * getAssociatedDecl() const
A template-like entity which owns the whole pattern being substituted.
void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context)
TemplateTemplateParmDecl * getParameterPack() const
Retrieve the template template parameter pack being substituted.
TemplateArgument getArgumentPack() const
Retrieve the template template argument pack with which this parameter was substituted.
unsigned getIndex() const
Returns the index of the replaced parameter in the associated declaration.
SubstTemplateTemplateParmPackStorage(ArrayRef< TemplateArgument > ArgPack, Decl *AssociatedDecl, unsigned Index, bool Final)
A structure for storing the information associated with a substituted template template parameter.
void Profile(llvm::FoldingSetNodeID &ID)
TemplateTemplateParmDecl * getParameter() const
unsigned getIndex() const
Returns the index of the replaced parameter in the associated declaration.
Decl * getAssociatedDecl() const
A template-like entity which owns the whole pattern being substituted.
Represents a template argument.
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const
Used to insert TemplateArguments into FoldingSets.
The base class of all kinds of template declarations (e.g., class, function, etc.).
Represents a C++ template name within the type system.
TemplateNameDependence getDependence() const
TemplateDecl * getAsTemplateDecl(bool IgnoreDeduced=false) const
Retrieve the underlying template declaration that this template name refers to, if known.
DeducedTemplateStorage * getAsDeducedTemplateName() const
Retrieve the deduced template info, if any.
bool isNull() const
Determine whether this template name is NULL.
TemplateName()=default
DependentTemplateName * getAsDependentTemplateName() const
Retrieve the underlying dependent template name structure, if any.
QualifiedTemplateName * getAsQualifiedTemplateName() const
Retrieve the underlying qualified template name structure, if any.
std::optional< TemplateName > desugar(bool IgnoreDeduced) const
void print(raw_ostream &OS, const PrintingPolicy &Policy, Qualified Qual=Qualified::AsWritten) const
Print the template name.
OverloadedTemplateStorage * getAsOverloadedTemplate() const
Retrieve the underlying, overloaded function template declarations that this template name refers to,...
bool containsUnexpandedParameterPack() const
Determines whether this template name contains an unexpanded parameter pack (for C++0x variadic templ...
AssumedTemplateStorage * getAsAssumedTemplateName() const
Retrieve information on a name that has been assumed to be a template-name in order to permit a call ...
std::pair< TemplateName, DefaultArguments > getTemplateDeclAndDefaultArgs() const
Retrieves the underlying template name that this template name refers to, along with the deduced defa...
NameKind getKind() const
@ UsingTemplate
A template name that refers to a template declaration found through a specific using shadow declarati...
@ OverloadedTemplate
A set of overloaded template declarations.
@ Template
A single template declaration.
@ DependentTemplate
A dependent template name that has not been resolved to a template (or set of templates).
@ SubstTemplateTemplateParm
A template template parameter that has been substituted for some other template name.
@ SubstTemplateTemplateParmPack
A template template parameter pack that has been substituted for a template template argument pack,...
@ DeducedTemplate
A template name that refers to another TemplateName with deduced default arguments.
@ QualifiedTemplate
A qualified template name, where the qualification is kept to describe the source code as written.
@ AssumedTemplate
An unqualified-id that has been assumed to name a function template that will be found by ADL.
UsingShadowDecl * getAsUsingShadowDecl() const
Retrieve the using shadow declaration through which the underlying template declaration is introduced...
SubstTemplateTemplateParmPackStorage * getAsSubstTemplateTemplateParmPack() const
Retrieve the substituted template template parameter pack, if known.
bool isDependent() const
Determines whether this is a dependent template name.
SubstTemplateTemplateParmStorage * getAsSubstTemplateTemplateParm() const
Retrieve the substituted template template parameter, if known.
bool isInstantiationDependent() const
Determines whether this is a template name that somehow depends on a template parameter.
std::tuple< NestedNameSpecifier, bool > getQualifierAndTemplateKeyword() const
TemplateTemplateParmDecl - Declares a template template parameter, e.g., "T" in.
Implementation class used to describe either a set of overloaded template names or an already-substit...
SubstTemplateTemplateParmPackStorage * getAsSubstTemplateTemplateParmPack()
UncommonTemplateNameStorage(Kind Kind, unsigned Index, unsigned Data)
SubstTemplateTemplateParmStorage * getAsSubstTemplateTemplateParm()
AssumedTemplateStorage * getAsAssumedTemplateName()
DeducedTemplateStorage * getAsDeducedTemplateName()
OverloadedTemplateStorage * getAsOverloadedStorage()
Represents a shadow declaration implicitly introduced into a scope by a (resolved) using-declaration ...
Definition DeclCXX.h:3399
The JSON file list parser is used to communicate input to InstallAPI.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
@ OO_None
Not an overloaded operator.
@ NUM_OVERLOADED_OPERATORS
bool isa(CodeGen::Address addr)
Definition Address.h:330
TemplateNameDependence toTemplateNameDependence(NestedNameSpecifierDependence D)
std::tuple< NamedDecl *, TemplateArgument > getReplacedTemplateParameter(Decl *D, unsigned Index)
Internal helper used by Subst* nodes to retrieve a parameter from the AssociatedDecl,...
const StreamingDiagnostic & operator<<(const StreamingDiagnostic &DB, const ConceptReference *C)
Insertion operator for diagnostics.
const char * getOperatorSpelling(OverloadedOperatorKind Operator)
Retrieve the spelling of the given overloaded operator, without the preceding "operator" keyword.
U cast(CodeGen::Address addr)
Definition Address.h:327
__UINTPTR_TYPE__ uintptr_t
An unsigned integer type with the property that any valid pointer to void can be converted to this ty...
ArrayRef< TemplateArgument > Args
const IdentifierInfo * getIdentifier() const
Returns the identifier to which this template name refers.
void Profile(llvm::FoldingSetNodeID &ID) const
OverloadedOperatorKind getOperator() const
Return the overloaded operator to which this template name refers.
Describes how types, statements, expressions, and declarations should be printed.
unsigned SuppressUnwrittenScope
Suppress printing parts of scope specifiers that are never written, e.g., for anonymous namespaces.
unsigned CleanUglifiedParameters
Whether to strip underscores when printing reserved parameter names.
unsigned SuppressScope
Suppresses printing of scope specifiers.
unsigned PrintAsCanonical
Whether to print entities as written or canonically.
constexpr unsigned toInternalRepresentation() const