|  | // 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 | 
|  |  | 
|  | // In non-modular case we ignore protocol redefinitions. But with modules | 
|  | // previous definition can come from a hidden [sub]module. And in this case we | 
|  | // allow a new definition if it is equivalent to the hidden one. | 
|  | // | 
|  | // This test case is to verify equivalence checks. | 
|  |  | 
|  | //--- include/common.h | 
|  | #ifndef COMMON_H | 
|  | #define COMMON_H | 
|  | @protocol CommonProtocol @end | 
|  | @protocol ExtraProtocol @end | 
|  | #endif | 
|  |  | 
|  | //--- include/first-empty.h | 
|  | //--- include/module.modulemap | 
|  | module Common { | 
|  | header "common.h" | 
|  | export * | 
|  | } | 
|  | 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) | 
|  | @protocol CompareForwardDeclaration1; | 
|  | @protocol CompareForwardDeclaration2<CommonProtocol> @end | 
|  | #elif defined(SECOND) | 
|  | @protocol CompareForwardDeclaration1<CommonProtocol> @end | 
|  | @protocol CompareForwardDeclaration2; | 
|  | #else | 
|  | id<CompareForwardDeclaration1> compareForwardDeclaration1; | 
|  | id<CompareForwardDeclaration2> compareForwardDeclaration2; | 
|  | #endif | 
|  |  | 
|  | #if defined(FIRST) | 
|  | @protocol CompareMatchingConformingProtocols<CommonProtocol> @end | 
|  | @protocol ForwardProtocol; | 
|  | @protocol CompareMatchingConformingForwardProtocols<ForwardProtocol> @end | 
|  |  | 
|  | @protocol CompareProtocolPresence1<CommonProtocol> @end | 
|  | @protocol CompareProtocolPresence2 @end | 
|  |  | 
|  | @protocol CompareDifferentProtocols<CommonProtocol> @end | 
|  | @protocol CompareProtocolOrder<CommonProtocol, ExtraProtocol> @end | 
|  | #elif defined(SECOND) | 
|  | @protocol CompareMatchingConformingProtocols<CommonProtocol> @end | 
|  | @protocol ForwardProtocol @end | 
|  | @protocol CompareMatchingConformingForwardProtocols<ForwardProtocol> @end | 
|  |  | 
|  | @protocol CompareProtocolPresence1 @end | 
|  | @protocol CompareProtocolPresence2<CommonProtocol> @end | 
|  |  | 
|  | @protocol CompareDifferentProtocols<ExtraProtocol> @end | 
|  | @protocol CompareProtocolOrder<ExtraProtocol, CommonProtocol> @end | 
|  | #else | 
|  | id<CompareMatchingConformingProtocols> compareMatchingConformingProtocols; | 
|  | id<CompareMatchingConformingForwardProtocols> compareMatchingConformingForwardProtocols; | 
|  |  | 
|  | id<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}} | 
|  | #ifdef TEST_MODULAR | 
|  | // expected-note@second.h:* {{but in 'Second' found 0 referenced protocols}} | 
|  | #else | 
|  | // expected-note@second.h:* {{but in definition here found 0 referenced protocols}} | 
|  | #endif | 
|  | id<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}} | 
|  |  | 
|  | id<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'}} | 
|  | id<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) | 
|  | @protocol CompareMatchingMethods | 
|  | - (float)matchingMethod:(int)arg; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodPresence1 | 
|  | - (void)presenceMethod1; | 
|  | @end | 
|  | @protocol CompareMethodPresence2 | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodName | 
|  | - (void)methodNameA; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodArgCount | 
|  | - (void)methodArgCount:(int)arg0 :(int)arg1; | 
|  | @end | 
|  | @protocol CompareMethodArgName | 
|  | - (void)methodArgName:(int)argNameA; | 
|  | @end | 
|  | @protocol CompareMethodArgType | 
|  | - (void)methodArgType:(int)argType; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodReturnType | 
|  | - (int)methodReturnType; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodOrder | 
|  | - (void)methodOrderFirst; | 
|  | - (void)methodOrderSecond; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodClassInstance | 
|  | - (void)methodClassInstance; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodRequirednessExplicit | 
|  | @optional | 
|  | - (void)methodRequiredness; | 
|  | @end | 
|  | @protocol CompareMethodRequirednessDefault | 
|  | // @required is default | 
|  | - (void)methodRequiredness; | 
|  | @end | 
|  | #elif defined(SECOND) | 
|  | @protocol CompareMatchingMethods | 
|  | - (float)matchingMethod:(int)arg; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodPresence1 | 
|  | @end | 
|  | @protocol CompareMethodPresence2 | 
|  | - (void)presenceMethod2; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodName | 
|  | - (void)methodNameB; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodArgCount | 
|  | - (void)methodArgCount:(int)arg0; | 
|  | @end | 
|  | @protocol CompareMethodArgName | 
|  | - (void)methodArgName:(int)argNameB; | 
|  | @end | 
|  | @protocol CompareMethodArgType | 
|  | - (void)methodArgType:(float)argType; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodReturnType | 
|  | - (float)methodReturnType; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodOrder | 
|  | - (void)methodOrderSecond; | 
|  | - (void)methodOrderFirst; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodClassInstance | 
|  | + (void)methodClassInstance; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMethodRequirednessExplicit | 
|  | @required | 
|  | - (void)methodRequiredness; | 
|  | @end | 
|  | @protocol CompareMethodRequirednessDefault | 
|  | @required | 
|  | - (void)methodRequiredness; | 
|  | @end | 
|  | #else | 
|  | id<CompareMatchingMethods> compareMatchingMethods; // no error | 
|  | id<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}} | 
|  | id<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}} | 
|  | id<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'}} | 
|  |  | 
|  | id<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}} | 
|  | id<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'}} | 
|  | id<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'}} | 
|  |  | 
|  | id<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'}} | 
|  |  | 
|  | id<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'}} | 
|  | id<CompareMethodClassInstance> compareMethodClassInstance; | 
|  | // expected-error@first.h:* {{'CompareMethodClassInstance' has different definitions in different modules; first difference is definition in module 'First.Hidden' found instance method 'methodClassInstance'}} | 
|  | // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found method 'methodClassInstance' as class method}} | 
|  |  | 
|  | id<CompareMethodRequirednessExplicit> compareMethodRequirednessExplicit; | 
|  | // expected-error@first.h:* {{'CompareMethodRequirednessExplicit' has different definitions in different modules; first difference is definition in module 'First.Hidden' found 'optional' method control}} | 
|  | // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found 'required' method control}} | 
|  | id<CompareMethodRequirednessDefault> compareMethodRequirednessDefault; // no error | 
|  | #endif | 
|  |  | 
|  | #if defined(FIRST) | 
|  | @protocol CompareMatchingProperties | 
|  | @property int matchingPropName; | 
|  | @end | 
|  |  | 
|  | @protocol ComparePropertyPresence1 | 
|  | @property int propPresence1; | 
|  | @end | 
|  | @protocol ComparePropertyPresence2 | 
|  | @end | 
|  |  | 
|  | @protocol ComparePropertyName | 
|  | @property int propNameA; | 
|  | @end | 
|  |  | 
|  | @protocol ComparePropertyType | 
|  | @property int propType; | 
|  | @end | 
|  |  | 
|  | @protocol ComparePropertyOrder | 
|  | @property int propOrderX; | 
|  | @property int propOrderY; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMatchingPropertyAttributes | 
|  | @property (nonatomic, assign) int matchingProp; | 
|  | @end | 
|  | @protocol ComparePropertyAttributes | 
|  | @property (nonatomic) int propAttributes; | 
|  | @end | 
|  | // Edge cases. | 
|  | @protocol CompareFirstImplAttribute | 
|  | @property int firstImplAttribute; | 
|  | @end | 
|  | @protocol CompareLastImplAttribute | 
|  | // Cannot test with protocols 'direct' attribute because it's not allowed. | 
|  | @property (class) int lastImplAttribute; | 
|  | @end | 
|  | #elif defined(SECOND) | 
|  | @protocol CompareMatchingProperties | 
|  | @property int matchingPropName; | 
|  | @end | 
|  |  | 
|  | @protocol ComparePropertyPresence1 | 
|  | @end | 
|  | @protocol ComparePropertyPresence2 | 
|  | @property int propPresence2; | 
|  | @end | 
|  |  | 
|  | @protocol ComparePropertyName | 
|  | @property int propNameB; | 
|  | @end | 
|  |  | 
|  | @protocol ComparePropertyType | 
|  | @property float propType; | 
|  | @end | 
|  |  | 
|  | @protocol ComparePropertyOrder | 
|  | @property int propOrderY; | 
|  | @property int propOrderX; | 
|  | @end | 
|  |  | 
|  | @protocol CompareMatchingPropertyAttributes | 
|  | @property (assign, nonatomic) int matchingProp; | 
|  | @end | 
|  | @protocol ComparePropertyAttributes | 
|  | @property (atomic) int propAttributes; | 
|  | @end | 
|  | // Edge cases. | 
|  | @protocol CompareFirstImplAttribute | 
|  | @property (readonly) int firstImplAttribute; | 
|  | @end | 
|  | @protocol CompareLastImplAttribute | 
|  | @property int lastImplAttribute; | 
|  | @end | 
|  | #else | 
|  | id<CompareMatchingProperties> compareMatchingProperties; | 
|  | id<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}} | 
|  | id<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}} | 
|  | id<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'}} | 
|  | id<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'}} | 
|  | id<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'}} | 
|  |  | 
|  | id<CompareMatchingPropertyAttributes> compareMatchingPropertyAttributes; | 
|  | id<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 'nonatomic' attribute}} | 
|  | // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'propAttributes' with different 'nonatomic' attribute}} | 
|  | id<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}} | 
|  | id<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 'class' attribute}} | 
|  | // expected-note-re@second.h:* {{but in {{'Second'|definition here}} found property 'lastImplAttribute' with different 'class' attribute}} | 
|  | #endif |