clang 22.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 // If we bail out during the process of calculating hash values for
26 // template arguments for any reason. We're allowed to do it since
27 // TemplateArgumentHasher are only required to give the same hash value
28 // for the same template arguments, but not required to give different
29 // hash value for different template arguments.
30 //
31 // So in the worst case, it is still a valid implementation to give all
32 // inputs the same BailedOutValue as output.
33 bool BailedOut = false;
34 static constexpr unsigned BailedOutValue = 0x12345678;
35
36 llvm::FoldingSetNodeID ID;
37
38public:
39 TemplateArgumentHasher() = default;
40
41 void AddTemplateArgument(TemplateArgument TA);
42
43 void AddInteger(unsigned V) { ID.AddInteger(V); }
44
45 unsigned getValue() {
46 if (BailedOut)
47 return BailedOutValue;
48
49 return ID.computeStableHash();
50 }
51
52 void setBailedOut() { BailedOut = true; }
53
54 void AddType(const Type *T);
55 void AddQualType(QualType T);
56 void AddDecl(const Decl *D);
57 void AddStructuralValue(const APValue &);
58 void AddTemplateName(TemplateName Name);
59 void AddDeclarationName(DeclarationName Name);
60 void AddIdentifierInfo(const IdentifierInfo *II);
61};
62
63void TemplateArgumentHasher::AddTemplateArgument(TemplateArgument TA) {
64 const auto Kind = TA.getKind();
65 AddInteger(Kind);
66
67 switch (Kind) {
69 // These can occur in incomplete substitutions performed with code
70 // completion (see PartialOverloading).
71 break;
73 AddQualType(TA.getAsType());
74 break;
76 AddDecl(TA.getAsDecl());
77 break;
79 ID.AddPointer(nullptr);
80 break;
82 // There are integrals (e.g.: _BitInt(128)) that cannot be represented as
83 // any builtin integral type, so we use the hash of APSInt instead.
84 TA.getAsIntegral().Profile(ID);
85 break;
86 }
88 AddQualType(TA.getStructuralValueType());
89 AddStructuralValue(TA.getAsStructuralValue());
90 break;
93 AddTemplateName(TA.getAsTemplateOrTemplatePattern());
94 break;
96 // If we meet expression in template argument, it implies
97 // that the template is still dependent. It is meaningless
98 // to get a stable hash for the template. Bail out simply.
99 BailedOut = true;
100 break;
102 AddInteger(TA.pack_size());
103 for (auto SubTA : TA.pack_elements()) {
104 AddTemplateArgument(SubTA);
105 }
106 break;
107 }
108}
109
110void TemplateArgumentHasher::AddStructuralValue(const APValue &Value) {
111 auto Kind = Value.getKind();
112 AddInteger(Kind);
113
114 // 'APValue::Profile' uses pointer values to make hash for LValue and
115 // MemberPointer, but they differ from one compiler invocation to another.
116 // It may be difficult to handle such cases. Bail out simply.
117
118 if (Kind == APValue::LValue || Kind == APValue::MemberPointer) {
119 BailedOut = true;
120 return;
121 }
122
123 Value.Profile(ID);
124}
125
126void TemplateArgumentHasher::AddTemplateName(TemplateName Name) {
127 switch (Name.getKind()) {
129 AddDecl(Name.getAsTemplateDecl());
130 break;
132 QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName();
133 AddTemplateName(QTN->getUnderlyingTemplate());
134 break;
135 }
141 BailedOut = true;
142 break;
144 UsingShadowDecl *USD = Name.getAsUsingShadowDecl();
145 if (USD)
146 AddDecl(USD->getTargetDecl());
147 else
148 BailedOut = true;
149 break;
150 }
152 AddTemplateName(Name.getAsDeducedTemplateName()->getUnderlying());
153 break;
154 }
155}
156
157void TemplateArgumentHasher::AddIdentifierInfo(const IdentifierInfo *II) {
158 assert(II && "Expecting non-null pointer.");
159 ID.AddString(II->getName());
160}
161
162void TemplateArgumentHasher::AddDeclarationName(DeclarationName Name) {
163 if (Name.isEmpty())
164 return;
165
166 switch (Name.getNameKind()) {
168 AddIdentifierInfo(Name.getAsIdentifierInfo());
169 break;
173 BailedOut = true;
174 break;
177 AddQualType(Name.getCXXNameType());
178 break;
180 AddInteger(Name.getCXXOverloadedOperator());
181 break;
183 AddIdentifierInfo(Name.getCXXLiteralIdentifier());
184 break;
186 AddQualType(Name.getCXXNameType());
187 break;
189 break;
191 if (auto *Template = Name.getCXXDeductionGuideTemplate())
192 AddDecl(Template);
193 }
194 }
195}
196
197void TemplateArgumentHasher::AddDecl(const Decl *D) {
198 const NamedDecl *ND = dyn_cast<NamedDecl>(D);
199 if (!ND) {
200 BailedOut = true;
201 return;
202 }
203
204 AddDeclarationName(ND->getDeclName());
205}
206
207void TemplateArgumentHasher::AddQualType(QualType T) {
208 if (T.isNull()) {
209 BailedOut = true;
210 return;
211 }
212 SplitQualType split = T.split();
213 AddInteger(split.Quals.getAsOpaqueValue());
214 AddType(split.Ty);
215}
216
217// Process a Type pointer. Add* methods call back into TemplateArgumentHasher
218// while Visit* methods process the relevant parts of the Type.
219// Any unhandled type will make the hash computation bail out.
220class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> {
221 typedef TypeVisitor<TypeVisitorHelper> Inherited;
222 llvm::FoldingSetNodeID &ID;
223 TemplateArgumentHasher &Hash;
224
225public:
226 TypeVisitorHelper(llvm::FoldingSetNodeID &ID, TemplateArgumentHasher &Hash)
227 : ID(ID), Hash(Hash) {}
228
229 void AddDecl(const Decl *D) {
230 if (D)
231 Hash.AddDecl(D);
232 else
233 Hash.AddInteger(0);
234 }
235
236 void AddQualType(QualType T) { Hash.AddQualType(T); }
237
238 void AddType(const Type *T) {
239 if (T)
240 Hash.AddType(T);
241 else
242 Hash.AddInteger(0);
243 }
244
245 void VisitQualifiers(Qualifiers Quals) {
246 Hash.AddInteger(Quals.getAsOpaqueValue());
247 }
248
249 void Visit(const Type *T) { Inherited::Visit(T); }
250
251 // Unhandled types. Bail out simply.
252 void VisitType(const Type *T) { Hash.setBailedOut(); }
253
254 void VisitAdjustedType(const AdjustedType *T) {
255 AddQualType(T->getOriginalType());
256 }
257
258 void VisitDecayedType(const DecayedType *T) {
259 // getDecayedType and getPointeeType are derived from getAdjustedType
260 // and don't need to be separately processed.
261 VisitAdjustedType(T);
262 }
263
264 void VisitArrayType(const ArrayType *T) {
265 AddQualType(T->getElementType());
266 Hash.AddInteger(llvm::to_underlying(T->getSizeModifier()));
267 VisitQualifiers(T->getIndexTypeQualifiers());
268 }
269 void VisitConstantArrayType(const ConstantArrayType *T) {
270 T->getSize().Profile(ID);
271 VisitArrayType(T);
272 }
273
274 void VisitAttributedType(const AttributedType *T) {
275 Hash.AddInteger(T->getAttrKind());
276 AddQualType(T->getModifiedType());
277 }
278
279 void VisitBuiltinType(const BuiltinType *T) { Hash.AddInteger(T->getKind()); }
280
281 void VisitComplexType(const ComplexType *T) {
282 AddQualType(T->getElementType());
283 }
284
285 void VisitDecltypeType(const DecltypeType *T) {
286 AddQualType(T->getUnderlyingType());
287 }
288
289 void VisitDeducedType(const DeducedType *T) {
290 AddQualType(T->getDeducedType());
291 }
292
293 void VisitAutoType(const AutoType *T) { VisitDeducedType(T); }
294
295 void VisitDeducedTemplateSpecializationType(
296 const DeducedTemplateSpecializationType *T) {
297 Hash.AddTemplateName(T->getTemplateName());
298 VisitDeducedType(T);
299 }
300
301 void VisitFunctionType(const FunctionType *T) {
302 AddQualType(T->getReturnType());
303 T->getExtInfo().Profile(ID);
304 Hash.AddInteger(T->isConst());
305 Hash.AddInteger(T->isVolatile());
306 Hash.AddInteger(T->isRestrict());
307 }
308
309 void VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
310 VisitFunctionType(T);
311 }
312
313 void VisitFunctionProtoType(const FunctionProtoType *T) {
314 Hash.AddInteger(T->getNumParams());
315 for (auto ParamType : T->getParamTypes())
316 AddQualType(ParamType);
317
318 VisitFunctionType(T);
319 }
320
321 void VisitMemberPointerType(const MemberPointerType *T) {
322 AddQualType(T->getPointeeType());
323 AddType(T->getQualifier().getAsType());
324 if (auto *RD = T->getMostRecentCXXRecordDecl())
325 AddDecl(RD->getCanonicalDecl());
326 }
327
328 void VisitPackExpansionType(const PackExpansionType *T) {
329 AddQualType(T->getPattern());
330 }
331
332 void VisitParenType(const ParenType *T) { AddQualType(T->getInnerType()); }
333
334 void VisitPointerType(const PointerType *T) {
335 AddQualType(T->getPointeeType());
336 }
337
338 void VisitReferenceType(const ReferenceType *T) {
339 AddQualType(T->getPointeeTypeAsWritten());
340 }
341
342 void VisitLValueReferenceType(const LValueReferenceType *T) {
343 VisitReferenceType(T);
344 }
345
346 void VisitRValueReferenceType(const RValueReferenceType *T) {
347 VisitReferenceType(T);
348 }
349
350 void
351 VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
352 AddDecl(T->getAssociatedDecl());
353 Hash.AddTemplateArgument(T->getArgumentPack());
354 }
355
356 void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
357 AddDecl(T->getAssociatedDecl());
358 AddQualType(T->getReplacementType());
359 }
360
361 void VisitTagType(const TagType *T) { AddDecl(T->getOriginalDecl()); }
362
363 void VisitRecordType(const RecordType *T) { VisitTagType(T); }
364 void VisitEnumType(const EnumType *T) { VisitTagType(T); }
365
366 void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
367 Hash.AddInteger(T->template_arguments().size());
368 for (const auto &TA : T->template_arguments()) {
369 Hash.AddTemplateArgument(TA);
370 }
371 Hash.AddTemplateName(T->getTemplateName());
372 }
373
374 void VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
375 Hash.AddInteger(T->getDepth());
376 Hash.AddInteger(T->getIndex());
377 Hash.AddInteger(T->isParameterPack());
378 }
379
380 void VisitTypedefType(const TypedefType *T) { AddDecl(T->getDecl()); }
381
382 void VisitUnaryTransformType(const UnaryTransformType *T) {
383 AddQualType(T->getUnderlyingType());
384 AddQualType(T->getBaseType());
385 }
386
387 void VisitVectorType(const VectorType *T) {
388 AddQualType(T->getElementType());
389 Hash.AddInteger(T->getNumElements());
390 Hash.AddInteger(llvm::to_underlying(T->getVectorKind()));
391 }
392
393 void VisitExtVectorType(const ExtVectorType *T) { VisitVectorType(T); }
394};
395
396void TemplateArgumentHasher::AddType(const Type *T) {
397 assert(T && "Expecting non-null pointer.");
398 TypeVisitorHelper(ID, *this).Visit(T);
399}
400
401} // namespace
402
405 llvm::TimeTraceScope TimeScope("Stable Hash for Template Arguments");
406 TemplateArgumentHasher Hasher;
407 Hasher.AddInteger(Args.size());
408 for (TemplateArgument Arg : Args)
409 Hasher.AddTemplateArgument(Arg);
410 return Hasher.getValue();
411}
#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:5542
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx)
Definition Type.cpp:3956
ArrayRef< QualType > getParamTypes() const
Definition TypeBase.h:5549
void Profile(llvm::FoldingSetNodeID &ID) const
Definition TypeBase.h:4687
ExtInfo getExtInfo() const
Definition TypeBase.h:4816
bool isConst() const
Definition TypeBase.h:4822
bool isRestrict() const
Definition TypeBase.h:4824
QualType getReturnType() const
Definition TypeBase.h:4800
bool isVolatile() const
Definition TypeBase.h:4823
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:339
TemplateName getUnderlyingTemplate() const
Return the underlying template name.
uint64_t getAsOpaqueValue() const
Definition TypeBase.h:455
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.
@ 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...
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:752
NamedDecl * getTargetDecl() const
Gets the underlying declaration which has been brought into the local scope.
Definition DeclCXX.h:3457
unsigned StableHashForTemplateArguments(llvm::ArrayRef< TemplateArgument > Args)
Calculate a stable hash value for template arguments.
The JSON file list parser is used to communicate input to InstallAPI.
@ 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:562
const Type * Ty
The locally-unqualified type.
Definition TypeBase.h:872
Qualifiers Quals
The local qualifiers.
Definition TypeBase.h:875