mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 14:56:07 +00:00

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
498 lines
17 KiB
C
498 lines
17 KiB
C
// RUN: rm -rf %t
|
|
// RUN: split-file %s %t
|
|
|
|
// Build first header file
|
|
// RUN: echo "#define FIRST" >> %t/include/first.h
|
|
// RUN: cat %t/test.c >> %t/include/first.h
|
|
// RUN: echo "#undef FIRST" >> %t/include/first.h
|
|
|
|
// Build second header file
|
|
// RUN: echo "#define SECOND" >> %t/include/second.h
|
|
// RUN: cat %t/test.c >> %t/include/second.h
|
|
// RUN: echo "#undef SECOND" >> %t/include/second.h
|
|
|
|
// Test that each header can compile
|
|
// RUN: %clang_cc1 -fsyntax-only -x objective-c %t/include/first.h -fblocks -fobjc-arc
|
|
// RUN: %clang_cc1 -fsyntax-only -x objective-c %t/include/second.h -fblocks -fobjc-arc
|
|
|
|
// Run test
|
|
// RUN: %clang_cc1 -I%t/include -verify %t/test.c -fblocks -fobjc-arc \
|
|
// RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache
|
|
|
|
// Run tests for nested structs
|
|
// DEFINE: %{filename} = test-nested-struct.c
|
|
// DEFINE: %{macro_flag} = -DCASE1=1
|
|
// DEFINE: %{command} = %clang_cc1 -I%t/include -verify %t/%{filename} -fblocks -fobjc-arc \
|
|
// DEFINE: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache \
|
|
// DEFINE: %{macro_flag} -emit-llvm -o %t/%{filename}.bc
|
|
// RUN: %{command}
|
|
// REDEFINE: %{macro_flag} = -DCASE2=1
|
|
// RUN: %{command}
|
|
// 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.
|
|
|
|
//--- include/first-empty.h
|
|
//--- include/module.modulemap
|
|
module First {
|
|
module Empty {
|
|
header "first-empty.h"
|
|
}
|
|
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 *
|
|
}
|
|
|
|
//--- test.c
|
|
#if !defined(FIRST) && !defined(SECOND)
|
|
# include "first-empty.h"
|
|
# include "second.h"
|
|
#endif
|
|
|
|
#if defined(FIRST)
|
|
struct CompareForwardDeclaration1;
|
|
struct CompareForwardDeclaration2 {};
|
|
#elif defined(SECOND)
|
|
struct CompareForwardDeclaration1 {};
|
|
struct CompareForwardDeclaration2;
|
|
#else
|
|
struct CompareForwardDeclaration1 *compareForwardDeclaration1;
|
|
struct CompareForwardDeclaration2 *compareForwardDeclaration2;
|
|
#endif
|
|
|
|
#if defined(FIRST)
|
|
struct CompareMatchingFields {
|
|
int matchingFieldName;
|
|
};
|
|
|
|
struct CompareFieldPresence1 {
|
|
int fieldPresence1;
|
|
};
|
|
struct CompareFieldPresence2 {};
|
|
|
|
struct CompareFieldName {
|
|
int fieldNameA;
|
|
};
|
|
|
|
struct CompareFieldOrder {
|
|
int fieldOrderX;
|
|
int fieldOrderY;
|
|
};
|
|
#elif defined(SECOND)
|
|
struct CompareMatchingFields {
|
|
int matchingFieldName;
|
|
};
|
|
|
|
struct CompareFieldPresence1 {
|
|
};
|
|
struct CompareFieldPresence2 {
|
|
int fieldPresence2;
|
|
};
|
|
|
|
struct CompareFieldName {
|
|
int fieldNameB;
|
|
};
|
|
|
|
struct CompareFieldOrder {
|
|
int fieldOrderY;
|
|
int fieldOrderX;
|
|
};
|
|
#else
|
|
struct CompareMatchingFields compareMatchingFields;
|
|
struct CompareFieldPresence1 compareFieldPresence1;
|
|
// expected-error@first.h:* {{'CompareFieldPresence1' has different definitions in different modules; first difference is definition in module 'First.Hidden' found field}}
|
|
// expected-note@second.h:* {{but in 'Second' found end of class}}
|
|
struct CompareFieldPresence2 compareFieldPresence2;
|
|
// expected-error@second.h:* {{'CompareFieldPresence2::fieldPresence2' from module 'Second' is not present in definition of 'struct CompareFieldPresence2' in module 'First.Hidden'}}
|
|
// expected-note@first.h:* {{definition has no member 'fieldPresence2'}}
|
|
struct CompareFieldName compareFieldName;
|
|
// expected-error@second.h:* {{'CompareFieldName::fieldNameB' from module 'Second' is not present in definition of 'struct CompareFieldName' in module 'First.Hidden'}}
|
|
// expected-note@first.h:* {{definition has no member 'fieldNameB'}}
|
|
struct CompareFieldOrder compareFieldOrder;
|
|
// expected-error@first.h:* {{'CompareFieldOrder' has different definitions in different modules; first difference is definition in module 'First.Hidden' found field 'fieldOrderX'}}
|
|
// expected-note@second.h:* {{but in 'Second' found field 'fieldOrderY'}}
|
|
#endif
|
|
|
|
#if defined(FIRST)
|
|
struct CompareFieldType {
|
|
int fieldType;
|
|
};
|
|
|
|
typedef int FieldTypedefNameA;
|
|
struct CompareFieldTypedefName {
|
|
FieldTypedefNameA fieldTypedefName;
|
|
};
|
|
|
|
typedef int TypedefUnderlyingType;
|
|
struct CompareFieldTypeUnderlyingTypedef {
|
|
TypedefUnderlyingType fieldTypeUnderlyingTypedef;
|
|
};
|
|
|
|
typedef int TypedefFinal;
|
|
struct CompareFieldTypedefChain {
|
|
TypedefFinal fieldTypeTypedefChain;
|
|
};
|
|
#elif defined(SECOND)
|
|
struct CompareFieldType {
|
|
float fieldType;
|
|
};
|
|
|
|
typedef int FieldTypedefNameB;
|
|
struct CompareFieldTypedefName {
|
|
FieldTypedefNameB fieldTypedefName;
|
|
};
|
|
|
|
struct CompareFieldTypeUnderlyingTypedef {
|
|
int fieldTypeUnderlyingTypedef;
|
|
};
|
|
|
|
typedef int TypedefIntermediate;
|
|
typedef TypedefIntermediate TypedefFinal;
|
|
struct CompareFieldTypedefChain {
|
|
TypedefFinal fieldTypeTypedefChain;
|
|
};
|
|
#else
|
|
struct CompareFieldType compareFieldType;
|
|
// expected-error@second.h:* {{'CompareFieldType::fieldType' from module 'Second' is not present in definition of 'struct CompareFieldType' in module 'First.Hidden'}}
|
|
// expected-note@first.h:* {{declaration of 'fieldType' does not match}}
|
|
struct CompareFieldTypedefName compareFieldTypedefName;
|
|
// expected-error@first.h:* {{'CompareFieldTypedefName' has different definitions in different modules; first difference is definition in module 'First.Hidden' found field 'fieldTypedefName' with type 'FieldTypedefNameA' (aka 'int')}}
|
|
// expected-note@second.h:* {{but in 'Second' found field 'fieldTypedefName' with type 'FieldTypedefNameB' (aka 'int')}}
|
|
struct CompareFieldTypeUnderlyingTypedef compareFieldTypeUnderlyingTypedef;
|
|
// expected-error@first.h:* {{'CompareFieldTypeUnderlyingTypedef' has different definitions in different modules; first difference is definition in module 'First.Hidden' found field 'fieldTypeUnderlyingTypedef' with type 'TypedefUnderlyingType' (aka 'int')}}
|
|
// expected-note@second.h:* {{but in 'Second' found field 'fieldTypeUnderlyingTypedef' with type 'int'}}
|
|
struct CompareFieldTypedefChain compareFieldTypedefChain;
|
|
#endif
|
|
|
|
#if defined(FIRST)
|
|
struct CompareMatchingBitfields {
|
|
unsigned matchingBitfields : 3;
|
|
};
|
|
|
|
struct CompareBitfieldPresence1 {
|
|
unsigned bitfieldPresence1 : 1;
|
|
};
|
|
struct CompareBitfieldPresence2 {
|
|
unsigned bitfieldPresence2;
|
|
};
|
|
|
|
struct CompareBitfieldWidth {
|
|
unsigned bitfieldWidth : 2;
|
|
};
|
|
|
|
struct CompareBitfieldWidthExpression {
|
|
unsigned bitfieldWidthExpression : 1 + 1;
|
|
};
|
|
#elif defined(SECOND)
|
|
struct CompareMatchingBitfields {
|
|
unsigned matchingBitfields : 3;
|
|
};
|
|
|
|
struct CompareBitfieldPresence1 {
|
|
unsigned bitfieldPresence1;
|
|
};
|
|
struct CompareBitfieldPresence2 {
|
|
unsigned bitfieldPresence2 : 1;
|
|
};
|
|
|
|
struct CompareBitfieldWidth {
|
|
unsigned bitfieldWidth : 1;
|
|
};
|
|
|
|
struct CompareBitfieldWidthExpression {
|
|
unsigned bitfieldWidthExpression : 2;
|
|
};
|
|
#else
|
|
struct CompareMatchingBitfields compareMatchingBitfields;
|
|
struct CompareBitfieldPresence1 compareBitfieldPresence1;
|
|
// expected-error@first.h:* {{'CompareBitfieldPresence1' has different definitions in different modules; first difference is definition in module 'First.Hidden' found bitfield 'bitfieldPresence1'}}
|
|
// expected-note@second.h:* {{but in 'Second' found non-bitfield 'bitfieldPresence1'}}
|
|
struct CompareBitfieldPresence2 compareBitfieldPresence2;
|
|
// expected-error@first.h:* {{'CompareBitfieldPresence2' has different definitions in different modules; first difference is definition in module 'First.Hidden' found non-bitfield 'bitfieldPresence2'}}
|
|
// expected-note@second.h:* {{but in 'Second' found bitfield 'bitfieldPresence2'}}
|
|
struct CompareBitfieldWidth compareBitfieldWidth;
|
|
// expected-error@first.h:* {{'CompareBitfieldWidth' has different definitions in different modules; first difference is definition in module 'First.Hidden' found bitfield 'bitfieldWidth' with one width expression}}
|
|
// expected-note@second.h:* {{but in 'Second' found bitfield 'bitfieldWidth' with different width expression}}
|
|
struct CompareBitfieldWidthExpression compareBitfieldWidthExpression;
|
|
// expected-error@first.h:* {{'CompareBitfieldWidthExpression' has different definitions in different modules; first difference is definition in module 'First.Hidden' found bitfield 'bitfieldWidthExpression' with one width expression}}
|
|
// expected-note@second.h:* {{but in 'Second' found bitfield 'bitfieldWidthExpression' with different width expressio}}
|
|
#endif
|
|
|
|
#if defined(FIRST)
|
|
struct CompareMatchingArrayFields {
|
|
int matchingArrayField[7];
|
|
};
|
|
|
|
struct CompareArrayLength {
|
|
int arrayLengthField[5];
|
|
};
|
|
|
|
struct CompareArrayType {
|
|
int arrayTypeField[5];
|
|
};
|
|
#elif defined(SECOND)
|
|
struct CompareMatchingArrayFields {
|
|
int matchingArrayField[7];
|
|
};
|
|
|
|
struct CompareArrayLength {
|
|
int arrayLengthField[7];
|
|
};
|
|
|
|
struct CompareArrayType {
|
|
float arrayTypeField[5];
|
|
};
|
|
#else
|
|
struct CompareMatchingArrayFields compareMatchingArrayFields;
|
|
struct CompareArrayLength compareArrayLength;
|
|
// expected-error@second.h:* {{'CompareArrayLength::arrayLengthField' from module 'Second' is not present in definition of 'struct CompareArrayLength' in module 'First.Hidden'}}
|
|
// expected-note@first.h:* {{declaration of 'arrayLengthField' does not match}}
|
|
struct CompareArrayType compareArrayType;
|
|
// expected-error@second.h:* {{'CompareArrayType::arrayTypeField' from module 'Second' is not present in definition of 'struct CompareArrayType' in module 'First.Hidden'}}
|
|
// expected-note@first.h:* {{declaration of 'arrayTypeField' does not match}}
|
|
#endif
|
|
|
|
#if defined(FIRST)
|
|
struct CompareFieldAsForwardDeclaration {
|
|
struct FieldForwardDeclaration *fieldForwardDeclaration;
|
|
};
|
|
|
|
enum FieldEnumA { kFieldEnumValue };
|
|
struct CompareFieldAsEnum {
|
|
enum FieldEnumA fieldEnum;
|
|
};
|
|
|
|
struct FieldStructA {};
|
|
struct CompareFieldAsStruct {
|
|
struct FieldStructA fieldStruct;
|
|
};
|
|
#elif defined(SECOND)
|
|
struct FieldForwardDeclaration {};
|
|
struct CompareFieldAsForwardDeclaration {
|
|
struct FieldForwardDeclaration *fieldForwardDeclaration;
|
|
};
|
|
|
|
enum FieldEnumB { kFieldEnumValue };
|
|
struct CompareFieldAsEnum {
|
|
enum FieldEnumB fieldEnum;
|
|
};
|
|
|
|
struct FieldStructB {};
|
|
struct CompareFieldAsStruct {
|
|
struct FieldStructB fieldStruct;
|
|
};
|
|
#else
|
|
struct CompareFieldAsForwardDeclaration compareFieldAsForwardDeclaration;
|
|
struct CompareFieldAsEnum compareFieldAsEnum;
|
|
// expected-error@second.h:* {{'CompareFieldAsEnum::fieldEnum' from module 'Second' is not present in definition of 'struct CompareFieldAsEnum' in module 'First.Hidden'}}
|
|
// expected-note@first.h:* {{declaration of 'fieldEnum' does not match}}
|
|
struct CompareFieldAsStruct compareFieldAsStruct;
|
|
// expected-error@second.h:* {{'CompareFieldAsStruct::fieldStruct' from module 'Second' is not present in definition of 'struct CompareFieldAsStruct' in module 'First.Hidden'}}
|
|
// expected-note@first.h:* {{declaration of 'fieldStruct' does not match}}
|
|
#endif
|
|
|
|
#if defined(FIRST)
|
|
union CompareMatchingUnionFields {
|
|
int matchingFieldA;
|
|
float matchingFieldB;
|
|
};
|
|
|
|
union CompareUnionFieldOrder {
|
|
int unionFieldOrderA;
|
|
float unionFieldOrderB;
|
|
};
|
|
|
|
union CompareUnionFieldType {
|
|
int unionFieldType;
|
|
};
|
|
#elif defined(SECOND)
|
|
union CompareMatchingUnionFields {
|
|
int matchingFieldA;
|
|
float matchingFieldB;
|
|
};
|
|
|
|
union CompareUnionFieldOrder {
|
|
float unionFieldOrderB;
|
|
int unionFieldOrderA;
|
|
};
|
|
|
|
union CompareUnionFieldType {
|
|
unsigned int unionFieldType;
|
|
};
|
|
#else
|
|
union CompareMatchingUnionFields compareMatchingUnionFields;
|
|
union CompareUnionFieldOrder compareUnionFieldOrder;
|
|
// expected-error@first.h:* {{'CompareUnionFieldOrder' has different definitions in different modules; first difference is definition in module 'First.Hidden' found field 'unionFieldOrderA'}}
|
|
// expected-note@second.h:* {{but in 'Second' found field 'unionFieldOrderB'}}
|
|
union CompareUnionFieldType compareUnionFieldType;
|
|
// expected-error@second.h:* {{'CompareUnionFieldType::unionFieldType' from module 'Second' is not present in definition of 'union CompareUnionFieldType' in module 'First.Hidden'}}
|
|
// expected-note@first.h:* {{declaration of 'unionFieldType' does not match}}
|
|
#endif
|
|
|
|
// Test that we find and compare definitions even if they are not the first encountered declaration in a module.
|
|
#if defined(FIRST)
|
|
struct CompareDefinitionsRegardlessForwardDeclarations {
|
|
int definitionField;
|
|
};
|
|
#elif defined(SECOND)
|
|
struct CompareDefinitionsRegardlessForwardDeclarations;
|
|
struct CompareDefinitionsRegardlessForwardDeclarations {
|
|
float definitionField;
|
|
};
|
|
#else
|
|
struct CompareDefinitionsRegardlessForwardDeclarations compareDefinitions;
|
|
// expected-error@second.h:* {{'CompareDefinitionsRegardlessForwardDeclarations::definitionField' from module 'Second' is not present in definition of 'struct CompareDefinitionsRegardlessForwardDeclarations' in module 'First.Hidden'}}
|
|
// expected-note@first.h:* {{declaration of 'definitionField' does not match}}
|
|
#endif
|
|
|
|
//--- include/first-nested-struct.h
|
|
struct CompareNestedStruct {
|
|
struct NestedLevel1 {
|
|
struct NestedLevel2 {
|
|
int a;
|
|
} y;
|
|
} x;
|
|
};
|
|
|
|
struct IndirectStruct {
|
|
int mismatchingField;
|
|
};
|
|
struct DirectStruct {
|
|
struct IndirectStruct indirectField;
|
|
};
|
|
struct CompareDifferentFieldInIndirectStruct {
|
|
struct DirectStruct directField;
|
|
};
|
|
struct CompareIndirectStructPointer {
|
|
struct DirectStruct *directFieldPointer;
|
|
};
|
|
|
|
//--- include/second-nested-struct.h
|
|
struct CompareNestedStruct {
|
|
struct NestedLevel1 {
|
|
struct NestedLevel2 {
|
|
float b;
|
|
} y;
|
|
} x;
|
|
};
|
|
|
|
struct IndirectStruct {
|
|
float mismatchingField;
|
|
};
|
|
struct DirectStruct {
|
|
struct IndirectStruct indirectField;
|
|
};
|
|
struct CompareDifferentFieldInIndirectStruct {
|
|
struct DirectStruct directField;
|
|
};
|
|
struct CompareIndirectStructPointer {
|
|
struct DirectStruct *directFieldPointer;
|
|
};
|
|
|
|
//--- test-nested-struct.c
|
|
#include "first-empty.h"
|
|
#include "second-nested-struct.h"
|
|
|
|
#if defined(CASE1)
|
|
struct CompareNestedStruct compareNestedStruct;
|
|
// expected-error@second-nested-struct.h:* {{'NestedLevel2::b' from module 'Second' is not present in definition of 'struct NestedLevel2' in module 'First.Hidden'}}
|
|
// expected-note@first-nested-struct.h:* {{definition has no member 'b'}}
|
|
#elif defined(CASE2)
|
|
struct CompareDifferentFieldInIndirectStruct compareIndirectStruct;
|
|
// 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}}
|
|
#elif defined(CASE3)
|
|
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
|