2017-02-22 01:11:25 +00:00
|
|
|
//===-- ODRHash.cpp - Hashing to diagnose ODR failures ----------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// 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
|
2017-02-22 01:11:25 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
///
|
|
|
|
/// \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;
|
|
|
|
|
2017-02-22 22:22:42 +00:00
|
|
|
void ODRHash::AddStmt(const Stmt *S) {
|
|
|
|
assert(S && "Expecting non-null pointer.");
|
|
|
|
S->ProcessODRHash(ID, *this);
|
|
|
|
}
|
2017-02-23 00:23:01 +00:00
|
|
|
|
|
|
|
void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) {
|
|
|
|
assert(II && "Expecting non-null pointer.");
|
|
|
|
ID.AddString(II->getName());
|
|
|
|
}
|
|
|
|
|
2018-09-04 22:53:19 +00:00
|
|
|
void ODRHash::AddDeclarationName(DeclarationName Name, bool TreatAsDecl) {
|
|
|
|
if (TreatAsDecl)
|
2018-09-14 01:15:28 +00:00
|
|
|
// Matches the NamedDecl check in AddDecl
|
2018-09-04 22:53:19 +00:00
|
|
|
AddBoolean(true);
|
|
|
|
|
2018-09-14 01:15:28 +00:00
|
|
|
AddDeclarationNameImpl(Name);
|
|
|
|
|
|
|
|
if (TreatAsDecl)
|
|
|
|
// Matches the ClassTemplateSpecializationDecl check in AddDecl
|
|
|
|
AddBoolean(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ODRHash::AddDeclarationNameImpl(DeclarationName Name) {
|
2018-02-22 05:32:25 +00:00
|
|
|
// 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) {
|
Misc typos fixes in ./lib folder
Summary: Found via `codespell -q 3 -I ../clang-whitelist.txt -L uint,importd,crasher,gonna,cant,ue,ons,orign,ned`
Reviewers: teemperor
Reviewed By: teemperor
Subscribers: teemperor, jholewinski, jvesely, nhaehnle, whisperity, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D55475
llvm-svn: 348755
2018-12-10 12:37:46 +00:00
|
|
|
// If found in map, the DeclarationName has previously been processed.
|
2018-02-22 05:32:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// First time processing each DeclarationName, also process its details.
|
2017-02-24 02:59:12 +00:00
|
|
|
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();
|
2019-06-28 17:42:17 +00:00
|
|
|
ID.AddInteger(NumArgs);
|
2017-02-24 02:59:12 +00:00
|
|
|
for (unsigned i = 0; i < NumArgs; ++i) {
|
2019-06-28 17:42:17 +00:00
|
|
|
const IdentifierInfo *II = S.getIdentifierInfoForSlot(i);
|
|
|
|
AddBoolean(II);
|
|
|
|
if (II) {
|
|
|
|
AddIdentifierInfo(II);
|
|
|
|
}
|
2017-02-24 02:59:12 +00:00
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-17 03:23:35 +00:00
|
|
|
void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
|
2017-07-01 02:00:05 +00:00
|
|
|
assert(NNS && "Expecting non-null pointer.");
|
|
|
|
const auto *Prefix = NNS->getPrefix();
|
|
|
|
AddBoolean(Prefix);
|
|
|
|
if (Prefix) {
|
|
|
|
AddNestedNameSpecifier(Prefix);
|
2017-05-17 03:23:35 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-31 00:31:58 +00:00
|
|
|
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:
|
2019-05-09 03:31:27 +00:00
|
|
|
case TemplateName::AssumedTemplate:
|
2017-05-31 00:31:58 +00:00
|
|
|
case TemplateName::QualifiedTemplate:
|
|
|
|
case TemplateName::DependentTemplate:
|
|
|
|
case TemplateName::SubstTemplateTemplateParm:
|
|
|
|
case TemplateName::SubstTemplateTemplateParmPack:
|
2022-04-12 15:51:16 +02:00
|
|
|
case TemplateName::UsingTemplate:
|
2017-05-31 00:31:58 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-13 22:21:18 +00:00
|
|
|
void ODRHash::AddTemplateArgument(TemplateArgument TA) {
|
|
|
|
const auto Kind = TA.getKind();
|
|
|
|
ID.AddInteger(Kind);
|
2017-06-14 01:28:00 +00:00
|
|
|
|
|
|
|
switch (Kind) {
|
|
|
|
case TemplateArgument::Null:
|
2017-06-30 22:40:33 +00:00
|
|
|
llvm_unreachable("Expected valid TemplateArgument");
|
2017-06-14 01:28:00 +00:00
|
|
|
case TemplateArgument::Type:
|
2017-06-30 22:40:33 +00:00
|
|
|
AddQualType(TA.getAsType());
|
|
|
|
break;
|
2017-06-14 01:28:00 +00:00
|
|
|
case TemplateArgument::Declaration:
|
2018-04-25 00:31:15 +00:00
|
|
|
AddDecl(TA.getAsDecl());
|
|
|
|
break;
|
2017-06-14 01:28:00 +00:00
|
|
|
case TemplateArgument::NullPtr:
|
|
|
|
case TemplateArgument::Integral:
|
2017-06-14 03:17:26 +00:00
|
|
|
break;
|
2017-06-14 01:28:00 +00:00
|
|
|
case TemplateArgument::Template:
|
|
|
|
case TemplateArgument::TemplateExpansion:
|
2017-06-14 03:17:26 +00:00
|
|
|
AddTemplateName(TA.getAsTemplateOrTemplatePattern());
|
2017-06-14 01:28:00 +00:00
|
|
|
break;
|
|
|
|
case TemplateArgument::Expression:
|
|
|
|
AddStmt(TA.getAsExpr());
|
|
|
|
break;
|
|
|
|
case TemplateArgument::Pack:
|
2017-06-15 01:35:06 +00:00
|
|
|
ID.AddInteger(TA.pack_size());
|
|
|
|
for (auto SubTA : TA.pack_elements()) {
|
|
|
|
AddTemplateArgument(SubTA);
|
|
|
|
}
|
2017-06-14 01:28:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-06-13 22:21:18 +00:00
|
|
|
}
|
|
|
|
|
2017-08-23 02:43:59 +00:00
|
|
|
void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {
|
|
|
|
assert(TPL && "Expecting non-null pointer.");
|
|
|
|
|
|
|
|
ID.AddInteger(TPL->size());
|
|
|
|
for (auto *ND : TPL->asArray()) {
|
|
|
|
AddSubDecl(ND);
|
|
|
|
}
|
|
|
|
}
|
2017-02-22 01:11:25 +00:00
|
|
|
|
|
|
|
void ODRHash::clear() {
|
2018-02-22 05:32:25 +00:00
|
|
|
DeclNameMap.clear();
|
2017-02-22 01:11:25 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2017-08-20 13:02:57 +00:00
|
|
|
namespace {
|
2017-02-22 01:11:25 +00:00
|
|
|
// 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;
|
2017-02-22 22:22:42 +00:00
|
|
|
ODRHash &Hash;
|
2017-02-22 01:11:25 +00:00
|
|
|
|
|
|
|
public:
|
2017-02-22 22:22:42 +00:00
|
|
|
ODRDeclVisitor(llvm::FoldingSetNodeID &ID, ODRHash &Hash)
|
|
|
|
: ID(ID), Hash(Hash) {}
|
|
|
|
|
|
|
|
void AddStmt(const Stmt *S) {
|
|
|
|
Hash.AddBoolean(S);
|
|
|
|
if (S) {
|
|
|
|
Hash.AddStmt(S);
|
|
|
|
}
|
|
|
|
}
|
2017-02-22 01:11:25 +00:00
|
|
|
|
2017-02-23 00:23:01 +00:00
|
|
|
void AddIdentifierInfo(const IdentifierInfo *II) {
|
|
|
|
Hash.AddBoolean(II);
|
|
|
|
if (II) {
|
|
|
|
Hash.AddIdentifierInfo(II);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-23 03:25:57 +00:00
|
|
|
void AddQualType(QualType T) {
|
|
|
|
Hash.AddQualType(T);
|
|
|
|
}
|
|
|
|
|
2017-07-08 02:04:42 +00:00
|
|
|
void AddDecl(const Decl *D) {
|
|
|
|
Hash.AddBoolean(D);
|
|
|
|
if (D) {
|
|
|
|
Hash.AddDecl(D);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-23 02:43:59 +00:00
|
|
|
void AddTemplateArgument(TemplateArgument TA) {
|
|
|
|
Hash.AddTemplateArgument(TA);
|
|
|
|
}
|
|
|
|
|
2017-02-22 01:11:25 +00:00
|
|
|
void Visit(const Decl *D) {
|
|
|
|
ID.AddInteger(D->getKind());
|
|
|
|
Inherited::Visit(D);
|
|
|
|
}
|
|
|
|
|
2017-02-23 00:23:01 +00:00
|
|
|
void VisitNamedDecl(const NamedDecl *D) {
|
2017-03-04 00:08:58 +00:00
|
|
|
Hash.AddDeclarationName(D->getDeclName());
|
2017-02-23 00:23:01 +00:00
|
|
|
Inherited::VisitNamedDecl(D);
|
|
|
|
}
|
|
|
|
|
2017-02-23 03:25:57 +00:00
|
|
|
void VisitValueDecl(const ValueDecl *D) {
|
2017-07-14 01:36:41 +00:00
|
|
|
if (!isa<FunctionDecl>(D)) {
|
|
|
|
AddQualType(D->getType());
|
|
|
|
}
|
2017-02-23 03:25:57 +00:00
|
|
|
Inherited::VisitValueDecl(D);
|
|
|
|
}
|
|
|
|
|
2017-06-16 02:44:29 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-05-02 23:58:52 +00:00
|
|
|
void VisitParmVarDecl(const ParmVarDecl *D) {
|
|
|
|
// TODO: Handle default arguments.
|
|
|
|
Inherited::VisitParmVarDecl(D);
|
|
|
|
}
|
|
|
|
|
2017-02-22 01:11:25 +00:00
|
|
|
void VisitAccessSpecDecl(const AccessSpecDecl *D) {
|
|
|
|
ID.AddInteger(D->getAccess());
|
|
|
|
Inherited::VisitAccessSpecDecl(D);
|
|
|
|
}
|
2017-02-22 22:22:42 +00:00
|
|
|
|
|
|
|
void VisitStaticAssertDecl(const StaticAssertDecl *D) {
|
|
|
|
AddStmt(D->getAssertExpr());
|
|
|
|
AddStmt(D->getMessage());
|
|
|
|
|
|
|
|
Inherited::VisitStaticAssertDecl(D);
|
|
|
|
}
|
2017-02-23 00:23:01 +00:00
|
|
|
|
|
|
|
void VisitFieldDecl(const FieldDecl *D) {
|
2017-02-24 20:59:28 +00:00
|
|
|
const bool IsBitfield = D->isBitField();
|
|
|
|
Hash.AddBoolean(IsBitfield);
|
|
|
|
|
|
|
|
if (IsBitfield) {
|
|
|
|
AddStmt(D->getBitWidth());
|
|
|
|
}
|
2017-02-24 23:35:37 +00:00
|
|
|
|
|
|
|
Hash.AddBoolean(D->isMutable());
|
|
|
|
AddStmt(D->getInClassInitializer());
|
2017-02-25 01:29:34 +00:00
|
|
|
|
|
|
|
Inherited::VisitFieldDecl(D);
|
2017-02-23 00:23:01 +00:00
|
|
|
}
|
2017-02-28 21:24:38 +00:00
|
|
|
|
|
|
|
void VisitFunctionDecl(const FunctionDecl *D) {
|
2018-07-10 01:40:50 +00:00
|
|
|
// Handled by the ODRHash for FunctionDecl
|
|
|
|
ID.AddInteger(D->getODRHash());
|
2018-04-25 00:31:15 +00:00
|
|
|
|
2017-02-28 21:24:38 +00:00
|
|
|
Inherited::VisitFunctionDecl(D);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VisitCXXMethodDecl(const CXXMethodDecl *D) {
|
2018-07-10 01:40:50 +00:00
|
|
|
// Handled by the ODRHash for FunctionDecl
|
2017-03-04 00:08:58 +00:00
|
|
|
|
2017-02-28 21:24:38 +00:00
|
|
|
Inherited::VisitCXXMethodDecl(D);
|
|
|
|
}
|
2017-03-08 00:13:19 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2017-07-08 02:04:42 +00:00
|
|
|
|
|
|
|
void VisitFriendDecl(const FriendDecl *D) {
|
|
|
|
TypeSourceInfo *TSI = D->getFriendType();
|
|
|
|
Hash.AddBoolean(TSI);
|
|
|
|
if (TSI) {
|
|
|
|
AddQualType(TSI->getType());
|
|
|
|
} else {
|
|
|
|
AddDecl(D->getFriendDecl());
|
|
|
|
}
|
|
|
|
}
|
2017-08-23 02:43:59 +00:00
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
2018-05-30 01:12:26 +00:00
|
|
|
Hash.AddBoolean(D->isParameterPack());
|
2017-08-23 02:43:59 +00:00
|
|
|
|
2020-01-15 02:48:42 +02:00
|
|
|
const TypeConstraint *TC = D->getTypeConstraint();
|
|
|
|
Hash.AddBoolean(TC != nullptr);
|
|
|
|
if (TC)
|
|
|
|
AddStmt(TC->getImmediatelyDeclaredConstraint());
|
|
|
|
|
2017-08-23 02:43:59 +00:00
|
|
|
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());
|
|
|
|
}
|
2018-05-30 01:12:26 +00:00
|
|
|
Hash.AddBoolean(D->isParameterPack());
|
2017-08-23 02:43:59 +00:00
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
2018-05-30 01:12:26 +00:00
|
|
|
Hash.AddBoolean(D->isParameterPack());
|
2017-08-23 02:43:59 +00:00
|
|
|
|
|
|
|
Inherited::VisitTemplateTemplateParmDecl(D);
|
|
|
|
}
|
2018-05-30 01:12:26 +00:00
|
|
|
|
|
|
|
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) {
|
2018-06-07 00:20:58 +00:00
|
|
|
AddDecl(D->getTemplatedDecl());
|
2018-09-04 22:53:19 +00:00
|
|
|
ID.AddInteger(D->getTemplatedDecl()->getODRHash());
|
2018-05-30 01:12:26 +00:00
|
|
|
Inherited::VisitFunctionTemplateDecl(D);
|
|
|
|
}
|
2018-07-25 22:52:05 +00:00
|
|
|
|
|
|
|
void VisitEnumConstantDecl(const EnumConstantDecl *D) {
|
|
|
|
AddStmt(D->getInitExpr());
|
|
|
|
Inherited::VisitEnumConstantDecl(D);
|
|
|
|
}
|
2017-02-22 01:11:25 +00:00
|
|
|
};
|
2017-08-20 13:02:57 +00:00
|
|
|
} // namespace
|
2017-02-22 01:11:25 +00:00
|
|
|
|
|
|
|
// Only allow a small portion of Decl's to be processed. Remove this once
|
|
|
|
// all Decl's can be handled.
|
2020-06-19 18:35:36 -07:00
|
|
|
bool ODRHash::isDeclToBeProcessed(const Decl *D, const DeclContext *Parent) {
|
2017-02-22 01:11:25 +00:00
|
|
|
if (D->isImplicit()) return false;
|
|
|
|
if (D->getDeclContext() != Parent) return false;
|
|
|
|
|
|
|
|
switch (D->getKind()) {
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
case Decl::AccessSpec:
|
2017-07-15 02:55:13 +00:00
|
|
|
case Decl::CXXConstructor:
|
|
|
|
case Decl::CXXDestructor:
|
2017-02-28 21:24:38 +00:00
|
|
|
case Decl::CXXMethod:
|
2018-07-25 22:52:05 +00:00
|
|
|
case Decl::EnumConstant: // Only found in EnumDecl's.
|
2017-02-23 00:23:01 +00:00
|
|
|
case Decl::Field:
|
2017-07-08 02:04:42 +00:00
|
|
|
case Decl::Friend:
|
2018-05-30 01:12:26 +00:00
|
|
|
case Decl::FunctionTemplate:
|
2017-02-22 22:22:42 +00:00
|
|
|
case Decl::StaticAssert:
|
2017-03-08 00:13:19 +00:00
|
|
|
case Decl::TypeAlias:
|
|
|
|
case Decl::Typedef:
|
2017-06-16 02:44:29 +00:00
|
|
|
case Decl::Var:
|
2017-02-22 01:11:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ODRHash::AddSubDecl(const Decl *D) {
|
|
|
|
assert(D && "Expecting non-null pointer.");
|
|
|
|
|
2017-02-22 22:22:42 +00:00
|
|
|
ODRDeclVisitor(ID, *this).Visit(D);
|
2017-02-22 01:11:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) {
|
|
|
|
assert(Record && Record->hasDefinition() &&
|
|
|
|
"Expected non-null record to be a definition.");
|
2017-05-02 23:58:52 +00:00
|
|
|
|
2017-08-05 00:54:19 +00:00
|
|
|
const DeclContext *DC = Record;
|
|
|
|
while (DC) {
|
|
|
|
if (isa<ClassTemplateSpecializationDecl>(DC)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DC = DC->getParent();
|
2017-05-02 23:58:52 +00:00
|
|
|
}
|
|
|
|
|
2017-02-22 01:11:25 +00:00
|
|
|
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;
|
2018-07-10 01:40:50 +00:00
|
|
|
for (Decl *SubDecl : Record->decls()) {
|
2020-06-19 18:35:36 -07:00
|
|
|
if (isDeclToBeProcessed(SubDecl, Record)) {
|
2017-02-22 01:11:25 +00:00
|
|
|
Decls.push_back(SubDecl);
|
2018-07-10 01:40:50 +00:00
|
|
|
if (auto *Function = dyn_cast<FunctionDecl>(SubDecl)) {
|
|
|
|
// Compute/Preload ODRHash into FunctionDecl.
|
|
|
|
Function->getODRHash();
|
|
|
|
}
|
2017-02-22 01:11:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ID.AddInteger(Decls.size());
|
|
|
|
for (auto SubDecl : Decls) {
|
|
|
|
AddSubDecl(SubDecl);
|
|
|
|
}
|
2017-08-23 02:43:59 +00:00
|
|
|
|
|
|
|
const ClassTemplateDecl *TD = Record->getDescribedClassTemplate();
|
|
|
|
AddBoolean(TD);
|
|
|
|
if (TD) {
|
|
|
|
AddTemplateParameterList(TD->getTemplateParameters());
|
|
|
|
}
|
2017-09-30 02:19:17 +00:00
|
|
|
|
|
|
|
ID.AddInteger(Record->getNumBases());
|
|
|
|
auto Bases = Record->bases();
|
|
|
|
for (auto Base : Bases) {
|
|
|
|
AddQualType(Base.getType());
|
|
|
|
ID.AddInteger(Base.isVirtual());
|
|
|
|
ID.AddInteger(Base.getAccessSpecifierAsWritten());
|
|
|
|
}
|
2017-02-22 01:11:25 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 01:40:50 +00:00
|
|
|
void ODRHash::AddFunctionDecl(const FunctionDecl *Function,
|
|
|
|
bool SkipBody) {
|
2017-12-23 00:41:01 +00:00
|
|
|
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;
|
2018-07-10 01:40:50 +00:00
|
|
|
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.
|
|
|
|
}
|
|
|
|
}
|
2017-12-23 00:41:01 +00:00
|
|
|
DC = DC->getParent();
|
|
|
|
}
|
|
|
|
|
2018-07-10 01:40:50 +00:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2021-01-04 23:17:45 +01:00
|
|
|
ID.AddInteger(Function->getStorageClass());
|
2018-07-10 01:40:50 +00:00
|
|
|
AddBoolean(Function->isInlineSpecified());
|
|
|
|
AddBoolean(Function->isVirtualAsWritten());
|
|
|
|
AddBoolean(Function->isPure());
|
|
|
|
AddBoolean(Function->isDeletedAsWritten());
|
|
|
|
AddBoolean(Function->isExplicitlyDefaulted());
|
|
|
|
|
2017-12-23 00:41:01 +00:00
|
|
|
AddDecl(Function);
|
|
|
|
|
|
|
|
AddQualType(Function->getReturnType());
|
|
|
|
|
|
|
|
ID.AddInteger(Function->param_size());
|
2022-09-03 23:27:27 -07:00
|
|
|
for (auto *Param : Function->parameters())
|
2017-12-23 00:41:01 +00:00
|
|
|
AddSubDecl(Param);
|
|
|
|
|
2018-07-10 01:40:50 +00:00
|
|
|
if (SkipBody) {
|
|
|
|
AddBoolean(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const bool HasBody = Function->isThisDeclarationADefinition() &&
|
|
|
|
!Function->isDefaulted() && !Function->isDeleted() &&
|
|
|
|
!Function->isLateTemplateParsed();
|
|
|
|
AddBoolean(HasBody);
|
2018-09-04 22:53:19 +00:00
|
|
|
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()) {
|
2020-06-19 18:35:36 -07:00
|
|
|
if (isDeclToBeProcessed(SubDecl, Function)) {
|
2018-09-04 22:53:19 +00:00
|
|
|
Decls.push_back(SubDecl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ID.AddInteger(Decls.size());
|
|
|
|
for (auto SubDecl : Decls) {
|
|
|
|
AddSubDecl(SubDecl);
|
2018-07-10 01:40:50 +00:00
|
|
|
}
|
2017-12-23 00:41:01 +00:00
|
|
|
}
|
|
|
|
|
2018-07-25 22:52:05 +00:00
|
|
|
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()) {
|
2020-06-19 18:35:36 -07:00
|
|
|
if (isDeclToBeProcessed(SubDecl, Enum)) {
|
2018-07-25 22:52:05 +00:00
|
|
|
assert(isa<EnumConstantDecl>(SubDecl) && "Unexpected Decl");
|
|
|
|
Decls.push_back(SubDecl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ID.AddInteger(Decls.size());
|
|
|
|
for (auto SubDecl : Decls) {
|
|
|
|
AddSubDecl(SubDecl);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-10-17 16:21:59 -07:00
|
|
|
void ODRHash::AddObjCProtocolDecl(const ObjCProtocolDecl *P) {
|
|
|
|
AddDecl(P);
|
|
|
|
|
|
|
|
// Hash referenced protocols.
|
|
|
|
ID.AddInteger(P->getReferencedProtocols().size());
|
|
|
|
for (const ObjCProtocolDecl *RefP : P->protocols()) {
|
|
|
|
// Hash the name only as a referenced protocol can be a forward declaration.
|
|
|
|
AddDeclarationName(RefP->getDeclName());
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 : P->decls()) {
|
|
|
|
if (isDeclToBeProcessed(SubDecl, P)) {
|
|
|
|
Decls.push_back(SubDecl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ID.AddInteger(Decls.size());
|
|
|
|
for (auto *SubDecl : Decls) {
|
|
|
|
AddSubDecl(SubDecl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-22 01:11:25 +00:00
|
|
|
void ODRHash::AddDecl(const Decl *D) {
|
|
|
|
assert(D && "Expecting non-null pointer.");
|
2017-12-21 22:38:29 +00:00
|
|
|
D = D->getCanonicalDecl();
|
2017-02-24 02:59:12 +00:00
|
|
|
|
2018-09-04 22:53:19 +00:00
|
|
|
const NamedDecl *ND = dyn_cast<NamedDecl>(D);
|
|
|
|
AddBoolean(ND);
|
|
|
|
if (!ND) {
|
|
|
|
ID.AddInteger(D->getKind());
|
2018-02-22 05:32:25 +00:00
|
|
|
return;
|
2017-02-24 02:59:12 +00:00
|
|
|
}
|
2018-02-22 05:32:25 +00:00
|
|
|
|
2018-09-04 22:53:19 +00:00
|
|
|
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);
|
|
|
|
}
|
2017-02-22 01:11:25 +00:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:02:57 +00:00
|
|
|
namespace {
|
2017-02-23 03:25:57 +00:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-14 13:48:18 +02:00
|
|
|
void AddDecl(const Decl *D) {
|
2017-02-24 02:59:12 +00:00
|
|
|
Hash.AddBoolean(D);
|
|
|
|
if (D) {
|
|
|
|
Hash.AddDecl(D);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-02 23:58:52 +00:00
|
|
|
void AddQualType(QualType T) {
|
|
|
|
Hash.AddQualType(T);
|
|
|
|
}
|
|
|
|
|
2017-06-29 22:53:04 +00:00
|
|
|
void AddType(const Type *T) {
|
|
|
|
Hash.AddBoolean(T);
|
|
|
|
if (T) {
|
|
|
|
Hash.AddType(T);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-17 02:29:02 +00:00
|
|
|
void AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
|
2017-07-01 02:00:05 +00:00
|
|
|
Hash.AddBoolean(NNS);
|
|
|
|
if (NNS) {
|
|
|
|
Hash.AddNestedNameSpecifier(NNS);
|
|
|
|
}
|
2017-05-17 02:29:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AddIdentifierInfo(const IdentifierInfo *II) {
|
|
|
|
Hash.AddBoolean(II);
|
|
|
|
if (II) {
|
|
|
|
Hash.AddIdentifierInfo(II);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-02 23:58:52 +00:00
|
|
|
void VisitQualifiers(Qualifiers Quals) {
|
|
|
|
ID.AddInteger(Quals.getAsOpaqueValue());
|
|
|
|
}
|
|
|
|
|
2019-06-22 00:32:19 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2017-02-23 03:25:57 +00:00
|
|
|
void Visit(const Type *T) {
|
2019-06-22 00:32:19 +00:00
|
|
|
T = RemoveTypedef(T);
|
2017-02-23 03:25:57 +00:00
|
|
|
ID.AddInteger(T->getTypeClass());
|
|
|
|
Inherited::Visit(T);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VisitType(const Type *T) {}
|
|
|
|
|
2017-05-02 23:58:52 +00:00
|
|
|
void VisitAdjustedType(const AdjustedType *T) {
|
2019-05-04 04:22:33 +00:00
|
|
|
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);
|
|
|
|
|
2017-05-02 23:58:52 +00:00
|
|
|
VisitType(T);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VisitDecayedType(const DecayedType *T) {
|
2019-05-04 04:22:33 +00:00
|
|
|
// getDecayedType and getPointeeType are derived from getAdjustedType
|
|
|
|
// and don't need to be separately processed.
|
2017-05-02 23:58:52 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-09-04 22:53:19 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-02-23 03:25:57 +00:00
|
|
|
void VisitBuiltinType(const BuiltinType *T) {
|
|
|
|
ID.AddInteger(T->getKind());
|
|
|
|
VisitType(T);
|
|
|
|
}
|
2017-02-24 02:59:12 +00:00
|
|
|
|
2018-09-04 22:53:19 +00:00
|
|
|
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());
|
2020-01-22 02:03:05 +02:00
|
|
|
ID.AddInteger(T->isConstrained());
|
|
|
|
if (T->isConstrained()) {
|
|
|
|
AddDecl(T->getTypeConstraintConcept());
|
|
|
|
ID.AddInteger(T->getNumArgs());
|
|
|
|
for (const auto &TA : T->getTypeConstraintArguments())
|
|
|
|
Hash.AddTemplateArgument(TA);
|
|
|
|
}
|
2018-09-04 22:53:19 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-05-02 23:58:52 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-09-04 22:53:19 +00:00
|
|
|
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());
|
2022-09-03 23:27:27 -07:00
|
|
|
for (auto *Protocol : Protocols) {
|
2018-09-04 22:53:19 +00:00
|
|
|
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());
|
2022-09-03 23:27:27 -07:00
|
|
|
for (auto *Protocol : Protocols) {
|
2018-09-04 22:53:19 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-04-13 22:34:43 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-09-04 22:53:19 +00:00
|
|
|
void
|
|
|
|
VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
|
2022-08-14 13:48:18 +02:00
|
|
|
AddDecl(T->getAssociatedDecl());
|
2018-09-04 22:53:19 +00:00
|
|
|
Hash.AddTemplateArgument(T->getArgumentPack());
|
|
|
|
VisitType(T);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
|
2022-08-14 13:48:18 +02:00
|
|
|
AddDecl(T->getAssociatedDecl());
|
2018-09-04 22:53:19 +00:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2017-02-24 02:59:12 +00:00
|
|
|
void VisitTypedefType(const TypedefType *T) {
|
|
|
|
AddDecl(T->getDecl());
|
2017-06-29 22:53:04 +00:00
|
|
|
QualType UnderlyingType = T->getDecl()->getUnderlyingType();
|
|
|
|
VisitQualifiers(UnderlyingType.getQualifiers());
|
2018-04-12 02:26:49 +00:00
|
|
|
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;
|
2017-06-29 22:53:04 +00:00
|
|
|
}
|
|
|
|
AddType(UnderlyingType.getTypePtr());
|
2017-02-24 02:59:12 +00:00
|
|
|
VisitType(T);
|
|
|
|
}
|
2017-05-17 02:29:02 +00:00
|
|
|
|
2018-09-04 22:53:19 +00:00
|
|
|
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) {
|
[C2x] implement typeof and typeof_unqual
This implements WG14 N2927 and WG14 N2930, which together define the
feature for typeof and typeof_unqual, which get the type of their
argument as either fully qualified or fully unqualified. The argument
to either operator is either a type name or an expression. If given a
type name, the type information is pulled directly from the given name.
If given an expression, the type information is pulled from the
expression. Recursive use of these operators is allowed and has the
expected behavior (the innermost operator is resolved to a type, and
that's used to resolve the next layer of typeof specifier, until a
fully resolved type is determined.
Note, we already supported typeof in GNU mode as a non-conforming
extension and we are *not* exposing typeof_unqual as a non-conforming
extension in that mode, nor are we exposing typeof or typeof_unqual as
a nonconforming extension in other language modes. The GNU variant of
typeof supports a form where the parentheses are elided from the
operator when given an expression (e.g., typeof 0 i = 12;). When in C2x
mode, we do not support this extension.
Differential Revision: https://reviews.llvm.org/D134286
2022-09-28 13:25:58 -04:00
|
|
|
AddQualType(T->getUnmodifiedType());
|
2017-05-17 02:29:02 +00:00
|
|
|
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);
|
|
|
|
}
|
2017-05-31 00:31:58 +00:00
|
|
|
|
2018-09-04 22:53:19 +00:00
|
|
|
void VisitUnaryTransformType(const UnaryTransformType *T) {
|
|
|
|
AddQualType(T->getUnderlyingType());
|
|
|
|
AddQualType(T->getBaseType());
|
2017-05-31 00:31:58 +00:00
|
|
|
VisitType(T);
|
|
|
|
}
|
2017-06-15 01:35:06 +00:00
|
|
|
|
2018-09-04 22:53:19 +00:00
|
|
|
void VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
|
2017-06-15 01:35:06 +00:00
|
|
|
AddDecl(T->getDecl());
|
2018-09-04 22:53:19 +00:00
|
|
|
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);
|
2017-06-15 01:35:06 +00:00
|
|
|
}
|
2017-02-23 03:25:57 +00:00
|
|
|
};
|
2017-08-20 13:02:57 +00:00
|
|
|
} // namespace
|
2017-02-23 03:25:57 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-02-22 01:11:25 +00:00
|
|
|
void ODRHash::AddBoolean(bool Value) {
|
|
|
|
Bools.push_back(Value);
|
|
|
|
}
|