[clang] 90f58ea - [ODRHash] Factor out functionality for CXXRecord ODR diagnostics (NFCI)

Bruno Cardoso Lopes via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 22 13:33:32 PST 2020


Author: Bruno Cardoso Lopes
Date: 2020-01-22T13:33:17-08:00
New Revision: 90f58eaeff5f1d5017e7b689fac79180cdfa0160

URL: https://github.com/llvm/llvm-project/commit/90f58eaeff5f1d5017e7b689fac79180cdfa0160
DIFF: https://github.com/llvm/llvm-project/commit/90f58eaeff5f1d5017e7b689fac79180cdfa0160.diff

LOG: [ODRHash] Factor out functionality for CXXRecord ODR diagnostics (NFCI)

There's going to be a lot of common code between RecordDecl and
CXXRecordDecl, factor out some of the logic in preparation for
adding the RecordDecl side.

Added: 
    

Modified: 
    clang/lib/Serialization/ASTReader.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 21f6a36565ef..5351ac31c179 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -9451,6 +9451,446 @@ void ASTReader::diagnoseOdrViolations() {
         return Hash.CalculateHash();
       };
 
+  // Used with err_module_odr_violation_mismatch_decl and
+  // note_module_odr_violation_mismatch_decl
+  // This list should be the same Decl's as in ODRHash::isWhiteListedDecl
+  enum ODRMismatchDecl {
+    EndOfClass,
+    PublicSpecifer,
+    PrivateSpecifer,
+    ProtectedSpecifer,
+    StaticAssert,
+    Field,
+    CXXMethod,
+    TypeAlias,
+    TypeDef,
+    Var,
+    Friend,
+    FunctionTemplate,
+    Other
+  };
+
+  // Used with err_module_odr_violation_mismatch_decl_
diff  and
+  // note_module_odr_violation_mismatch_decl_
diff 
+  enum ODRMismatchDeclDifference {
+    StaticAssertCondition,
+    StaticAssertMessage,
+    StaticAssertOnlyMessage,
+    FieldName,
+    FieldTypeName,
+    FieldSingleBitField,
+    FieldDifferentWidthBitField,
+    FieldSingleMutable,
+    FieldSingleInitializer,
+    FieldDifferentInitializers,
+    MethodName,
+    MethodDeleted,
+    MethodDefaulted,
+    MethodVirtual,
+    MethodStatic,
+    MethodVolatile,
+    MethodConst,
+    MethodInline,
+    MethodNumberParameters,
+    MethodParameterType,
+    MethodParameterName,
+    MethodParameterSingleDefaultArgument,
+    MethodParameterDifferentDefaultArgument,
+    MethodNoTemplateArguments,
+    MethodDifferentNumberTemplateArguments,
+    MethodDifferentTemplateArgument,
+    MethodSingleBody,
+    MethodDifferentBody,
+    TypedefName,
+    TypedefType,
+    VarName,
+    VarType,
+    VarSingleInitializer,
+    VarDifferentInitializer,
+    VarConstexpr,
+    FriendTypeFunction,
+    FriendType,
+    FriendFunction,
+    FunctionTemplateDifferentNumberParameters,
+    FunctionTemplateParameterDifferentKind,
+    FunctionTemplateParameterName,
+    FunctionTemplateParameterSingleDefaultArgument,
+    FunctionTemplateParameterDifferentDefaultArgument,
+    FunctionTemplateParameterDifferentType,
+    FunctionTemplatePackParameter,
+  };
+
+  // These lambdas have the common portions of the ODR diagnostics.  This
+  // has the same return as Diag(), so addition parameters can be passed
+  // in with operator<<
+  auto ODRDiagDeclError = [this](NamedDecl *FirstRecord, StringRef FirstModule,
+                                 SourceLocation Loc, SourceRange Range,
+                                 ODRMismatchDeclDifference DiffType) {
+    return Diag(Loc, diag::err_module_odr_violation_mismatch_decl_
diff )
+           << FirstRecord << FirstModule.empty() << FirstModule << Range
+           << DiffType;
+  };
+  auto ODRDiagDeclNote = [this](StringRef SecondModule, SourceLocation Loc,
+                                SourceRange Range, ODRMismatchDeclDifference DiffType) {
+    return Diag(Loc, diag::note_module_odr_violation_mismatch_decl_
diff )
+           << SecondModule << Range << DiffType;
+  };
+
+  auto ODRDiagField = [this, &ODRDiagDeclError, &ODRDiagDeclNote,
+                       &ComputeQualTypeODRHash, &ComputeODRHash](
+                          NamedDecl *FirstRecord, StringRef FirstModule,
+                          StringRef SecondModule, FieldDecl *FirstField,
+                          FieldDecl *SecondField) {
+    IdentifierInfo *FirstII = FirstField->getIdentifier();
+    IdentifierInfo *SecondII = SecondField->getIdentifier();
+    if (FirstII->getName() != SecondII->getName()) {
+      ODRDiagDeclError(FirstRecord, FirstModule, FirstField->getLocation(),
+                       FirstField->getSourceRange(), FieldName)
+          << FirstII;
+      ODRDiagDeclNote(SecondModule, SecondField->getLocation(),
+                      SecondField->getSourceRange(), FieldName)
+          << SecondII;
+
+      return true;
+    }
+
+    assert(getContext().hasSameType(FirstField->getType(),
+                                    SecondField->getType()));
+
+    QualType FirstType = FirstField->getType();
+    QualType SecondType = SecondField->getType();
+    if (ComputeQualTypeODRHash(FirstType) !=
+        ComputeQualTypeODRHash(SecondType)) {
+      ODRDiagDeclError(FirstRecord, FirstModule, FirstField->getLocation(),
+                       FirstField->getSourceRange(), FieldTypeName)
+          << FirstII << FirstType;
+      ODRDiagDeclNote(SecondModule, SecondField->getLocation(),
+                      SecondField->getSourceRange(), FieldTypeName)
+          << SecondII << SecondType;
+
+      return true;
+    }
+
+    const bool IsFirstBitField = FirstField->isBitField();
+    const bool IsSecondBitField = SecondField->isBitField();
+    if (IsFirstBitField != IsSecondBitField) {
+      ODRDiagDeclError(FirstRecord, FirstModule, FirstField->getLocation(),
+                       FirstField->getSourceRange(), FieldSingleBitField)
+          << FirstII << IsFirstBitField;
+      ODRDiagDeclNote(SecondModule, SecondField->getLocation(),
+                      SecondField->getSourceRange(), FieldSingleBitField)
+          << SecondII << IsSecondBitField;
+      return true;
+    }
+
+    if (IsFirstBitField && IsSecondBitField) {
+      unsigned FirstBitWidthHash =
+          ComputeODRHash(FirstField->getBitWidth());
+      unsigned SecondBitWidthHash =
+          ComputeODRHash(SecondField->getBitWidth());
+      if (FirstBitWidthHash != SecondBitWidthHash) {
+        ODRDiagDeclError(FirstRecord, FirstModule, FirstField->getLocation(),
+                         FirstField->getSourceRange(),
+                         FieldDifferentWidthBitField)
+            << FirstII << FirstField->getBitWidth()->getSourceRange();
+        ODRDiagDeclNote(SecondModule, SecondField->getLocation(),
+                        SecondField->getSourceRange(),
+                        FieldDifferentWidthBitField)
+            << SecondII << SecondField->getBitWidth()->getSourceRange();
+        return true;
+      }
+    }
+
+    if (!PP.getLangOpts().CPlusPlus)
+      return false;
+
+    const bool IsFirstMutable = FirstField->isMutable();
+    const bool IsSecondMutable = SecondField->isMutable();
+    if (IsFirstMutable != IsSecondMutable) {
+      ODRDiagDeclError(FirstRecord, FirstModule, FirstField->getLocation(),
+                       FirstField->getSourceRange(), FieldSingleMutable)
+          << FirstII << IsFirstMutable;
+      ODRDiagDeclNote(SecondModule, SecondField->getLocation(),
+                      SecondField->getSourceRange(), FieldSingleMutable)
+          << SecondII << IsSecondMutable;
+      return true;
+    }
+
+    const Expr *FirstInitializer = FirstField->getInClassInitializer();
+    const Expr *SecondInitializer = SecondField->getInClassInitializer();
+    if ((!FirstInitializer && SecondInitializer) ||
+        (FirstInitializer && !SecondInitializer)) {
+      ODRDiagDeclError(FirstRecord, FirstModule, FirstField->getLocation(),
+                       FirstField->getSourceRange(), FieldSingleInitializer)
+          << FirstII << (FirstInitializer != nullptr);
+      ODRDiagDeclNote(SecondModule, SecondField->getLocation(),
+                      SecondField->getSourceRange(), FieldSingleInitializer)
+          << SecondII << (SecondInitializer != nullptr);
+      return true;
+    }
+
+    if (FirstInitializer && SecondInitializer) {
+      unsigned FirstInitHash = ComputeODRHash(FirstInitializer);
+      unsigned SecondInitHash = ComputeODRHash(SecondInitializer);
+      if (FirstInitHash != SecondInitHash) {
+        ODRDiagDeclError(FirstRecord, FirstModule, FirstField->getLocation(),
+                         FirstField->getSourceRange(),
+                         FieldDifferentInitializers)
+            << FirstII << FirstInitializer->getSourceRange();
+        ODRDiagDeclNote(SecondModule, SecondField->getLocation(),
+                        SecondField->getSourceRange(),
+                        FieldDifferentInitializers)
+            << SecondII << SecondInitializer->getSourceRange();
+        return true;
+      }
+    }
+
+    return false;
+  };
+
+  auto ODRDiagTypeDefOrAlias =
+      [&ODRDiagDeclError, &ODRDiagDeclNote, &ComputeQualTypeODRHash](
+          NamedDecl *FirstRecord, StringRef FirstModule, StringRef SecondModule,
+          TypedefNameDecl *FirstTD, TypedefNameDecl *SecondTD,
+          bool IsTypeAlias) {
+        auto FirstName = FirstTD->getDeclName();
+        auto SecondName = SecondTD->getDeclName();
+        if (FirstName != SecondName) {
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstTD->getLocation(),
+                           FirstTD->getSourceRange(), TypedefName)
+              << IsTypeAlias << FirstName;
+          ODRDiagDeclNote(SecondModule, SecondTD->getLocation(),
+                          SecondTD->getSourceRange(), TypedefName)
+              << IsTypeAlias << SecondName;
+          return true;
+        }
+
+        QualType FirstType = FirstTD->getUnderlyingType();
+        QualType SecondType = SecondTD->getUnderlyingType();
+        if (ComputeQualTypeODRHash(FirstType) !=
+            ComputeQualTypeODRHash(SecondType)) {
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstTD->getLocation(),
+                           FirstTD->getSourceRange(), TypedefType)
+              << IsTypeAlias << FirstName << FirstType;
+          ODRDiagDeclNote(SecondModule, SecondTD->getLocation(),
+                          SecondTD->getSourceRange(), TypedefType)
+              << IsTypeAlias << SecondName << SecondType;
+          return true;
+        }
+
+        return false;
+  };
+
+  auto ODRDiagVar = [&ODRDiagDeclError, &ODRDiagDeclNote,
+                     &ComputeQualTypeODRHash, &ComputeODRHash,
+                     this](NamedDecl *FirstRecord, StringRef FirstModule,
+                           StringRef SecondModule, VarDecl *FirstVD,
+                           VarDecl *SecondVD) {
+    auto FirstName = FirstVD->getDeclName();
+    auto SecondName = SecondVD->getDeclName();
+    if (FirstName != SecondName) {
+      ODRDiagDeclError(FirstRecord, FirstModule, FirstVD->getLocation(),
+                       FirstVD->getSourceRange(), VarName)
+          << FirstName;
+      ODRDiagDeclNote(SecondModule, SecondVD->getLocation(),
+                      SecondVD->getSourceRange(), VarName)
+          << SecondName;
+      return true;
+    }
+
+    QualType FirstType = FirstVD->getType();
+    QualType SecondType = SecondVD->getType();
+    if (ComputeQualTypeODRHash(FirstType) !=
+        ComputeQualTypeODRHash(SecondType)) {
+      ODRDiagDeclError(FirstRecord, FirstModule, FirstVD->getLocation(),
+                       FirstVD->getSourceRange(), VarType)
+          << FirstName << FirstType;
+      ODRDiagDeclNote(SecondModule, SecondVD->getLocation(),
+                      SecondVD->getSourceRange(), VarType)
+          << SecondName << SecondType;
+      return true;
+    }
+
+    if (!PP.getLangOpts().CPlusPlus)
+      return false;
+
+    const Expr *FirstInit = FirstVD->getInit();
+    const Expr *SecondInit = SecondVD->getInit();
+    if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+      ODRDiagDeclError(FirstRecord, FirstModule, FirstVD->getLocation(),
+                       FirstVD->getSourceRange(), VarSingleInitializer)
+          << FirstName << (FirstInit == nullptr)
+          << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
+      ODRDiagDeclNote(SecondModule, SecondVD->getLocation(),
+                      SecondVD->getSourceRange(), VarSingleInitializer)
+          << SecondName << (SecondInit == nullptr)
+          << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+      return true;
+    }
+
+    if (FirstInit && SecondInit &&
+        ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
+      ODRDiagDeclError(FirstRecord, FirstModule, FirstVD->getLocation(),
+                       FirstVD->getSourceRange(), VarDifferentInitializer)
+          << FirstName << FirstInit->getSourceRange();
+      ODRDiagDeclNote(SecondModule, SecondVD->getLocation(),
+                      SecondVD->getSourceRange(), VarDifferentInitializer)
+          << SecondName << SecondInit->getSourceRange();
+      return true;
+    }
+
+    const bool FirstIsConstexpr = FirstVD->isConstexpr();
+    const bool SecondIsConstexpr = SecondVD->isConstexpr();
+    if (FirstIsConstexpr != SecondIsConstexpr) {
+      ODRDiagDeclError(FirstRecord, FirstModule, FirstVD->getLocation(),
+                       FirstVD->getSourceRange(), VarConstexpr)
+          << FirstName << FirstIsConstexpr;
+      ODRDiagDeclNote(SecondModule, SecondVD->getLocation(),
+                      SecondVD->getSourceRange(), VarConstexpr)
+          << SecondName << SecondIsConstexpr;
+      return true;
+    }
+    return false;
+  };
+
+  auto DifferenceSelector = [](Decl *D) {
+    assert(D && "valid Decl required");
+    switch (D->getKind()) {
+    default:
+      return Other;
+    case Decl::AccessSpec:
+      switch (D->getAccess()) {
+      case AS_public:
+        return PublicSpecifer;
+      case AS_private:
+        return PrivateSpecifer;
+      case AS_protected:
+        return ProtectedSpecifer;
+      case AS_none:
+        break;
+      }
+      llvm_unreachable("Invalid access specifier");
+    case Decl::StaticAssert:
+      return StaticAssert;
+    case Decl::Field:
+      return Field;
+    case Decl::CXXMethod:
+    case Decl::CXXConstructor:
+    case Decl::CXXDestructor:
+      return CXXMethod;
+    case Decl::TypeAlias:
+      return TypeAlias;
+    case Decl::Typedef:
+      return TypeDef;
+    case Decl::Var:
+      return Var;
+    case Decl::Friend:
+      return Friend;
+    case Decl::FunctionTemplate:
+      return FunctionTemplate;
+    }
+  };
+
+  using DeclHashes = llvm::SmallVector<std::pair<Decl *, unsigned>, 4>;
+  auto PopulateHashes = [&ComputeSubDeclODRHash](DeclHashes &Hashes,
+                                                 RecordDecl *Record,
+                                                 const DeclContext *DC) {
+    for (auto *D : Record->decls()) {
+      if (!ODRHash::isWhitelistedDecl(D, DC))
+        continue;
+      Hashes.emplace_back(D, ComputeSubDeclODRHash(D));
+    }
+  };
+
+  struct DiffResult {
+    Decl *FirstDecl = nullptr, *SecondDecl = nullptr;
+    ODRMismatchDecl FirstDiffType = Other, SecondDiffType = Other;
+  };
+
+  // If there is a diagnoseable 
diff erence, FirstDiffType and
+  // SecondDiffType will not be Other and FirstDecl and SecondDecl will be
+  // filled in if not EndOfClass.
+  auto FindTypeDiffs = [&DifferenceSelector](DeclHashes &FirstHashes,
+                                             DeclHashes &SecondHashes) {
+    DiffResult DR;
+    auto FirstIt = FirstHashes.begin();
+    auto SecondIt = SecondHashes.begin();
+    while (FirstIt != FirstHashes.end() || SecondIt != SecondHashes.end()) {
+      if (FirstIt != FirstHashes.end() && SecondIt != SecondHashes.end() &&
+          FirstIt->second == SecondIt->second) {
+        ++FirstIt;
+        ++SecondIt;
+        continue;
+      }
+
+      DR.FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first;
+      DR.SecondDecl =
+          SecondIt == SecondHashes.end() ? nullptr : SecondIt->first;
+
+      DR.FirstDiffType =
+          DR.FirstDecl ? DifferenceSelector(DR.FirstDecl) : EndOfClass;
+      DR.SecondDiffType =
+          DR.SecondDecl ? DifferenceSelector(DR.SecondDecl) : EndOfClass;
+      return DR;
+    }
+    return DR;
+  };
+
+  // Use this to diagnose that an unexpected Decl was encountered
+  // or no 
diff erence was detected. This causes a generic error
+  // message to be emitted.
+  auto DiagnoseODRUnexpected = [this](DiffResult &DR, NamedDecl *FirstRecord,
+                                      StringRef FirstModule,
+                                      NamedDecl *SecondRecord,
+                                      StringRef SecondModule) {
+    Diag(FirstRecord->getLocation(),
+         diag::err_module_odr_violation_
diff erent_definitions)
+        << FirstRecord << FirstModule.empty() << FirstModule;
+
+    if (DR.FirstDecl) {
+      Diag(DR.FirstDecl->getLocation(), diag::note_first_module_
diff erence)
+          << FirstRecord << DR.FirstDecl->getSourceRange();
+    }
+
+    Diag(SecondRecord->getLocation(),
+         diag::note_module_odr_violation_
diff erent_definitions)
+        << SecondModule;
+
+    if (DR.SecondDecl) {
+      Diag(DR.SecondDecl->getLocation(), diag::note_second_module_
diff erence)
+          << DR.SecondDecl->getSourceRange();
+    }
+  };
+
+  auto DiagnoseODRMismatch =
+      [this](DiffResult &DR, NamedDecl *FirstRecord, StringRef FirstModule,
+             NamedDecl *SecondRecord, StringRef SecondModule) {
+        SourceLocation FirstLoc;
+        SourceRange FirstRange;
+        auto *FirstTag = dyn_cast<TagDecl>(FirstRecord);
+        if (DR.FirstDiffType == EndOfClass && FirstTag) {
+          FirstLoc = FirstTag->getBraceRange().getEnd();
+        } else {
+          FirstLoc = DR.FirstDecl->getLocation();
+          FirstRange = DR.FirstDecl->getSourceRange();
+        }
+        Diag(FirstLoc, diag::err_module_odr_violation_mismatch_decl)
+            << FirstRecord << FirstModule.empty() << FirstModule << FirstRange
+            << DR.FirstDiffType;
+
+        SourceLocation SecondLoc;
+        SourceRange SecondRange;
+        auto *SecondTag = dyn_cast<TagDecl>(SecondRecord);
+        if (DR.SecondDiffType == EndOfClass && SecondTag) {
+          SecondLoc = SecondTag->getBraceRange().getEnd();
+        } else {
+          SecondLoc = DR.SecondDecl->getLocation();
+          SecondRange = DR.SecondDecl->getSourceRange();
+        }
+        Diag(SecondLoc, diag::note_module_odr_violation_mismatch_decl)
+            << SecondModule << SecondRange << DR.SecondDiffType;
+      };
+
   // Issue any pending ODR-failure diagnostics.
   for (auto &Merge : OdrMergeFailures) {
     // If we've already pointed out a specific problem with this class, don't
@@ -9484,16 +9924,16 @@ void ASTReader::diagnoseOdrViolations() {
           BaseVirtual,
           BaseAccess,
         };
-        auto ODRDiagError = [FirstRecord, &FirstModule,
-                             this](SourceLocation Loc, SourceRange Range,
-                                   ODRDefinitionDataDifference DiffType) {
+        auto ODRDiagBaseError = [FirstRecord, &FirstModule,
+                                 this](SourceLocation Loc, SourceRange Range,
+                                       ODRDefinitionDataDifference DiffType) {
           return Diag(Loc, diag::err_module_odr_violation_definition_data)
                  << FirstRecord << FirstModule.empty() << FirstModule << Range
                  << DiffType;
         };
-        auto ODRDiagNote = [&SecondModule,
-                            this](SourceLocation Loc, SourceRange Range,
-                                  ODRDefinitionDataDifference DiffType) {
+        auto ODRDiagBaseNote = [&SecondModule,
+                                this](SourceLocation Loc, SourceRange Range,
+                                      ODRDefinitionDataDifference DiffType) {
           return Diag(Loc, diag::note_module_odr_violation_definition_data)
                  << SecondModule << Range << DiffType;
         };
@@ -9512,22 +9952,22 @@ void ASTReader::diagnoseOdrViolations() {
         };
 
         if (FirstNumBases != SecondNumBases) {
-          ODRDiagError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
-                       NumBases)
+          ODRDiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
+                           NumBases)
               << FirstNumBases;
-          ODRDiagNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
-                      NumBases)
+          ODRDiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
+                          NumBases)
               << SecondNumBases;
           Diagnosed = true;
           break;
         }
 
         if (FirstNumVBases != SecondNumVBases) {
-          ODRDiagError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
-                       NumVBases)
+          ODRDiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
+                           NumVBases)
               << FirstNumVBases;
-          ODRDiagNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
-                      NumVBases)
+          ODRDiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
+                          NumVBases)
               << SecondNumVBases;
           Diagnosed = true;
           break;
@@ -9541,33 +9981,33 @@ void ASTReader::diagnoseOdrViolations() {
           auto SecondBase = SecondBases[i];
           if (ComputeQualTypeODRHash(FirstBase.getType()) !=
               ComputeQualTypeODRHash(SecondBase.getType())) {
-            ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
-                         BaseType)
+            ODRDiagBaseError(FirstRecord->getLocation(),
+                             FirstBase.getSourceRange(), BaseType)
                 << (i + 1) << FirstBase.getType();
-            ODRDiagNote(SecondRecord->getLocation(),
-                        SecondBase.getSourceRange(), BaseType)
+            ODRDiagBaseNote(SecondRecord->getLocation(),
+                            SecondBase.getSourceRange(), BaseType)
                 << (i + 1) << SecondBase.getType();
             break;
           }
 
           if (FirstBase.isVirtual() != SecondBase.isVirtual()) {
-            ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
-                         BaseVirtual)
+            ODRDiagBaseError(FirstRecord->getLocation(),
+                             FirstBase.getSourceRange(), BaseVirtual)
                 << (i + 1) << FirstBase.isVirtual() << FirstBase.getType();
-            ODRDiagNote(SecondRecord->getLocation(),
-                        SecondBase.getSourceRange(), BaseVirtual)
+            ODRDiagBaseNote(SecondRecord->getLocation(),
+                            SecondBase.getSourceRange(), BaseVirtual)
                 << (i + 1) << SecondBase.isVirtual() << SecondBase.getType();
             break;
           }
 
           if (FirstBase.getAccessSpecifierAsWritten() !=
               SecondBase.getAccessSpecifierAsWritten()) {
-            ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
-                         BaseAccess)
+            ODRDiagBaseError(FirstRecord->getLocation(),
+                             FirstBase.getSourceRange(), BaseAccess)
                 << (i + 1) << FirstBase.getType()
                 << (int)FirstBase.getAccessSpecifierAsWritten();
-            ODRDiagNote(SecondRecord->getLocation(),
-                        SecondBase.getSourceRange(), BaseAccess)
+            ODRDiagBaseNote(SecondRecord->getLocation(),
+                            SecondBase.getSourceRange(), BaseAccess)
                 << (i + 1) << SecondBase.getType()
                 << (int)SecondBase.getAccessSpecifierAsWritten();
             break;
@@ -9580,8 +10020,6 @@ void ASTReader::diagnoseOdrViolations() {
         }
       }
 
-      using DeclHashes = llvm::SmallVector<std::pair<Decl *, unsigned>, 4>;
-
       const ClassTemplateDecl *FirstTemplate =
           FirstRecord->getDescribedClassTemplate();
       const ClassTemplateDecl *SecondTemplate =
@@ -9622,16 +10060,16 @@ void ASTReader::diagnoseOdrViolations() {
           if (FirstIt->second == SecondIt->second)
             continue;
 
-          auto ODRDiagError = [FirstRecord, &FirstModule,
-                               this](SourceLocation Loc, SourceRange Range,
-                                     ODRTemplateDifference DiffType) {
+          auto ODRDiagTemplateError = [FirstRecord, &FirstModule, this](
+                                          SourceLocation Loc, SourceRange Range,
+                                          ODRTemplateDifference DiffType) {
             return Diag(Loc, diag::err_module_odr_violation_template_parameter)
                    << FirstRecord << FirstModule.empty() << FirstModule << Range
                    << DiffType;
           };
-          auto ODRDiagNote = [&SecondModule,
-                              this](SourceLocation Loc, SourceRange Range,
-                                    ODRTemplateDifference DiffType) {
+          auto ODRDiagTemplateNote = [&SecondModule, this](
+                                         SourceLocation Loc, SourceRange Range,
+                                         ODRTemplateDifference DiffType) {
             return Diag(Loc, diag::note_module_odr_violation_template_parameter)
                    << SecondModule << Range << DiffType;
           };
@@ -9652,11 +10090,13 @@ void ASTReader::diagnoseOdrViolations() {
                 SecondName.isIdentifier() && !SecondName.getAsIdentifierInfo();
             assert((!FirstNameEmpty || !SecondNameEmpty) &&
                    "Both template parameters cannot be unnamed.");
-            ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(),
-                         FirstNameEmpty ? ParamEmptyName : ParamName)
+            ODRDiagTemplateError(FirstDecl->getLocation(),
+                                 FirstDecl->getSourceRange(),
+                                 FirstNameEmpty ? ParamEmptyName : ParamName)
                 << FirstName;
-            ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(),
-                        SecondNameEmpty ? ParamEmptyName : ParamName)
+            ODRDiagTemplateNote(SecondDecl->getLocation(),
+                                SecondDecl->getSourceRange(),
+                                SecondNameEmpty ? ParamEmptyName : ParamName)
                 << SecondName;
             break;
           }
@@ -9675,13 +10115,13 @@ void ASTReader::diagnoseOdrViolations() {
                 !SecondParam->defaultArgumentWasInherited();
 
             if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
-              ODRDiagError(FirstDecl->getLocation(),
-                           FirstDecl->getSourceRange(),
-                           ParamSingleDefaultArgument)
+              ODRDiagTemplateError(FirstDecl->getLocation(),
+                                   FirstDecl->getSourceRange(),
+                                   ParamSingleDefaultArgument)
                   << HasFirstDefaultArgument;
-              ODRDiagNote(SecondDecl->getLocation(),
-                          SecondDecl->getSourceRange(),
-                          ParamSingleDefaultArgument)
+              ODRDiagTemplateNote(SecondDecl->getLocation(),
+                                  SecondDecl->getSourceRange(),
+                                  ParamSingleDefaultArgument)
                   << HasSecondDefaultArgument;
               break;
             }
@@ -9689,10 +10129,12 @@ void ASTReader::diagnoseOdrViolations() {
             assert(HasFirstDefaultArgument && HasSecondDefaultArgument &&
                    "Expecting default arguments.");
 
-            ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(),
-                         ParamDifferentDefaultArgument);
-            ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(),
-                        ParamDifferentDefaultArgument);
+            ODRDiagTemplateError(FirstDecl->getLocation(),
+                                 FirstDecl->getSourceRange(),
+                                 ParamDifferentDefaultArgument);
+            ODRDiagTemplateNote(SecondDecl->getLocation(),
+                                SecondDecl->getSourceRange(),
+                                ParamDifferentDefaultArgument);
 
             break;
           }
@@ -9707,13 +10149,13 @@ void ASTReader::diagnoseOdrViolations() {
                 !SecondParam->defaultArgumentWasInherited();
 
             if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
-              ODRDiagError(FirstDecl->getLocation(),
-                           FirstDecl->getSourceRange(),
-                           ParamSingleDefaultArgument)
+              ODRDiagTemplateError(FirstDecl->getLocation(),
+                                   FirstDecl->getSourceRange(),
+                                   ParamSingleDefaultArgument)
                   << HasFirstDefaultArgument;
-              ODRDiagNote(SecondDecl->getLocation(),
-                          SecondDecl->getSourceRange(),
-                          ParamSingleDefaultArgument)
+              ODRDiagTemplateNote(SecondDecl->getLocation(),
+                                  SecondDecl->getSourceRange(),
+                                  ParamSingleDefaultArgument)
                   << HasSecondDefaultArgument;
               break;
             }
@@ -9721,10 +10163,12 @@ void ASTReader::diagnoseOdrViolations() {
             assert(HasFirstDefaultArgument && HasSecondDefaultArgument &&
                    "Expecting default arguments.");
 
-            ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(),
-                         ParamDifferentDefaultArgument);
-            ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(),
-                        ParamDifferentDefaultArgument);
+            ODRDiagTemplateError(FirstDecl->getLocation(),
+                                 FirstDecl->getSourceRange(),
+                                 ParamDifferentDefaultArgument);
+            ODRDiagTemplateNote(SecondDecl->getLocation(),
+                                SecondDecl->getSourceRange(),
+                                ParamDifferentDefaultArgument);
 
             break;
           }
@@ -9740,13 +10184,13 @@ void ASTReader::diagnoseOdrViolations() {
                 !SecondParam->defaultArgumentWasInherited();
 
             if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
-              ODRDiagError(FirstDecl->getLocation(),
-                           FirstDecl->getSourceRange(),
-                           ParamSingleDefaultArgument)
+              ODRDiagTemplateError(FirstDecl->getLocation(),
+                                   FirstDecl->getSourceRange(),
+                                   ParamSingleDefaultArgument)
                   << HasFirstDefaultArgument;
-              ODRDiagNote(SecondDecl->getLocation(),
-                          SecondDecl->getSourceRange(),
-                          ParamSingleDefaultArgument)
+              ODRDiagTemplateNote(SecondDecl->getLocation(),
+                                  SecondDecl->getSourceRange(),
+                                  ParamSingleDefaultArgument)
                   << HasSecondDefaultArgument;
               break;
             }
@@ -9754,10 +10198,12 @@ void ASTReader::diagnoseOdrViolations() {
             assert(HasFirstDefaultArgument && HasSecondDefaultArgument &&
                    "Expecting default arguments.");
 
-            ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(),
-                         ParamDifferentDefaultArgument);
-            ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(),
-                        ParamDifferentDefaultArgument);
+            ODRDiagTemplateError(FirstDecl->getLocation(),
+                                 FirstDecl->getSourceRange(),
+                                 ParamDifferentDefaultArgument);
+            ODRDiagTemplateNote(SecondDecl->getLocation(),
+                                SecondDecl->getSourceRange(),
+                                ParamDifferentDefaultArgument);
 
             break;
           }
@@ -9774,224 +10220,32 @@ void ASTReader::diagnoseOdrViolations() {
 
       DeclHashes FirstHashes;
       DeclHashes SecondHashes;
+      const DeclContext *DC = FirstRecord;
+      PopulateHashes(FirstHashes, FirstRecord, DC);
+      PopulateHashes(SecondHashes, SecondRecord, DC);
 
-      auto PopulateHashes = [&ComputeSubDeclODRHash, FirstRecord](
-                                DeclHashes &Hashes, CXXRecordDecl *Record) {
-        for (auto *D : Record->decls()) {
-          // Due to decl merging, the first CXXRecordDecl is the parent of
-          // Decls in both records.
-          if (!ODRHash::isWhitelistedDecl(D, FirstRecord))
-            continue;
-          Hashes.emplace_back(D, ComputeSubDeclODRHash(D));
-        }
-      };
-      PopulateHashes(FirstHashes, FirstRecord);
-      PopulateHashes(SecondHashes, SecondRecord);
-
-      // Used with err_module_odr_violation_mismatch_decl and
-      // note_module_odr_violation_mismatch_decl
-      // This list should be the same Decl's as in ODRHash::isWhiteListedDecl
-      enum {
-        EndOfClass,
-        PublicSpecifer,
-        PrivateSpecifer,
-        ProtectedSpecifer,
-        StaticAssert,
-        Field,
-        CXXMethod,
-        TypeAlias,
-        TypeDef,
-        Var,
-        Friend,
-        FunctionTemplate,
-        Other
-      } FirstDiffType = Other,
-        SecondDiffType = Other;
-
-      auto DifferenceSelector = [](Decl *D) {
-        assert(D && "valid Decl required");
-        switch (D->getKind()) {
-        default:
-          return Other;
-        case Decl::AccessSpec:
-          switch (D->getAccess()) {
-          case AS_public:
-            return PublicSpecifer;
-          case AS_private:
-            return PrivateSpecifer;
-          case AS_protected:
-            return ProtectedSpecifer;
-          case AS_none:
-            break;
-          }
-          llvm_unreachable("Invalid access specifier");
-        case Decl::StaticAssert:
-          return StaticAssert;
-        case Decl::Field:
-          return Field;
-        case Decl::CXXMethod:
-        case Decl::CXXConstructor:
-        case Decl::CXXDestructor:
-          return CXXMethod;
-        case Decl::TypeAlias:
-          return TypeAlias;
-        case Decl::Typedef:
-          return TypeDef;
-        case Decl::Var:
-          return Var;
-        case Decl::Friend:
-          return Friend;
-        case Decl::FunctionTemplate:
-          return FunctionTemplate;
-        }
-      };
-
-      Decl *FirstDecl = nullptr;
-      Decl *SecondDecl = nullptr;
-      auto FirstIt = FirstHashes.begin();
-      auto SecondIt = SecondHashes.begin();
-
-      // If there is a diagnoseable 
diff erence, FirstDiffType and
-      // SecondDiffType will not be Other and FirstDecl and SecondDecl will be
-      // filled in if not EndOfClass.
-      while (FirstIt != FirstHashes.end() || SecondIt != SecondHashes.end()) {
-        if (FirstIt != FirstHashes.end() && SecondIt != SecondHashes.end() &&
-            FirstIt->second == SecondIt->second) {
-          ++FirstIt;
-          ++SecondIt;
-          continue;
-        }
-
-        FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first;
-        SecondDecl = SecondIt == SecondHashes.end() ? nullptr : SecondIt->first;
-
-        FirstDiffType = FirstDecl ? DifferenceSelector(FirstDecl) : EndOfClass;
-        SecondDiffType =
-            SecondDecl ? DifferenceSelector(SecondDecl) : EndOfClass;
-
-        break;
-      }
+      auto DR = FindTypeDiffs(FirstHashes, SecondHashes);
+      ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
+      ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
+      Decl *FirstDecl = DR.FirstDecl;
+      Decl *SecondDecl = DR.SecondDecl;
 
       if (FirstDiffType == Other || SecondDiffType == Other) {
-        // Reaching this point means an unexpected Decl was encountered
-        // or no 
diff erence was detected.  This causes a generic error
-        // message to be emitted.
-        Diag(FirstRecord->getLocation(),
-             diag::err_module_odr_violation_
diff erent_definitions)
-            << FirstRecord << FirstModule.empty() << FirstModule;
-
-        if (FirstDecl) {
-          Diag(FirstDecl->getLocation(), diag::note_first_module_
diff erence)
-              << FirstRecord << FirstDecl->getSourceRange();
-        }
-
-        Diag(SecondRecord->getLocation(),
-             diag::note_module_odr_violation_
diff erent_definitions)
-            << SecondModule;
-
-        if (SecondDecl) {
-          Diag(SecondDecl->getLocation(), diag::note_second_module_
diff erence)
-              << SecondDecl->getSourceRange();
-        }
-
+        DiagnoseODRUnexpected(DR, FirstRecord, FirstModule, SecondRecord,
+                              SecondModule);
         Diagnosed = true;
         break;
       }
 
       if (FirstDiffType != SecondDiffType) {
-        SourceLocation FirstLoc;
-        SourceRange FirstRange;
-        if (FirstDiffType == EndOfClass) {
-          FirstLoc = FirstRecord->getBraceRange().getEnd();
-        } else {
-          FirstLoc = FirstIt->first->getLocation();
-          FirstRange = FirstIt->first->getSourceRange();
-        }
-        Diag(FirstLoc, diag::err_module_odr_violation_mismatch_decl)
-            << FirstRecord << FirstModule.empty() << FirstModule << FirstRange
-            << FirstDiffType;
-
-        SourceLocation SecondLoc;
-        SourceRange SecondRange;
-        if (SecondDiffType == EndOfClass) {
-          SecondLoc = SecondRecord->getBraceRange().getEnd();
-        } else {
-          SecondLoc = SecondDecl->getLocation();
-          SecondRange = SecondDecl->getSourceRange();
-        }
-        Diag(SecondLoc, diag::note_module_odr_violation_mismatch_decl)
-            << SecondModule << SecondRange << SecondDiffType;
+        DiagnoseODRMismatch(DR, FirstRecord, FirstModule, SecondRecord,
+                            SecondModule);
         Diagnosed = true;
         break;
       }
 
       assert(FirstDiffType == SecondDiffType);
 
-      // Used with err_module_odr_violation_mismatch_decl_
diff  and
-      // note_module_odr_violation_mismatch_decl_
diff 
-      enum ODRDeclDifference {
-        StaticAssertCondition,
-        StaticAssertMessage,
-        StaticAssertOnlyMessage,
-        FieldName,
-        FieldTypeName,
-        FieldSingleBitField,
-        FieldDifferentWidthBitField,
-        FieldSingleMutable,
-        FieldSingleInitializer,
-        FieldDifferentInitializers,
-        MethodName,
-        MethodDeleted,
-        MethodDefaulted,
-        MethodVirtual,
-        MethodStatic,
-        MethodVolatile,
-        MethodConst,
-        MethodInline,
-        MethodNumberParameters,
-        MethodParameterType,
-        MethodParameterName,
-        MethodParameterSingleDefaultArgument,
-        MethodParameterDifferentDefaultArgument,
-        MethodNoTemplateArguments,
-        MethodDifferentNumberTemplateArguments,
-        MethodDifferentTemplateArgument,
-        MethodSingleBody,
-        MethodDifferentBody,
-        TypedefName,
-        TypedefType,
-        VarName,
-        VarType,
-        VarSingleInitializer,
-        VarDifferentInitializer,
-        VarConstexpr,
-        FriendTypeFunction,
-        FriendType,
-        FriendFunction,
-        FunctionTemplateDifferentNumberParameters,
-        FunctionTemplateParameterDifferentKind,
-        FunctionTemplateParameterName,
-        FunctionTemplateParameterSingleDefaultArgument,
-        FunctionTemplateParameterDifferentDefaultArgument,
-        FunctionTemplateParameterDifferentType,
-        FunctionTemplatePackParameter,
-      };
-
-      // These lambdas have the common portions of the ODR diagnostics.  This
-      // has the same return as Diag(), so addition parameters can be passed
-      // in with operator<<
-      auto ODRDiagError = [FirstRecord, &FirstModule, this](
-          SourceLocation Loc, SourceRange Range, ODRDeclDifference DiffType) {
-        return Diag(Loc, diag::err_module_odr_violation_mismatch_decl_
diff )
-               << FirstRecord << FirstModule.empty() << FirstModule << Range
-               << DiffType;
-      };
-      auto ODRDiagNote = [&SecondModule, this](
-          SourceLocation Loc, SourceRange Range, ODRDeclDifference DiffType) {
-        return Diag(Loc, diag::note_module_odr_violation_mismatch_decl_
diff )
-               << SecondModule << Range << DiffType;
-      };
-
       switch (FirstDiffType) {
       case Other:
       case EndOfClass:
@@ -10009,10 +10263,10 @@ void ASTReader::diagnoseOdrViolations() {
         unsigned FirstODRHash = ComputeODRHash(FirstExpr);
         unsigned SecondODRHash = ComputeODRHash(SecondExpr);
         if (FirstODRHash != SecondODRHash) {
-          ODRDiagError(FirstExpr->getBeginLoc(), FirstExpr->getSourceRange(),
-                       StaticAssertCondition);
-          ODRDiagNote(SecondExpr->getBeginLoc(), SecondExpr->getSourceRange(),
-                      StaticAssertCondition);
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstExpr->getBeginLoc(),
+                           FirstExpr->getSourceRange(), StaticAssertCondition);
+          ODRDiagDeclNote(SecondModule, SecondExpr->getBeginLoc(),
+                          SecondExpr->getSourceRange(), StaticAssertCondition);
           Diagnosed = true;
           break;
         }
@@ -10037,9 +10291,11 @@ void ASTReader::diagnoseOdrViolations() {
             SecondLoc = SecondSA->getBeginLoc();
             SecondRange = SecondSA->getSourceRange();
           }
-          ODRDiagError(FirstLoc, FirstRange, StaticAssertOnlyMessage)
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstLoc, FirstRange,
+                           StaticAssertOnlyMessage)
               << (FirstStr == nullptr);
-          ODRDiagNote(SecondLoc, SecondRange, StaticAssertOnlyMessage)
+          ODRDiagDeclNote(SecondModule, SecondLoc, SecondRange,
+                          StaticAssertOnlyMessage)
               << (SecondStr == nullptr);
           Diagnosed = true;
           break;
@@ -10047,126 +10303,19 @@ void ASTReader::diagnoseOdrViolations() {
 
         if (FirstStr && SecondStr &&
             FirstStr->getString() != SecondStr->getString()) {
-          ODRDiagError(FirstStr->getBeginLoc(), FirstStr->getSourceRange(),
-                       StaticAssertMessage);
-          ODRDiagNote(SecondStr->getBeginLoc(), SecondStr->getSourceRange(),
-                      StaticAssertMessage);
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstStr->getBeginLoc(),
+                           FirstStr->getSourceRange(), StaticAssertMessage);
+          ODRDiagDeclNote(SecondModule, SecondStr->getBeginLoc(),
+                          SecondStr->getSourceRange(), StaticAssertMessage);
           Diagnosed = true;
           break;
         }
         break;
       }
       case Field: {
-        FieldDecl *FirstField = cast<FieldDecl>(FirstDecl);
-        FieldDecl *SecondField = cast<FieldDecl>(SecondDecl);
-        IdentifierInfo *FirstII = FirstField->getIdentifier();
-        IdentifierInfo *SecondII = SecondField->getIdentifier();
-        if (FirstII->getName() != SecondII->getName()) {
-          ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
-                       FieldName)
-              << FirstII;
-          ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
-                      FieldName)
-              << SecondII;
-
-          Diagnosed = true;
-          break;
-        }
-
-        assert(getContext().hasSameType(FirstField->getType(),
-                                        SecondField->getType()));
-
-        QualType FirstType = FirstField->getType();
-        QualType SecondType = SecondField->getType();
-        if (ComputeQualTypeODRHash(FirstType) !=
-            ComputeQualTypeODRHash(SecondType)) {
-          ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
-                       FieldTypeName)
-              << FirstII << FirstType;
-          ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
-                      FieldTypeName)
-              << SecondII << SecondType;
-
-          Diagnosed = true;
-          break;
-        }
-
-        const bool IsFirstBitField = FirstField->isBitField();
-        const bool IsSecondBitField = SecondField->isBitField();
-        if (IsFirstBitField != IsSecondBitField) {
-          ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
-                       FieldSingleBitField)
-              << FirstII << IsFirstBitField;
-          ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
-                      FieldSingleBitField)
-              << SecondII << IsSecondBitField;
-          Diagnosed = true;
-          break;
-        }
-
-        if (IsFirstBitField && IsSecondBitField) {
-          unsigned FirstBitWidthHash =
-              ComputeODRHash(FirstField->getBitWidth());
-          unsigned SecondBitWidthHash =
-              ComputeODRHash(SecondField->getBitWidth());
-          if (FirstBitWidthHash != SecondBitWidthHash) {
-            ODRDiagError(FirstField->getLocation(),
-                         FirstField->getSourceRange(),
-                         FieldDifferentWidthBitField)
-                << FirstII << FirstField->getBitWidth()->getSourceRange();
-            ODRDiagNote(SecondField->getLocation(),
-                        SecondField->getSourceRange(),
-                        FieldDifferentWidthBitField)
-                << SecondII << SecondField->getBitWidth()->getSourceRange();
-            Diagnosed = true;
-            break;
-          }
-        }
-
-        const bool IsFirstMutable = FirstField->isMutable();
-        const bool IsSecondMutable = SecondField->isMutable();
-        if (IsFirstMutable != IsSecondMutable) {
-          ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
-                       FieldSingleMutable)
-              << FirstII << IsFirstMutable;
-          ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
-                      FieldSingleMutable)
-              << SecondII << IsSecondMutable;
-          Diagnosed = true;
-          break;
-        }
-
-        const Expr *FirstInitializer = FirstField->getInClassInitializer();
-        const Expr *SecondInitializer = SecondField->getInClassInitializer();
-        if ((!FirstInitializer && SecondInitializer) ||
-            (FirstInitializer && !SecondInitializer)) {
-          ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
-                       FieldSingleInitializer)
-              << FirstII << (FirstInitializer != nullptr);
-          ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
-                      FieldSingleInitializer)
-              << SecondII << (SecondInitializer != nullptr);
-          Diagnosed = true;
-          break;
-        }
-
-        if (FirstInitializer && SecondInitializer) {
-          unsigned FirstInitHash = ComputeODRHash(FirstInitializer);
-          unsigned SecondInitHash = ComputeODRHash(SecondInitializer);
-          if (FirstInitHash != SecondInitHash) {
-            ODRDiagError(FirstField->getLocation(),
-                         FirstField->getSourceRange(),
-                         FieldDifferentInitializers)
-                << FirstII << FirstInitializer->getSourceRange();
-            ODRDiagNote(SecondField->getLocation(),
-                        SecondField->getSourceRange(),
-                        FieldDifferentInitializers)
-                << SecondII << SecondInitializer->getSourceRange();
-            Diagnosed = true;
-            break;
-          }
-        }
-
+        Diagnosed = ODRDiagField(FirstRecord, FirstModule, SecondModule,
+                                 cast<FieldDecl>(FirstDecl),
+                                 cast<FieldDecl>(SecondDecl));
         break;
       }
       case CXXMethod: {
@@ -10188,11 +10337,11 @@ void ASTReader::diagnoseOdrViolations() {
         auto FirstName = FirstMethod->getDeclName();
         auto SecondName = SecondMethod->getDeclName();
         if (FirstMethodType != SecondMethodType || FirstName != SecondName) {
-          ODRDiagError(FirstMethod->getLocation(),
-                       FirstMethod->getSourceRange(), MethodName)
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(), MethodName)
               << FirstMethodType << FirstName;
-          ODRDiagNote(SecondMethod->getLocation(),
-                      SecondMethod->getSourceRange(), MethodName)
+          ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(), MethodName)
               << SecondMethodType << SecondName;
 
           Diagnosed = true;
@@ -10202,12 +10351,12 @@ void ASTReader::diagnoseOdrViolations() {
         const bool FirstDeleted = FirstMethod->isDeletedAsWritten();
         const bool SecondDeleted = SecondMethod->isDeletedAsWritten();
         if (FirstDeleted != SecondDeleted) {
-          ODRDiagError(FirstMethod->getLocation(),
-                       FirstMethod->getSourceRange(), MethodDeleted)
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(), MethodDeleted)
               << FirstMethodType << FirstName << FirstDeleted;
 
-          ODRDiagNote(SecondMethod->getLocation(),
-                      SecondMethod->getSourceRange(), MethodDeleted)
+          ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(), MethodDeleted)
               << SecondMethodType << SecondName << SecondDeleted;
           Diagnosed = true;
           break;
@@ -10216,12 +10365,12 @@ void ASTReader::diagnoseOdrViolations() {
         const bool FirstDefaulted = FirstMethod->isExplicitlyDefaulted();
         const bool SecondDefaulted = SecondMethod->isExplicitlyDefaulted();
         if (FirstDefaulted != SecondDefaulted) {
-          ODRDiagError(FirstMethod->getLocation(),
-                       FirstMethod->getSourceRange(), MethodDefaulted)
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(), MethodDefaulted)
               << FirstMethodType << FirstName << FirstDefaulted;
 
-          ODRDiagNote(SecondMethod->getLocation(),
-                      SecondMethod->getSourceRange(), MethodDefaulted)
+          ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(), MethodDefaulted)
               << SecondMethodType << SecondName << SecondDefaulted;
           Diagnosed = true;
           break;
@@ -10233,11 +10382,11 @@ void ASTReader::diagnoseOdrViolations() {
         const bool SecondPure = SecondMethod->isPure();
         if ((FirstVirtual || SecondVirtual) &&
             (FirstVirtual != SecondVirtual || FirstPure != SecondPure)) {
-          ODRDiagError(FirstMethod->getLocation(),
-                       FirstMethod->getSourceRange(), MethodVirtual)
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(), MethodVirtual)
               << FirstMethodType << FirstName << FirstPure << FirstVirtual;
-          ODRDiagNote(SecondMethod->getLocation(),
-                      SecondMethod->getSourceRange(), MethodVirtual)
+          ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(), MethodVirtual)
               << SecondMethodType << SecondName << SecondPure << SecondVirtual;
           Diagnosed = true;
           break;
@@ -10251,11 +10400,11 @@ void ASTReader::diagnoseOdrViolations() {
         const bool FirstStatic = FirstStorage == SC_Static;
         const bool SecondStatic = SecondStorage == SC_Static;
         if (FirstStatic != SecondStatic) {
-          ODRDiagError(FirstMethod->getLocation(),
-                       FirstMethod->getSourceRange(), MethodStatic)
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(), MethodStatic)
               << FirstMethodType << FirstName << FirstStatic;
-          ODRDiagNote(SecondMethod->getLocation(),
-                      SecondMethod->getSourceRange(), MethodStatic)
+          ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(), MethodStatic)
               << SecondMethodType << SecondName << SecondStatic;
           Diagnosed = true;
           break;
@@ -10264,11 +10413,11 @@ void ASTReader::diagnoseOdrViolations() {
         const bool FirstVolatile = FirstMethod->isVolatile();
         const bool SecondVolatile = SecondMethod->isVolatile();
         if (FirstVolatile != SecondVolatile) {
-          ODRDiagError(FirstMethod->getLocation(),
-                       FirstMethod->getSourceRange(), MethodVolatile)
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(), MethodVolatile)
               << FirstMethodType << FirstName << FirstVolatile;
-          ODRDiagNote(SecondMethod->getLocation(),
-                      SecondMethod->getSourceRange(), MethodVolatile)
+          ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(), MethodVolatile)
               << SecondMethodType << SecondName << SecondVolatile;
           Diagnosed = true;
           break;
@@ -10277,11 +10426,11 @@ void ASTReader::diagnoseOdrViolations() {
         const bool FirstConst = FirstMethod->isConst();
         const bool SecondConst = SecondMethod->isConst();
         if (FirstConst != SecondConst) {
-          ODRDiagError(FirstMethod->getLocation(),
-                       FirstMethod->getSourceRange(), MethodConst)
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(), MethodConst)
               << FirstMethodType << FirstName << FirstConst;
-          ODRDiagNote(SecondMethod->getLocation(),
-                      SecondMethod->getSourceRange(), MethodConst)
+          ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(), MethodConst)
               << SecondMethodType << SecondName << SecondConst;
           Diagnosed = true;
           break;
@@ -10290,11 +10439,11 @@ void ASTReader::diagnoseOdrViolations() {
         const bool FirstInline = FirstMethod->isInlineSpecified();
         const bool SecondInline = SecondMethod->isInlineSpecified();
         if (FirstInline != SecondInline) {
-          ODRDiagError(FirstMethod->getLocation(),
-                       FirstMethod->getSourceRange(), MethodInline)
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(), MethodInline)
               << FirstMethodType << FirstName << FirstInline;
-          ODRDiagNote(SecondMethod->getLocation(),
-                      SecondMethod->getSourceRange(), MethodInline)
+          ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(), MethodInline)
               << SecondMethodType << SecondName << SecondInline;
           Diagnosed = true;
           break;
@@ -10303,11 +10452,13 @@ void ASTReader::diagnoseOdrViolations() {
         const unsigned FirstNumParameters = FirstMethod->param_size();
         const unsigned SecondNumParameters = SecondMethod->param_size();
         if (FirstNumParameters != SecondNumParameters) {
-          ODRDiagError(FirstMethod->getLocation(),
-                       FirstMethod->getSourceRange(), MethodNumberParameters)
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(),
+                           MethodNumberParameters)
               << FirstMethodType << FirstName << FirstNumParameters;
-          ODRDiagNote(SecondMethod->getLocation(),
-                      SecondMethod->getSourceRange(), MethodNumberParameters)
+          ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(),
+                          MethodNumberParameters)
               << SecondMethodType << SecondName << SecondNumParameters;
           Diagnosed = true;
           break;
@@ -10326,27 +10477,31 @@ void ASTReader::diagnoseOdrViolations() {
                   ComputeQualTypeODRHash(SecondParamType)) {
             if (const DecayedType *ParamDecayedType =
                     FirstParamType->getAs<DecayedType>()) {
-              ODRDiagError(FirstMethod->getLocation(),
-                           FirstMethod->getSourceRange(), MethodParameterType)
+              ODRDiagDeclError(
+                  FirstRecord, FirstModule, FirstMethod->getLocation(),
+                  FirstMethod->getSourceRange(), MethodParameterType)
                   << FirstMethodType << FirstName << (I + 1) << FirstParamType
                   << true << ParamDecayedType->getOriginalType();
             } else {
-              ODRDiagError(FirstMethod->getLocation(),
-                           FirstMethod->getSourceRange(), MethodParameterType)
+              ODRDiagDeclError(
+                  FirstRecord, FirstModule, FirstMethod->getLocation(),
+                  FirstMethod->getSourceRange(), MethodParameterType)
                   << FirstMethodType << FirstName << (I + 1) << FirstParamType
                   << false;
             }
 
             if (const DecayedType *ParamDecayedType =
                     SecondParamType->getAs<DecayedType>()) {
-              ODRDiagNote(SecondMethod->getLocation(),
-                          SecondMethod->getSourceRange(), MethodParameterType)
+              ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                              SecondMethod->getSourceRange(),
+                              MethodParameterType)
                   << SecondMethodType << SecondName << (I + 1)
                   << SecondParamType << true
                   << ParamDecayedType->getOriginalType();
             } else {
-              ODRDiagNote(SecondMethod->getLocation(),
-                          SecondMethod->getSourceRange(), MethodParameterType)
+              ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                              SecondMethod->getSourceRange(),
+                              MethodParameterType)
                   << SecondMethodType << SecondName << (I + 1)
                   << SecondParamType << false;
             }
@@ -10357,11 +10512,12 @@ void ASTReader::diagnoseOdrViolations() {
           DeclarationName FirstParamName = FirstParam->getDeclName();
           DeclarationName SecondParamName = SecondParam->getDeclName();
           if (FirstParamName != SecondParamName) {
-            ODRDiagError(FirstMethod->getLocation(),
-                         FirstMethod->getSourceRange(), MethodParameterName)
+            ODRDiagDeclError(FirstRecord, FirstModule,
+                             FirstMethod->getLocation(),
+                             FirstMethod->getSourceRange(), MethodParameterName)
                 << FirstMethodType << FirstName << (I + 1) << FirstParamName;
-            ODRDiagNote(SecondMethod->getLocation(),
-                        SecondMethod->getSourceRange(), MethodParameterName)
+            ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                            SecondMethod->getSourceRange(), MethodParameterName)
                 << SecondMethodType << SecondName << (I + 1) << SecondParamName;
             ParameterMismatch = true;
             break;
@@ -10370,15 +10526,16 @@ void ASTReader::diagnoseOdrViolations() {
           const Expr *FirstInit = FirstParam->getInit();
           const Expr *SecondInit = SecondParam->getInit();
           if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
-            ODRDiagError(FirstMethod->getLocation(),
-                         FirstMethod->getSourceRange(),
-                         MethodParameterSingleDefaultArgument)
+            ODRDiagDeclError(FirstRecord, FirstModule,
+                             FirstMethod->getLocation(),
+                             FirstMethod->getSourceRange(),
+                             MethodParameterSingleDefaultArgument)
                 << FirstMethodType << FirstName << (I + 1)
                 << (FirstInit == nullptr)
                 << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
-            ODRDiagNote(SecondMethod->getLocation(),
-                        SecondMethod->getSourceRange(),
-                        MethodParameterSingleDefaultArgument)
+            ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                            SecondMethod->getSourceRange(),
+                            MethodParameterSingleDefaultArgument)
                 << SecondMethodType << SecondName << (I + 1)
                 << (SecondInit == nullptr)
                 << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
@@ -10388,14 +10545,15 @@ void ASTReader::diagnoseOdrViolations() {
 
           if (FirstInit && SecondInit &&
               ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
-            ODRDiagError(FirstMethod->getLocation(),
-                         FirstMethod->getSourceRange(),
-                         MethodParameterDifferentDefaultArgument)
+            ODRDiagDeclError(FirstRecord, FirstModule,
+                             FirstMethod->getLocation(),
+                             FirstMethod->getSourceRange(),
+                             MethodParameterDifferentDefaultArgument)
                 << FirstMethodType << FirstName << (I + 1)
                 << FirstInit->getSourceRange();
-            ODRDiagNote(SecondMethod->getLocation(),
-                        SecondMethod->getSourceRange(),
-                        MethodParameterDifferentDefaultArgument)
+            ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                            SecondMethod->getSourceRange(),
+                            MethodParameterDifferentDefaultArgument)
                 << SecondMethodType << SecondName << (I + 1)
                 << SecondInit->getSourceRange();
             ParameterMismatch = true;
@@ -10416,11 +10574,13 @@ void ASTReader::diagnoseOdrViolations() {
 
         if ((FirstTemplateArgs && !SecondTemplateArgs) ||
             (!FirstTemplateArgs && SecondTemplateArgs)) {
-          ODRDiagError(FirstMethod->getLocation(),
-                       FirstMethod->getSourceRange(), MethodNoTemplateArguments)
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(),
+                           MethodNoTemplateArguments)
               << FirstMethodType << FirstName << (FirstTemplateArgs != nullptr);
-          ODRDiagNote(SecondMethod->getLocation(),
-                      SecondMethod->getSourceRange(), MethodNoTemplateArguments)
+          ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(),
+                          MethodNoTemplateArguments)
               << SecondMethodType << SecondName
               << (SecondTemplateArgs != nullptr);
 
@@ -10450,14 +10610,15 @@ void ASTReader::diagnoseOdrViolations() {
               ExpandTemplateArgumentList(SecondTemplateArgs);
 
           if (FirstExpandedList.size() != SecondExpandedList.size()) {
-            ODRDiagError(FirstMethod->getLocation(),
-                         FirstMethod->getSourceRange(),
-                         MethodDifferentNumberTemplateArguments)
+            ODRDiagDeclError(FirstRecord, FirstModule,
+                             FirstMethod->getLocation(),
+                             FirstMethod->getSourceRange(),
+                             MethodDifferentNumberTemplateArguments)
                 << FirstMethodType << FirstName
                 << (unsigned)FirstExpandedList.size();
-            ODRDiagNote(SecondMethod->getLocation(),
-                        SecondMethod->getSourceRange(),
-                        MethodDifferentNumberTemplateArguments)
+            ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                            SecondMethod->getSourceRange(),
+                            MethodDifferentNumberTemplateArguments)
                 << SecondMethodType << SecondName
                 << (unsigned)SecondExpandedList.size();
 
@@ -10474,13 +10635,13 @@ void ASTReader::diagnoseOdrViolations() {
               continue;
             }
 
-            ODRDiagError(FirstMethod->getLocation(),
-                         FirstMethod->getSourceRange(),
-                         MethodDifferentTemplateArgument)
+            ODRDiagDeclError(
+                FirstRecord, FirstModule, FirstMethod->getLocation(),
+                FirstMethod->getSourceRange(), MethodDifferentTemplateArgument)
                 << FirstMethodType << FirstName << FirstTA << i + 1;
-            ODRDiagNote(SecondMethod->getLocation(),
-                        SecondMethod->getSourceRange(),
-                        MethodDifferentTemplateArgument)
+            ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                            SecondMethod->getSourceRange(),
+                            MethodDifferentTemplateArgument)
                 << SecondMethodType << SecondName << SecondTA << i + 1;
 
             TemplateArgumentMismatch = true;
@@ -10509,22 +10670,22 @@ void ASTReader::diagnoseOdrViolations() {
             ComputeCXXMethodODRHash(SecondMethod) != SecondMethod->getODRHash();
 
         if (HasFirstBody != HasSecondBody) {
-          ODRDiagError(FirstMethod->getLocation(),
-                       FirstMethod->getSourceRange(), MethodSingleBody)
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(), MethodSingleBody)
               << FirstMethodType << FirstName << HasFirstBody;
-          ODRDiagNote(SecondMethod->getLocation(),
-                      SecondMethod->getSourceRange(), MethodSingleBody)
+          ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(), MethodSingleBody)
               << SecondMethodType << SecondName << HasSecondBody;
           Diagnosed = true;
           break;
         }
 
         if (HasFirstBody && HasSecondBody) {
-          ODRDiagError(FirstMethod->getLocation(),
-                       FirstMethod->getSourceRange(), MethodDifferentBody)
+          ODRDiagDeclError(FirstRecord, FirstModule, FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(), MethodDifferentBody)
               << FirstMethodType << FirstName;
-          ODRDiagNote(SecondMethod->getLocation(),
-                      SecondMethod->getSourceRange(), MethodDifferentBody)
+          ODRDiagDeclNote(SecondModule, SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(), MethodDifferentBody)
               << SecondMethodType << SecondName;
           Diagnosed = true;
           break;
@@ -10534,105 +10695,16 @@ void ASTReader::diagnoseOdrViolations() {
       }
       case TypeAlias:
       case TypeDef: {
-        TypedefNameDecl *FirstTD = cast<TypedefNameDecl>(FirstDecl);
-        TypedefNameDecl *SecondTD = cast<TypedefNameDecl>(SecondDecl);
-        auto FirstName = FirstTD->getDeclName();
-        auto SecondName = SecondTD->getDeclName();
-        if (FirstName != SecondName) {
-          ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(),
-                       TypedefName)
-              << (FirstDiffType == TypeAlias) << FirstName;
-          ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(),
-                      TypedefName)
-              << (FirstDiffType == TypeAlias) << SecondName;
-          Diagnosed = true;
-          break;
-        }
-
-        QualType FirstType = FirstTD->getUnderlyingType();
-        QualType SecondType = SecondTD->getUnderlyingType();
-        if (ComputeQualTypeODRHash(FirstType) !=
-            ComputeQualTypeODRHash(SecondType)) {
-          ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(),
-                       TypedefType)
-              << (FirstDiffType == TypeAlias) << FirstName << FirstType;
-          ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(),
-                      TypedefType)
-              << (FirstDiffType == TypeAlias) << SecondName << SecondType;
-          Diagnosed = true;
-          break;
-        }
+        Diagnosed = ODRDiagTypeDefOrAlias(
+            FirstRecord, FirstModule, SecondModule,
+            cast<TypedefNameDecl>(FirstDecl), cast<TypedefNameDecl>(SecondDecl),
+            FirstDiffType == TypeAlias);
         break;
       }
       case Var: {
-        VarDecl *FirstVD = cast<VarDecl>(FirstDecl);
-        VarDecl *SecondVD = cast<VarDecl>(SecondDecl);
-        auto FirstName = FirstVD->getDeclName();
-        auto SecondName = SecondVD->getDeclName();
-        if (FirstName != SecondName) {
-          ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
-                       VarName)
-              << FirstName;
-          ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
-                      VarName)
-              << SecondName;
-          Diagnosed = true;
-          break;
-        }
-
-        QualType FirstType = FirstVD->getType();
-        QualType SecondType = SecondVD->getType();
-        if (ComputeQualTypeODRHash(FirstType) !=
-                        ComputeQualTypeODRHash(SecondType)) {
-          ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
-                       VarType)
-              << FirstName << FirstType;
-          ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
-                      VarType)
-              << SecondName << SecondType;
-          Diagnosed = true;
-          break;
-        }
-
-        const Expr *FirstInit = FirstVD->getInit();
-        const Expr *SecondInit = SecondVD->getInit();
-        if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
-          ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
-                       VarSingleInitializer)
-              << FirstName << (FirstInit == nullptr)
-              << (FirstInit ? FirstInit->getSourceRange(): SourceRange());
-          ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
-                      VarSingleInitializer)
-              << SecondName << (SecondInit == nullptr)
-              << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
-          Diagnosed = true;
-          break;
-        }
-
-        if (FirstInit && SecondInit &&
-            ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
-          ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
-                       VarDifferentInitializer)
-              << FirstName << FirstInit->getSourceRange();
-          ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
-                      VarDifferentInitializer)
-              << SecondName << SecondInit->getSourceRange();
-          Diagnosed = true;
-          break;
-        }
-
-        const bool FirstIsConstexpr = FirstVD->isConstexpr();
-        const bool SecondIsConstexpr = SecondVD->isConstexpr();
-        if (FirstIsConstexpr != SecondIsConstexpr) {
-          ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
-                       VarConstexpr)
-              << FirstName << FirstIsConstexpr;
-          ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
-                      VarConstexpr)
-              << SecondName << SecondIsConstexpr;
-          Diagnosed = true;
-          break;
-        }
+        Diagnosed =
+            ODRDiagVar(FirstRecord, FirstModule, SecondModule,
+                       cast<VarDecl>(FirstDecl), cast<VarDecl>(SecondDecl));
         break;
       }
       case Friend: {
@@ -10646,11 +10718,12 @@ void ASTReader::diagnoseOdrViolations() {
         TypeSourceInfo *SecondTSI = SecondFriend->getFriendType();
 
         if (FirstND && SecondND) {
-          ODRDiagError(FirstFriend->getFriendLoc(),
-                       FirstFriend->getSourceRange(), FriendFunction)
+          ODRDiagDeclError(FirstRecord, FirstModule,
+                           FirstFriend->getFriendLoc(),
+                           FirstFriend->getSourceRange(), FriendFunction)
               << FirstND;
-          ODRDiagNote(SecondFriend->getFriendLoc(),
-                      SecondFriend->getSourceRange(), FriendFunction)
+          ODRDiagDeclNote(SecondModule, SecondFriend->getFriendLoc(),
+                          SecondFriend->getSourceRange(), FriendFunction)
               << SecondND;
 
           Diagnosed = true;
@@ -10662,21 +10735,22 @@ void ASTReader::diagnoseOdrViolations() {
           QualType SecondFriendType = SecondTSI->getType();
           assert(ComputeQualTypeODRHash(FirstFriendType) !=
                  ComputeQualTypeODRHash(SecondFriendType));
-          ODRDiagError(FirstFriend->getFriendLoc(),
-                       FirstFriend->getSourceRange(), FriendType)
+          ODRDiagDeclError(FirstRecord, FirstModule,
+                           FirstFriend->getFriendLoc(),
+                           FirstFriend->getSourceRange(), FriendType)
               << FirstFriendType;
-          ODRDiagNote(SecondFriend->getFriendLoc(),
-                      SecondFriend->getSourceRange(), FriendType)
+          ODRDiagDeclNote(SecondModule, SecondFriend->getFriendLoc(),
+                          SecondFriend->getSourceRange(), FriendType)
               << SecondFriendType;
           Diagnosed = true;
           break;
         }
 
-        ODRDiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(),
-                     FriendTypeFunction)
+        ODRDiagDeclError(FirstRecord, FirstModule, FirstFriend->getFriendLoc(),
+                         FirstFriend->getSourceRange(), FriendTypeFunction)
             << (FirstTSI == nullptr);
-        ODRDiagNote(SecondFriend->getFriendLoc(),
-                    SecondFriend->getSourceRange(), FriendTypeFunction)
+        ODRDiagDeclNote(SecondModule, SecondFriend->getFriendLoc(),
+                        SecondFriend->getSourceRange(), FriendTypeFunction)
             << (SecondTSI == nullptr);
 
         Diagnosed = true;
@@ -10694,14 +10768,15 @@ void ASTReader::diagnoseOdrViolations() {
             SecondTemplate->getTemplateParameters();
 
         if (FirstTPL->size() != SecondTPL->size()) {
-          ODRDiagError(FirstTemplate->getLocation(),
-                       FirstTemplate->getSourceRange(),
-                       FunctionTemplateDifferentNumberParameters)
+          ODRDiagDeclError(FirstRecord, FirstModule,
+                           FirstTemplate->getLocation(),
+                           FirstTemplate->getSourceRange(),
+                           FunctionTemplateDifferentNumberParameters)
               << FirstTemplate << FirstTPL->size();
-          ODRDiagNote(SecondTemplate->getLocation(),
-                      SecondTemplate->getSourceRange(),
-                      FunctionTemplateDifferentNumberParameters)
-              << SecondTemplate  << SecondTPL->size();
+          ODRDiagDeclNote(SecondModule, SecondTemplate->getLocation(),
+                          SecondTemplate->getSourceRange(),
+                          FunctionTemplateDifferentNumberParameters)
+              << SecondTemplate << SecondTPL->size();
 
           Diagnosed = true;
           break;
@@ -10731,13 +10806,14 @@ void ASTReader::diagnoseOdrViolations() {
               }
             };
 
-            ODRDiagError(FirstTemplate->getLocation(),
-                         FirstTemplate->getSourceRange(),
-                         FunctionTemplateParameterDifferentKind)
+            ODRDiagDeclError(FirstRecord, FirstModule,
+                             FirstTemplate->getLocation(),
+                             FirstTemplate->getSourceRange(),
+                             FunctionTemplateParameterDifferentKind)
                 << FirstTemplate << (i + 1) << GetParamType(FirstParam);
-            ODRDiagNote(SecondTemplate->getLocation(),
-                        SecondTemplate->getSourceRange(),
-                        FunctionTemplateParameterDifferentKind)
+            ODRDiagDeclNote(SecondModule, SecondTemplate->getLocation(),
+                            SecondTemplate->getSourceRange(),
+                            FunctionTemplateParameterDifferentKind)
                 << SecondTemplate << (i + 1) << GetParamType(SecondParam);
 
             ParameterMismatch = true;
@@ -10745,14 +10821,14 @@ void ASTReader::diagnoseOdrViolations() {
           }
 
           if (FirstParam->getName() != SecondParam->getName()) {
-            ODRDiagError(FirstTemplate->getLocation(),
-                         FirstTemplate->getSourceRange(),
-                         FunctionTemplateParameterName)
+            ODRDiagDeclError(
+                FirstRecord, FirstModule, FirstTemplate->getLocation(),
+                FirstTemplate->getSourceRange(), FunctionTemplateParameterName)
                 << FirstTemplate << (i + 1) << (bool)FirstParam->getIdentifier()
                 << FirstParam;
-            ODRDiagNote(SecondTemplate->getLocation(),
-                        SecondTemplate->getSourceRange(),
-                        FunctionTemplateParameterName)
+            ODRDiagDeclNote(SecondModule, SecondTemplate->getLocation(),
+                            SecondTemplate->getSourceRange(),
+                            FunctionTemplateParameterName)
                 << SecondTemplate << (i + 1)
                 << (bool)SecondParam->getIdentifier() << SecondParam;
             ParameterMismatch = true;
@@ -10772,13 +10848,14 @@ void ASTReader::diagnoseOdrViolations() {
                 SecondTTPD->hasDefaultArgument() &&
                 !SecondTTPD->defaultArgumentWasInherited();
             if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
-              ODRDiagError(FirstTemplate->getLocation(),
-                           FirstTemplate->getSourceRange(),
-                           FunctionTemplateParameterSingleDefaultArgument)
+              ODRDiagDeclError(FirstRecord, FirstModule,
+                               FirstTemplate->getLocation(),
+                               FirstTemplate->getSourceRange(),
+                               FunctionTemplateParameterSingleDefaultArgument)
                   << FirstTemplate << (i + 1) << HasFirstDefaultArgument;
-              ODRDiagNote(SecondTemplate->getLocation(),
-                          SecondTemplate->getSourceRange(),
-                          FunctionTemplateParameterSingleDefaultArgument)
+              ODRDiagDeclNote(SecondModule, SecondTemplate->getLocation(),
+                              SecondTemplate->getSourceRange(),
+                              FunctionTemplateParameterSingleDefaultArgument)
                   << SecondTemplate << (i + 1) << HasSecondDefaultArgument;
               ParameterMismatch = true;
               break;
@@ -10789,13 +10866,15 @@ void ASTReader::diagnoseOdrViolations() {
               QualType SecondType = SecondTTPD->getDefaultArgument();
               if (ComputeQualTypeODRHash(FirstType) !=
                   ComputeQualTypeODRHash(SecondType)) {
-                ODRDiagError(FirstTemplate->getLocation(),
-                             FirstTemplate->getSourceRange(),
-                             FunctionTemplateParameterDifferentDefaultArgument)
+                ODRDiagDeclError(
+                    FirstRecord, FirstModule, FirstTemplate->getLocation(),
+                    FirstTemplate->getSourceRange(),
+                    FunctionTemplateParameterDifferentDefaultArgument)
                     << FirstTemplate << (i + 1) << FirstType;
-                ODRDiagNote(SecondTemplate->getLocation(),
-                            SecondTemplate->getSourceRange(),
-                            FunctionTemplateParameterDifferentDefaultArgument)
+                ODRDiagDeclNote(
+                    SecondModule, SecondTemplate->getLocation(),
+                    SecondTemplate->getSourceRange(),
+                    FunctionTemplateParameterDifferentDefaultArgument)
                     << SecondTemplate << (i + 1) << SecondType;
                 ParameterMismatch = true;
                 break;
@@ -10804,13 +10883,14 @@ void ASTReader::diagnoseOdrViolations() {
 
             if (FirstTTPD->isParameterPack() !=
                 SecondTTPD->isParameterPack()) {
-              ODRDiagError(FirstTemplate->getLocation(),
-                           FirstTemplate->getSourceRange(),
-                           FunctionTemplatePackParameter)
+              ODRDiagDeclError(FirstRecord, FirstModule,
+                               FirstTemplate->getLocation(),
+                               FirstTemplate->getSourceRange(),
+                               FunctionTemplatePackParameter)
                   << FirstTemplate << (i + 1) << FirstTTPD->isParameterPack();
-              ODRDiagNote(SecondTemplate->getLocation(),
-                          SecondTemplate->getSourceRange(),
-                          FunctionTemplatePackParameter)
+              ODRDiagDeclNote(SecondModule, SecondTemplate->getLocation(),
+                              SecondTemplate->getSourceRange(),
+                              FunctionTemplatePackParameter)
                   << SecondTemplate << (i + 1) << SecondTTPD->isParameterPack();
               ParameterMismatch = true;
               break;
@@ -10831,13 +10911,14 @@ void ASTReader::diagnoseOdrViolations() {
 
             if (ComputeTemplateParameterListODRHash(FirstTPL) !=
                 ComputeTemplateParameterListODRHash(SecondTPL)) {
-              ODRDiagError(FirstTemplate->getLocation(),
-                           FirstTemplate->getSourceRange(),
-                           FunctionTemplateParameterDifferentType)
+              ODRDiagDeclError(FirstRecord, FirstModule,
+                               FirstTemplate->getLocation(),
+                               FirstTemplate->getSourceRange(),
+                               FunctionTemplateParameterDifferentType)
                   << FirstTemplate << (i + 1);
-              ODRDiagNote(SecondTemplate->getLocation(),
-                          SecondTemplate->getSourceRange(),
-                          FunctionTemplateParameterDifferentType)
+              ODRDiagDeclNote(SecondModule, SecondTemplate->getLocation(),
+                              SecondTemplate->getSourceRange(),
+                              FunctionTemplateParameterDifferentType)
                   << SecondTemplate << (i + 1);
               ParameterMismatch = true;
               break;
@@ -10850,13 +10931,14 @@ void ASTReader::diagnoseOdrViolations() {
                 SecondTTPD->hasDefaultArgument() &&
                 !SecondTTPD->defaultArgumentWasInherited();
             if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
-              ODRDiagError(FirstTemplate->getLocation(),
-                           FirstTemplate->getSourceRange(),
-                           FunctionTemplateParameterSingleDefaultArgument)
+              ODRDiagDeclError(FirstRecord, FirstModule,
+                               FirstTemplate->getLocation(),
+                               FirstTemplate->getSourceRange(),
+                               FunctionTemplateParameterSingleDefaultArgument)
                   << FirstTemplate << (i + 1) << HasFirstDefaultArgument;
-              ODRDiagNote(SecondTemplate->getLocation(),
-                          SecondTemplate->getSourceRange(),
-                          FunctionTemplateParameterSingleDefaultArgument)
+              ODRDiagDeclNote(SecondModule, SecondTemplate->getLocation(),
+                              SecondTemplate->getSourceRange(),
+                              FunctionTemplateParameterSingleDefaultArgument)
                   << SecondTemplate << (i + 1) << HasSecondDefaultArgument;
               ParameterMismatch = true;
               break;
@@ -10869,13 +10951,15 @@ void ASTReader::diagnoseOdrViolations() {
                   SecondTTPD->getDefaultArgument().getArgument();
               if (ComputeTemplateArgumentODRHash(FirstTA) !=
                   ComputeTemplateArgumentODRHash(SecondTA)) {
-                ODRDiagError(FirstTemplate->getLocation(),
-                             FirstTemplate->getSourceRange(),
-                             FunctionTemplateParameterDifferentDefaultArgument)
+                ODRDiagDeclError(
+                    FirstRecord, FirstModule, FirstTemplate->getLocation(),
+                    FirstTemplate->getSourceRange(),
+                    FunctionTemplateParameterDifferentDefaultArgument)
                     << FirstTemplate << (i + 1) << FirstTA;
-                ODRDiagNote(SecondTemplate->getLocation(),
-                            SecondTemplate->getSourceRange(),
-                            FunctionTemplateParameterDifferentDefaultArgument)
+                ODRDiagDeclNote(
+                    SecondModule, SecondTemplate->getLocation(),
+                    SecondTemplate->getSourceRange(),
+                    FunctionTemplateParameterDifferentDefaultArgument)
                     << SecondTemplate << (i + 1) << SecondTA;
                 ParameterMismatch = true;
                 break;
@@ -10884,13 +10968,14 @@ void ASTReader::diagnoseOdrViolations() {
 
             if (FirstTTPD->isParameterPack() !=
                 SecondTTPD->isParameterPack()) {
-              ODRDiagError(FirstTemplate->getLocation(),
-                           FirstTemplate->getSourceRange(),
-                           FunctionTemplatePackParameter)
+              ODRDiagDeclError(FirstRecord, FirstModule,
+                               FirstTemplate->getLocation(),
+                               FirstTemplate->getSourceRange(),
+                               FunctionTemplatePackParameter)
                   << FirstTemplate << (i + 1) << FirstTTPD->isParameterPack();
-              ODRDiagNote(SecondTemplate->getLocation(),
-                          SecondTemplate->getSourceRange(),
-                          FunctionTemplatePackParameter)
+              ODRDiagDeclNote(SecondModule, SecondTemplate->getLocation(),
+                              SecondTemplate->getSourceRange(),
+                              FunctionTemplatePackParameter)
                   << SecondTemplate << (i + 1) << SecondTTPD->isParameterPack();
               ParameterMismatch = true;
               break;
@@ -10908,13 +10993,14 @@ void ASTReader::diagnoseOdrViolations() {
             QualType SecondType = SecondNTTPD->getType();
             if (ComputeQualTypeODRHash(FirstType) !=
                 ComputeQualTypeODRHash(SecondType)) {
-              ODRDiagError(FirstTemplate->getLocation(),
-                           FirstTemplate->getSourceRange(),
-                           FunctionTemplateParameterDifferentType)
+              ODRDiagDeclError(FirstRecord, FirstModule,
+                               FirstTemplate->getLocation(),
+                               FirstTemplate->getSourceRange(),
+                               FunctionTemplateParameterDifferentType)
                   << FirstTemplate << (i + 1);
-              ODRDiagNote(SecondTemplate->getLocation(),
-                          SecondTemplate->getSourceRange(),
-                          FunctionTemplateParameterDifferentType)
+              ODRDiagDeclNote(SecondModule, SecondTemplate->getLocation(),
+                              SecondTemplate->getSourceRange(),
+                              FunctionTemplateParameterDifferentType)
                   << SecondTemplate << (i + 1);
               ParameterMismatch = true;
               break;
@@ -10927,13 +11013,14 @@ void ASTReader::diagnoseOdrViolations() {
                 SecondNTTPD->hasDefaultArgument() &&
                 !SecondNTTPD->defaultArgumentWasInherited();
             if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
-              ODRDiagError(FirstTemplate->getLocation(),
-                           FirstTemplate->getSourceRange(),
-                           FunctionTemplateParameterSingleDefaultArgument)
+              ODRDiagDeclError(FirstRecord, FirstModule,
+                               FirstTemplate->getLocation(),
+                               FirstTemplate->getSourceRange(),
+                               FunctionTemplateParameterSingleDefaultArgument)
                   << FirstTemplate << (i + 1) << HasFirstDefaultArgument;
-              ODRDiagNote(SecondTemplate->getLocation(),
-                          SecondTemplate->getSourceRange(),
-                          FunctionTemplateParameterSingleDefaultArgument)
+              ODRDiagDeclNote(SecondModule, SecondTemplate->getLocation(),
+                              SecondTemplate->getSourceRange(),
+                              FunctionTemplateParameterSingleDefaultArgument)
                   << SecondTemplate << (i + 1) << HasSecondDefaultArgument;
               ParameterMismatch = true;
               break;
@@ -10944,13 +11031,15 @@ void ASTReader::diagnoseOdrViolations() {
               Expr *SecondDefaultArgument = SecondNTTPD->getDefaultArgument();
               if (ComputeODRHash(FirstDefaultArgument) !=
                   ComputeODRHash(SecondDefaultArgument)) {
-                ODRDiagError(FirstTemplate->getLocation(),
-                             FirstTemplate->getSourceRange(),
-                             FunctionTemplateParameterDifferentDefaultArgument)
+                ODRDiagDeclError(
+                    FirstRecord, FirstModule, FirstTemplate->getLocation(),
+                    FirstTemplate->getSourceRange(),
+                    FunctionTemplateParameterDifferentDefaultArgument)
                     << FirstTemplate << (i + 1) << FirstDefaultArgument;
-                ODRDiagNote(SecondTemplate->getLocation(),
-                            SecondTemplate->getSourceRange(),
-                            FunctionTemplateParameterDifferentDefaultArgument)
+                ODRDiagDeclNote(
+                    SecondModule, SecondTemplate->getLocation(),
+                    SecondTemplate->getSourceRange(),
+                    FunctionTemplateParameterDifferentDefaultArgument)
                     << SecondTemplate << (i + 1) << SecondDefaultArgument;
                 ParameterMismatch = true;
                 break;
@@ -10959,13 +11048,14 @@ void ASTReader::diagnoseOdrViolations() {
 
             if (FirstNTTPD->isParameterPack() !=
                 SecondNTTPD->isParameterPack()) {
-              ODRDiagError(FirstTemplate->getLocation(),
-                           FirstTemplate->getSourceRange(),
-                           FunctionTemplatePackParameter)
+              ODRDiagDeclError(FirstRecord, FirstModule,
+                               FirstTemplate->getLocation(),
+                               FirstTemplate->getSourceRange(),
+                               FunctionTemplatePackParameter)
                   << FirstTemplate << (i + 1) << FirstNTTPD->isParameterPack();
-              ODRDiagNote(SecondTemplate->getLocation(),
-                          SecondTemplate->getSourceRange(),
-                          FunctionTemplatePackParameter)
+              ODRDiagDeclNote(SecondModule, SecondTemplate->getLocation(),
+                              SecondTemplate->getSourceRange(),
+                              FunctionTemplatePackParameter)
                   << SecondTemplate << (i + 1)
                   << SecondNTTPD->isParameterPack();
               ParameterMismatch = true;


        


More information about the cfe-commits mailing list