Author: Volodymyr Sapsai Date: 2023-01-19T15:58:31-06:00 New Revision: f33b5b1bf703ee5ff73126fefe2a9bcbd54db457
URL: https://github.com/llvm/llvm-project/commit/f33b5b1bf703ee5ff73126fefe2a9bcbd54db457 DIFF: https://github.com/llvm/llvm-project/commit/f33b5b1bf703ee5ff73126fefe2a9bcbd54db457.diff LOG: [ODRHash] Detect mismatches in anonymous `RecordDecl`. Allow completing a redeclaration check for anonymous structs/unions inside `RecordDecl`, so we deserialize and compare anonymous entities from different modules. Completing the redeclaration chain for `RecordDecl` in `ASTContext::getASTRecordLayout` mimics the behavior in `CXXRecordDecl::dataPtr`. Instead of completing the redeclaration chain every time we request a definition, do that right before we need a complete definition in `ASTContext::getASTRecordLayout`. Such code is required only for anonymous `RecordDecl` because we deserialize named decls when we look them up by name. But it doesn't work for anonymous decls as they don't have a name. That's why need to force deserialization of anonymous decls in a different way. rdar://81864186 Differential Revision: https://reviews.llvm.org/D140055 Added: Modified: clang/lib/AST/RecordLayoutBuilder.cpp clang/lib/Serialization/ASTReader.cpp clang/test/Modules/compare-record.c Removed: ################################################################################ diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 52bd3f20221f4..da27f73ea94e2 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -3280,6 +3280,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { if (D->hasExternalLexicalStorage() && !D->getDefinition()) getExternalSource()->CompleteType(const_cast<RecordDecl*>(D)); + // Complete the redecl chain (if necessary). + (void)D->getMostRecentDecl(); D = D->getDefinition(); assert(D && "Cannot get layout of forward declarations!"); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 77f29f6be4063..88d548a45b37d 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7301,7 +7301,7 @@ void ASTReader::CompleteRedeclChain(const Decl *D) { // // FIXME: Merging a function definition should merge // all mergeable entities within it. - if (isa<TranslationUnitDecl, NamespaceDecl, CXXRecordDecl, EnumDecl>(DC)) { + if (isa<TranslationUnitDecl, NamespaceDecl, RecordDecl, EnumDecl>(DC)) { if (DeclarationName Name = cast<NamedDecl>(D)->getDeclName()) { if (!getContext().getLangOpts().CPlusPlus && isa<TranslationUnitDecl>(DC)) { diff --git a/clang/test/Modules/compare-record.c b/clang/test/Modules/compare-record.c index 23dbe8191a343..a07843341296d 100644 --- a/clang/test/Modules/compare-record.c +++ b/clang/test/Modules/compare-record.c @@ -31,6 +31,15 @@ // REDEFINE: %{macro_flag} = -DCASE3=1 // RUN: %{command} +// Run tests for anonymous nested structs and unions +// REDEFINE: %{filename} = test-anonymous.c +// REDEFINE: %{macro_flag} = -DCASE1=1 +// RUN: %{command} +// REDEFINE: %{macro_flag} = -DCASE2=1 +// RUN: %{command} +// REDEFINE: %{macro_flag} = -DCASE3=1 +// RUN: %{command} + // Test that we don't accept diff erent structs and unions with the same name // from multiple modules but detect mismatches and provide actionable // diagnostic. @@ -44,12 +53,14 @@ module First { module Hidden { header "first.h" header "first-nested-struct.h" + header "first-anonymous.h" export * } } module Second { header "second.h" header "second-nested-struct.h" + header "second-anonymous.h" export * } @@ -416,3 +427,71 @@ struct CompareIndirectStructPointer compareIndirectStructPointer; // expected-error@second-nested-struct.h:* {{'IndirectStruct::mismatchingField' from module 'Second' is not present in definition of 'struct IndirectStruct' in module 'First.Hidden'}} // expected-note@first-nested-struct.h:* {{declaration of 'mismatchingField' does not match}} #endif + +//--- include/first-anonymous.h +struct CompareAnonymousNestedUnion { + union { + int anonymousNestedUnionField; + }; +}; + +struct CompareAnonymousNestedStruct { + struct { + int anonymousNestedStructField; + }; +}; + +struct CompareDeeplyNestedAnonymousUnionsAndStructs { + union { + int x; + union { + int y; + struct { + int z; + }; + }; + }; +}; + +//--- include/second-anonymous.h +struct CompareAnonymousNestedUnion { + union { + float anonymousNestedUnionField; + }; +}; + +struct CompareAnonymousNestedStruct { + struct { + float anonymousNestedStructField; + }; +}; + +struct CompareDeeplyNestedAnonymousUnionsAndStructs { + union { + int x; + union { + int y; + struct { + float z; + }; + }; + }; +}; + +//--- test-anonymous.c +#include "first-empty.h" +#include "second-anonymous.h" + +#if defined(CASE1) +struct CompareAnonymousNestedUnion compareAnonymousNestedUnion; +// expected-error-re@second-anonymous.h:* {{'CompareAnonymousNestedUnion::(anonymous union)::anonymousNestedUnionField' from module 'Second' is not present in definition of 'union CompareAnonymousNestedUnion::(anonymous at {{.*}})' in module 'First.Hidden'}} +// expected-note@first-anonymous.h:* {{declaration of 'anonymousNestedUnionField' does not match}} +#elif defined(CASE2) +struct CompareAnonymousNestedStruct compareAnonymousNestedStruct; +// expected-error-re@second-anonymous.h:* {{'CompareAnonymousNestedStruct::(anonymous struct)::anonymousNestedStructField' from module 'Second' is not present in definition of 'struct CompareAnonymousNestedStruct::(anonymous at {{.*}})' in module 'First.Hidden'}} +// expected-note@first-anonymous.h:* {{declaration of 'anonymousNestedStructField' does not match}} +#elif defined(CASE3) +struct CompareDeeplyNestedAnonymousUnionsAndStructs compareDeeplyNested; +// expected-error-re@second-anonymous.h:* {{'CompareDeeplyNestedAnonymousUnionsAndStructs::(anonymous union)::(anonymous union)::(anonymous struct)::z' from module 'Second' is not present in definition of 'struct CompareDeeplyNestedAnonymousUnionsAndStructs::(anonymous at {{.*}})' in module 'First.Hidden'}} +// expected-note@first-anonymous.h:* {{declaration of 'z' does not match}} +#endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits