Add more ODR checking.

Add the basics for the ODRHash class, which will only process Decl's from
a whitelist, which currently only has AccessSpecDecl.  Different access
specifiers in merged classes can now be detected.

Differential Revision: https://reviews.llvm.org/D21675

llvm-svn: 295800
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
new file mode 100644
index 0000000..b588b31
--- /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);
+}