rtrieu updated this revision to Diff 68278.
rtrieu added a comment.

Add function void ODRHash(llvm::FoldingSetNodeID &ID) to several classes for 
computing the hash.  Decl, Stmt, TemplateArgument, Type and QualType now have 
this function, and can call among each others' functions.


https://reviews.llvm.org/D21675

Files:
  include/clang/AST/DeclBase.h
  include/clang/AST/DeclCXX.h
  include/clang/AST/Stmt.h
  include/clang/AST/TemplateBase.h
  include/clang/AST/Type.h
  lib/AST/DeclBase.cpp
  lib/AST/DeclCXX.cpp
  lib/AST/StmtProfile.cpp
  lib/AST/TemplateBase.cpp
  lib/AST/Type.cpp
  lib/Sema/SemaDecl.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriter.cpp
  test/Modules/Inputs/odr_hash/first.h
  test/Modules/Inputs/odr_hash/module.map
  test/Modules/Inputs/odr_hash/second.h
  test/Modules/merge-using-decls.cpp
  test/Modules/odr_hash.cpp

Index: test/Modules/odr_hash.cpp
===================================================================
--- test/Modules/odr_hash.cpp
+++ test/Modules/odr_hash.cpp
@@ -0,0 +1,191 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/odr_hash -verify %s -std=c++11
+
+#include "first.h"
+#include "second.h"
+
+namespace test1 {
+S1 s1;
+// expected-error@first.h:* {{'S1' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S2 s2;
+// expected-error@first.h:* {{'S2' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S3 s3;
+// expected-error@first.h:* {{'S3' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S4 s4;
+// expected-error@first.h:* {{'S4' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S5 s5;
+// expected-error@first.h:* {{'S5' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S6 s6;
+// expected-error@second.h:* {{'S6::Second' from module 'second' is not present in definition of 'S6' in module 'first'}}
+// expected-note@first.h:* {{definition has no member 'Second'}}
+
+S7 s7;
+// expected-error@second.h:* {{'S7::foo' from module 'second' is not present in definition of 'S7' in module 'first'}}
+// expected-note@first.h:* {{declaration of 'foo' does not match}}
+
+S8 s8;
+// expected-error@first.h:* {{'S8' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S9 s9;
+// expected-error@first.h:* {{'S9' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S10 s10;
+// expected-error@second.h:* {{'S10::(anonymous struct)::y' from module 'second' is not present in definition of 'S10::(anonymous struct at /usr/local/google/home/rtrieu/clang/miss/llvm/tools/clang/test/Modules/Inputs/odr_hash/first.h:42:3)' in module 'first'}}
+// expected-note@first.h:* {{definition has no member 'y'}}
+
+// expected-error@first.h:* {{'S10' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S11 s11;
+// expected-error@first.h:* {{'S11' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S12 s12;
+
+S13 s13;
+// expected-error@first.h:* {{'S13' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S14 s14;
+// expected-error@second.h:* {{'S14::foo' from module 'second' is not present in definition of 'S14' in module 'first'}}
+// expected-note@first.h:* {{declaration of 'foo' does not match}}
+
+template <typename T>
+void Test15() {
+  S15<T> s15;
+// expected-error@first.h:* {{'S15' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+}
+
+void TestS16() {
+  S16 s16;
+}
+// expected-error@first.h:* {{'S16' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S17 s17;
+// expected-error@second.h:* {{'S17::Q_type' from module 'second' is not present in definition of 'S17' in module 'first'}}
+// expected-note@first.h:* {{declaration of 'Q_type' does not match}}
+
+S18 s18;
+// expected-error@second.h:* {{'S18::X' from module 'second' is not present in definition of 'S18' in module 'first'}}
+// expected-note@first.h:* {{definition has no member 'X'}}
+
+S19 s19;
+// expected-error@first.h:* {{'S19' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S20 s20;
+// expected-error@first.h:* {{'S20' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S21 s21;
+// expected-error@first.h:* {{'S21' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S22 s22;
+// expected-error@first.h:* {{'S22' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S23 s23;
+// expected-error@second.h:* {{'S23::a' from module 'second' is not present in definition of 'S23' in module 'first'}}
+// expected-note@first.h:* {{declaration of 'a' does not match}}
+// expected-error@second.h:* {{'S23::b' from module 'second' is not present in definition of 'S23' in module 'first'}}
+// expected-note@first.h:* {{declaration of 'b' does not match}}
+
+S24 s24;
+// expected-error@first.h:* {{'S24' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S25 s25;
+// expected-error@first.h:* {{'S25' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+S26 s26;
+// expected-error@first.h:* {{'S26' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+S27 s27;
+// expected-error@first.h:* {{'S27' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S28 s28;
+// expected-error@first.h:* {{'S28' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S29 s29;
+// expected-error@first.h:* {{'S29' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S30 s30;
+// expected-error@first.h:* {{'S30' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S31 s31;
+// expected-error@first.h:* {{'S31' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S32 s32;
+// expected-error@first.h:* {{'S32' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S33 s33;
+// expected-error@first.h:* {{'S33' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S34 s34;
+// expected-error@second.h:* {{'S34::operator int' from module 'second' is not present in definition of 'S34' in module 'first'}}
+// expected-note@first.h:* {{definition has no member 'operator int'}}
+
+S35 s35;
+// expected-error@first.h:* {{'S35' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S36 s36;
+// expected-error@first.h:* {{'S36' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S37 s37;
+// expected-error@first.h:* {{'S37' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S38<int> s38;
+// expected-error@first.h:* {{'S38' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S39<> s39;
+// expected-error@first.h:* {{'S39' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S40<> s40;
+// expected-error@first.h:* {{'S40' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+using ::S41;
+// expected-error@first.h:* {{'S41' has different definitions in different modules; definition in module 'first' is here}}
+// expected-note@second.h:* {{definition in module 'second' is here}}
+
+S42 s42;
+// expected-error@second.h:* {{'S42::bar' from module 'second' is not present in definition of 'S42' in module 'first'}}
+// expected-note@first.h:* {{declaration of 'bar' does not match}}
+// expected-error@second.h:* {{'S42::foo' from module 'second' is not present in definition of 'S42' in module 'first'}}
+// expected-note@first.h:* {{declaration of 'foo' does not match}}
+
+S43 s43;
+// expected-error@second.h:* {{'S43::x' from module 'second' is not present in definition of 'S43' in module 'first'}}
+// expected-note@first.h:* {{declaration of 'x' does not match}}
+// expected-error@second.h:* {{'S43::y' from module 'second' is not present in definition of 'S43' in module 'first'}}
+// expected-note@first.h:* {{declaration of 'y' does not match}}
+
+}
Index: test/Modules/merge-using-decls.cpp
===================================================================
--- test/Modules/merge-using-decls.cpp
+++ test/Modules/merge-using-decls.cpp
@@ -37,6 +37,9 @@
 // Here, we're instantiating the definition from 'A' and merging the definition
 // from 'B' into it.
 
+// expected-error@b.h:* {{'D::type' from module 'B' is not present in definition of 'D<T>' in module 'A'}}
+// expected-error@b.h:* {{'D::value' from module 'B' is not present in definition of 'D<T>' in module 'A'}}
+
 // expected-error@b.h:* {{'E::value' from module 'B' is not present in definition of 'E<T>' in module 'A'}}
 // expected-error@b.h:* {{'E::v' from module 'B' is not present in definition of 'E<T>' in module 'A'}}
 
Index: test/Modules/Inputs/odr_hash/second.h
===================================================================
--- test/Modules/Inputs/odr_hash/second.h
+++ test/Modules/Inputs/odr_hash/second.h
@@ -0,0 +1,203 @@
+struct S1 {
+  private:
+};
+
+struct S2Friend1 {};
+struct S2 {
+  friend S2Friend1;
+};
+
+template<class>
+struct S3Template {};
+
+struct S3 {
+  friend S3Template<double>;
+};
+
+struct S4 {
+  static_assert(1 == 1, "Second");
+};
+
+struct S5 {
+  static_assert(2 == 2, "Message");
+};
+
+struct S6 {
+  int Second();
+};
+
+struct S7 {
+  int foo();
+};
+
+struct S8 {
+  void foo() {}
+};
+
+struct S9 {
+  void foo() { int x = 5; }
+};
+
+struct S10 {
+  struct {
+    int x;
+    int y;
+  } a;
+};
+
+struct S11 {
+  void foo() { int y = sizeof(double); }
+};
+
+struct S12 {
+  int x = sizeof(x);
+  int y = sizeof(y);
+};
+
+struct S13 {
+  template <typename B> void foo();
+};
+
+struct S14 {
+  template <typename A> void foo();
+};
+
+template <typename T>
+struct S15 : T {
+  void foo() {
+    int x = __builtin_offsetof(T, second);
+  }
+};
+
+struct S16 {
+  template <template<int = 1> class Y>
+  void foo() {
+    Y<> y;
+  }
+};
+
+struct S17 {
+  template <template <typename> class T>
+  static int foo(int a = 1);
+  template <template <typename> class T, template <typename> class U>
+  using Q_type = U<int>;
+};
+
+struct S18 {
+  enum X { X1 };
+};
+
+struct S19 {
+  enum E { X1, X2 };
+};
+
+struct S20 {
+  enum E { X1 = 5};
+};
+
+struct S21 {
+  void foo() {
+    ;
+  }
+};
+
+struct S22 {
+  void foo() {
+    label_second:
+    ;
+  }
+};
+
+struct S23 {
+  typedef char a;
+  typedef int b;
+};
+
+struct S24 {
+  int foo();
+};
+
+struct S25 {
+  int x;
+  S25() {}
+};
+
+struct S26 {
+  int x;
+  S26() : x(2) {}
+};
+
+struct S27 {
+  S27(int) {}
+  S27() {}
+};
+
+struct Base1 {
+  Base1();
+  Base1(int);
+  Base1(double);
+};
+
+struct Base2 {
+  Base2();
+  Base2(int);
+  Base2(double);
+};
+
+struct S28 : public Base2 {};
+struct S29 : virtual Base2 {};
+
+struct S30 : public Base1 {
+  S30() : Base1(1.0) {}
+};
+struct S31 : virtual Base1 {
+  S31() : Base1(1.0) {}
+};
+struct S32 : public Base2, Base1 {
+  S32() : Base2(1), Base1(1.0) {}
+};
+
+struct S33 {
+  S33() : S33(5) {}
+  S33(int) {}
+};
+
+struct S34 {
+  operator int();
+};
+
+struct S35 {
+  operator bool();
+};
+
+struct S36 {
+  int x : 4;
+};
+
+struct S37 {
+  int x;
+  mutable int y;
+};
+
+template <class Y>
+struct S38 { };
+
+template <class X = double>
+struct S39 { X x; };
+
+template <int X = 7>
+struct S40 { int x = X; };
+
+template <int> class T41b{};
+template <template<int> class T = T41b>
+struct S41 {};
+
+struct S42 {
+  void foo() {}
+  void bar() const {}
+};
+
+struct S43 {
+  int x = 1;
+  static constexpr int y = 1;
+};
Index: test/Modules/Inputs/odr_hash/module.map
===================================================================
--- test/Modules/Inputs/odr_hash/module.map
+++ test/Modules/Inputs/odr_hash/module.map
@@ -0,0 +1,6 @@
+module first {
+  header "first.h"
+}
+module second {
+  header "second.h"
+}
Index: test/Modules/Inputs/odr_hash/first.h
===================================================================
--- test/Modules/Inputs/odr_hash/first.h
+++ test/Modules/Inputs/odr_hash/first.h
@@ -0,0 +1,204 @@
+struct S1 {
+  public:
+};
+
+struct S2Friend2 {};
+struct S2 {
+  friend S2Friend2;
+};
+
+template<class>
+struct S3Template {};
+
+struct S3 {
+  friend S3Template<int>;
+};
+
+struct S4 {
+  static_assert(1 == 1, "First");
+};
+
+struct S5 {
+  static_assert(1 == 1, "Message");
+};
+
+struct S6 {
+  int First();
+};
+
+struct S7 {
+  double foo();
+};
+
+struct S8 {
+  void foo();
+};
+
+struct S9 {
+  void foo() { int y = 5; }
+};
+
+struct S10 {
+  struct {
+    int x;
+  } a;
+};
+
+struct S11 {
+  void foo() { int y = sizeof(int); }
+};
+
+struct S12 {
+  int x = sizeof(x);
+  int y = sizeof(x);
+};
+
+struct S13 {
+  template <typename A> void foo();
+};
+
+struct S14 {
+  template <typename A, typename B> void foo();
+};
+
+template <typename T>
+struct S15 : T {
+  void foo() {
+    int x = __builtin_offsetof(T, first);
+  }
+};
+
+struct S16 {
+  template <template<int = 0> class Y>
+  void foo() {
+    Y<> y;
+  }
+};
+
+struct S17 {
+  template <template <typename> class T>
+  static int foo(int a = 1);
+  template <template <typename> class T, template <typename> class U>
+  using Q_type = T<int>;
+};
+
+struct S18 {
+  enum E { X1 };
+};
+
+struct S19 {
+  enum E { X1 };
+};
+
+struct S20 {
+  enum E { X1 = 1 };
+};
+
+struct S21 {
+  void foo() {
+    label:
+    ;
+  }
+};
+
+struct S22 {
+  void foo() {
+    label_first:
+    ;
+  }
+};
+
+struct S23 {
+  typedef int a;
+  typedef char b;
+};
+
+struct S24 {
+  inline int foo();
+};
+
+struct S25 {
+  int x;
+  S25() : x(5) {}
+};
+
+struct S26 {
+  int x;
+  S26() : x(5) {}
+};
+
+struct S27 {
+  explicit S27(int) {}
+  S27() {}
+};
+
+struct Base1 {
+  Base1();
+  Base1(int);
+  Base1(double);
+};
+
+struct Base2 {
+  Base2();
+  Base2(int);
+  Base2(double);
+};
+
+struct S28 : public Base1 {};
+struct S29 : virtual Base1 {};
+
+struct S30 : public Base1 {
+  S30() : Base1(1) {}
+};
+struct S31 : virtual Base1 {
+  S31() : Base1(1) {}
+};
+struct S32 : public Base1, Base2 {
+  S32() : Base1(1), Base2(1.0) {}
+};
+
+struct S33 {
+  S33() : S33(5) {}
+  S33(int) {int a;}
+};
+
+struct S34 {
+  operator bool();
+};
+
+struct S35 {
+  explicit operator bool();
+};
+
+struct S36 {
+  int x : 3;
+};
+
+struct S37 {
+  mutable int x;
+  int y;
+};
+
+template <class X>
+struct S38 { };
+
+template <class X = int>
+struct S39 { X x; };
+
+template <int X = 5>
+struct S40 { int x = X; };
+
+template <int> class T41a{};
+template <template<int> class T = T41a>
+struct S41 {};
+
+struct S42 {
+  void foo() const {}
+  void bar() {}
+};
+
+struct S43 {
+  static constexpr int x = 1;
+  int y = 1;
+};
+
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -5511,6 +5511,7 @@
   Record->push_back(Data.ImplicitCopyAssignmentHasConstParam);
   Record->push_back(Data.HasDeclaredCopyConstructorWithConstParam);
   Record->push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
+  Record->push_back(Data.ODRHash);
   // IsLambda bit is already saved.
 
   Record->push_back(Data.NumBases);
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -1489,6 +1489,7 @@
   Data.ImplicitCopyAssignmentHasConstParam = Record[Idx++];
   Data.HasDeclaredCopyConstructorWithConstParam = Record[Idx++];
   Data.HasDeclaredCopyAssignmentWithConstParam = Record[Idx++];
+  Data.ODRHash = Record[Idx++];
 
   Data.NumBases = Record[Idx++];
   if (Data.NumBases)
@@ -1619,6 +1620,7 @@
   OR_FIELD(HasDeclaredCopyConstructorWithConstParam)
   OR_FIELD(HasDeclaredCopyAssignmentWithConstParam)
   MATCH_FIELD(IsLambda)
+  MATCH_FIELD(ODRHash)
 #undef OR_FIELD
 #undef MATCH_FIELD
 
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -13142,8 +13142,11 @@
       RD->completeDefinition();
   }
 
-  if (isa<CXXRecordDecl>(Tag))
+  if (auto *RD = dyn_cast<CXXRecordDecl>(Tag)) {
     FieldCollector->FinishClass();
+    if (Context.getLangOpts().Modules)
+      RD->computeODRHash();
+  }
 
   // Exit this scope of this tag's definition.
   PopDeclContext();
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -3783,3 +3783,422 @@
 CXXRecordDecl *MemberPointerType::getMostRecentCXXRecordDecl() const {
   return getClass()->getAsCXXRecordDecl()->getMostRecentDecl();
 }
+
+static void VisitQualifiers(llvm::FoldingSetNodeID &ID, Qualifiers Quals) {
+  ID.AddInteger(Quals.getAsOpaqueValue());
+}
+
+class ODRTypeVisitor : public TypeVisitor<ODRTypeVisitor> {
+  typedef TypeVisitor<ODRTypeVisitor> Inherited;
+  llvm::FoldingSetNodeID &ID;
+
+public:
+  ODRTypeVisitor(llvm::FoldingSetNodeID &ID) : ID(ID) {}
+
+  void VisitQualType(QualType T) {
+    if (T.isNull())
+      return;
+    SplitQualType split = T.split();
+    VisitQualifiers(split.Quals);
+    Visit(split.Ty);
+  }
+
+  // This prevents possible recursion between Decl and QaulType ODRHash
+  // functions.
+  void VisitDecl(Decl *D) {
+    if (!D)
+      return;
+
+    if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
+      if (IdentifierInfo *II = ND->getIdentifier())
+        ID.AddString(II->getName());
+  }
+
+  void VisitTemplateArgument(const TemplateArgument &TA) {
+    TA.ODRHash(ID);
+  }
+
+  void VisitQualifiers(Qualifiers Quals) {
+    ID.AddInteger(Quals.getAsOpaqueValue());
+  }
+
+  void VisitStmt(Stmt *S) {
+    S->ODRHash(ID);
+  }
+
+  void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) {
+    if (!NNS) {
+      ID.AddInteger(0);
+      return;
+    }
+    VisitNestedNameSpecifier(NNS->getPrefix());
+    auto Kind = NNS->getKind();
+    ID.AddInteger(Kind);
+    switch (Kind) {
+    case NestedNameSpecifier::Identifier:
+      if (IdentifierInfo *II = NNS->getAsIdentifier()) {
+        ID.AddString(II->getName());
+      }
+      break;
+    case NestedNameSpecifier::Namespace:
+      VisitDecl(NNS->getAsNamespace());
+      break;
+    case NestedNameSpecifier::NamespaceAlias:
+      VisitDecl(NNS->getAsNamespaceAlias());
+      break;
+    case NestedNameSpecifier::Global:
+      break;
+    case NestedNameSpecifier::Super:
+      break;
+    case NestedNameSpecifier::TypeSpecWithTemplate:
+    case NestedNameSpecifier::TypeSpec:
+      VisitQualType(QualType(NNS->getAsType(), 0));
+      break;
+    }
+  }
+
+  void VisitIdentiferInfo(const IdentifierInfo *II) {
+    if (II)
+      ID.AddString(II->getName());
+  }
+
+  void VisitTemplateName(const TemplateName &TN) {
+    switch (TN.getKind()) {
+    case TemplateName::Template:
+      VisitDecl(TN.getAsTemplateDecl());
+      break;
+    case TemplateName::OverloadedTemplate: {
+      OverloadedTemplateStorage *Storage = TN.getAsOverloadedTemplate();
+      ID.AddInteger(Storage->size());
+      for (NamedDecl *ND : *Storage)
+        VisitDecl(ND);
+      break;
+    }
+    case TemplateName::QualifiedTemplate: {
+      QualifiedTemplateName *QTN = TN.getAsQualifiedTemplateName();
+      VisitNestedNameSpecifier(QTN->getQualifier());
+      ID.AddBoolean(QTN->hasTemplateKeyword());
+      VisitDecl(QTN->getTemplateDecl());
+      break;
+    }
+    case TemplateName::DependentTemplate: {
+      DependentTemplateName *DTN = TN.getAsDependentTemplateName();
+      VisitNestedNameSpecifier(DTN->getQualifier());
+      ID.AddBoolean(DTN->isIdentifier());
+      if (DTN->isIdentifier()) {
+        VisitIdentiferInfo(DTN->getIdentifier());
+      } else {
+        ID.AddInteger(DTN->getOperator());
+      }
+      break;
+    }
+    case TemplateName::SubstTemplateTemplateParm: {
+      SubstTemplateTemplateParmStorage *Storage =
+          TN.getAsSubstTemplateTemplateParm();
+      VisitDecl(Storage->getParameter());
+      VisitTemplateName(Storage->getReplacement());
+      break;
+    }
+    case TemplateName::SubstTemplateTemplateParmPack: {
+      SubstTemplateTemplateParmPackStorage *Storage =
+          TN.getAsSubstTemplateTemplateParmPack();
+      VisitDecl(Storage->getParameterPack());
+      VisitTemplateArgument(Storage->getArgumentPack());
+      break;
+    }
+    }
+  }
+
+  void VisitType(const Type *T) { ID.AddInteger(T->getTypeClass()); }
+
+  void VisitAdjustedType(const AdjustedType *T) {
+    VisitQualType(T->getOriginalType());
+    VisitQualType(T->getAdjustedType());
+    VisitType(T);
+  }
+
+  void VisitDecayedType(const DecayedType *T) {
+    VisitQualType(T->getDecayedType());
+    VisitQualType(T->getPointeeType());
+    VisitAdjustedType(T);
+  }
+
+  void VisitArrayType(const ArrayType *T) {
+    VisitQualType(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) {
+    VisitStmt(T->getSizeExpr());
+    VisitArrayType(T);
+  }
+
+  void VisitIncompleteArrayType(const IncompleteArrayType *T) {
+    VisitArrayType(T);
+  }
+
+  void VisitVariableArrayType(const VariableArrayType *T) {
+    VisitStmt(T->getSizeExpr());
+    VisitArrayType(T);
+  }
+
+  void VisitAtomicType(const AtomicType *T) {
+    VisitQualType(T->getValueType());
+    VisitType(T);
+  }
+
+  void VisitAttributedType(const AttributedType *T) {
+    ID.AddInteger(T->getAttrKind());
+    VisitQualType(T->getModifiedType());
+    VisitQualType(T->getEquivalentType());
+    VisitType(T);
+  }
+
+  void VisitBlockPointerType(const BlockPointerType *T) {
+    VisitQualType(T->getPointeeType());
+    VisitType(T);
+  }
+
+  void VisitBuiltinType(const BuiltinType *T) {
+    ID.AddInteger(T->getKind());
+    VisitType(T);
+  }
+
+  void VisitComplexType(const ComplexType *T) {
+    VisitQualType(T->getElementType());
+    VisitType(T);
+  }
+
+  void VisitDecltypeType(const DecltypeType *T) {
+    VisitQualType(T->getUnderlyingType());
+    VisitStmt(T->getUnderlyingExpr());
+    VisitType(T);
+  }
+
+  void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T) {
+    VisitQualType(T->getElementType());
+    VisitStmt(T->getSizeExpr());
+    VisitType(T);
+  }
+
+  void VisitFunctionType(const FunctionType *T) {
+    VisitQualType(T->getReturnType());
+    T->getExtInfo().Profile(ID);
+    ID.AddInteger(T->isConst());
+    ID.AddInteger(T->isVolatile());
+    ID.AddInteger(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())
+      VisitQualType(ParamType);
+
+    const auto &epi = T->getExtProtoInfo();
+    ID.AddInteger(epi.Variadic);
+    ID.AddInteger(epi.TypeQuals);
+    ID.AddInteger(epi.RefQualifier);
+    ID.AddInteger(epi.ExceptionSpec.Type);
+
+    if (epi.ExceptionSpec.Type == EST_Dynamic) {
+      for (QualType Ex : epi.ExceptionSpec.Exceptions)
+        VisitQualType(Ex);
+    } else if (epi.ExceptionSpec.Type == EST_ComputedNoexcept &&
+               epi.ExceptionSpec.NoexceptExpr) {
+      VisitStmt(epi.ExceptionSpec.NoexceptExpr);
+    } else if (epi.ExceptionSpec.Type == EST_Uninstantiated ||
+               epi.ExceptionSpec.Type == EST_Unevaluated) {
+      VisitDecl(epi.ExceptionSpec.SourceDecl->getCanonicalDecl());
+    }
+    if (epi.ExtParameterInfos) {
+      for (unsigned i = 0; i != T->getNumParams(); ++i)
+        ID.AddInteger(epi.ExtParameterInfos[i].getOpaqueValue());
+    }
+    epi.ExtInfo.Profile(ID);
+    ID.AddBoolean(epi.HasTrailingReturn);
+
+    VisitFunctionType(T);
+  }
+
+  void VisitInjectedClassNameType(const InjectedClassNameType *T) {
+    VisitQualType(T->getInjectedSpecializationType());
+    VisitDecl(T->getDecl());
+    VisitType(T);
+  }
+
+  void VisitMemberPointerType(const MemberPointerType *T) {
+    VisitQualType(T->getPointeeType());
+    Visit(T->getClass());
+    VisitType(T);
+  }
+
+  void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
+    VisitQualType(T->getPointeeType());
+    VisitType(T);
+  }
+
+  void VisitObjCObjectType(const ObjCObjectType *T) {
+    QualType Base = T->getBaseType();
+    if (Base.getTypePtr() != T)
+      VisitQualType(Base);
+    auto TypeArgs = T->getTypeArgsAsWritten();
+    ID.AddInteger(TypeArgs.size());
+    for (auto TypeArg : TypeArgs)
+      VisitQualType(TypeArg);
+    ID.AddInteger(T->getNumProtocols());
+    for (auto proto : T->quals())
+      VisitDecl(proto);
+    ID.AddInteger(T->isKindOfTypeAsWritten());
+    VisitType(T);
+  }
+
+  void VisitObjCInterfaceType(const ObjCInterfaceType *T) {
+    VisitObjCObjectType(T);
+  }
+
+  void VisitObjCObjectTypeImpl(const ObjCObjectTypeImpl *T) {
+    VisitObjCObjectType(T);
+  }
+
+  void VisitPackExpansionType(const PackExpansionType *T) {
+    VisitQualType(T->getPattern());
+    auto NumExpansions = T->getNumExpansions();
+    ID.AddBoolean(NumExpansions.hasValue());
+    if (NumExpansions)
+      ID.AddInteger(*NumExpansions);
+    VisitType(T);
+  };
+
+  void VisitPointerType(const PointerType *T) {
+    VisitQualType(T->getPointeeType());
+    VisitType(T);
+  }
+
+  void VisitReferenceType(const ReferenceType *T) {
+    VisitQualType(T->getPointeeTypeAsWritten());
+    VisitType(T);
+  }
+
+  void VisitLValueReferenceType(const LValueReferenceType *T) {
+    VisitReferenceType(T);
+  }
+
+  void VisitRValueReferenceType(const RValueReferenceType *T) {
+    VisitReferenceType(T);
+  }
+
+  void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
+    VisitQualType(T->getReplacementType());
+    VisitQualType(QualType(T->getReplacedParameter(), 0));
+    VisitType(T);
+  }
+
+  void
+  VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
+    VisitQualType(QualType(T->getReplacedParameter(), 0));
+    VisitTemplateArgument(T->getArgumentPack());
+    VisitType(T);
+  }
+
+  void VisitTagType(const TagType *T) {
+    VisitDecl(T->getDecl());
+    ID.AddBoolean(T->isBeingDefined());
+    VisitType(T);
+  }
+
+  void VisitEnumType(const EnumType *T) {
+    VisitDecl(T->getDecl());
+    VisitTagType(T);
+  }
+
+  void VisitRecordType(const RecordType *T) {
+    VisitDecl(T->getDecl());
+    VisitTagType(T);
+  }
+
+  void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
+    VisitTemplateName(T->getTemplateName());
+    for (auto I = T->begin(), E = T->end(); I != E; ++I)
+      VisitTemplateArgument(*I);
+    VisitType(T);
+  }
+
+  void VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
+    ID.AddInteger(T->getDepth());
+    ID.AddInteger(T->getIndex());
+    ID.AddBoolean(T->isParameterPack());
+    VisitDecl(T->getDecl());
+    VisitType(T);
+  }
+
+  void VisitTypedefType(const TypedefType *T) {
+    VisitDecl(T->getDecl());
+    VisitType(T);
+  }
+
+  void VisitTypeOfExprType(const TypeOfExprType *T) {
+    VisitStmt(T->getUnderlyingExpr());
+    VisitType(T);
+  }
+
+  void VisitDependentTypeOfExprType(const DependentTypeOfExprType *T) {
+    VisitTypeOfExprType(T);
+  }
+
+  void VisitTypeWithKeyword(const TypeWithKeyword *T) { VisitType(T); }
+
+  void VisitElaboratedType(const ElaboratedType *T) {
+    ID.AddInteger(T->getKeyword());
+    VisitNestedNameSpecifier(T->getQualifier());
+    VisitQualType(T->getNamedType());
+    VisitTypeWithKeyword(T);
+  }
+
+  void VisitUnaryTransformType(const UnaryTransformType *T) {
+    VisitQualType(T->getBaseType());
+    ID.AddInteger(T->getUTTKind());
+    VisitType(T);
+  }
+
+  void VisitDependentUnaryTransformType(const DependentUnaryTransformType *T) {
+    VisitUnaryTransformType(T);
+  }
+
+  void VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
+    VisitDecl(T->getDecl());
+    VisitType(T);
+  }
+
+  void VisitVectorType(const VectorType *T) {
+    VisitQualType(T->getElementType());
+    ID.AddInteger(T->getNumElements());
+    ID.AddInteger(T->getVectorKind());
+    VisitType(T);
+  }
+
+  void VisitExtVectorType(const ExtVectorType *T) { VisitVectorType(T); }
+};
+
+void Type::ODRHash(llvm::FoldingSetNodeID &ID) const {
+  ODRTypeVisitor(ID).Visit(this);
+}
+
+void QualType::ODRHash(llvm::FoldingSetNodeID &ID) const {
+  if (isNull())
+    return;
+  SplitQualType split = this->split();
+  VisitQualifiers(ID, split.Quals);
+  split.Ty->ODRHash(ID);
+}
Index: lib/AST/TemplateBase.cpp
===================================================================
--- lib/AST/TemplateBase.cpp
+++ lib/AST/TemplateBase.cpp
@@ -296,6 +296,39 @@
   }
 }
 
+void TemplateArgument::ODRHash(llvm::FoldingSetNodeID &ID) const {
+  ID.AddInteger(getKind());
+  switch (getKind()) {
+  case TemplateArgument::Null:
+    llvm_unreachable("Require valid TemplateArgument");
+  case TemplateArgument::Type:
+    getAsType().ODRHash(ID);
+    return;
+  case TemplateArgument::Declaration:
+    getAsDecl()->ODRHash(ID);
+    return;
+  case TemplateArgument::NullPtr:
+    ID.AddInteger(0);
+    return;
+  case TemplateArgument::Integral:
+    getAsIntegral().Profile(ID);
+    getIntegralType().ODRHash(ID);
+    break;
+  case TemplateArgument::Template:
+  case TemplateArgument::TemplateExpansion:
+    getAsTemplateOrTemplatePattern().getAsTemplateDecl()->ODRHash(ID);
+    break;
+  case TemplateArgument::Expression:
+    getAsExpr()->ODRHash(ID);
+    break;
+  case TemplateArgument::Pack:
+    ID.AddInteger(pack_size());
+    for (auto SubTA : pack_elements())
+      SubTA.ODRHash(ID);
+    break;
+  }
+}
+
 bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
   if (getKind() != Other.getKind()) return false;
 
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
@@ -25,38 +26,42 @@
 
 namespace {
   class StmtProfiler : public ConstStmtVisitor<StmtProfiler> {
+   protected:
     llvm::FoldingSetNodeID &ID;
-    const ASTContext &Context;
     bool Canonical;
 
   public:
-    StmtProfiler(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
-                 bool Canonical)
-      : ID(ID), Context(Context), Canonical(Canonical) { }
+    StmtProfiler(llvm::FoldingSetNodeID &ID, bool Canonical)
+        : ID(ID), Canonical(Canonical) {}
+
+    virtual ~StmtProfiler() {}
 
     void VisitStmt(const Stmt *S);
 
 #define STMT(Node, Base) void Visit##Node(const Node *S);
 #include "clang/AST/StmtNodes.inc"
 
     /// \brief Visit a declaration that is referenced within an expression
     /// or statement.
-    void VisitDecl(const Decl *D);
+    virtual void VisitDecl(const Decl *D) = 0;
 
     /// \brief Visit a type that is referenced within an expression or
     /// statement.
-    void VisitType(QualType T);
+    virtual void VisitType(QualType T) = 0;
 
     /// \brief Visit a name that occurs within an expression or statement.
-    void VisitName(DeclarationName Name);
+    virtual void VisitName(DeclarationName Name) = 0;
+
+    /// \brief Visit identifiers that are not in Decl's or Type's.
+    virtual void VisitIdentifierInfo(IdentifierInfo *II) = 0;
 
     /// \brief Visit a nested-name-specifier that occurs within an expression
     /// or statement.
-    void VisitNestedNameSpecifier(NestedNameSpecifier *NNS);
+    virtual void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) = 0;
 
     /// \brief Visit a template name that occurs within an expression or
     /// statement.
-    void VisitTemplateName(TemplateName Name);
+    virtual void VisitTemplateName(TemplateName Name) = 0;
 
     /// \brief Visit template arguments that occur within an expression or
     /// statement.
@@ -66,6 +71,129 @@
     /// \brief Visit a single template argument.
     void VisitTemplateArgument(const TemplateArgument &Arg);
   };
+
+  class StmtProfilerWithPointers : public StmtProfiler {
+    const ASTContext &Context;
+
+  public:
+    StmtProfilerWithPointers(llvm::FoldingSetNodeID &ID,
+                             const ASTContext &Context, bool Canonical)
+        : StmtProfiler(ID, Canonical), Context(Context) {}
+  private:
+    void VisitDecl(const Decl *D) override {
+      ID.AddInteger(D ? D->getKind() : 0);
+
+      if (Canonical && D) {
+        if (const NonTypeTemplateParmDecl *NTTP =
+                dyn_cast<NonTypeTemplateParmDecl>(D)) {
+          ID.AddInteger(NTTP->getDepth());
+          ID.AddInteger(NTTP->getIndex());
+          ID.AddBoolean(NTTP->isParameterPack());
+          VisitType(NTTP->getType());
+          return;
+        }
+
+        if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
+          // The Itanium C++ ABI uses the type, scope depth, and scope
+          // index of a parameter when mangling expressions that involve
+          // function parameters, so we will use the parameter's type for
+          // establishing function parameter identity. That way, our
+          // definition of "equivalent" (per C++ [temp.over.link]) is at
+          // least as strong as the definition of "equivalent" used for
+          // name mangling.
+          VisitType(Parm->getType());
+          ID.AddInteger(Parm->getFunctionScopeDepth());
+          ID.AddInteger(Parm->getFunctionScopeIndex());
+          return;
+        }
+
+        if (const TemplateTypeParmDecl *TTP =
+                dyn_cast<TemplateTypeParmDecl>(D)) {
+          ID.AddInteger(TTP->getDepth());
+          ID.AddInteger(TTP->getIndex());
+          ID.AddBoolean(TTP->isParameterPack());
+          return;
+        }
+
+        if (const TemplateTemplateParmDecl *TTP =
+                dyn_cast<TemplateTemplateParmDecl>(D)) {
+          ID.AddInteger(TTP->getDepth());
+          ID.AddInteger(TTP->getIndex());
+          ID.AddBoolean(TTP->isParameterPack());
+          return;
+        }
+      }
+
+      ID.AddPointer(D ? D->getCanonicalDecl() : nullptr);
+    }
+
+    void VisitType(QualType T) override {
+      if (Canonical)
+        T = Context.getCanonicalType(T);
+
+      ID.AddPointer(T.getAsOpaquePtr());
+    }
+
+    void VisitName(DeclarationName Name) override {
+      ID.AddPointer(Name.getAsOpaquePtr());
+    }
+
+    void VisitIdentifierInfo(IdentifierInfo *II) override {
+      ID.AddPointer(II);
+    }
+
+    void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override {
+      if (Canonical)
+        NNS = Context.getCanonicalNestedNameSpecifier(NNS);
+      ID.AddPointer(NNS);
+    }
+
+    void VisitTemplateName(TemplateName Name) override {
+      if (Canonical)
+        Name = Context.getCanonicalTemplateName(Name);
+
+      Name.Profile(ID);
+    }
+  };
+
+  class StmtProfilerWithoutPointers : public StmtProfiler {
+  public:
+    StmtProfilerWithoutPointers(llvm::FoldingSetNodeID &ID)
+        : StmtProfiler(ID, false) {}
+
+  private:
+    void VisitType(QualType T) override {
+      T.ODRHash(ID);
+    }
+    void VisitName(DeclarationName Name) override {
+      if (Name.isEmpty()) {
+        ID.AddInteger(0);
+        return;
+      }
+      auto Kind = Name.getNameKind();
+      ID.AddInteger(Kind);
+      // TODO: Hash the relevant parts of DeclarationName instead of using
+      // the string.
+      SmallString<64> Buffer;
+      llvm::raw_svector_ostream StrOS(Buffer);
+      Name.print(StrOS, PrintingPolicy(LangOptions()));
+      ID.AddString(Buffer);
+    }
+    void VisitIdentifierInfo(IdentifierInfo *II) override {
+      ID.AddString(II->getName());
+    }
+    void VisitDecl(const Decl *D) override {
+      ID.AddInteger(D ? D->getKind() : 0);
+      if (!D) {
+        return;
+      }
+      if (auto *ND = dyn_cast<NamedDecl>(D)) {
+        ID.AddString(ND->getNameAsString());
+      }
+    }
+    void VisitTemplateName(TemplateName Name) override { }
+    void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override { }
+  };
 }
 
 void StmtProfiler::VisitStmt(const Stmt *S) {
@@ -775,15 +903,15 @@
       break;
 
     case OffsetOfNode::Identifier:
-      ID.AddPointer(ON.getFieldName());
+      VisitIdentifierInfo(ON.getFieldName());
       break;
 
     case OffsetOfNode::Base:
       // These nodes are implicit, and therefore don't need profiling.
       break;
     }
   }
-  
+
   VisitExpr(S);
 }
 
@@ -1355,7 +1483,7 @@
   if (S->getDestroyedTypeInfo())
     VisitType(S->getDestroyedType());
   else
-    ID.AddPointer(S->getDestroyedTypeIdentifier());
+    VisitIdentifierInfo(S->getDestroyedTypeIdentifier());
 }
 
 void StmtProfiler::VisitOverloadExpr(const OverloadExpr *S) {
@@ -1600,77 +1728,6 @@
   ID.AddBoolean(S->getBridgeKind());
 }
 
-void StmtProfiler::VisitDecl(const Decl *D) {
-  ID.AddInteger(D? D->getKind() : 0);
-
-  if (Canonical && D) {
-    if (const NonTypeTemplateParmDecl *NTTP =
-          dyn_cast<NonTypeTemplateParmDecl>(D)) {
-      ID.AddInteger(NTTP->getDepth());
-      ID.AddInteger(NTTP->getIndex());
-      ID.AddBoolean(NTTP->isParameterPack());
-      VisitType(NTTP->getType());
-      return;
-    }
-
-    if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
-      // The Itanium C++ ABI uses the type, scope depth, and scope
-      // index of a parameter when mangling expressions that involve
-      // function parameters, so we will use the parameter's type for
-      // establishing function parameter identity. That way, our
-      // definition of "equivalent" (per C++ [temp.over.link]) is at
-      // least as strong as the definition of "equivalent" used for
-      // name mangling.
-      VisitType(Parm->getType());
-      ID.AddInteger(Parm->getFunctionScopeDepth());
-      ID.AddInteger(Parm->getFunctionScopeIndex());
-      return;
-    }
-
-    if (const TemplateTypeParmDecl *TTP =
-          dyn_cast<TemplateTypeParmDecl>(D)) {
-      ID.AddInteger(TTP->getDepth());
-      ID.AddInteger(TTP->getIndex());
-      ID.AddBoolean(TTP->isParameterPack());
-      return;
-    }
-
-    if (const TemplateTemplateParmDecl *TTP =
-          dyn_cast<TemplateTemplateParmDecl>(D)) {
-      ID.AddInteger(TTP->getDepth());
-      ID.AddInteger(TTP->getIndex());
-      ID.AddBoolean(TTP->isParameterPack());
-      return;
-    }
-  }
-
-  ID.AddPointer(D? D->getCanonicalDecl() : nullptr);
-}
-
-void StmtProfiler::VisitType(QualType T) {
-  if (Canonical)
-    T = Context.getCanonicalType(T);
-
-  ID.AddPointer(T.getAsOpaquePtr());
-}
-
-void StmtProfiler::VisitName(DeclarationName Name) {
-  ID.AddPointer(Name.getAsOpaquePtr());
-}
-
-void StmtProfiler::VisitNestedNameSpecifier(NestedNameSpecifier *NNS) {
-  if (Canonical)
-    NNS = Context.getCanonicalNestedNameSpecifier(NNS);
-  ID.AddPointer(NNS);
-}
-
-void StmtProfiler::VisitTemplateName(TemplateName Name) {
-  if (Canonical)
-    Name = Context.getCanonicalTemplateName(Name);
-
-  Name.Profile(ID);
-}
-
 void StmtProfiler::VisitTemplateArguments(const TemplateArgumentLoc *Args,
                                           unsigned NumArgs) {
   ID.AddInteger(NumArgs);
@@ -1720,6 +1777,11 @@
 
 void Stmt::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
                    bool Canonical) const {
-  StmtProfiler Profiler(ID, Context, Canonical);
+  StmtProfilerWithPointers Profiler(ID, Context, Canonical);
+  Profiler.Visit(this);
+}
+
+void Stmt::ODRHash(llvm::FoldingSetNodeID &ID) const {
+  StmtProfilerWithoutPointers Profiler(ID);
   Profiler.Visit(this);
 }
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -16,9 +16,11 @@
 #include "clang/AST/ASTMutationListener.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/TypeLoc.h"
+#include "clang/AST/TypeVisitor.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
@@ -71,8 +73,8 @@
       ImplicitCopyAssignmentHasConstParam(true),
       HasDeclaredCopyConstructorWithConstParam(false),
       HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false),
-      IsParsingBaseSpecifiers(false), NumBases(0), NumVBases(0), Bases(),
-      VBases(), Definition(D), FirstFriend() {}
+      IsParsingBaseSpecifiers(false), ODRHash(0), NumBases(0), NumVBases(0),
+      Bases(), VBases(), Definition(D), FirstFriend() {}
 
 CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
   return Bases.get(Definition->getASTContext().getExternalSource());
@@ -371,6 +373,28 @@
   data().IsParsingBaseSpecifiers = false;
 }
 
+void CXXRecordDecl::computeODRHash() {
+  if (!DefinitionData)
+    return;
+  llvm::FoldingSetNodeID ID;
+  for (auto *D : decls()) {
+    D->ODRHash(ID);
+  }
+
+  for (auto base : bases()) {
+    ID.AddInteger(base.isVirtual());
+    base.getType().ODRHash(ID);
+  }
+
+  if (ClassTemplateDecl *TD = getDescribedClassTemplate()) {
+    TemplateParameterList *TPL = TD->getTemplateParameters();
+    for (NamedDecl *ND : TPL->asArray())
+      ND->ODRHash(ID);
+  }
+
+  DefinitionData->ODRHash = ID.ComputeHash();
+}
+
 void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
   // C++11 [class.copy]p11:
   //   A defaulted copy/move constructor for a class X is defined as
Index: lib/AST/DeclBase.cpp
===================================================================
--- lib/AST/DeclBase.cpp
+++ lib/AST/DeclBase.cpp
@@ -22,13 +22,15 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclOpenMP.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
 #include "clang/AST/DependentDiagnostic.h"
 #include "clang/AST/ExternalASTSource.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
 using namespace clang;
@@ -1760,3 +1762,185 @@
 
   return DD;
 }
+
+class ODRDeclVisitor : public ConstDeclVisitor<ODRDeclVisitor> {
+  typedef ConstDeclVisitor<ODRDeclVisitor> Inherited;
+  llvm::FoldingSetNodeID &ID;
+
+public:
+  ODRDeclVisitor(llvm::FoldingSetNodeID &ID) : ID(ID) {}
+
+  void VisitDecl(const Decl *D) {
+    if (D->isImplicit())
+      return;
+    if (D->isInvalidDecl())
+      return;
+    ID.AddInteger(D->getKind());
+    ID.AddInteger(D->hasAttrs());
+
+    if (auto *DC = dyn_cast<DeclContext>(D))
+      for (auto *SubD : DC->decls())
+        Visit(SubD);
+
+    Inherited::VisitDecl(D);
+  }
+
+  void VisitLabelDecl(const LabelDecl *D) {
+    Inherited::VisitLabelDecl(D);
+  }
+
+  void VisitEnumDecl(const EnumDecl *D) {
+    ID.AddInteger(D->isFixed());
+    if (D->isFixed())
+      D->getIntegerType().ODRHash(ID);
+    ID.AddInteger(D->isScoped());
+    ID.AddInteger(D->isScopedUsingClassTag());
+
+    Inherited::VisitEnumDecl(D);
+  }
+
+  void VisitEnumConstantDecl(const EnumConstantDecl *D) {
+    if (auto *E = D->getInitExpr())
+      VisitStmt(E);
+
+    Inherited::VisitEnumConstantDecl(D);
+  }
+
+  void VisitNamedDecl(const NamedDecl *D) {
+    if (IdentifierInfo *II = D->getIdentifier()) {
+      ID.AddString(II->getName());
+    }
+    Inherited::VisitNamedDecl(D);
+  }
+
+  void VisitValueDecl(const ValueDecl *D) {
+    D->getType().ODRHash(ID);
+    Inherited::VisitValueDecl(D);
+  }
+
+  void VisitAccessSpecDecl(const AccessSpecDecl *D) {
+    ID.AddInteger(D->getAccess());
+    Inherited::VisitAccessSpecDecl(D);
+  }
+
+  void VisitFriendDecl(const FriendDecl *D) {
+    if (TypeSourceInfo *TSI = D->getFriendType()) {
+      TSI->getType().ODRHash(ID);
+    }
+    unsigned NumLists = D->getFriendTypeNumTemplateParameterLists();
+    ID.AddInteger(NumLists);
+    for (unsigned i = 0; i < NumLists; ++i)
+      VisitTemplateParameterList(D->getFriendTypeTemplateParameterList(i));
+    Inherited::VisitFriendDecl(D);
+  }
+
+  void VisitStaticAssertDecl(const StaticAssertDecl *D) {
+    VisitStmt(D->getAssertExpr());
+    ID.AddString(D->getMessage()->getString());
+    Inherited::VisitStaticAssertDecl(D);
+  }
+
+  void VisitTypedefNameDecl(const TypedefNameDecl *D) {
+    D->getUnderlyingType().ODRHash(ID);
+
+    Inherited::VisitTypedefNameDecl(D);
+  }
+
+  void VisitFunctionDecl(const FunctionDecl *D) {
+    if (D->hasBody())
+      VisitStmt(D->getBody());
+    else
+      ID.AddInteger(false);
+
+    ID.AddInteger(D->getStorageClass());
+    ID.AddInteger(D->isInlineSpecified());
+    ID.AddInteger(D->isVirtualAsWritten());
+    ID.AddInteger(D->isPure());
+    ID.AddInteger(D->isDeletedAsWritten());
+
+    Inherited::VisitFunctionDecl(D);
+  }
+
+  void VisitCXXMethodDecl(const CXXMethodDecl *D) {
+    ID.AddInteger(D->isStatic());
+    ID.AddInteger(D->isInstance());
+    ID.AddInteger(D->isConst());
+    ID.AddInteger(D->isVolatile());
+    Inherited::VisitCXXMethodDecl(D);
+  }
+
+  void VisitCXXConstructorDecl(const CXXConstructorDecl *D) {
+    ID.AddInteger(D->isExplicitSpecified());
+    ID.AddInteger(D->getNumCtorInitializers());
+    for (auto Initializer : D->inits()) {
+      if (Initializer->isWritten()) {
+        VisitStmt(Initializer->getInit());
+      }
+    }
+    Inherited::VisitCXXConstructorDecl(D);
+  }
+
+  void VisitCXXConversionDecl(const CXXConversionDecl *D) {
+    D->getConversionType().ODRHash(ID);
+    ID.AddInteger(D->isExplicitSpecified());
+    Inherited::VisitCXXConversionDecl(D);
+  }
+
+  void VisitFieldDecl(const FieldDecl *D) {
+    ID.AddInteger(D->isMutable());
+    ID.AddInteger(D->isBitField());
+    if (D->isBitField())
+      VisitStmt(D->getBitWidth());
+    Inherited::VisitFieldDecl(D);
+  }
+
+  void VisitTemplateDecl(const TemplateDecl *D) {
+    if (NamedDecl *ND = D->getTemplatedDecl())
+      Visit(ND);
+    auto *Parameters = D->getTemplateParameters();
+    ID.AddInteger(Parameters->size());
+    for (auto *ND : *Parameters)
+      Visit(ND);
+    Inherited::VisitTemplateDecl(D);
+  }
+
+  void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
+    Inherited::VisitFunctionTemplateDecl(D);
+  }
+
+  void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
+    if (D->hasDefaultArgument())
+      D->getDefaultArgument().ODRHash(ID);
+    Inherited::VisitTemplateTypeParmDecl(D);
+  }
+
+  void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
+    if (D->hasDefaultArgument())
+      VisitStmt(D->getDefaultArgument());
+    Inherited::VisitNonTypeTemplateParmDecl(D);
+  }
+
+  void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) {
+    if (D->hasDefaultArgument())
+      D->getDefaultArgument().getArgument().ODRHash(ID);
+    Inherited::VisitTemplateTemplateParmDecl(D);
+  }
+
+  void VisitStmt(const Stmt *S) {
+    if (!S)
+      return;
+    S->ODRHash(ID);
+  }
+
+  void VisitTemplateParameterList(TemplateParameterList *TPL) {
+    if (!TPL)
+      return;
+    for (auto *ND : TPL->asArray()) {
+      Visit(ND);
+    }
+  }
+};
+
+void Decl::ODRHash(llvm::FoldingSetNodeID &ID) const {
+  ODRDeclVisitor(ID).Visit(this);
+}
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -1093,6 +1093,8 @@
   /// Remove all qualifiers including _Atomic.
   QualType getAtomicUnqualifiedType() const;
 
+  void ODRHash(llvm::FoldingSetNodeID &ID) const;
+
 private:
   // These methods are implemented in a separate translation unit;
   // "static"-ize them to avoid creating temporary QualTypes in the
@@ -1999,6 +2001,8 @@
   CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h
   void dump() const;
 
+  void ODRHash(llvm::FoldingSetNodeID &ID) const;
+
   friend class ASTReader;
   friend class ASTWriter;
 };
Index: include/clang/AST/TemplateBase.h
===================================================================
--- include/clang/AST/TemplateBase.h
+++ include/clang/AST/TemplateBase.h
@@ -362,6 +362,9 @@
              
   /// \brief Used to insert TemplateArguments into FoldingSets.
   void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const;
+
+  /// \brief Calculate an independent hash value of the TemplateArgument.
+  void ODRHash(llvm::FoldingSetNodeID &ID) const;
 };
 
 /// Location information for a TemplateArgument.
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -422,6 +422,12 @@
   /// written in the source.
   void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
                bool Canonical) const;
+
+  /// Unlike Profile, ODRHash does not compute values that are dependent on
+  /// the value of pointers, making it stable across runs.  To achieve this,
+  /// ODRHash dives deeper into AST nodes and includes more values into ID
+  /// than Profile.
+  void ODRHash(llvm::FoldingSetNodeID &ID) const;
 };
 
 /// DeclStmt - Adaptor class for mixing declarations with statements and
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -457,6 +457,9 @@
     /// \brief Whether we are currently parsing base specifiers.
     unsigned IsParsingBaseSpecifiers : 1;
 
+    /// \brief A hash of parts of the class to help in ODR checking.
+    unsigned ODRHash;
+
     /// \brief The number of base class specifiers in Bases.
     unsigned NumBases;
 
@@ -703,6 +706,9 @@
     return data().IsParsingBaseSpecifiers;
   }
 
+  void computeODRHash();
+  unsigned getODRHash() { return data().ODRHash; }
+
   /// \brief Sets the base classes of this struct or class.
   void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases);
 
Index: include/clang/AST/DeclBase.h
===================================================================
--- include/clang/AST/DeclBase.h
+++ include/clang/AST/DeclBase.h
@@ -17,6 +17,7 @@
 #include "clang/AST/AttrIterator.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/PointerUnion.h"
 #include "llvm/ADT/iterator.h"
 #include "llvm/ADT/iterator_range.h"
@@ -1026,6 +1027,9 @@
   /// have a FunctionType.
   const FunctionType *getFunctionType(bool BlocksToo = true) const;
 
+  /// Adds the Decl specific values for the ODR hash to ID.
+  void ODRHash(llvm::FoldingSetNodeID &ID) const;
+
 private:
   void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx);
   void setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to