[clang] f33b5b1 - [ODRHash] Detect mismatches in anonymous `RecordDecl`.

Volodymyr Sapsai via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 19 13:59:58 PST 2023


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 at second-nested-struct.h:* {{'IndirectStruct::mismatchingField' from module 'Second' is not present in definition of 'struct IndirectStruct' in module 'First.Hidden'}}
 // expected-note at 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 at 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 at first-anonymous.h:* {{declaration of 'anonymousNestedUnionField' does not match}}
+#elif defined(CASE2)
+struct CompareAnonymousNestedStruct compareAnonymousNestedStruct;
+// expected-error-re at 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 at first-anonymous.h:* {{declaration of 'anonymousNestedStructField' does not match}}
+#elif defined(CASE3)
+struct CompareDeeplyNestedAnonymousUnionsAndStructs compareDeeplyNested;
+// expected-error-re at 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 at first-anonymous.h:* {{declaration of 'z' does not match}}
+#endif


        


More information about the cfe-commits mailing list