summaryrefslogtreecommitdiffstats
path: root/clang/lib/Serialization/ASTReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Serialization/ASTReader.cpp')
-rw-r--r--clang/lib/Serialization/ASTReader.cpp193
1 files changed, 193 insertions, 0 deletions
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index eb49a90d721..55136e3a3ce 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -9274,6 +9274,199 @@ void ASTReader::diagnoseOdrViolations() {
std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord);
using DeclHashes = llvm::SmallVector<std::pair<Decl *, unsigned>, 4>;
+
+ const ClassTemplateDecl *FirstTemplate =
+ FirstRecord->getDescribedClassTemplate();
+ const ClassTemplateDecl *SecondTemplate =
+ SecondRecord->getDescribedClassTemplate();
+
+ assert(!FirstTemplate == !SecondTemplate &&
+ "Both pointers should be null or non-null");
+
+ enum ODRTemplateDifference {
+ ParamEmptyName,
+ ParamName,
+ ParamSingleDefaultArgument,
+ ParamDifferentDefaultArgument,
+ };
+
+ if (FirstTemplate && SecondTemplate) {
+ DeclHashes FirstTemplateHashes;
+ DeclHashes SecondTemplateHashes;
+ ODRHash Hash;
+
+ auto PopulateTemplateParameterHashs =
+ [&Hash](DeclHashes &Hashes, const ClassTemplateDecl *TD) {
+ for (auto *D : TD->getTemplateParameters()->asArray()) {
+ Hash.clear();
+ Hash.AddSubDecl(D);
+ Hashes.emplace_back(D, Hash.CalculateHash());
+ }
+ };
+
+ PopulateTemplateParameterHashs(FirstTemplateHashes, FirstTemplate);
+ PopulateTemplateParameterHashs(SecondTemplateHashes, SecondTemplate);
+
+ assert(FirstTemplateHashes.size() == SecondTemplateHashes.size() &&
+ "Number of template parameters should be equal.");
+
+ auto FirstIt = FirstTemplateHashes.begin();
+ auto FirstEnd = FirstTemplateHashes.end();
+ auto SecondIt = SecondTemplateHashes.begin();
+ for (; FirstIt != FirstEnd; ++FirstIt, ++SecondIt) {
+ if (FirstIt->second == SecondIt->second)
+ continue;
+
+ auto ODRDiagError = [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) {
+ return Diag(Loc, diag::note_module_odr_violation_template_parameter)
+ << SecondModule << Range << DiffType;
+ };
+
+ const NamedDecl* FirstDecl = cast<NamedDecl>(FirstIt->first);
+ const NamedDecl* SecondDecl = cast<NamedDecl>(SecondIt->first);
+
+ assert(FirstDecl->getKind() == SecondDecl->getKind() &&
+ "Parameter Decl's should be the same kind.");
+
+ DeclarationName FirstName = FirstDecl->getDeclName();
+ DeclarationName SecondName = SecondDecl->getDeclName();
+
+ if (FirstName != SecondName) {
+ const bool FirstNameEmpty =
+ FirstName.isIdentifier() && !FirstName.getAsIdentifierInfo();
+ const bool SecondNameEmpty =
+ SecondName.isIdentifier() && !SecondName.getAsIdentifierInfo();
+ assert((!FirstNameEmpty || !SecondNameEmpty) &&
+ "Both template parameters cannot be unnamed.");
+ ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(),
+ FirstNameEmpty ? ParamEmptyName : ParamName)
+ << FirstName;
+ ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(),
+ SecondNameEmpty ? ParamEmptyName : ParamName)
+ << SecondName;
+ break;
+ }
+
+ switch (FirstDecl->getKind()) {
+ default:
+ llvm_unreachable("Invalid template parameter type.");
+ case Decl::TemplateTypeParm: {
+ const auto *FirstParam = cast<TemplateTypeParmDecl>(FirstDecl);
+ const auto *SecondParam = cast<TemplateTypeParmDecl>(SecondDecl);
+ const bool HasFirstDefaultArgument =
+ FirstParam->hasDefaultArgument() &&
+ !FirstParam->defaultArgumentWasInherited();
+ const bool HasSecondDefaultArgument =
+ SecondParam->hasDefaultArgument() &&
+ !SecondParam->defaultArgumentWasInherited();
+
+ if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
+ ODRDiagError(FirstDecl->getLocation(),
+ FirstDecl->getSourceRange(),
+ ParamSingleDefaultArgument)
+ << HasFirstDefaultArgument;
+ ODRDiagNote(SecondDecl->getLocation(),
+ SecondDecl->getSourceRange(),
+ ParamSingleDefaultArgument)
+ << HasSecondDefaultArgument;
+ break;
+ }
+
+ assert(HasFirstDefaultArgument && HasSecondDefaultArgument &&
+ "Expecting default arguments.");
+
+ ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(),
+ ParamDifferentDefaultArgument);
+ ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(),
+ ParamDifferentDefaultArgument);
+
+ break;
+ }
+ case Decl::NonTypeTemplateParm: {
+ const auto *FirstParam = cast<NonTypeTemplateParmDecl>(FirstDecl);
+ const auto *SecondParam = cast<NonTypeTemplateParmDecl>(SecondDecl);
+ const bool HasFirstDefaultArgument =
+ FirstParam->hasDefaultArgument() &&
+ !FirstParam->defaultArgumentWasInherited();
+ const bool HasSecondDefaultArgument =
+ SecondParam->hasDefaultArgument() &&
+ !SecondParam->defaultArgumentWasInherited();
+
+ if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
+ ODRDiagError(FirstDecl->getLocation(),
+ FirstDecl->getSourceRange(),
+ ParamSingleDefaultArgument)
+ << HasFirstDefaultArgument;
+ ODRDiagNote(SecondDecl->getLocation(),
+ SecondDecl->getSourceRange(),
+ ParamSingleDefaultArgument)
+ << HasSecondDefaultArgument;
+ break;
+ }
+
+ assert(HasFirstDefaultArgument && HasSecondDefaultArgument &&
+ "Expecting default arguments.");
+
+ ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(),
+ ParamDifferentDefaultArgument);
+ ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(),
+ ParamDifferentDefaultArgument);
+
+ break;
+ }
+ case Decl::TemplateTemplateParm: {
+ const auto *FirstParam = cast<TemplateTemplateParmDecl>(FirstDecl);
+ const auto *SecondParam =
+ cast<TemplateTemplateParmDecl>(SecondDecl);
+ const bool HasFirstDefaultArgument =
+ FirstParam->hasDefaultArgument() &&
+ !FirstParam->defaultArgumentWasInherited();
+ const bool HasSecondDefaultArgument =
+ SecondParam->hasDefaultArgument() &&
+ !SecondParam->defaultArgumentWasInherited();
+
+ if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
+ ODRDiagError(FirstDecl->getLocation(),
+ FirstDecl->getSourceRange(),
+ ParamSingleDefaultArgument)
+ << HasFirstDefaultArgument;
+ ODRDiagNote(SecondDecl->getLocation(),
+ SecondDecl->getSourceRange(),
+ ParamSingleDefaultArgument)
+ << HasSecondDefaultArgument;
+ break;
+ }
+
+ assert(HasFirstDefaultArgument && HasSecondDefaultArgument &&
+ "Expecting default arguments.");
+
+ ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(),
+ ParamDifferentDefaultArgument);
+ ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(),
+ ParamDifferentDefaultArgument);
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ if (FirstIt != FirstEnd) {
+ Diagnosed = true;
+ break;
+ }
+ }
+
DeclHashes FirstHashes;
DeclHashes SecondHashes;
ODRHash Hash;
OpenPOWER on IntegriCloud