diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td index de52d994a8e0..0dfab4fc69e9 100644 --- a/clang/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td @@ -121,10 +121,10 @@ def err_module_odr_violation_mismatch_decl : Error< "%q0 has different definitions in different modules; first difference is " "%select{definition in module '%2'|defined here}1 found " "%select{end of class|public access specifier|private access specifier|" - "protected access specifier|static assert}3">; + "protected access specifier|static assert|field}3">; def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found " "%select{end of class|public access specifier|private access specifier|" - "protected access specifier|static assert}1">; + "protected access specifier|static assert|field}1">; def err_module_odr_violation_mismatch_decl_diff : Error< "%q0 has different definitions in different modules; first difference is " @@ -132,13 +132,15 @@ def err_module_odr_violation_mismatch_decl_diff : Error< "%select{" "static assert with condition|" "static assert with message|" - "static assert with %select{|no }4message}3">; + "static assert with %select{|no }4message|" + "field %4}3">; def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found " "%select{" "static assert with different condition|" "static assert with different message|" - "static assert with %select{|no }2message}1">; + "static assert with %select{|no }2message|" + "field %2}1">; def warn_module_uses_date_time : Warning< "%select{precompiled header|module}0 uses __DATE__ or __TIME__">, diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 9c6f38c2d9da..35af0e98a912 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -26,7 +26,12 @@ void ODRHash::AddStmt(const Stmt *S) { assert(S && "Expecting non-null pointer."); S->ProcessODRHash(ID, *this); } -void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) {} + +void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) { + assert(II && "Expecting non-null pointer."); + ID.AddString(II->getName()); +} + void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {} void ODRHash::AddTemplateName(TemplateName Name) {} void ODRHash::AddDeclarationName(DeclarationName Name) {} @@ -90,11 +95,23 @@ public: } } + void AddIdentifierInfo(const IdentifierInfo *II) { + Hash.AddBoolean(II); + if (II) { + Hash.AddIdentifierInfo(II); + } + } + void Visit(const Decl *D) { ID.AddInteger(D->getKind()); Inherited::Visit(D); } + void VisitNamedDecl(const NamedDecl *D) { + AddIdentifierInfo(D->getIdentifier()); + Inherited::VisitNamedDecl(D); + } + void VisitAccessSpecDecl(const AccessSpecDecl *D) { ID.AddInteger(D->getAccess()); Inherited::VisitAccessSpecDecl(D); @@ -106,6 +123,10 @@ public: Inherited::VisitStaticAssertDecl(D); } + + void VisitFieldDecl(const FieldDecl *D) { + Inherited::VisitFieldDecl(D); + } }; // Only allow a small portion of Decl's to be processed. Remove this once @@ -118,6 +139,7 @@ bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) { default: return false; case Decl::AccessSpec: + case Decl::Field: case Decl::StaticAssert: return true; } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 977cc115ca19..72d4c75b0631 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -8956,6 +8956,7 @@ void ASTReader::diagnoseOdrViolations() { PrivateSpecifer, ProtectedSpecifer, StaticAssert, + Field, Other } FirstDiffType = Other, SecondDiffType = Other; @@ -8979,6 +8980,8 @@ void ASTReader::diagnoseOdrViolations() { llvm_unreachable("Invalid access specifier"); case Decl::StaticAssert: return StaticAssert; + case Decl::Field: + return Field; } }; @@ -9058,6 +9061,7 @@ void ASTReader::diagnoseOdrViolations() { StaticAssertCondition, StaticAssertMessage, StaticAssertOnlyMessage, + FieldName, }; // These lambdas have the common portions of the ODR diagnostics. This @@ -9146,6 +9150,24 @@ void ASTReader::diagnoseOdrViolations() { } break; } + case Field: { + FieldDecl *FirstField = cast(FirstDecl); + FieldDecl *SecondField = cast(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; + } + break; + } } if (Diagnosed == true) diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp index 652e74f95695..2b2a788efc7b 100644 --- a/clang/test/Modules/odr_hash.cpp +++ b/clang/test/Modules/odr_hash.cpp @@ -115,6 +115,41 @@ S4 s4; #endif } +namespace Field { +#if defined(FIRST) +struct S1 { + int x; + private: + int y; +}; +#elif defined(SECOND) +struct S1 { + int x; + int y; +}; +#else +S1 s1; +// expected-error@second.h:* {{'Field::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found field}} +// expected-note@first.h:* {{but in 'FirstModule' found private access specifier}} +#endif + +#if defined(FIRST) +struct S2 { + int x; + int y; +}; +#elif defined(SECOND) +struct S2 { + int y; + int x; +}; +#else +S2 s2; +// expected-error@second.h:* {{'Field::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'y'}} +// expected-note@first.h:* {{but in 'FirstModule' found field 'x'}} +#endif +} // namespace Field + // Naive parsing of AST can lead to cycles in processing. Ensure // self-references don't trigger an endless cycles of AST node processing. namespace SelfReference { @@ -151,6 +186,9 @@ struct S { static_assert(1 == 1, "Message"); static_assert(2 == 2); + + int x; + double y; }; #elif defined(SECOND) struct S { @@ -160,6 +198,9 @@ struct S { static_assert(1 == 1, "Message"); static_assert(2 == 2); + + int x; + double y; }; #else S s; @@ -174,6 +215,9 @@ struct T { static_assert(1 == 1, "Message"); static_assert(2 == 2); + int x; + double y; + private: }; #elif defined(SECOND) @@ -185,6 +229,9 @@ struct T { static_assert(1 == 1, "Message"); static_assert(2 == 2); + int x; + double y; + public: }; #else