r314581 - [ODRHash] Add base classes to hashing CXXRecordDecl.
Richard Trieu via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 29 19:19:17 PDT 2017
Author: rtrieu
Date: Fri Sep 29 19:19:17 2017
New Revision: 314581
URL: http://llvm.org/viewvc/llvm-project?rev=314581&view=rev
Log:
[ODRHash] Add base classes to hashing CXXRecordDecl.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td
cfe/trunk/include/clang/Serialization/ASTReader.h
cfe/trunk/lib/AST/ODRHash.cpp
cfe/trunk/lib/Serialization/ASTReader.cpp
cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
cfe/trunk/test/Modules/odr_hash.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td?rev=314581&r1=314580&r2=314581&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td Fri Sep 29 19:19:17 2017
@@ -122,6 +122,27 @@ def note_second_module_difference : Note
def err_module_odr_violation_different_instantiations : Error<
"instantiation of %q0 is different in different modules">;
+def err_module_odr_violation_definition_data : Error <
+ "%q0 has different definitions in different modules; first difference is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{"
+ "%4 base %plural{1:class|:classes}4|"
+ "%4 virtual base %plural{1:class|:classes}4|"
+ "%ordinal4 base class with type %5|"
+ "%ordinal4 %select{non-virtual|virtual}5 base class %6|"
+ "%ordinal4 base class %5 with "
+ "%select{public|protected|private|no}6 access specifier}3">;
+
+def note_module_odr_violation_definition_data : Note <
+ "but in '%0' found "
+ "%select{"
+ "%2 base %plural{1:class|:classes}2|"
+ "%2 virtual base %plural{1:class|:classes}2|"
+ "%ordinal2 base class with different type %3|"
+ "%ordinal2 %select{non-virtual|virtual}3 base class %4|"
+ "%ordinal2 base class %3 with "
+ "%select{public|protected|private|no}4 access specifier}1">;
+
def err_module_odr_violation_template_parameter : Error <
"%q0 has different definitions in different modules; first difference is "
"%select{definition in module '%2'|defined here}1 found "
Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=314581&r1=314580&r2=314581&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Fri Sep 29 19:19:17 2017
@@ -1043,8 +1043,11 @@ private:
/// once recursing loading has been completed.
llvm::SmallVector<NamedDecl *, 16> PendingOdrMergeChecks;
+ using DataPointers =
+ std::pair<CXXRecordDecl *, struct CXXRecordDecl::DefinitionData *>;
+
/// \brief Record definitions in which we found an ODR violation.
- llvm::SmallDenseMap<CXXRecordDecl *, llvm::TinyPtrVector<CXXRecordDecl *>, 2>
+ llvm::SmallDenseMap<CXXRecordDecl *, llvm::SmallVector<DataPointers, 2>, 2>
PendingOdrMergeFailures;
/// \brief DeclContexts in which we have diagnosed an ODR violation.
Modified: cfe/trunk/lib/AST/ODRHash.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ODRHash.cpp?rev=314581&r1=314580&r2=314581&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ODRHash.cpp (original)
+++ cfe/trunk/lib/AST/ODRHash.cpp Fri Sep 29 19:19:17 2017
@@ -456,6 +456,14 @@ void ODRHash::AddCXXRecordDecl(const CXX
if (TD) {
AddTemplateParameterList(TD->getTemplateParameters());
}
+
+ ID.AddInteger(Record->getNumBases());
+ auto Bases = Record->bases();
+ for (auto Base : Bases) {
+ AddQualType(Base.getType());
+ ID.AddInteger(Base.isVirtual());
+ ID.AddInteger(Base.getAccessSpecifierAsWritten());
+ }
}
void ODRHash::AddDecl(const Decl *D) {
Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=314581&r1=314580&r2=314581&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Fri Sep 29 19:19:17 2017
@@ -9190,7 +9190,8 @@ void ASTReader::diagnoseOdrViolations()
Merge.first->decls_begin();
Merge.first->bases_begin();
Merge.first->vbases_begin();
- for (auto *RD : Merge.second) {
+ for (auto &RecordPair : Merge.second) {
+ auto *RD = RecordPair.first;
RD->decls_begin();
RD->bases_begin();
RD->vbases_begin();
@@ -9296,13 +9297,132 @@ void ASTReader::diagnoseOdrViolations()
bool Diagnosed = false;
CXXRecordDecl *FirstRecord = Merge.first;
std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord);
- for (CXXRecordDecl *SecondRecord : Merge.second) {
+ for (auto &RecordPair : Merge.second) {
+ CXXRecordDecl *SecondRecord = RecordPair.first;
// Multiple different declarations got merged together; tell the user
// where they came from.
if (FirstRecord == SecondRecord)
continue;
std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord);
+
+ auto *FirstDD = FirstRecord->DefinitionData;
+ auto *SecondDD = RecordPair.second;
+
+ assert(FirstDD && SecondDD && "Definitions without DefinitionData");
+
+ // Diagnostics from DefinitionData are emitted here.
+ if (FirstDD != SecondDD) {
+ enum ODRDefinitionDataDifference {
+ NumBases,
+ NumVBases,
+ BaseType,
+ BaseVirtual,
+ BaseAccess,
+ };
+ auto ODRDiagError = [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) {
+ return Diag(Loc, diag::note_module_odr_violation_definition_data)
+ << SecondModule << Range << DiffType;
+ };
+
+ ODRHash Hash;
+ auto ComputeQualTypeODRHash = [&Hash](QualType Ty) {
+ Hash.clear();
+ Hash.AddQualType(Ty);
+ return Hash.CalculateHash();
+ };
+
+ unsigned FirstNumBases = FirstDD->NumBases;
+ unsigned FirstNumVBases = FirstDD->NumVBases;
+ unsigned SecondNumBases = SecondDD->NumBases;
+ unsigned SecondNumVBases = SecondDD->NumVBases;
+
+ auto GetSourceRange = [](struct CXXRecordDecl::DefinitionData *DD) {
+ unsigned NumBases = DD->NumBases;
+ if (NumBases == 0) return SourceRange();
+ auto bases = DD->bases();
+ return SourceRange(bases[0].getLocStart(),
+ bases[NumBases - 1].getLocEnd());
+ };
+
+ if (FirstNumBases != SecondNumBases) {
+ ODRDiagError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
+ NumBases)
+ << FirstNumBases;
+ ODRDiagNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
+ NumBases)
+ << SecondNumBases;
+ Diagnosed = true;
+ break;
+ }
+
+ if (FirstNumVBases != SecondNumVBases) {
+ ODRDiagError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
+ NumVBases)
+ << FirstNumVBases;
+ ODRDiagNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
+ NumVBases)
+ << SecondNumVBases;
+ Diagnosed = true;
+ break;
+ }
+
+ auto FirstBases = FirstDD->bases();
+ auto SecondBases = SecondDD->bases();
+ unsigned i = 0;
+ for (i = 0; i < FirstNumBases; ++i) {
+ auto FirstBase = FirstBases[i];
+ auto SecondBase = SecondBases[i];
+ if (ComputeQualTypeODRHash(FirstBase.getType()) !=
+ ComputeQualTypeODRHash(SecondBase.getType())) {
+ ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
+ BaseType)
+ << (i + 1) << FirstBase.getType();
+ ODRDiagNote(SecondRecord->getLocation(),
+ SecondBase.getSourceRange(), BaseType)
+ << (i + 1) << SecondBase.getType();
+ break;
+ }
+
+ if (FirstBase.isVirtual() != SecondBase.isVirtual()) {
+ ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
+ BaseVirtual)
+ << (i + 1) << FirstBase.isVirtual() << FirstBase.getType();
+ ODRDiagNote(SecondRecord->getLocation(),
+ SecondBase.getSourceRange(), BaseVirtual)
+ << (i + 1) << SecondBase.isVirtual() << SecondBase.getType();
+ break;
+ }
+
+ if (FirstBase.getAccessSpecifierAsWritten() !=
+ SecondBase.getAccessSpecifierAsWritten()) {
+ ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
+ BaseAccess)
+ << (i + 1) << FirstBase.getType()
+ << (int)FirstBase.getAccessSpecifierAsWritten();
+ ODRDiagNote(SecondRecord->getLocation(),
+ SecondBase.getSourceRange(), BaseAccess)
+ << (i + 1) << SecondBase.getType()
+ << (int)SecondBase.getAccessSpecifierAsWritten();
+ break;
+ }
+ }
+
+ if (i != FirstNumBases) {
+ Diagnosed = true;
+ break;
+ }
+ }
+
using DeclHashes = llvm::SmallVector<std::pair<Decl *, unsigned>, 4>;
const ClassTemplateDecl *FirstTemplate =
Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=314581&r1=314580&r2=314581&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Fri Sep 29 19:19:17 2017
@@ -1755,7 +1755,8 @@ void ASTDeclReader::MergeDefinitionData(
}
if (DetectedOdrViolation)
- Reader.PendingOdrMergeFailures[DD.Definition].push_back(MergeDD.Definition);
+ Reader.PendingOdrMergeFailures[DD.Definition].push_back(
+ {MergeDD.Definition, &MergeDD});
}
void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update) {
Modified: cfe/trunk/test/Modules/odr_hash.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/odr_hash.cpp?rev=314581&r1=314580&r2=314581&view=diff
==============================================================================
--- cfe/trunk/test/Modules/odr_hash.cpp (original)
+++ cfe/trunk/test/Modules/odr_hash.cpp Fri Sep 29 19:19:17 2017
@@ -1577,6 +1577,126 @@ using TemplateParameters::S6;
#endif
} // namespace TemplateParameters
+namespace BaseClass {
+#if defined(FIRST)
+struct B1 {};
+struct S1 : B1 {};
+#elif defined(SECOND)
+struct S1 {};
+#else
+S1 s1;
+// expected-error at second.h:* {{'BaseClass::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found 0 base classes}}
+// expected-note at first.h:* {{but in 'FirstModule' found 1 base class}}
+#endif
+
+#if defined(FIRST)
+struct S2 {};
+#elif defined(SECOND)
+struct B2 {};
+struct S2 : virtual B2 {};
+#else
+S2 s2;
+// expected-error at second.h:* {{'BaseClass::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1 base class}}
+// expected-note at first.h:* {{but in 'FirstModule' found 0 base classes}}
+#endif
+
+#if defined(FIRST)
+struct B3a {};
+struct S3 : B3a {};
+#elif defined(SECOND)
+struct B3b {};
+struct S3 : virtual B3b {};
+#else
+S3 s3;
+// expected-error at second.h:* {{'BaseClass::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1 virtual base class}}
+// expected-note at first.h:* {{but in 'FirstModule' found 0 virtual base classes}}
+#endif
+
+#if defined(FIRST)
+struct B4a {};
+struct S4 : B4a {};
+#elif defined(SECOND)
+struct B4b {};
+struct S4 : B4b {};
+#else
+S4 s4;
+// expected-error at second.h:* {{'BaseClass::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class with type 'BaseClass::B4b'}}
+// expected-note at first.h:* {{but in 'FirstModule' found 1st base class with different type 'BaseClass::B4a'}}
+#endif
+
+#if defined(FIRST)
+struct B5a {};
+struct S5 : virtual B5a {};
+#elif defined(SECOND)
+struct B5a {};
+struct S5 : B5a {};
+#else
+S5 s5;
+// expected-error at second.h:* {{'BaseClass::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found 0 virtual base classes}}
+// expected-note at first.h:* {{but in 'FirstModule' found 1 virtual base class}}
+#endif
+
+#if defined(FIRST)
+struct B6a {};
+struct S6 : B6a {};
+#elif defined(SECOND)
+struct B6a {};
+struct S6 : virtual B6a {};
+#else
+S6 s6;
+// expected-error at second.h:* {{'BaseClass::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1 virtual base class}}
+// expected-note at first.h:* {{but in 'FirstModule' found 0 virtual base classes}}
+#endif
+
+#if defined(FIRST)
+struct B7a {};
+struct S7 : protected B7a {};
+#elif defined(SECOND)
+struct B7a {};
+struct S7 : B7a {};
+#else
+S7 s7;
+// expected-error at second.h:* {{'BaseClass::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class 'BaseClass::B7a' with no access specifier}}
+// expected-note at first.h:* {{but in 'FirstModule' found 1st base class 'BaseClass::B7a' with protected access specifier}}
+#endif
+
+#if defined(FIRST)
+struct B8a {};
+struct S8 : public B8a {};
+#elif defined(SECOND)
+struct B8a {};
+struct S8 : private B8a {};
+#else
+S8 s8;
+// expected-error at second.h:* {{'BaseClass::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class 'BaseClass::B8a' with private access specifier}}
+// expected-note at first.h:* {{but in 'FirstModule' found 1st base class 'BaseClass::B8a' with public access specifier}}
+#endif
+
+#if defined(FIRST)
+struct B9a {};
+struct S9 : private B9a {};
+#elif defined(SECOND)
+struct B9a {};
+struct S9 : public B9a {};
+#else
+S9 s9;
+// expected-error at second.h:* {{'BaseClass::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class 'BaseClass::B9a' with public access specifier}}
+// expected-note at first.h:* {{but in 'FirstModule' found 1st base class 'BaseClass::B9a' with private access specifier}}
+#endif
+
+#if defined(FIRST)
+struct B10a {};
+struct S10 : B10a {};
+#elif defined(SECOND)
+struct B10a {};
+struct S10 : protected B10a {};
+#else
+S10 s10;
+// expected-error at second.h:* {{'BaseClass::S10' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class 'BaseClass::B10a' with protected access specifier}}
+// expected-note at first.h:* {{but in 'FirstModule' found 1st base class 'BaseClass::B10a' with no access specifier}}
+#endif
+} // namespace BaseClass
+
// Interesting cases that should not cause errors. struct S should not error
// while struct T should error at the access specifier mismatch at the end.
namespace AllDecls {
More information about the cfe-commits
mailing list