diff options
Diffstat (limited to 'clang/lib/AST/ODRHash.cpp')
| -rw-r--r-- | clang/lib/AST/ODRHash.cpp | 1123 | 
1 files changed, 1123 insertions, 0 deletions
| diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp new file mode 100644 index 000000000000..3b89c630b451 --- /dev/null +++ b/clang/lib/AST/ODRHash.cpp @@ -0,0 +1,1123 @@ +//===-- ODRHash.cpp - Hashing to diagnose ODR failures ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements the ODRHash class, which calculates a hash based +/// on AST nodes, which is stable across different runs. +/// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ODRHash.h" + +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeVisitor.h" + +using namespace clang; + +void ODRHash::AddStmt(const Stmt *S) { +  assert(S && "Expecting non-null pointer."); +  S->ProcessODRHash(ID, *this); +} + +void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) { +  assert(II && "Expecting non-null pointer."); +  ID.AddString(II->getName()); +} + +void ODRHash::AddDeclarationName(DeclarationName Name, bool TreatAsDecl) { +  if (TreatAsDecl) +    // Matches the NamedDecl check in AddDecl +    AddBoolean(true); + +  AddDeclarationNameImpl(Name); + +  if (TreatAsDecl) +    // Matches the ClassTemplateSpecializationDecl check in AddDecl +    AddBoolean(false); +} + +void ODRHash::AddDeclarationNameImpl(DeclarationName Name) { +  // Index all DeclarationName and use index numbers to refer to them. +  auto Result = DeclNameMap.insert(std::make_pair(Name, DeclNameMap.size())); +  ID.AddInteger(Result.first->second); +  if (!Result.second) { +    // If found in map, the DeclarationName has previously been processed. +    return; +  } + +  // First time processing each DeclarationName, also process its details. +  AddBoolean(Name.isEmpty()); +  if (Name.isEmpty()) +    return; + +  auto Kind = Name.getNameKind(); +  ID.AddInteger(Kind); +  switch (Kind) { +  case DeclarationName::Identifier: +    AddIdentifierInfo(Name.getAsIdentifierInfo()); +    break; +  case DeclarationName::ObjCZeroArgSelector: +  case DeclarationName::ObjCOneArgSelector: +  case DeclarationName::ObjCMultiArgSelector: { +    Selector S = Name.getObjCSelector(); +    AddBoolean(S.isNull()); +    AddBoolean(S.isKeywordSelector()); +    AddBoolean(S.isUnarySelector()); +    unsigned NumArgs = S.getNumArgs(); +    ID.AddInteger(NumArgs); +    for (unsigned i = 0; i < NumArgs; ++i) { +      const IdentifierInfo *II = S.getIdentifierInfoForSlot(i); +      AddBoolean(II); +      if (II) { +        AddIdentifierInfo(II); +      } +    } +    break; +  } +  case DeclarationName::CXXConstructorName: +  case DeclarationName::CXXDestructorName: +    AddQualType(Name.getCXXNameType()); +    break; +  case DeclarationName::CXXOperatorName: +    ID.AddInteger(Name.getCXXOverloadedOperator()); +    break; +  case DeclarationName::CXXLiteralOperatorName: +    AddIdentifierInfo(Name.getCXXLiteralIdentifier()); +    break; +  case DeclarationName::CXXConversionFunctionName: +    AddQualType(Name.getCXXNameType()); +    break; +  case DeclarationName::CXXUsingDirective: +    break; +  case DeclarationName::CXXDeductionGuideName: { +    auto *Template = Name.getCXXDeductionGuideTemplate(); +    AddBoolean(Template); +    if (Template) { +      AddDecl(Template); +    } +  } +  } +} + +void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { +  assert(NNS && "Expecting non-null pointer."); +  const auto *Prefix = NNS->getPrefix(); +  AddBoolean(Prefix); +  if (Prefix) { +    AddNestedNameSpecifier(Prefix); +  } +  auto Kind = NNS->getKind(); +  ID.AddInteger(Kind); +  switch (Kind) { +  case NestedNameSpecifier::Identifier: +    AddIdentifierInfo(NNS->getAsIdentifier()); +    break; +  case NestedNameSpecifier::Namespace: +    AddDecl(NNS->getAsNamespace()); +    break; +  case NestedNameSpecifier::NamespaceAlias: +    AddDecl(NNS->getAsNamespaceAlias()); +    break; +  case NestedNameSpecifier::TypeSpec: +  case NestedNameSpecifier::TypeSpecWithTemplate: +    AddType(NNS->getAsType()); +    break; +  case NestedNameSpecifier::Global: +  case NestedNameSpecifier::Super: +    break; +  } +} + +void ODRHash::AddTemplateName(TemplateName Name) { +  auto Kind = Name.getKind(); +  ID.AddInteger(Kind); + +  switch (Kind) { +  case TemplateName::Template: +    AddDecl(Name.getAsTemplateDecl()); +    break; +  // TODO: Support these cases. +  case TemplateName::OverloadedTemplate: +  case TemplateName::AssumedTemplate: +  case TemplateName::QualifiedTemplate: +  case TemplateName::DependentTemplate: +  case TemplateName::SubstTemplateTemplateParm: +  case TemplateName::SubstTemplateTemplateParmPack: +    break; +  } +} + +void ODRHash::AddTemplateArgument(TemplateArgument TA) { +  const auto Kind = TA.getKind(); +  ID.AddInteger(Kind); + +  switch (Kind) { +    case TemplateArgument::Null: +      llvm_unreachable("Expected valid TemplateArgument"); +    case TemplateArgument::Type: +      AddQualType(TA.getAsType()); +      break; +    case TemplateArgument::Declaration: +      AddDecl(TA.getAsDecl()); +      break; +    case TemplateArgument::NullPtr: +    case TemplateArgument::Integral: +      break; +    case TemplateArgument::Template: +    case TemplateArgument::TemplateExpansion: +      AddTemplateName(TA.getAsTemplateOrTemplatePattern()); +      break; +    case TemplateArgument::Expression: +      AddStmt(TA.getAsExpr()); +      break; +    case TemplateArgument::Pack: +      ID.AddInteger(TA.pack_size()); +      for (auto SubTA : TA.pack_elements()) { +        AddTemplateArgument(SubTA); +      } +      break; +  } +} + +void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) { +  assert(TPL && "Expecting non-null pointer."); + +  ID.AddInteger(TPL->size()); +  for (auto *ND : TPL->asArray()) { +    AddSubDecl(ND); +  } +} + +void ODRHash::clear() { +  DeclNameMap.clear(); +  Bools.clear(); +  ID.clear(); +} + +unsigned ODRHash::CalculateHash() { +  // Append the bools to the end of the data segment backwards.  This allows +  // for the bools data to be compressed 32 times smaller compared to using +  // ID.AddBoolean +  const unsigned unsigned_bits = sizeof(unsigned) * CHAR_BIT; +  const unsigned size = Bools.size(); +  const unsigned remainder = size % unsigned_bits; +  const unsigned loops = size / unsigned_bits; +  auto I = Bools.rbegin(); +  unsigned value = 0; +  for (unsigned i = 0; i < remainder; ++i) { +    value <<= 1; +    value |= *I; +    ++I; +  } +  ID.AddInteger(value); + +  for (unsigned i = 0; i < loops; ++i) { +    value = 0; +    for (unsigned j = 0; j < unsigned_bits; ++j) { +      value <<= 1; +      value |= *I; +      ++I; +    } +    ID.AddInteger(value); +  } + +  assert(I == Bools.rend()); +  Bools.clear(); +  return ID.ComputeHash(); +} + +namespace { +// Process a Decl pointer.  Add* methods call back into ODRHash while Visit* +// methods process the relevant parts of the Decl. +class ODRDeclVisitor : public ConstDeclVisitor<ODRDeclVisitor> { +  typedef ConstDeclVisitor<ODRDeclVisitor> Inherited; +  llvm::FoldingSetNodeID &ID; +  ODRHash &Hash; + +public: +  ODRDeclVisitor(llvm::FoldingSetNodeID &ID, ODRHash &Hash) +      : ID(ID), Hash(Hash) {} + +  void AddStmt(const Stmt *S) { +    Hash.AddBoolean(S); +    if (S) { +      Hash.AddStmt(S); +    } +  } + +  void AddIdentifierInfo(const IdentifierInfo *II) { +    Hash.AddBoolean(II); +    if (II) { +      Hash.AddIdentifierInfo(II); +    } +  } + +  void AddQualType(QualType T) { +    Hash.AddQualType(T); +  } + +  void AddDecl(const Decl *D) { +    Hash.AddBoolean(D); +    if (D) { +      Hash.AddDecl(D); +    } +  } + +  void AddTemplateArgument(TemplateArgument TA) { +    Hash.AddTemplateArgument(TA); +  } + +  void Visit(const Decl *D) { +    ID.AddInteger(D->getKind()); +    Inherited::Visit(D); +  } + +  void VisitNamedDecl(const NamedDecl *D) { +    Hash.AddDeclarationName(D->getDeclName()); +    Inherited::VisitNamedDecl(D); +  } + +  void VisitValueDecl(const ValueDecl *D) { +    if (!isa<FunctionDecl>(D)) { +      AddQualType(D->getType()); +    } +    Inherited::VisitValueDecl(D); +  } + +  void VisitVarDecl(const VarDecl *D) { +    Hash.AddBoolean(D->isStaticLocal()); +    Hash.AddBoolean(D->isConstexpr()); +    const bool HasInit = D->hasInit(); +    Hash.AddBoolean(HasInit); +    if (HasInit) { +      AddStmt(D->getInit()); +    } +    Inherited::VisitVarDecl(D); +  } + +  void VisitParmVarDecl(const ParmVarDecl *D) { +    // TODO: Handle default arguments. +    Inherited::VisitParmVarDecl(D); +  } + +  void VisitAccessSpecDecl(const AccessSpecDecl *D) { +    ID.AddInteger(D->getAccess()); +    Inherited::VisitAccessSpecDecl(D); +  } + +  void VisitStaticAssertDecl(const StaticAssertDecl *D) { +    AddStmt(D->getAssertExpr()); +    AddStmt(D->getMessage()); + +    Inherited::VisitStaticAssertDecl(D); +  } + +  void VisitFieldDecl(const FieldDecl *D) { +    const bool IsBitfield = D->isBitField(); +    Hash.AddBoolean(IsBitfield); + +    if (IsBitfield) { +      AddStmt(D->getBitWidth()); +    } + +    Hash.AddBoolean(D->isMutable()); +    AddStmt(D->getInClassInitializer()); + +    Inherited::VisitFieldDecl(D); +  } + +  void VisitFunctionDecl(const FunctionDecl *D) { +    // Handled by the ODRHash for FunctionDecl +    ID.AddInteger(D->getODRHash()); + +    Inherited::VisitFunctionDecl(D); +  } + +  void VisitCXXMethodDecl(const CXXMethodDecl *D) { +    // Handled by the ODRHash for FunctionDecl + +    Inherited::VisitCXXMethodDecl(D); +  } + +  void VisitTypedefNameDecl(const TypedefNameDecl *D) { +    AddQualType(D->getUnderlyingType()); + +    Inherited::VisitTypedefNameDecl(D); +  } + +  void VisitTypedefDecl(const TypedefDecl *D) { +    Inherited::VisitTypedefDecl(D); +  } + +  void VisitTypeAliasDecl(const TypeAliasDecl *D) { +    Inherited::VisitTypeAliasDecl(D); +  } + +  void VisitFriendDecl(const FriendDecl *D) { +    TypeSourceInfo *TSI = D->getFriendType(); +    Hash.AddBoolean(TSI); +    if (TSI) { +      AddQualType(TSI->getType()); +    } else { +      AddDecl(D->getFriendDecl()); +    } +  } + +  void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { +    // Only care about default arguments as part of the definition. +    const bool hasDefaultArgument = +        D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); +    Hash.AddBoolean(hasDefaultArgument); +    if (hasDefaultArgument) { +      AddTemplateArgument(D->getDefaultArgument()); +    } +    Hash.AddBoolean(D->isParameterPack()); + +    Inherited::VisitTemplateTypeParmDecl(D); +  } + +  void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { +    // Only care about default arguments as part of the definition. +    const bool hasDefaultArgument = +        D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); +    Hash.AddBoolean(hasDefaultArgument); +    if (hasDefaultArgument) { +      AddStmt(D->getDefaultArgument()); +    } +    Hash.AddBoolean(D->isParameterPack()); + +    Inherited::VisitNonTypeTemplateParmDecl(D); +  } + +  void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) { +    // Only care about default arguments as part of the definition. +    const bool hasDefaultArgument = +        D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); +    Hash.AddBoolean(hasDefaultArgument); +    if (hasDefaultArgument) { +      AddTemplateArgument(D->getDefaultArgument().getArgument()); +    } +    Hash.AddBoolean(D->isParameterPack()); + +    Inherited::VisitTemplateTemplateParmDecl(D); +  } + +  void VisitTemplateDecl(const TemplateDecl *D) { +    Hash.AddTemplateParameterList(D->getTemplateParameters()); + +    Inherited::VisitTemplateDecl(D); +  } + +  void VisitRedeclarableTemplateDecl(const RedeclarableTemplateDecl *D) { +    Hash.AddBoolean(D->isMemberSpecialization()); +    Inherited::VisitRedeclarableTemplateDecl(D); +  } + +  void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { +    AddDecl(D->getTemplatedDecl()); +    ID.AddInteger(D->getTemplatedDecl()->getODRHash()); +    Inherited::VisitFunctionTemplateDecl(D); +  } + +  void VisitEnumConstantDecl(const EnumConstantDecl *D) { +    AddStmt(D->getInitExpr()); +    Inherited::VisitEnumConstantDecl(D); +  } +}; +} // namespace + +// Only allow a small portion of Decl's to be processed.  Remove this once +// all Decl's can be handled. +bool ODRHash::isWhitelistedDecl(const Decl *D, const DeclContext *Parent) { +  if (D->isImplicit()) return false; +  if (D->getDeclContext() != Parent) return false; + +  switch (D->getKind()) { +    default: +      return false; +    case Decl::AccessSpec: +    case Decl::CXXConstructor: +    case Decl::CXXDestructor: +    case Decl::CXXMethod: +    case Decl::EnumConstant: // Only found in EnumDecl's. +    case Decl::Field: +    case Decl::Friend: +    case Decl::FunctionTemplate: +    case Decl::StaticAssert: +    case Decl::TypeAlias: +    case Decl::Typedef: +    case Decl::Var: +      return true; +  } +} + +void ODRHash::AddSubDecl(const Decl *D) { +  assert(D && "Expecting non-null pointer."); + +  ODRDeclVisitor(ID, *this).Visit(D); +} + +void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) { +  assert(Record && Record->hasDefinition() && +         "Expected non-null record to be a definition."); + +  const DeclContext *DC = Record; +  while (DC) { +    if (isa<ClassTemplateSpecializationDecl>(DC)) { +      return; +    } +    DC = DC->getParent(); +  } + +  AddDecl(Record); + +  // Filter out sub-Decls which will not be processed in order to get an +  // accurate count of Decl's. +  llvm::SmallVector<const Decl *, 16> Decls; +  for (Decl *SubDecl : Record->decls()) { +    if (isWhitelistedDecl(SubDecl, Record)) { +      Decls.push_back(SubDecl); +      if (auto *Function = dyn_cast<FunctionDecl>(SubDecl)) { +        // Compute/Preload ODRHash into FunctionDecl. +        Function->getODRHash(); +      } +    } +  } + +  ID.AddInteger(Decls.size()); +  for (auto SubDecl : Decls) { +    AddSubDecl(SubDecl); +  } + +  const ClassTemplateDecl *TD = Record->getDescribedClassTemplate(); +  AddBoolean(TD); +  if (TD) { +    AddTemplateParameterList(TD->getTemplateParameters()); +  } + +  ID.AddInteger(Record->getNumBases()); +  auto Bases = Record->bases(); +  for (auto Base : Bases) { +    AddQualType(Base.getType()); +    ID.AddInteger(Base.isVirtual()); +    ID.AddInteger(Base.getAccessSpecifierAsWritten()); +  } +} + +void ODRHash::AddFunctionDecl(const FunctionDecl *Function, +                              bool SkipBody) { +  assert(Function && "Expecting non-null pointer."); + +  // Skip functions that are specializations or in specialization context. +  const DeclContext *DC = Function; +  while (DC) { +    if (isa<ClassTemplateSpecializationDecl>(DC)) return; +    if (auto *F = dyn_cast<FunctionDecl>(DC)) { +      if (F->isFunctionTemplateSpecialization()) { +        if (!isa<CXXMethodDecl>(DC)) return; +        if (DC->getLexicalParent()->isFileContext()) return; +        // Inline method specializations are the only supported +        // specialization for now. +      } +    } +    DC = DC->getParent(); +  } + +  ID.AddInteger(Function->getDeclKind()); + +  const auto *SpecializationArgs = Function->getTemplateSpecializationArgs(); +  AddBoolean(SpecializationArgs); +  if (SpecializationArgs) { +    ID.AddInteger(SpecializationArgs->size()); +    for (const TemplateArgument &TA : SpecializationArgs->asArray()) { +      AddTemplateArgument(TA); +    } +  } + +  if (const auto *Method = dyn_cast<CXXMethodDecl>(Function)) { +    AddBoolean(Method->isConst()); +    AddBoolean(Method->isVolatile()); +  } + +  ID.AddInteger(Function->getStorageClass()); +  AddBoolean(Function->isInlineSpecified()); +  AddBoolean(Function->isVirtualAsWritten()); +  AddBoolean(Function->isPure()); +  AddBoolean(Function->isDeletedAsWritten()); +  AddBoolean(Function->isExplicitlyDefaulted()); + +  AddDecl(Function); + +  AddQualType(Function->getReturnType()); + +  ID.AddInteger(Function->param_size()); +  for (auto Param : Function->parameters()) +    AddSubDecl(Param); + +  if (SkipBody) { +    AddBoolean(false); +    return; +  } + +  const bool HasBody = Function->isThisDeclarationADefinition() && +                       !Function->isDefaulted() && !Function->isDeleted() && +                       !Function->isLateTemplateParsed(); +  AddBoolean(HasBody); +  if (!HasBody) { +    return; +  } + +  auto *Body = Function->getBody(); +  AddBoolean(Body); +  if (Body) +    AddStmt(Body); + +  // Filter out sub-Decls which will not be processed in order to get an +  // accurate count of Decl's. +  llvm::SmallVector<const Decl *, 16> Decls; +  for (Decl *SubDecl : Function->decls()) { +    if (isWhitelistedDecl(SubDecl, Function)) { +      Decls.push_back(SubDecl); +    } +  } + +  ID.AddInteger(Decls.size()); +  for (auto SubDecl : Decls) { +    AddSubDecl(SubDecl); +  } +} + +void ODRHash::AddEnumDecl(const EnumDecl *Enum) { +  assert(Enum); +  AddDeclarationName(Enum->getDeclName()); + +  AddBoolean(Enum->isScoped()); +  if (Enum->isScoped()) +    AddBoolean(Enum->isScopedUsingClassTag()); + +  if (Enum->getIntegerTypeSourceInfo()) +    AddQualType(Enum->getIntegerType()); + +  // Filter out sub-Decls which will not be processed in order to get an +  // accurate count of Decl's. +  llvm::SmallVector<const Decl *, 16> Decls; +  for (Decl *SubDecl : Enum->decls()) { +    if (isWhitelistedDecl(SubDecl, Enum)) { +      assert(isa<EnumConstantDecl>(SubDecl) && "Unexpected Decl"); +      Decls.push_back(SubDecl); +    } +  } + +  ID.AddInteger(Decls.size()); +  for (auto SubDecl : Decls) { +    AddSubDecl(SubDecl); +  } + +} + +void ODRHash::AddDecl(const Decl *D) { +  assert(D && "Expecting non-null pointer."); +  D = D->getCanonicalDecl(); + +  const NamedDecl *ND = dyn_cast<NamedDecl>(D); +  AddBoolean(ND); +  if (!ND) { +    ID.AddInteger(D->getKind()); +    return; +  } + +  AddDeclarationName(ND->getDeclName()); + +  const auto *Specialization = +            dyn_cast<ClassTemplateSpecializationDecl>(D); +  AddBoolean(Specialization); +  if (Specialization) { +    const TemplateArgumentList &List = Specialization->getTemplateArgs(); +    ID.AddInteger(List.size()); +    for (const TemplateArgument &TA : List.asArray()) +      AddTemplateArgument(TA); +  } +} + +namespace { +// Process a Type pointer.  Add* methods call back into ODRHash while Visit* +// methods process the relevant parts of the Type. +class ODRTypeVisitor : public TypeVisitor<ODRTypeVisitor> { +  typedef TypeVisitor<ODRTypeVisitor> Inherited; +  llvm::FoldingSetNodeID &ID; +  ODRHash &Hash; + +public: +  ODRTypeVisitor(llvm::FoldingSetNodeID &ID, ODRHash &Hash) +      : ID(ID), Hash(Hash) {} + +  void AddStmt(Stmt *S) { +    Hash.AddBoolean(S); +    if (S) { +      Hash.AddStmt(S); +    } +  } + +  void AddDecl(Decl *D) { +    Hash.AddBoolean(D); +    if (D) { +      Hash.AddDecl(D); +    } +  } + +  void AddQualType(QualType T) { +    Hash.AddQualType(T); +  } + +  void AddType(const Type *T) { +    Hash.AddBoolean(T); +    if (T) { +      Hash.AddType(T); +    } +  } + +  void AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { +    Hash.AddBoolean(NNS); +    if (NNS) { +      Hash.AddNestedNameSpecifier(NNS); +    } +  } + +  void AddIdentifierInfo(const IdentifierInfo *II) { +    Hash.AddBoolean(II); +    if (II) { +      Hash.AddIdentifierInfo(II); +    } +  } + +  void VisitQualifiers(Qualifiers Quals) { +    ID.AddInteger(Quals.getAsOpaqueValue()); +  } + +  // Return the RecordType if the typedef only strips away a keyword. +  // Otherwise, return the original type. +  static const Type *RemoveTypedef(const Type *T) { +    const auto *TypedefT = dyn_cast<TypedefType>(T); +    if (!TypedefT) { +      return T; +    } + +    const TypedefNameDecl *D = TypedefT->getDecl(); +    QualType UnderlyingType = D->getUnderlyingType(); + +    if (UnderlyingType.hasLocalQualifiers()) { +      return T; +    } + +    const auto *ElaboratedT = dyn_cast<ElaboratedType>(UnderlyingType); +    if (!ElaboratedT) { +      return T; +    } + +    if (ElaboratedT->getQualifier() != nullptr) { +      return T; +    } + +    QualType NamedType = ElaboratedT->getNamedType(); +    if (NamedType.hasLocalQualifiers()) { +      return T; +    } + +    const auto *RecordT = dyn_cast<RecordType>(NamedType); +    if (!RecordT) { +      return T; +    } + +    const IdentifierInfo *TypedefII = TypedefT->getDecl()->getIdentifier(); +    const IdentifierInfo *RecordII = RecordT->getDecl()->getIdentifier(); +    if (!TypedefII || !RecordII || +        TypedefII->getName() != RecordII->getName()) { +      return T; +    } + +    return RecordT; +  } + +  void Visit(const Type *T) { +    T = RemoveTypedef(T); +    ID.AddInteger(T->getTypeClass()); +    Inherited::Visit(T); +  } + +  void VisitType(const Type *T) {} + +  void VisitAdjustedType(const AdjustedType *T) { +    QualType Original = T->getOriginalType(); +    QualType Adjusted = T->getAdjustedType(); + +    // The original type and pointee type can be the same, as in the case of +    // function pointers decaying to themselves.  Set a bool and only process +    // the type once, to prevent doubling the work. +    SplitQualType split = Adjusted.split(); +    if (auto Pointer = dyn_cast<PointerType>(split.Ty)) { +      if (Pointer->getPointeeType() == Original) { +        Hash.AddBoolean(true); +        ID.AddInteger(split.Quals.getAsOpaqueValue()); +        AddQualType(Original); +        VisitType(T); +        return; +      } +    } + +    // The original type and pointee type are different, such as in the case +    // of a array decaying to an element pointer.  Set a bool to false and +    // process both types. +    Hash.AddBoolean(false); +    AddQualType(Original); +    AddQualType(Adjusted); + +    VisitType(T); +  } + +  void VisitDecayedType(const DecayedType *T) { +    // getDecayedType and getPointeeType are derived from getAdjustedType +    // and don't need to be separately processed. +    VisitAdjustedType(T); +  } + +  void VisitArrayType(const ArrayType *T) { +    AddQualType(T->getElementType()); +    ID.AddInteger(T->getSizeModifier()); +    VisitQualifiers(T->getIndexTypeQualifiers()); +    VisitType(T); +  } +  void VisitConstantArrayType(const ConstantArrayType *T) { +    T->getSize().Profile(ID); +    VisitArrayType(T); +  } + +  void VisitDependentSizedArrayType(const DependentSizedArrayType *T) { +    AddStmt(T->getSizeExpr()); +    VisitArrayType(T); +  } + +  void VisitIncompleteArrayType(const IncompleteArrayType *T) { +    VisitArrayType(T); +  } + +  void VisitVariableArrayType(const VariableArrayType *T) { +    AddStmt(T->getSizeExpr()); +    VisitArrayType(T); +  } + +  void VisitAttributedType(const AttributedType *T) { +    ID.AddInteger(T->getAttrKind()); +    AddQualType(T->getModifiedType()); +    AddQualType(T->getEquivalentType()); + +    VisitType(T); +  } + +  void VisitBlockPointerType(const BlockPointerType *T) { +    AddQualType(T->getPointeeType()); +    VisitType(T); +  } + +  void VisitBuiltinType(const BuiltinType *T) { +    ID.AddInteger(T->getKind()); +    VisitType(T); +  } + +  void VisitComplexType(const ComplexType *T) { +    AddQualType(T->getElementType()); +    VisitType(T); +  } + +  void VisitDecltypeType(const DecltypeType *T) { +    AddStmt(T->getUnderlyingExpr()); +    AddQualType(T->getUnderlyingType()); +    VisitType(T); +  } + +  void VisitDependentDecltypeType(const DependentDecltypeType *T) { +    VisitDecltypeType(T); +  } + +  void VisitDeducedType(const DeducedType *T) { +    AddQualType(T->getDeducedType()); +    VisitType(T); +  } + +  void VisitAutoType(const AutoType *T) { +    ID.AddInteger((unsigned)T->getKeyword()); +    VisitDeducedType(T); +  } + +  void VisitDeducedTemplateSpecializationType( +      const DeducedTemplateSpecializationType *T) { +    Hash.AddTemplateName(T->getTemplateName()); +    VisitDeducedType(T); +  } + +  void VisitDependentAddressSpaceType(const DependentAddressSpaceType *T) { +    AddQualType(T->getPointeeType()); +    AddStmt(T->getAddrSpaceExpr()); +    VisitType(T); +  } + +  void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T) { +    AddQualType(T->getElementType()); +    AddStmt(T->getSizeExpr()); +    VisitType(T); +  } + +  void VisitFunctionType(const FunctionType *T) { +    AddQualType(T->getReturnType()); +    T->getExtInfo().Profile(ID); +    Hash.AddBoolean(T->isConst()); +    Hash.AddBoolean(T->isVolatile()); +    Hash.AddBoolean(T->isRestrict()); +    VisitType(T); +  } + +  void VisitFunctionNoProtoType(const FunctionNoProtoType *T) { +    VisitFunctionType(T); +  } + +  void VisitFunctionProtoType(const FunctionProtoType *T) { +    ID.AddInteger(T->getNumParams()); +    for (auto ParamType : T->getParamTypes()) +      AddQualType(ParamType); + +    VisitFunctionType(T); +  } + +  void VisitInjectedClassNameType(const InjectedClassNameType *T) { +    AddDecl(T->getDecl()); +    VisitType(T); +  } + +  void VisitMemberPointerType(const MemberPointerType *T) { +    AddQualType(T->getPointeeType()); +    AddType(T->getClass()); +    VisitType(T); +  } + +  void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { +    AddQualType(T->getPointeeType()); +    VisitType(T); +  } + +  void VisitObjCObjectType(const ObjCObjectType *T) { +    AddDecl(T->getInterface()); + +    auto TypeArgs = T->getTypeArgsAsWritten(); +    ID.AddInteger(TypeArgs.size()); +    for (auto Arg : TypeArgs) { +      AddQualType(Arg); +    } + +    auto Protocols = T->getProtocols(); +    ID.AddInteger(Protocols.size()); +    for (auto Protocol : Protocols) { +      AddDecl(Protocol); +    } + +    Hash.AddBoolean(T->isKindOfType()); + +    VisitType(T); +  } + +  void VisitObjCInterfaceType(const ObjCInterfaceType *T) { +    // This type is handled by the parent type ObjCObjectType. +    VisitObjCObjectType(T); +  } + +  void VisitObjCTypeParamType(const ObjCTypeParamType *T) { +    AddDecl(T->getDecl()); +    auto Protocols = T->getProtocols(); +    ID.AddInteger(Protocols.size()); +    for (auto Protocol : Protocols) { +      AddDecl(Protocol); +    } + +    VisitType(T); +  } + +  void VisitPackExpansionType(const PackExpansionType *T) { +    AddQualType(T->getPattern()); +    VisitType(T); +  } + +  void VisitParenType(const ParenType *T) { +    AddQualType(T->getInnerType()); +    VisitType(T); +  } + +  void VisitPipeType(const PipeType *T) { +    AddQualType(T->getElementType()); +    Hash.AddBoolean(T->isReadOnly()); +    VisitType(T); +  } + +  void VisitPointerType(const PointerType *T) { +    AddQualType(T->getPointeeType()); +    VisitType(T); +  } + +  void VisitReferenceType(const ReferenceType *T) { +    AddQualType(T->getPointeeTypeAsWritten()); +    VisitType(T); +  } + +  void VisitLValueReferenceType(const LValueReferenceType *T) { +    VisitReferenceType(T); +  } + +  void VisitRValueReferenceType(const RValueReferenceType *T) { +    VisitReferenceType(T); +  } + +  void +  VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) { +    AddType(T->getReplacedParameter()); +    Hash.AddTemplateArgument(T->getArgumentPack()); +    VisitType(T); +  } + +  void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { +    AddType(T->getReplacedParameter()); +    AddQualType(T->getReplacementType()); +    VisitType(T); +  } + +  void VisitTagType(const TagType *T) { +    AddDecl(T->getDecl()); +    VisitType(T); +  } + +  void VisitRecordType(const RecordType *T) { VisitTagType(T); } +  void VisitEnumType(const EnumType *T) { VisitTagType(T); } + +  void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { +    ID.AddInteger(T->getNumArgs()); +    for (const auto &TA : T->template_arguments()) { +      Hash.AddTemplateArgument(TA); +    } +    Hash.AddTemplateName(T->getTemplateName()); +    VisitType(T); +  } + +  void VisitTemplateTypeParmType(const TemplateTypeParmType *T) { +    ID.AddInteger(T->getDepth()); +    ID.AddInteger(T->getIndex()); +    Hash.AddBoolean(T->isParameterPack()); +    AddDecl(T->getDecl()); +  } + +  void VisitTypedefType(const TypedefType *T) { +    AddDecl(T->getDecl()); +    QualType UnderlyingType = T->getDecl()->getUnderlyingType(); +    VisitQualifiers(UnderlyingType.getQualifiers()); +    while (true) { +      if (const TypedefType *Underlying = +              dyn_cast<TypedefType>(UnderlyingType.getTypePtr())) { +        UnderlyingType = Underlying->getDecl()->getUnderlyingType(); +        continue; +      } +      if (const ElaboratedType *Underlying = +              dyn_cast<ElaboratedType>(UnderlyingType.getTypePtr())) { +        UnderlyingType = Underlying->getNamedType(); +        continue; +      } + +      break; +    } +    AddType(UnderlyingType.getTypePtr()); +    VisitType(T); +  } + +  void VisitTypeOfExprType(const TypeOfExprType *T) { +    AddStmt(T->getUnderlyingExpr()); +    Hash.AddBoolean(T->isSugared()); +    if (T->isSugared()) +      AddQualType(T->desugar()); + +    VisitType(T); +  } +  void VisitTypeOfType(const TypeOfType *T) { +    AddQualType(T->getUnderlyingType()); +    VisitType(T); +  } + +  void VisitTypeWithKeyword(const TypeWithKeyword *T) { +    ID.AddInteger(T->getKeyword()); +    VisitType(T); +  }; + +  void VisitDependentNameType(const DependentNameType *T) { +    AddNestedNameSpecifier(T->getQualifier()); +    AddIdentifierInfo(T->getIdentifier()); +    VisitTypeWithKeyword(T); +  } + +  void VisitDependentTemplateSpecializationType( +      const DependentTemplateSpecializationType *T) { +    AddIdentifierInfo(T->getIdentifier()); +    AddNestedNameSpecifier(T->getQualifier()); +    ID.AddInteger(T->getNumArgs()); +    for (const auto &TA : T->template_arguments()) { +      Hash.AddTemplateArgument(TA); +    } +    VisitTypeWithKeyword(T); +  } + +  void VisitElaboratedType(const ElaboratedType *T) { +    AddNestedNameSpecifier(T->getQualifier()); +    AddQualType(T->getNamedType()); +    VisitTypeWithKeyword(T); +  } + +  void VisitUnaryTransformType(const UnaryTransformType *T) { +    AddQualType(T->getUnderlyingType()); +    AddQualType(T->getBaseType()); +    VisitType(T); +  } + +  void VisitUnresolvedUsingType(const UnresolvedUsingType *T) { +    AddDecl(T->getDecl()); +    VisitType(T); +  } + +  void VisitVectorType(const VectorType *T) { +    AddQualType(T->getElementType()); +    ID.AddInteger(T->getNumElements()); +    ID.AddInteger(T->getVectorKind()); +    VisitType(T); +  } + +  void VisitExtVectorType(const ExtVectorType * T) { +    VisitVectorType(T); +  } +}; +} // namespace + +void ODRHash::AddType(const Type *T) { +  assert(T && "Expecting non-null pointer."); +  ODRTypeVisitor(ID, *this).Visit(T); +} + +void ODRHash::AddQualType(QualType T) { +  AddBoolean(T.isNull()); +  if (T.isNull()) +    return; +  SplitQualType split = T.split(); +  ID.AddInteger(split.Quals.getAsOpaqueValue()); +  AddType(split.Ty); +} + +void ODRHash::AddBoolean(bool Value) { +  Bools.push_back(Value); +} | 
