|
@@ -9274,6 +9274,199 @@ void ASTReader::diagnoseOdrViolations() {
|
|
|
|
|
|
std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord);
|
|
std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord);
|
|
using DeclHashes = llvm::SmallVector<std::pair<Decl *, unsigned>, 4>;
|
|
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 FirstHashes;
|
|
DeclHashes SecondHashes;
|
|
DeclHashes SecondHashes;
|
|
ODRHash Hash;
|
|
ODRHash Hash;
|