summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/ODRHash.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST/ODRHash.cpp')
-rw-r--r--clang/lib/AST/ODRHash.cpp152
1 files changed, 152 insertions, 0 deletions
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
new file mode 100644
index 00000000000..b588b31db98
--- /dev/null
+++ b/clang/lib/AST/ODRHash.cpp
@@ -0,0 +1,152 @@
+//===-- ODRHash.cpp - Hashing to diagnose ODR failures ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \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) {}
+void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) {}
+void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {}
+void ODRHash::AddTemplateName(TemplateName Name) {}
+void ODRHash::AddDeclarationName(DeclarationName Name) {}
+void ODRHash::AddTemplateArgument(TemplateArgument TA) {}
+void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {}
+
+void ODRHash::clear() {
+ DeclMap.clear();
+ TypeMap.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();
+}
+
+// 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 Visit(const Decl *D) {
+ ID.AddInteger(D->getKind());
+ Inherited::Visit(D);
+ }
+
+ void VisitAccessSpecDecl(const AccessSpecDecl *D) {
+ ID.AddInteger(D->getAccess());
+ Inherited::VisitAccessSpecDecl(D);
+ }
+};
+
+// 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 CXXRecordDecl *Parent) {
+ if (D->isImplicit()) return false;
+ if (D->getDeclContext() != Parent) return false;
+
+ switch (D->getKind()) {
+ default:
+ return false;
+ case Decl::AccessSpec:
+ return true;
+ }
+}
+
+void ODRHash::AddSubDecl(const Decl *D) {
+ assert(D && "Expecting non-null pointer.");
+ AddDecl(D);
+
+ ODRDeclVisitor(ID, *this).Visit(D);
+}
+
+void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) {
+ assert(Record && Record->hasDefinition() &&
+ "Expected non-null record to be a definition.");
+ 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 (const Decl *SubDecl : Record->decls()) {
+ if (isWhitelistedDecl(SubDecl, Record)) {
+ 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.");
+ auto Result = DeclMap.insert(std::make_pair(D, DeclMap.size()));
+ ID.AddInteger(Result.first->second);
+ // On first encounter of a Decl pointer, process it. Every time afterwards,
+ // only the index value is needed.
+ if (!Result.second) {
+ return;
+ }
+
+ ID.AddInteger(D->getKind());
+}
+
+void ODRHash::AddType(const Type *T) {}
+void ODRHash::AddQualType(QualType T) {}
+void ODRHash::AddBoolean(bool Value) {
+ Bools.push_back(Value);
+}
OpenPOWER on IntegriCloud