[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