vsapsai created this revision. vsapsai added reviewers: bruno, jansvoboda11, ChuanqiXu. Herald added a subscriber: ributzka. Herald added a project: All. vsapsai requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
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 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D140055 Files: clang/lib/AST/RecordLayoutBuilder.cpp clang/lib/Serialization/ASTReader.cpp clang/test/Modules/compare-record.c
Index: clang/test/Modules/compare-record.c =================================================================== --- clang/test/Modules/compare-record.c +++ 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 different structs and unions with the same name // from multiple modules but detect mismatches and provide actionable // diagnostic. @@ -44,12 +53,14 @@ 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 @@ // 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 Index: clang/lib/Serialization/ASTReader.cpp =================================================================== --- clang/lib/Serialization/ASTReader.cpp +++ clang/lib/Serialization/ASTReader.cpp @@ -7301,7 +7301,7 @@ // // 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)) { Index: clang/lib/AST/RecordLayoutBuilder.cpp =================================================================== --- clang/lib/AST/RecordLayoutBuilder.cpp +++ clang/lib/AST/RecordLayoutBuilder.cpp @@ -3280,6 +3280,8 @@ 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!");
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits