| // 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.m >> %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.m >> %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.m -fblocks -fobjc-arc \ |
| // RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache |
| |
| // Run the same test with second.h being modular |
| // RUN: cat %t/include/second.modulemap >> %t/include/module.modulemap |
| // RUN: %clang_cc1 -I%t/include -verify %t/test.m -fblocks -fobjc-arc -DTEST_MODULAR=1 \ |
| // RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache |
| |
| // Test that we don't accept different class definitions with the same name |
| // from multiple modules but detect mismatches and provide actionable |
| // diagnostic. |
| |
| //--- include/common.h |
| #ifndef COMMON_H |
| #define COMMON_H |
| @interface NSObject @end |
| @protocol CommonProtocol @end |
| @protocol ExtraProtocol @end |
| #endif |
| |
| //--- include/first-empty.h |
| //--- include/module.modulemap |
| module First { |
| module Empty { |
| header "first-empty.h" |
| } |
| module Hidden { |
| header "first.h" |
| export * |
| } |
| } |
| |
| //--- include/second.modulemap |
| module Second { |
| header "second.h" |
| export * |
| } |
| |
| //--- test.m |
| #if defined(FIRST) || defined(SECOND) |
| # include "common.h" |
| #endif |
| |
| #if !defined(FIRST) && !defined(SECOND) |
| # include "first-empty.h" |
| # include "second.h" |
| #endif |
| |
| #if defined(FIRST) |
| @class CompareForwardDeclaration1; |
| @interface CompareForwardDeclaration2: NSObject @end |
| #elif defined(SECOND) |
| @interface CompareForwardDeclaration1: NSObject @end |
| @class CompareForwardDeclaration2; |
| #else |
| CompareForwardDeclaration1 *compareForwardDeclaration1; |
| CompareForwardDeclaration2 *compareForwardDeclaration2; |
| #endif |
| |
| #if defined(FIRST) |
| @interface CompareMatchingSuperclass: NSObject @end |
| |
| @interface CompareSuperclassPresence1: NSObject @end |
| @interface CompareSuperclassPresence2 @end |
| |
| @interface CompareDifferentSuperclass: NSObject @end |
| #elif defined(SECOND) |
| @interface CompareMatchingSuperclass: NSObject @end |
| |
| @interface CompareSuperclassPresence1 @end |
| @interface CompareSuperclassPresence2: NSObject @end |
| |
| @interface DifferentSuperclass: NSObject @end |
| @interface CompareDifferentSuperclass: DifferentSuperclass @end |
| #else |
| CompareMatchingSuperclass *compareMatchingSuperclass; |
| CompareSuperclassPresence1 *compareSuperclassPresence1; |
| // expected-error@first.h:* {{'CompareSuperclassPresence1' has different definitions in different modules; first difference is definition in module 'First.Hidden' found super class with type 'NSObject'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found no super class}} |
| CompareSuperclassPresence2 *compareSuperclassPresence2; |
| // expected-error@first.h:* {{'CompareSuperclassPresence2' has different definitions in different modules; first difference is definition in module 'First.Hidden' found no super class}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found super class with type 'NSObject'}} |
| CompareDifferentSuperclass *compareDifferentSuperclass; |
| // expected-error@first.h:* {{'CompareDifferentSuperclass' has different definitions in different modules; first difference is definition in module 'First.Hidden' found super class with type 'NSObject'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found super class with type 'DifferentSuperclass'}} |
| #endif |
| |
| #if defined(FIRST) |
| @interface CompareMatchingConformingProtocols: NSObject<CommonProtocol> @end |
| @protocol ForwardProtocol; |
| @interface CompareMatchingConformingForwardProtocols: NSObject<ForwardProtocol> @end |
| |
| @interface CompareProtocolPresence1: NSObject<CommonProtocol> @end |
| @interface CompareProtocolPresence2: NSObject @end |
| |
| @interface CompareDifferentProtocols: NSObject<CommonProtocol> @end |
| @interface CompareProtocolOrder: NSObject<CommonProtocol, ExtraProtocol> @end |
| #elif defined(SECOND) |
| @interface CompareMatchingConformingProtocols: NSObject<CommonProtocol> @end |
| @protocol ForwardProtocol @end |
| @interface CompareMatchingConformingForwardProtocols: NSObject<ForwardProtocol> @end |
| |
| @interface CompareProtocolPresence1: NSObject @end |
| @interface CompareProtocolPresence2: NSObject<CommonProtocol> @end |
| |
| @interface CompareDifferentProtocols: NSObject<ExtraProtocol> @end |
| @interface CompareProtocolOrder: NSObject<ExtraProtocol, CommonProtocol> @end |
| #else |
| CompareMatchingConformingProtocols *compareMatchingConformingProtocols; |
| CompareMatchingConformingForwardProtocols *compareMatchingConformingForwardProtocols; |
| |
| CompareProtocolPresence1 *compareProtocolPresence1; |
| // expected-error@first.h:* {{'CompareProtocolPresence1' has different definitions in different modules; first difference is definition in module 'First.Hidden' found 1 referenced protocol}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found 0 referenced protocols}} |
| CompareProtocolPresence2 *compareProtocolPresence2; |
| // expected-error@first.h:* {{'CompareProtocolPresence2' has different definitions in different modules; first difference is definition in module 'First.Hidden' found 0 referenced protocols}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found 1 referenced protocol}} |
| |
| CompareDifferentProtocols *compareDifferentProtocols; |
| // expected-error@first.h:* {{'CompareDifferentProtocols' has different definitions in different modules; first difference is definition in module 'First.Hidden' found 1st referenced protocol with name 'CommonProtocol'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found 1st referenced protocol with different name 'ExtraProtocol'}} |
| CompareProtocolOrder *compareProtocolOrder; |
| // expected-error@first.h:* {{'CompareProtocolOrder' has different definitions in different modules; first difference is definition in module 'First.Hidden' found 1st referenced protocol with name 'CommonProtocol'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found 1st referenced protocol with different name 'ExtraProtocol'}} |
| #endif |
| |
| #if defined(FIRST) |
| @interface CompareMatchingIVars: NSObject { int ivarName; } @end |
| |
| @interface CompareIVarPresence1: NSObject @end |
| @interface CompareIVarPresence2: NSObject { int ivarPresence2; } @end |
| |
| @interface CompareIVarName: NSObject { int ivarName; } @end |
| @interface CompareIVarType: NSObject { int ivarType; } @end |
| @interface CompareIVarOrder: NSObject { |
| int ivarNameInt; |
| float ivarNameFloat; |
| } |
| @end |
| |
| @interface CompareIVarVisibilityExplicit: NSObject { |
| @public |
| int ivarVisibility; |
| } |
| @end |
| @interface CompareIVarVisibilityDefault: NSObject { |
| int ivarVisibilityDefault; |
| } |
| @end |
| #elif defined(SECOND) |
| @interface CompareMatchingIVars: NSObject { int ivarName; } @end |
| |
| @interface CompareIVarPresence1: NSObject { int ivarPresence1; } @end |
| @interface CompareIVarPresence2: NSObject @end |
| |
| @interface CompareIVarName: NSObject { int differentIvarName; } @end |
| @interface CompareIVarType: NSObject { float ivarType; } @end |
| @interface CompareIVarOrder: NSObject { |
| float ivarNameFloat; |
| int ivarNameInt; |
| } |
| @end |
| |
| @interface CompareIVarVisibilityExplicit: NSObject { |
| @private |
| int ivarVisibility; |
| } |
| @end |
| @interface CompareIVarVisibilityDefault: NSObject { |
| @public |
| int ivarVisibilityDefault; |
| } |
| @end |
| #else |
| CompareMatchingIVars *compareMatchingIVars; |
| |
| CompareIVarPresence1 *compareIVarPresence1; |
| #ifdef TEST_MODULAR |
| // expected-error@second.h:* {{'CompareIVarPresence1::ivarPresence1' from module 'Second' is not present in definition of 'CompareIVarPresence1' in module 'First.Hidden'}} |
| // expected-note@first.h:* {{definition has no member 'ivarPresence1'}} |
| #else |
| // expected-error@first.h:* {{'CompareIVarPresence1' has different definitions in different modules; first difference is definition in module 'First.Hidden' found end of class}} |
| // expected-note@second.h:* {{but in definition here found instance variable}} |
| #endif |
| CompareIVarPresence2 *compareIVarPresence2; |
| // expected-error@first.h:* {{'CompareIVarPresence2' has different definitions in different modules; first difference is definition in module 'First.Hidden' found instance variable}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found end of class}} |
| |
| CompareIVarName *compareIVarName; |
| #ifdef TEST_MODULAR |
| // expected-error@second.h:* {{'CompareIVarName::differentIvarName' from module 'Second' is not present in definition of 'CompareIVarName' in module 'First.Hidden'}} |
| // expected-note@first.h:* {{definition has no member 'differentIvarName'}} |
| #else |
| // expected-error@first.h:* {{'CompareIVarName' has different definitions in different modules; first difference is definition in module 'First.Hidden' found field 'ivarName'}} |
| // expected-note@second.h:* {{but in definition here found field 'differentIvarName'}} |
| #endif |
| CompareIVarType *compareIVarType; |
| #ifdef TEST_MODULAR |
| // expected-error@second.h:* {{'CompareIVarType::ivarType' from module 'Second' is not present in definition of 'CompareIVarType' in module 'First.Hidden'}} |
| // expected-note@first.h:* {{declaration of 'ivarType' does not match}} |
| #else |
| // expected-error@first.h:* {{'CompareIVarType' has different definitions in different modules; first difference is definition in module 'First.Hidden' found field 'ivarType' with type 'int'}} |
| // expected-note@second.h:* {{but in definition here found field 'ivarType' with type 'float'}} |
| #endif |
| CompareIVarOrder *compareIVarOrder; |
| // expected-error@first.h:* {{'CompareIVarOrder' has different definitions in different modules; first difference is definition in module 'First.Hidden' found field 'ivarNameInt'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found field 'ivarNameFloat'}} |
| |
| CompareIVarVisibilityExplicit *compareIVarVisibilityExplicit; |
| // expected-error@first.h:* {{'CompareIVarVisibilityExplicit' has different definitions in different modules; first difference is definition in module 'First.Hidden' found instance variable 'ivarVisibility' access control is @public}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found instance variable 'ivarVisibility' access control is @private}} |
| CompareIVarVisibilityDefault *compareIVarVisibilityDefault; |
| // expected-error@first.h:* {{'CompareIVarVisibilityDefault' has different definitions in different modules; first difference is definition in module 'First.Hidden' found instance variable 'ivarVisibilityDefault' access control is @protected}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found instance variable 'ivarVisibilityDefault' access control is @public}} |
| #endif |
| |
| #if defined(FIRST) |
| @interface CompareMatchingMethods: NSObject |
| - (float)matchingMethod:(int)arg; |
| @end |
| |
| @interface CompareMethodPresence1: NSObject |
| - (void)presenceMethod1; |
| @end |
| @interface CompareMethodPresence2: NSObject |
| @end |
| |
| @interface CompareMethodName: NSObject |
| - (void)methodNameA; |
| @end |
| |
| @interface CompareMethodArgCount: NSObject |
| - (void)methodArgCount:(int)arg0 :(int)arg1; |
| @end |
| @interface CompareMethodArgName: NSObject |
| - (void)methodArgName:(int)argNameA; |
| @end |
| @interface CompareMethodArgType: NSObject |
| - (void)methodArgType:(int)argType; |
| @end |
| |
| @interface CompareMethodReturnType: NSObject |
| - (int)methodReturnType; |
| @end |
| |
| @interface CompareMethodOrder: NSObject |
| - (void)methodOrderFirst; |
| - (void)methodOrderSecond; |
| @end |
| |
| @interface CompareMethodClassInstance: NSObject |
| + (void)methodClassInstance; |
| @end |
| #elif defined(SECOND) |
| @interface CompareMatchingMethods: NSObject |
| - (float)matchingMethod:(int)arg; |
| @end |
| |
| @interface CompareMethodPresence1: NSObject |
| @end |
| @interface CompareMethodPresence2: NSObject |
| - (void)presenceMethod2; |
| @end |
| |
| @interface CompareMethodName: NSObject |
| - (void)methodNameB; |
| @end |
| |
| @interface CompareMethodArgCount: NSObject |
| - (void)methodArgCount:(int)arg0; |
| @end |
| @interface CompareMethodArgName: NSObject |
| - (void)methodArgName:(int)argNameB; |
| @end |
| @interface CompareMethodArgType: NSObject |
| - (void)methodArgType:(float)argType; |
| @end |
| |
| @interface CompareMethodReturnType: NSObject |
| - (float)methodReturnType; |
| @end |
| |
| @interface CompareMethodOrder: NSObject |
| - (void)methodOrderSecond; |
| - (void)methodOrderFirst; |
| @end |
| |
| @interface CompareMethodClassInstance: NSObject |
| - (void)methodClassInstance; |
| @end |
| #else |
| CompareMatchingMethods *compareMatchingMethods; |
| CompareMethodPresence1 *compareMethodPresence1; |
| // expected-error@first.h:* {{'CompareMethodPresence1' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found end of class}} |
| CompareMethodPresence2 *compareMethodPresence2; |
| // expected-error@first.h:* {{'CompareMethodPresence2' has different definitions in different modules; first difference is definition in module 'First.Hidden' found end of class}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found method}} |
| CompareMethodName *compareMethodName; |
| // expected-error@first.h:* {{'CompareMethodName' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method 'methodNameA'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found different method 'methodNameB'}} |
| |
| CompareMethodArgCount *compareMethodArgCount; |
| // expected-error@first.h:* {{'CompareMethodArgCount' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method 'methodArgCount::' that has 2 parameters}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found method 'methodArgCount:' that has 1 parameter}} |
| CompareMethodArgName *compareMethodArgName; |
| // expected-error@first.h:* {{'CompareMethodArgName' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method 'methodArgName:' with 1st parameter named 'argNameA'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found method 'methodArgName:' with 1st parameter named 'argNameB'}} |
| CompareMethodArgType *compareMethodArgType; |
| // expected-error@first.h:* {{'CompareMethodArgType' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method 'methodArgType:' with 1st parameter of type 'int'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found method 'methodArgType:' with 1st parameter of type 'float'}} |
| |
| CompareMethodReturnType *compareMethodReturnType; |
| // expected-error@first.h:* {{'CompareMethodReturnType' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method 'methodReturnType' with return type 'int'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found method 'methodReturnType' with different return type 'float'}} |
| |
| CompareMethodOrder *compareMethodOrder; |
| // expected-error@first.h:* {{'CompareMethodOrder' has different definitions in different modules; first difference is definition in module 'First.Hidden' found method 'methodOrderFirst'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found different method 'methodOrderSecond'}} |
| CompareMethodClassInstance *compareMethodClassInstance; |
| // expected-error@first.h:* {{'CompareMethodClassInstance' has different definitions in different modules; first difference is definition in module 'First.Hidden' found class method 'methodClassInstance'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found method 'methodClassInstance' as instance method}} |
| #endif |
| |
| #if defined(FIRST) |
| @interface CompareMatchingProperties: NSObject |
| @property int matchingPropName; |
| @end |
| |
| @interface ComparePropertyPresence1: NSObject |
| @property int propPresence1; |
| @end |
| @interface ComparePropertyPresence2: NSObject |
| @end |
| |
| @interface ComparePropertyName: NSObject |
| @property int propNameA; |
| @end |
| |
| @interface ComparePropertyType: NSObject |
| @property int propType; |
| @end |
| |
| @interface ComparePropertyOrder: NSObject |
| @property int propOrderX; |
| @property int propOrderY; |
| @end |
| |
| @interface CompareMatchingPropertyAttributes: NSObject |
| @property (nonatomic, assign) int matchingProp; |
| @end |
| @interface ComparePropertyAttributes: NSObject |
| @property (readonly) int propAttributes; |
| @end |
| // Edge cases. |
| @interface CompareFirstImplAttribute: NSObject |
| @property int firstImplAttribute; |
| @end |
| @interface CompareLastImplAttribute: NSObject |
| @property (direct) int lastImplAttribute; |
| @end |
| #elif defined(SECOND) |
| @interface CompareMatchingProperties: NSObject |
| @property int matchingPropName; |
| @end |
| |
| @interface ComparePropertyPresence1: NSObject |
| @end |
| @interface ComparePropertyPresence2: NSObject |
| @property int propPresence2; |
| @end |
| |
| @interface ComparePropertyName: NSObject |
| @property int propNameB; |
| @end |
| |
| @interface ComparePropertyType: NSObject |
| @property float propType; |
| @end |
| |
| @interface ComparePropertyOrder: NSObject |
| @property int propOrderY; |
| @property int propOrderX; |
| @end |
| |
| @interface CompareMatchingPropertyAttributes: NSObject |
| @property (assign, nonatomic) int matchingProp; |
| @end |
| @interface ComparePropertyAttributes: NSObject |
| @property (readwrite) int propAttributes; |
| @end |
| // Edge cases. |
| @interface CompareFirstImplAttribute: NSObject |
| @property (readonly) int firstImplAttribute; |
| @end |
| @interface CompareLastImplAttribute: NSObject |
| @property int lastImplAttribute; |
| @end |
| #else |
| CompareMatchingProperties *compareMatchingProperties; |
| ComparePropertyPresence1 *comparePropertyPresence1; |
| // expected-error@first.h:* {{'ComparePropertyPresence1' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found end of class}} |
| ComparePropertyPresence2 *comparePropertyPresence2; |
| // expected-error@first.h:* {{'ComparePropertyPresence2' has different definitions in different modules; first difference is definition in module 'First.Hidden' found end of class}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property}} |
| |
| ComparePropertyName *comparePropertyName; |
| // expected-error@first.h:* {{'ComparePropertyName' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property 'propNameA'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'propNameB'}} |
| ComparePropertyType *comparePropertyType; |
| // expected-error@first.h:* {{'ComparePropertyType' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property 'propType' with type 'int'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'propType' with type 'float'}} |
| ComparePropertyOrder *comparePropertyOrder; |
| // expected-error@first.h:* {{'ComparePropertyOrder' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property 'propOrderX'}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'propOrderY'}} |
| |
| CompareMatchingPropertyAttributes *compareMatchingPropertyAttributes; |
| ComparePropertyAttributes *comparePropertyAttributes; |
| // expected-error@first.h:* {{'ComparePropertyAttributes' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property 'propAttributes' with 'readonly' attribute}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'propAttributes' with different 'readonly' attribute}} |
| CompareFirstImplAttribute *compareFirstImplAttribute; |
| // expected-error@first.h:* {{'CompareFirstImplAttribute' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property 'firstImplAttribute' with default 'readonly' attribute}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'firstImplAttribute' with different 'readonly' attribute}} |
| CompareLastImplAttribute *compareLastImplAttribute; |
| // expected-error@first.h:* {{'CompareLastImplAttribute' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property 'lastImplAttribute' with 'direct' attribute}} |
| // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'lastImplAttribute' with different 'direct' attribute}} |
| #endif |
| |
| #if defined(FIRST) |
| @interface CompareMatchingCategories: NSObject @end |
| @interface CompareMatchingCategories(Matching) |
| - (int)testMethod; |
| @end |
| |
| @interface CompareMismatchingCategories1: NSObject @end |
| @interface CompareMismatchingCategories1(Category1) |
| - (void)presentMethod; |
| @end |
| @interface CompareMismatchingCategories2: NSObject @end |
| @interface CompareMismatchingCategories2(Category2) |
| @end |
| |
| @interface CompareDifferentCategoryNames: NSObject @end |
| @interface CompareDifferentCategoryNames(CategoryFirst) |
| - (void)firstMethod:(int)x; |
| @end |
| #elif defined(SECOND) |
| @interface CompareMatchingCategories: NSObject @end |
| @interface CompareMatchingCategories(Matching) |
| - (int)testMethod; |
| @end |
| |
| @interface CompareMismatchingCategories1: NSObject @end |
| @interface CompareMismatchingCategories1(Category1) |
| @end |
| @interface CompareMismatchingCategories2: NSObject @end |
| @interface CompareMismatchingCategories2(Category2) |
| - (void)presentMethod; |
| @end |
| |
| @interface CompareDifferentCategoryNames: NSObject @end |
| @interface CompareDifferentCategoryNames(CategorySecond) |
| - (void)secondMethod; |
| @end |
| #else |
| CompareMatchingCategories *compareMatchingCategories; // no diagnostic |
| CompareMismatchingCategories1 *compareMismatchingCategories1; |
| #ifdef TEST_MODULAR |
| // expected-warning@second.h:* {{duplicate definition of category 'Category1' on interface 'CompareMismatchingCategories1'}} |
| // expected-note@first.h:* {{previous definition is here}} |
| #endif |
| CompareMismatchingCategories2 *compareMismatchingCategories2; |
| #ifdef TEST_MODULAR |
| // expected-warning@second.h:* {{duplicate definition of category 'Category2' on interface 'CompareMismatchingCategories2'}} |
| // expected-note@first.h:* {{previous definition is here}} |
| #endif |
| CompareDifferentCategoryNames *compareDifferentCategoryNames; // no diagnostic |
| #endif |