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

Reply via email to