[clang] ed7a46a - [modules] Allow parsing a duplicate Obj-C interface if a previous one comes from a hidden [sub]module.

Volodymyr Sapsai via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 20 08:18:28 PST 2023


Author: Volodymyr Sapsai
Date: 2023-01-20T10:18:18-06:00
New Revision: ed7a46a8de77087447936965044e2faf734102e5

URL: https://github.com/llvm/llvm-project/commit/ed7a46a8de77087447936965044e2faf734102e5
DIFF: https://github.com/llvm/llvm-project/commit/ed7a46a8de77087447936965044e2faf734102e5.diff

LOG: [modules] Allow parsing a duplicate Obj-C interface if a previous one comes from a hidden [sub]module.

Instead of emitting a redefinition error, check that definitions are
equivalent and allow such scenario.

A few non-obvious implementation details:
* to avoid multiple definitions in the redeclaration chain we just drop
  the new definition after checking for equivalence;
* for checking definition equivalence use ODR hash instead of
  ASTStructuralEquivalence because it avoids excessive recursive
  deserialization. Though after detecting a mismatch we do deserialize
  multiple entities to provide a better error message.

rdar://82908223

Differential Revision: https://reviews.llvm.org/D124286

Added: 
    

Modified: 
    clang/include/clang/AST/DeclObjC.h
    clang/include/clang/AST/ODRDiagsEmitter.h
    clang/include/clang/Basic/DiagnosticASTKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/DeclObjC.cpp
    clang/lib/AST/ODRDiagsEmitter.cpp
    clang/lib/Parse/ParseObjc.cpp
    clang/lib/Sema/SemaDeclObjC.cpp
    clang/test/Modules/compare-objc-interface.m
    clang/test/Modules/hidden-duplicates.m

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h
index 77fde99b6b60b..3d650b82f2b9b 100644
--- a/clang/include/clang/AST/DeclObjC.h
+++ b/clang/include/clang/AST/DeclObjC.h
@@ -1542,6 +1542,13 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
   /// a forward declaration (\@class) to a definition (\@interface).
   void startDefinition();
 
+  /// Starts the definition without sharing it with other redeclarations.
+  /// Such definition shouldn't be used for anything but only to compare if
+  /// a duplicate is compatible with previous definition or if it is
+  /// a distinct duplicate.
+  void startDuplicateDefinitionForComparison();
+  void mergeDuplicateDefinitionWithCommon(const ObjCInterfaceDecl *Definition);
+
   /// Retrieve the superclass type.
   const ObjCObjectType *getSuperClassType() const {
     if (TypeSourceInfo *TInfo = getSuperClassTInfo())

diff  --git a/clang/include/clang/AST/ODRDiagsEmitter.h b/clang/include/clang/AST/ODRDiagsEmitter.h
index fdbd85cb10e5b..1f7faaa06e540 100644
--- a/clang/include/clang/AST/ODRDiagsEmitter.h
+++ b/clang/include/clang/AST/ODRDiagsEmitter.h
@@ -58,6 +58,15 @@ class ODRDiagsEmitter {
       const ObjCInterfaceDecl *FirstID, const ObjCInterfaceDecl *SecondID,
       const struct ObjCInterfaceDecl::DefinitionData *SecondDD) const;
 
+  /// Diagnose ODR mismatch between ObjCInterfaceDecl with 
diff erent
+  /// definitions.
+  bool diagnoseMismatch(const ObjCInterfaceDecl *FirstID,
+                        const ObjCInterfaceDecl *SecondID) const {
+    assert(FirstID->data().Definition != SecondID->data().Definition &&
+           "Don't diagnose 
diff erences when definitions are merged already");
+    return diagnoseMismatch(FirstID, SecondID, &SecondID->data());
+  }
+
   /// Diagnose ODR mismatch between 2 ObjCProtocolDecl.
   ///
   /// Returns true if found a mismatch and diagnosed it.

diff  --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 715249b9d6f5e..28120d13fd9e7 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -624,12 +624,12 @@ def err_module_odr_violation_objc_interface : Error <
     "%select{|@private|@protected|@public|@package}5"
   "}3">;
 def note_module_odr_violation_objc_interface : Note <
-  "but in '%0' found "
+  "but in %select{'%1'|definition here}0 found "
   "%select{"
-  "%select{no super class|super class with type %3}2|"
-  "instance variable '%2' access control is "
-    "%select{|@private|@protected|@public|@package}3"
-  "}1">;
+  "%select{no super class|super class with type %4}3|"
+  "instance variable '%3' access control is "
+    "%select{|@private|@protected|@public|@package}4"
+  "}2">;
 
 def err_module_odr_violation_template_parameter : Error <
   "%q0 has 
diff erent definitions in 
diff erent modules; first 
diff erence is "
@@ -778,16 +778,17 @@ def err_module_odr_violation_field : Error<
   "field %4 with %select{no|an}5 initalizer|"
   "field %4 with an initializer"
   "}3">;
-def note_module_odr_violation_field : Note<"but in '%0' found "
+def note_module_odr_violation_field : Note<
+  "but in %select{'%1'|definition here}0 found "
   "%select{"
-  "field %2|"
-  "field %2 with type %3|"
-  "%select{non-|}3bitfield %2|"
-  "bitfield %2 with 
diff erent width expression|"
-  "%select{non-|}3mutable field %2|"
-  "field %2 with %select{no|an}3 initializer|"
-  "field %2 with a 
diff erent initializer"
-  "}1">;
+  "field %3|"
+  "field %3 with type %4|"
+  "%select{non-|}4bitfield %3|"
+  "bitfield %3 with 
diff erent width expression|"
+  "%select{non-|}4mutable field %3|"
+  "field %3 with %select{no|an}4 initializer|"
+  "field %3 with a 
diff erent initializer"
+  "}2">;
 
 def err_module_odr_violation_typedef : Error<
   "%q0 has 
diff erent definitions in 
diff erent modules; first 
diff erence is "

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index e504111fce059..0891dd0e0dd87 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10186,7 +10186,7 @@ class Sema final {
       ArrayRef<ParsedType> SuperTypeArgs, SourceRange SuperTypeArgsRange,
       Decl *const *ProtoRefs, unsigned NumProtoRefs,
       const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc,
-      const ParsedAttributesView &AttrList);
+      const ParsedAttributesView &AttrList, SkipBodyInfo *SkipBody);
 
   void ActOnSuperClassOfClassInterface(Scope *S,
                                        SourceLocation AtInterfaceLoc,

diff  --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp
index 33b9d33075a2a..e934a81d086e3 100644
--- a/clang/lib/AST/DeclObjC.cpp
+++ b/clang/lib/AST/DeclObjC.cpp
@@ -624,6 +624,17 @@ void ObjCInterfaceDecl::startDefinition() {
   }
 }
 
+void ObjCInterfaceDecl::startDuplicateDefinitionForComparison() {
+  Data.setPointer(nullptr);
+  allocateDefinitionData();
+  // Don't propagate data to other redeclarations.
+}
+
+void ObjCInterfaceDecl::mergeDuplicateDefinitionWithCommon(
+    const ObjCInterfaceDecl *Definition) {
+  Data = Definition->Data;
+}
+
 ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
                                               ObjCInterfaceDecl *&clsDeclared) {
   // FIXME: Should make sure no callers ever do this.

diff  --git a/clang/lib/AST/ODRDiagsEmitter.cpp b/clang/lib/AST/ODRDiagsEmitter.cpp
index bd23fda6ac921..b3fe070889c5f 100644
--- a/clang/lib/AST/ODRDiagsEmitter.cpp
+++ b/clang/lib/AST/ODRDiagsEmitter.cpp
@@ -164,7 +164,7 @@ bool ODRDiagsEmitter::diagnoseSubMismatchField(
                    this](ODRFieldDifference DiffType) {
     return Diag(SecondField->getLocation(),
                 diag::note_module_odr_violation_field)
-           << SecondModule << SecondField->getSourceRange() << DiffType;
+           << SecondModule.empty() << SecondModule << SecondField->getSourceRange() << DiffType;
   };
 
   IdentifierInfo *FirstII = FirstField->getIdentifier();
@@ -175,9 +175,6 @@ bool ODRDiagsEmitter::diagnoseSubMismatchField(
     return true;
   }
 
-  assert(Context.hasSameType(FirstField->getType(), SecondField->getType()));
-  (void)Context;
-
   QualType FirstType = FirstField->getType();
   QualType SecondType = SecondField->getType();
   if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
@@ -186,6 +183,9 @@ bool ODRDiagsEmitter::diagnoseSubMismatchField(
     return true;
   }
 
+  assert(Context.hasSameType(FirstField->getType(), SecondField->getType()));
+  (void)Context;
+
   const bool IsFirstBitField = FirstField->isBitField();
   const bool IsSecondBitField = SecondField->isBitField();
   if (IsFirstBitField != IsSecondBitField) {
@@ -1941,7 +1941,7 @@ bool ODRDiagsEmitter::diagnoseMismatch(
   auto DiagNote = [&SecondModule, this](SourceLocation Loc, SourceRange Range,
                                         ODRInterfaceDifference DiffType) {
     return Diag(Loc, diag::note_module_odr_violation_objc_interface)
-           << SecondModule << Range << DiffType;
+           << SecondModule.empty() << SecondModule << Range << DiffType;
   };
 
   const struct ObjCInterfaceDecl::DefinitionData *FirstDD = &FirstID->data();
@@ -2007,8 +2007,10 @@ bool ODRDiagsEmitter::diagnoseMismatch(
 
   DeclHashes FirstHashes;
   DeclHashes SecondHashes;
-  PopulateHashes(FirstHashes, FirstID, FirstID);
-  PopulateHashes(SecondHashes, SecondID, FirstID);
+  // Use definition as DeclContext because definitions are merged when
+  // DeclContexts are merged and separate when DeclContexts are separate.
+  PopulateHashes(FirstHashes, FirstID, FirstID->getDefinition());
+  PopulateHashes(SecondHashes, SecondID, SecondID->getDefinition());
 
   DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
   ODRMismatchDecl FirstDiffType = DR.FirstDiffType;

diff  --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 4a18cce11febc..079bf9a9c08cc 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -370,17 +370,30 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
     Actions.ActOnTypedefedProtocols(protocols, protocolLocs,
                                     superClassId, superClassLoc);
 
+  Sema::SkipBodyInfo SkipBody;
   ObjCInterfaceDecl *ClsType = Actions.ActOnStartClassInterface(
       getCurScope(), AtLoc, nameId, nameLoc, typeParameterList, superClassId,
       superClassLoc, typeArgs,
       SourceRange(typeArgsLAngleLoc, typeArgsRAngleLoc), protocols.data(),
-      protocols.size(), protocolLocs.data(), EndProtoLoc, attrs);
+      protocols.size(), protocolLocs.data(), EndProtoLoc, attrs, &SkipBody);
 
   if (Tok.is(tok::l_brace))
     ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
 
   ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
 
+  if (SkipBody.CheckSameAsPrevious) {
+    auto *PreviousDef = cast<ObjCInterfaceDecl>(SkipBody.Previous);
+    if (Actions.ActOnDuplicateODRHashDefinition(ClsType, PreviousDef)) {
+      ClsType->mergeDuplicateDefinitionWithCommon(PreviousDef->getDefinition());
+    } else {
+      ODRDiagsEmitter DiagsEmitter(Diags, Actions.getASTContext(),
+                                   getPreprocessor().getLangOpts());
+      DiagsEmitter.diagnoseMismatch(PreviousDef, ClsType);
+      ClsType->setInvalidDecl();
+    }
+  }
+
   return ClsType;
 }
 

diff  --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index a7443f736e363..fdfc6d312b387 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -978,7 +978,7 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(
     ArrayRef<ParsedType> SuperTypeArgs, SourceRange SuperTypeArgsRange,
     Decl *const *ProtoRefs, unsigned NumProtoRefs,
     const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc,
-    const ParsedAttributesView &AttrList) {
+    const ParsedAttributesView &AttrList, SkipBodyInfo *SkipBody) {
   assert(ClassName && "Missing class identifier");
 
   // Check for another declaration kind with the same name.
@@ -1057,10 +1057,16 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(
   if (PrevIDecl) {
     // Class already seen. Was it a definition?
     if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
-      Diag(AtInterfaceLoc, diag::err_duplicate_class_def)
-        << PrevIDecl->getDeclName();
-      Diag(Def->getLocation(), diag::note_previous_definition);
-      IDecl->setInvalidDecl();
+      if (SkipBody && !hasVisibleDefinition(Def)) {
+        SkipBody->CheckSameAsPrevious = true;
+        SkipBody->New = IDecl;
+        SkipBody->Previous = Def;
+      } else {
+        Diag(AtInterfaceLoc, diag::err_duplicate_class_def)
+            << PrevIDecl->getDeclName();
+        Diag(Def->getLocation(), diag::note_previous_definition);
+        IDecl->setInvalidDecl();
+      }
     }
   }
 
@@ -1075,7 +1081,9 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(
 
   // Start the definition of this class. If we're in a redefinition case, there
   // may already be a definition, so we'll end up adding to it.
-  if (!IDecl->hasDefinition())
+  if (SkipBody && SkipBody->CheckSameAsPrevious)
+    IDecl->startDuplicateDefinitionForComparison();
+  else if (!IDecl->hasDefinition())
     IDecl->startDefinition();
 
   if (SuperName) {

diff  --git a/clang/test/Modules/compare-objc-interface.m b/clang/test/Modules/compare-objc-interface.m
index 71f1cc853a7a3..17a03de3ce29b 100644
--- a/clang/test/Modules/compare-objc-interface.m
+++ b/clang/test/Modules/compare-objc-interface.m
@@ -19,6 +19,11 @@
 // 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 
diff erent class definitions with the same name
 // from multiple modules but detect mismatches and provide actionable
 // diagnostic.
@@ -42,6 +47,8 @@ @protocol ExtraProtocol @end
     export *
   }
 }
+
+//--- include/second.modulemap
 module Second {
   header "second.h"
   export *
@@ -87,13 +94,13 @@ @interface CompareDifferentSuperclass: DifferentSuperclass @end
 CompareMatchingSuperclass *compareMatchingSuperclass;
 CompareSuperclassPresence1 *compareSuperclassPresence1;
 // expected-error at first.h:* {{'CompareSuperclassPresence1' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found super class with type 'NSObject'}}
-// expected-note at second.h:* {{but in 'Second' found no super class}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found no super class}}
 CompareSuperclassPresence2 *compareSuperclassPresence2;
 // expected-error at first.h:* {{'CompareSuperclassPresence2' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found no super class}}
-// expected-note at second.h:* {{but in 'Second' found super class with type 'NSObject'}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found super class with type 'NSObject'}}
 CompareDifferentSuperclass *compareDifferentSuperclass;
 // expected-error at first.h:* {{'CompareDifferentSuperclass' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found super class with type 'NSObject'}}
-// expected-note at second.h:* {{but in 'Second' found super class with type 'DifferentSuperclass'}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found super class with type 'DifferentSuperclass'}}
 #endif
 
 #if defined(FIRST)
@@ -122,17 +129,17 @@ @interface CompareProtocolOrder: NSObject<ExtraProtocol, CommonProtocol> @end
 
 CompareProtocolPresence1 *compareProtocolPresence1;
 // expected-error at first.h:* {{'CompareProtocolPresence1' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found 1 referenced protocol}}
-// expected-note at second.h:* {{but in 'Second' found 0 referenced protocols}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found 0 referenced protocols}}
 CompareProtocolPresence2 *compareProtocolPresence2;
 // expected-error at first.h:* {{'CompareProtocolPresence2' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found 0 referenced protocols}}
-// expected-note at second.h:* {{but in 'Second' found 1 referenced protocol}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found 1 referenced protocol}}
 
 CompareDifferentProtocols *compareDifferentProtocols;
 // expected-error at first.h:* {{'CompareDifferentProtocols' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found 1st referenced protocol with name 'CommonProtocol'}}
-// expected-note at second.h:* {{but in 'Second' found 1st referenced protocol with 
diff erent name 'ExtraProtocol'}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found 1st referenced protocol with 
diff erent name 'ExtraProtocol'}}
 CompareProtocolOrder *compareProtocolOrder;
 // expected-error at first.h:* {{'CompareProtocolOrder' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found 1st referenced protocol with name 'CommonProtocol'}}
-// expected-note at second.h:* {{but in 'Second' found 1st referenced protocol with 
diff erent name 'ExtraProtocol'}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found 1st referenced protocol with 
diff erent name 'ExtraProtocol'}}
 #endif
 
 #if defined(FIRST)
@@ -186,28 +193,43 @@ @interface CompareIVarVisibilityDefault: NSObject {
 CompareMatchingIVars *compareMatchingIVars;
 
 CompareIVarPresence1 *compareIVarPresence1;
+#ifdef TEST_MODULAR
 // expected-error at second.h:* {{'CompareIVarPresence1::ivarPresence1' from module 'Second' is not present in definition of 'CompareIVarPresence1' in module 'First.Hidden'}}
 // expected-note at first.h:* {{definition has no member 'ivarPresence1'}}
+#else
+// expected-error at first.h:* {{'CompareIVarPresence1' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found end of class}}
+// expected-note at second.h:* {{but in definition here found instance variable}}
+#endif
 CompareIVarPresence2 *compareIVarPresence2;
 // expected-error at first.h:* {{'CompareIVarPresence2' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found instance variable}}
-// expected-note at second.h:* {{but in 'Second' found end of class}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found end of class}}
 
 CompareIVarName *compareIVarName;
+#ifdef TEST_MODULAR
 // expected-error at second.h:* {{'CompareIVarName::
diff erentIvarName' from module 'Second' is not present in definition of 'CompareIVarName' in module 'First.Hidden'}}
 // expected-note at first.h:* {{definition has no member '
diff erentIvarName'}}
+#else
+// expected-error at first.h:* {{'CompareIVarName' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found field 'ivarName'}}
+// expected-note at second.h:* {{but in definition here found field '
diff erentIvarName'}}
+#endif
 CompareIVarType *compareIVarType;
+#ifdef TEST_MODULAR
 // expected-error at second.h:* {{'CompareIVarType::ivarType' from module 'Second' is not present in definition of 'CompareIVarType' in module 'First.Hidden'}}
 // expected-note at first.h:* {{declaration of 'ivarType' does not match}}
+#else
+// expected-error at first.h:* {{'CompareIVarType' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found field 'ivarType' with type 'int'}}
+// expected-note at second.h:* {{but in definition here found field 'ivarType' with type 'float'}}
+#endif
 CompareIVarOrder *compareIVarOrder;
 // expected-error at first.h:* {{'CompareIVarOrder' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found field 'ivarNameInt'}}
-// expected-note at second.h:* {{but in 'Second' found field 'ivarNameFloat'}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found field 'ivarNameFloat'}}
 
 CompareIVarVisibilityExplicit *compareIVarVisibilityExplicit;
 // expected-error at first.h:* {{'CompareIVarVisibilityExplicit' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found instance variable 'ivarVisibility' access control is @public}}
-// expected-note at second.h:* {{but in 'Second' found instance variable 'ivarVisibility' access control is @private}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found instance variable 'ivarVisibility' access control is @private}}
 CompareIVarVisibilityDefault *compareIVarVisibilityDefault;
 // expected-error at first.h:* {{'CompareIVarVisibilityDefault' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found instance variable 'ivarVisibilityDefault' access control is @protected}}
-// expected-note at second.h:* {{but in 'Second' found instance variable 'ivarVisibilityDefault' access control is @public}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found instance variable 'ivarVisibilityDefault' access control is @public}}
 #endif
 
 #if defined(FIRST)
@@ -288,34 +310,34 @@ - (void)methodClassInstance;
 CompareMatchingMethods *compareMatchingMethods;
 CompareMethodPresence1 *compareMethodPresence1;
 // expected-error at first.h:* {{'CompareMethodPresence1' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found method}}
-// expected-note at second.h:* {{but in 'Second' found end of class}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found end of class}}
 CompareMethodPresence2 *compareMethodPresence2;
 // expected-error at first.h:* {{'CompareMethodPresence2' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found end of class}}
-// expected-note at second.h:* {{but in 'Second' found method}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found method}}
 CompareMethodName *compareMethodName;
 // expected-error at first.h:* {{'CompareMethodName' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found method 'methodNameA'}}
-// expected-note at second.h:* {{but in 'Second' found 
diff erent method 'methodNameB'}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found 
diff erent method 'methodNameB'}}
 
 CompareMethodArgCount *compareMethodArgCount;
 // expected-error at first.h:* {{'CompareMethodArgCount' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found method 'methodArgCount::' that has 2 parameters}}
-// expected-note at second.h:* {{but in 'Second' found method 'methodArgCount:' that has 1 parameter}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found method 'methodArgCount:' that has 1 parameter}}
 CompareMethodArgName *compareMethodArgName;
 // expected-error at first.h:* {{'CompareMethodArgName' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found method 'methodArgName:' with 1st parameter named 'argNameA'}}
-// expected-note at second.h:* {{but in 'Second' found method 'methodArgName:' with 1st parameter named 'argNameB'}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found method 'methodArgName:' with 1st parameter named 'argNameB'}}
 CompareMethodArgType *compareMethodArgType;
 // expected-error at first.h:* {{'CompareMethodArgType' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found method 'methodArgType:' with 1st parameter of type 'int'}}
-// expected-note at second.h:* {{but in 'Second' found method 'methodArgType:' with 1st parameter of type 'float'}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found method 'methodArgType:' with 1st parameter of type 'float'}}
 
 CompareMethodReturnType *compareMethodReturnType;
 // expected-error at first.h:* {{'CompareMethodReturnType' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found method 'methodReturnType' with return type 'int'}}
-// expected-note at second.h:* {{but in 'Second' found method 'methodReturnType' with 
diff erent return type 'float'}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found method 'methodReturnType' with 
diff erent return type 'float'}}
 
 CompareMethodOrder *compareMethodOrder;
 // expected-error at first.h:* {{'CompareMethodOrder' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found method 'methodOrderFirst'}}
-// expected-note at second.h:* {{but in 'Second' found 
diff erent method 'methodOrderSecond'}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found 
diff erent method 'methodOrderSecond'}}
 CompareMethodClassInstance *compareMethodClassInstance;
 // expected-error at first.h:* {{'CompareMethodClassInstance' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found class method 'methodClassInstance'}}
-// expected-note at second.h:* {{but in 'Second' found method 'methodClassInstance' as instance method}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found method 'methodClassInstance' as instance method}}
 #endif
 
 #if defined(FIRST)
@@ -396,29 +418,29 @@ @interface CompareLastImplAttribute: NSObject
 CompareMatchingProperties *compareMatchingProperties;
 ComparePropertyPresence1 *comparePropertyPresence1;
 // expected-error at first.h:* {{'ComparePropertyPresence1' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found property}}
-// expected-note at second.h:* {{but in 'Second' found end of class}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found end of class}}
 ComparePropertyPresence2 *comparePropertyPresence2;
 // expected-error at first.h:* {{'ComparePropertyPresence2' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found end of class}}
-// expected-note at second.h:* {{but in 'Second' found property}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found property}}
 
 ComparePropertyName *comparePropertyName;
 // expected-error at first.h:* {{'ComparePropertyName' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found property 'propNameA'}}
-// expected-note at second.h:* {{but in 'Second' found property 'propNameB'}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found property 'propNameB'}}
 ComparePropertyType *comparePropertyType;
 // expected-error at first.h:* {{'ComparePropertyType' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found property 'propType' with type 'int'}}
-// expected-note at second.h:* {{but in 'Second' found property 'propType' with type 'float'}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found property 'propType' with type 'float'}}
 ComparePropertyOrder *comparePropertyOrder;
 // expected-error at first.h:* {{'ComparePropertyOrder' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found property 'propOrderX'}}
-// expected-note at second.h:* {{but in 'Second' found property 'propOrderY'}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found property 'propOrderY'}}
 
 CompareMatchingPropertyAttributes *compareMatchingPropertyAttributes;
 ComparePropertyAttributes *comparePropertyAttributes;
 // expected-error at first.h:* {{'ComparePropertyAttributes' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found property 'propAttributes' with 'readonly' attribute}}
-// expected-note at second.h:* {{but in 'Second' found property 'propAttributes' with 
diff erent 'readonly' attribute}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found property 'propAttributes' with 
diff erent 'readonly' attribute}}
 CompareFirstImplAttribute *compareFirstImplAttribute;
 // expected-error at first.h:* {{'CompareFirstImplAttribute' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found property 'firstImplAttribute' with default 'readonly' attribute}}
-// expected-note at second.h:* {{but in 'Second' found property 'firstImplAttribute' with 
diff erent 'readonly' attribute}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found property 'firstImplAttribute' with 
diff erent 'readonly' attribute}}
 CompareLastImplAttribute *compareLastImplAttribute;
 // expected-error at first.h:* {{'CompareLastImplAttribute' has 
diff erent definitions in 
diff erent modules; first 
diff erence is definition in module 'First.Hidden' found property 'lastImplAttribute' with 'direct' attribute}}
-// expected-note at second.h:* {{but in 'Second' found property 'lastImplAttribute' with 
diff erent 'direct' attribute}}
+// expected-note-re at second.h:* {{but in {{'Second'|definition here}} found property 'lastImplAttribute' with 
diff erent 'direct' attribute}}
 #endif

diff  --git a/clang/test/Modules/hidden-duplicates.m b/clang/test/Modules/hidden-duplicates.m
index 423654502fd81..b3af9697cc0b8 100644
--- a/clang/test/Modules/hidden-duplicates.m
+++ b/clang/test/Modules/hidden-duplicates.m
@@ -30,6 +30,12 @@ @protocol ForwardDeclaredProtocolWithoutDefinition;
 id<ForwardDeclaredProtocolWithoutDefinition> forwardDeclaredProtocol(
     id<ForwardDeclaredProtocolWithoutDefinition> t);
 
+ at interface NSObject @end
+ at class ForwardDeclaredInterfaceWithoutDefinition;
+
+NSObject *interfaceDefinition(NSObject *o);
+NSObject *forwardDeclaredInterface(NSObject *o);
+
 #endif
 
 //--- include/empty.h


        


More information about the cfe-commits mailing list