clang 24.0.0git
TemplateArgumentHasher.cpp
Go to the documentation of this file.
1//===- TemplateArgumentHasher.cpp - Hash Template Arguments -----*- C++ -*-===//
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
10#include "clang/AST/APValue.h"
11#include "clang/AST/Decl.h"
12#include "clang/AST/DeclCXX.h"
17#include "llvm/ADT/FoldingSet.h"
18#include "llvm/Support/TimeProfiler.h"
19
20using namespace clang;
21
22namespace {
23
24class TemplateArgumentHasher {
25 llvm::FoldingSetNodeID ID;
26
27public:
28 TemplateArgumentHasher() = default;
29
30 void AddTemplateArgument(TemplateArgument TA);
31
32 void AddInteger(unsigned V) { ID.AddInteger(V); }
33
34 unsigned getValue() { return ID.computeStableHash(); }
35
36 void AddType(const Type *T);
37 void AddQualType(QualType T);
38 void AddDecl(const Decl *D);
39 void AddStructuralValue(const APValue &);
40 void AddTemplateName(TemplateName Name);
41 void AddDeclarationName(DeclarationName Name);
42 void AddIdentifierInfo(const IdentifierInfo *II);
43};
44
45void TemplateArgumentHasher::AddTemplateArgument(TemplateArgument TA) {
46 const auto Kind = TA.getKind();
47 AddInteger(Kind);
48
49 switch (Kind) {
51 // These can occur in incomplete substitutions performed with code
52 // completion (see PartialOverloading).
53 break;
55 AddQualType(TA.getAsType());
56 break;
58 AddDecl(TA.getAsDecl());
59 break;
61 ID.AddPointer(nullptr);
62 break;
64 // There are integrals (e.g.: _BitInt(128)) that cannot be represented as
65 // any builtin integral type, so we use the hash of APSInt instead.
66 TA.getAsIntegral().Profile(ID);
67 break;
68 }
70 AddQualType(TA.getStructuralValueType());
71 AddStructuralValue(TA.getAsStructuralValue());
72 break;
75 AddTemplateName(TA.getAsTemplateOrTemplatePattern());
76 break;
78 // If we meet expression in template argument, it implies
79 // that the template is still dependent. It is meaningless
80 // to get a stable hash for the template.
81 break;
83 AddInteger(TA.pack_size());
84 for (auto SubTA : TA.pack_elements()) {
85 AddTemplateArgument(SubTA);
86 }
87 break;
88 }
89}
90
91void TemplateArgumentHasher::AddStructuralValue(const APValue &Value) {
92 auto Kind = Value.getKind();
93 AddInteger(Kind);
94
95 // 'APValue::Profile' uses pointer values to make hash for LValue and
96 // MemberPointer, but they differ from one compiler invocation to another.
97 // It may be difficult to handle such cases.
98
99 if (Kind == APValue::LValue || Kind == APValue::MemberPointer) {
100 return;
101 }
102
103 Value.Profile(ID);
104}
105
106void TemplateArgumentHasher::AddTemplateName(TemplateName Name) {
107 switch (Name.getKind()) {
109 AddDecl(Name.getAsTemplateDecl());
110 break;
112 QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName();
113 AddTemplateName(QTN->getUnderlyingTemplate());
114 break;
115 }
117 AddTemplateName(Name.getAsPackIndexingTemplate()->getPattern());
118 break;
124 break;
126 UsingShadowDecl *USD = Name.getAsUsingShadowDecl();
127 if (USD)
128 AddDecl(USD->getTargetDecl());
129 break;
130 }
132 AddTemplateName(Name.getAsDeducedTemplateName()->getUnderlying());
133 break;
134 }
135}
136
137void TemplateArgumentHasher::AddIdentifierInfo(const IdentifierInfo *II) {
138 assert(II && "Expecting non-null pointer.");
139 ID.AddString(II->getName());
140}
141
142void TemplateArgumentHasher::AddDeclarationName(DeclarationName Name) {
143 if (Name.isEmpty())
144 return;
145
146 switch (Name.getNameKind()) {
148 AddIdentifierInfo(Name.getAsIdentifierInfo());
149 break;
153 break;
156 AddQualType(Name.getCXXNameType());
157 break;
159 AddInteger(Name.getCXXOverloadedOperator());
160 break;
162 AddIdentifierInfo(Name.getCXXLiteralIdentifier());
163 break;
165 AddQualType(Name.getCXXNameType());
166 break;
168 break;
170 if (auto *Template = Name.getCXXDeductionGuideTemplate())
171 AddDecl(Template);
172 }
173 }
174}
175
176void TemplateArgumentHasher::AddDecl(const Decl *D) {
177 const NamedDecl *ND = dyn_cast<NamedDecl>(D);
178 if (!ND) {
179 return;
180 }
181
182 AddDeclarationName(ND->getDeclName());
183
184 // If this was a specialization we should take into account its template
185 // arguments. This helps to reduce collisions coming when visiting template
186 // specialization types (eg. when processing type template arguments).
187 ArrayRef<TemplateArgument> Args;
188 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
189 Args = CTSD->getTemplateArgs().asArray();
190 else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
191 Args = VTSD->getTemplateArgs().asArray();
192 else if (auto *FD = dyn_cast<FunctionDecl>(D))
193 if (FD->getTemplateSpecializationArgs())
194 Args = FD->getTemplateSpecializationArgs()->asArray();
195
196 for (auto &TA : Args)
197 AddTemplateArgument(TA);
198}
199
200void TemplateArgumentHasher::AddQualType(QualType T) {
201 if (T.isNull()) {
202 return;
203 }
204 SplitQualType split = T.split();
205 AddInteger(split.Quals.getAsOpaqueValue());
206 AddType(split.Ty);
207}
208
209// Process a Type pointer. Add* methods call back into TemplateArgumentHasher
210// while Visit* methods process the relevant parts of the Type.
211class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> {
212 typedef TypeVisitor<TypeVisitorHelper> Inherited;
213 llvm::FoldingSetNodeID &ID;
214 TemplateArgumentHasher &Hash;
215
216public:
217 TypeVisitorHelper(llvm::FoldingSetNodeID &ID, TemplateArgumentHasher &Hash)
218 : ID(ID), Hash(Hash) {}
219
220 void AddDecl(const Decl *D) {
221 if (D)
222 Hash.AddDecl(D);
223 else
224 Hash.AddInteger(0);
225 }
226
227 void AddQualType(QualType T) { Hash.AddQualType(T); }
228
229 void AddType(const Type *T) {
230 if (T)
231 Hash.AddType(T);
232 else
233 Hash.AddInteger(0);
234 }
235
236 void VisitQualifiers(Qualifiers Quals) {
237 Hash.AddInteger(Quals.getAsOpaqueValue());
238 }
239
240 void Visit(const Type *T) { Inherited::Visit(T); }
241
242 void VisitAdjustedType(const AdjustedType *T) {
243 AddQualType(T->getOriginalType());
244 }
245
246 void VisitDecayedType(const DecayedType *T) {
247 // getDecayedType and getPointeeType are derived from getAdjustedType
248 // and don't need to be separately processed.
249 VisitAdjustedType(T);
250 }
251
252 void VisitArrayType(const ArrayType *T) {
253 AddQualType(T->getElementType());
254 Hash.AddInteger(llvm::to_underlying(T->getSizeModifier()));
255 VisitQualifiers(T->getIndexTypeQualifiers());
256 }
257 void VisitConstantArrayType(const ConstantArrayType *T) {
258 T->getSize().Profile(ID);
259 VisitArrayType(T);
260 }
261
262 void VisitAttributedType(const AttributedType *T) {
263 Hash.AddInteger(T->getAttrKind());
264 AddQualType(T->getModifiedType());
265 }
266
267 void VisitBuiltinType(const BuiltinType *T) { Hash.AddInteger(T->getKind()); }
268
269 void VisitComplexType(const ComplexType *T) {
270 AddQualType(T->getElementType());
271 }
272
273 void VisitDecltypeType(const DecltypeType *T) {
274 AddQualType(T->getUnderlyingType());
275 }
276
277 void VisitDeducedType(const DeducedType *T) {
278 AddQualType(T->getDeducedType());
279 }
280
281 void VisitAutoType(const AutoType *T) { VisitDeducedType(T); }
282
283 void VisitDeducedTemplateSpecializationType(
284 const DeducedTemplateSpecializationType *T) {
285 Hash.AddTemplateName(T->getTemplateName());
286 VisitDeducedType(T);
287 }
288
289 void VisitFunctionType(const FunctionType *T) {
290 AddQualType(T->getReturnType());
291 T->getExtInfo().Profile(ID);
292 Hash.AddInteger(T->isConst());
293 Hash.AddInteger(T->isVolatile());
294 Hash.AddInteger(T->isRestrict());
295 }
296
297 void VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
298 VisitFunctionType(T);
299 }
300
301 void VisitFunctionProtoType(const FunctionProtoType *T) {
302 Hash.AddInteger(T->getNumParams());
303 for (auto ParamType : T->getParamTypes())
304 AddQualType(ParamType);
305
306 VisitFunctionType(T);
307 }
308
309 void VisitMemberPointerType(const MemberPointerType *T) {
310 AddQualType(T->getPointeeType());
311 AddType(T->getQualifier().getAsType());
312 if (auto *RD = T->getMostRecentCXXRecordDecl())
313 AddDecl(RD->getCanonicalDecl());
314 }
315
316 void VisitPackExpansionType(const PackExpansionType *T) {
317 AddQualType(T->getPattern());
318 }
319
320 void VisitParenType(const ParenType *T) { AddQualType(T->getInnerType()); }
321
322 void VisitPointerType(const PointerType *T) {
323 AddQualType(T->getPointeeType());
324 }
325
326 void VisitReferenceType(const ReferenceType *T) {
327 AddQualType(T->getPointeeTypeAsWritten());
328 }
329
330 void VisitLValueReferenceType(const LValueReferenceType *T) {
331 VisitReferenceType(T);
332 }
333
334 void VisitRValueReferenceType(const RValueReferenceType *T) {
335 VisitReferenceType(T);
336 }
337
338 void
339 VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
340 AddDecl(T->getAssociatedDecl());
341 Hash.AddTemplateArgument(T->getArgumentPack());
342 }
343
344 void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
345 AddDecl(T->getAssociatedDecl());
346 AddQualType(T->getReplacementType());
347 }
348
349 void VisitTagType(const TagType *T) { AddDecl(T->getDecl()); }
350
351 void VisitRecordType(const RecordType *T) { VisitTagType(T); }
352 void VisitEnumType(const EnumType *T) { VisitTagType(T); }
353
354 void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
355 Hash.AddInteger(T->template_arguments().size());
356 for (const auto &TA : T->template_arguments()) {
357 Hash.AddTemplateArgument(TA);
358 }
359 Hash.AddTemplateName(T->getTemplateName());
360 }
361
362 void VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
363 Hash.AddInteger(T->getDepth());
364 Hash.AddInteger(T->getIndex());
365 Hash.AddInteger(T->isParameterPack());
366 }
367
368 void VisitTypedefType(const TypedefType *T) { AddDecl(T->getDecl()); }
369
370 void VisitUnaryTransformType(const UnaryTransformType *T) {
371 AddQualType(T->getUnderlyingType());
372 AddQualType(T->getBaseType());
373 }
374
375 void VisitVectorType(const VectorType *T) {
376 AddQualType(T->getElementType());
377 Hash.AddInteger(T->getNumElements());
378 Hash.AddInteger(llvm::to_underlying(T->getVectorKind()));
379 }
380
381 void VisitExtVectorType(const ExtVectorType *T) { VisitVectorType(T); }
382};
383
384void TemplateArgumentHasher::AddType(const Type *T) {
385 assert(T && "Expecting non-null pointer.");
386 TypeVisitorHelper(ID, *this).Visit(T);
387}
388
389} // namespace
390
393 llvm::TimeTraceScope TimeScope("Stable Hash for Template Arguments");
394 TemplateArgumentHasher Hasher;
395 Hasher.AddInteger(Args.size());
396 for (TemplateArgument Arg : Args)
397 Hasher.AddTemplateArgument(Arg);
398 return Hasher.getValue();
399}
#define V(N, I)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
IdentifierInfo * getAsIdentifierInfo() const
Retrieve the IdentifierInfo * stored in this declaration name, or null if this declaration name isn't...
TemplateDecl * getCXXDeductionGuideTemplate() const
If this name is the name of a C++ deduction guide, return the template associated with that name.
const IdentifierInfo * getCXXLiteralIdentifier() const
If this name is the name of a literal operator, retrieve the identifier associated with it.
OverloadedOperatorKind getCXXOverloadedOperator() const
If this name is the name of an overloadable operator in C++ (e.g., operator+), retrieve the kind of o...
QualType getCXXNameType() const
If this name is one of the C++ names (of a constructor, destructor, or conversion function),...
NameKind getNameKind() const
Determine what kind of name this is.
bool isEmpty() const
Evaluates true when this declaration name is empty.
TemplateName getUnderlying() const
unsigned getNumParams() const
Definition TypeBase.h:5663
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx)
Definition Type.cpp:4118
ArrayRef< QualType > getParamTypes() const
Definition TypeBase.h:5670
void Profile(llvm::FoldingSetNodeID &ID) const
Definition TypeBase.h:4808
ExtInfo getExtInfo() const
Definition TypeBase.h:4937
bool isConst() const
Definition TypeBase.h:4943
bool isRestrict() const
Definition TypeBase.h:4945
QualType getReturnType() const
Definition TypeBase.h:4921
bool isVolatile() const
Definition TypeBase.h:4944
StringRef getName() const
Return the actual identifier string.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition Decl.h:341
TemplateName getUnderlyingTemplate() const
Return the underlying template name.
uint64_t getAsOpaqueValue() const
Definition TypeBase.h:456
Represents a template argument.
QualType getStructuralValueType() const
Get the type of a StructuralValue.
QualType getAsType() const
Retrieve the type for a type template argument.
llvm::APSInt getAsIntegral() const
Retrieve the template argument as an integral value.
unsigned pack_size() const
The number of template arguments in the given template argument pack.
ValueDecl * getAsDecl() const
Retrieve the declaration for a declaration non-type template argument.
ArrayRef< TemplateArgument > pack_elements() const
Iterator range referencing all of the elements of a template argument pack.
@ Declaration
The template argument is a declaration that was provided for a pointer, reference,...
@ Template
The template argument is a template name that was provided for a template template parameter.
@ StructuralValue
The template argument is a non-type template argument that can't be represented by the special-case D...
@ Pack
The template argument is actually a parameter pack.
@ TemplateExpansion
The template argument is a pack expansion of a template name that was provided for a template templat...
@ NullPtr
The template argument is a null pointer or null pointer to member that was provided for a non-type te...
@ Type
The template argument is a type.
@ Null
Represents an empty template argument, e.g., one that has not been deduced.
@ Integral
The template argument is an integral value stored in an llvm::APSInt that was provided for an integra...
@ Expression
The template argument is an expression, and we've not resolved it to one of the other forms yet,...
ArgKind getKind() const
Return the kind of stored template argument.
TemplateName getAsTemplateOrTemplatePattern() const
Retrieve the template argument as a template name; if the argument is a pack expansion,...
const APValue & getAsStructuralValue() const
Get the value of a StructuralValue.
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.
QualifiedTemplateName * getAsQualifiedTemplateName() const
Retrieve the underlying qualified template name structure, if any.
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.
@ PackIndexingTemplate
A pack-index-template-name.
@ 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...
PackIndexingTemplateStorage * getAsPackIndexingTemplate() const
Retrieve the pack-index-template-name storage, if any.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
NamedDecl * getTargetDecl() const
Gets the underlying declaration which has been brought into the local scope.
Definition DeclCXX.h:3492
unsigned StableHashForTemplateArguments(llvm::ArrayRef< TemplateArgument > Args)
Calculate a stable hash value for template arguments.
Top level wrappers for InstallAPI frontend operations.
@ TemplateName
The identifier is a template name. FIXME: Add an annotation for that.
Definition Parser.h:61
const FunctionProtoType * T
@ Template
We are parsing a template declaration.
Definition Parser.h:81
@ Type
The name was classified as a type.
Definition Sema.h:558
const Type * Ty
The locally-unqualified type.
Definition TypeBase.h:873
Qualifiers Quals
The local qualifiers.
Definition TypeBase.h:876