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