[cfe-commits] r172635 - in /cfe/trunk: lib/Sema/SemaDeclObjC.cpp test/Modules/Inputs/MethodPoolASub.h test/Modules/Inputs/MethodPoolBSub.h test/Modules/Inputs/module.map test/Modules/method_pool.m

Douglas Gregor dgregor at apple.com
Wed Jan 16 10:47:39 PST 2013


Author: dgregor
Date: Wed Jan 16 12:47:38 2013
New Revision: 172635

URL: http://llvm.org/viewvc/llvm-project?rev=172635&view=rev
Log:
Teach global selector lookup to ignore hidden methods, which occur
when the methods are declared in a submodule that has not yet been
imported. Part of <rdar://problem/10634711>. 

Added:
    cfe/trunk/test/Modules/Inputs/MethodPoolASub.h
    cfe/trunk/test/Modules/Inputs/MethodPoolBSub.h
Modified:
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/test/Modules/Inputs/module.map
    cfe/trunk/test/Modules/method_pool.m

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=172635&r1=172634&r2=172635&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Wed Jan 16 12:47:38 2013
@@ -2167,61 +2167,79 @@
   if (Pos == MethodPool.end())
     return 0;
 
+  // Gather the non-hidden methods.
   ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
+  llvm::SmallVector<ObjCMethodDecl *, 4> Methods;
+  for (ObjCMethodList *M = &MethList; M; M = M->Next) {
+    if (M->Method && !M->Method->isHidden()) {
+      // If we're not supposed to warn about mismatches, we're done.
+      if (!warn)
+        return M->Method;
 
-  if (warn && MethList.Method && MethList.Next) {
-    bool issueDiagnostic = false, issueError = false;
+      Methods.push_back(M->Method);
+    }
+  }
 
-    // We support a warning which complains about *any* difference in
-    // method signature.
-    bool strictSelectorMatch =
-      (receiverIdOrClass && warn &&
-       (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
-                                 R.getBegin()) != 
-      DiagnosticsEngine::Ignored));
-    if (strictSelectorMatch)
-      for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
-        if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
-                                        MMS_strict)) {
-          issueDiagnostic = true;
-          break;
-        }
+  // If there aren't any visible methods, we're done.
+  // FIXME: Recover if there are any known-but-hidden methods?
+  if (Methods.empty())
+    return 0;
+
+  if (Methods.size() == 1)
+    return Methods[0];
+
+  // We found multiple methods, so we may have to complain.
+  bool issueDiagnostic = false, issueError = false;
+
+  // We support a warning which complains about *any* difference in
+  // method signature.
+  bool strictSelectorMatch =
+    (receiverIdOrClass && warn &&
+     (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
+                               R.getBegin())
+        != DiagnosticsEngine::Ignored));
+  if (strictSelectorMatch) {
+    for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
+      if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_strict)) {
+        issueDiagnostic = true;
+        break;
       }
+    }
+  }
 
-    // If we didn't see any strict differences, we won't see any loose
-    // differences.  In ARC, however, we also need to check for loose
-    // mismatches, because most of them are errors.
-    if (!strictSelectorMatch ||
-        (issueDiagnostic && getLangOpts().ObjCAutoRefCount))
-      for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
-        // This checks if the methods differ in type mismatch.
-        if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
-                                        MMS_loose) &&
-            !isAcceptableMethodMismatch(MethList.Method, Next->Method)) {
-          issueDiagnostic = true;
-          if (getLangOpts().ObjCAutoRefCount)
-            issueError = true;
-          break;
-        }
+  // If we didn't see any strict differences, we won't see any loose
+  // differences.  In ARC, however, we also need to check for loose
+  // mismatches, because most of them are errors.
+  if (!strictSelectorMatch ||
+      (issueDiagnostic && getLangOpts().ObjCAutoRefCount))
+    for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
+      // This checks if the methods differ in type mismatch.
+      if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_loose) &&
+          !isAcceptableMethodMismatch(Methods[0], Methods[I])) {
+        issueDiagnostic = true;
+        if (getLangOpts().ObjCAutoRefCount)
+          issueError = true;
+        break;
       }
+    }
 
-    if (issueDiagnostic) {
-      if (issueError)
-        Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R;
-      else if (strictSelectorMatch)
-        Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;
-      else
-        Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
+  if (issueDiagnostic) {
+    if (issueError)
+      Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R;
+    else if (strictSelectorMatch)
+      Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;
+    else
+      Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
 
-      Diag(MethList.Method->getLocStart(), 
-           issueError ? diag::note_possibility : diag::note_using)
-        << MethList.Method->getSourceRange();
-      for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
-        Diag(Next->Method->getLocStart(), diag::note_also_found)
-          << Next->Method->getSourceRange();
-    }
+    Diag(Methods[0]->getLocStart(),
+         issueError ? diag::note_possibility : diag::note_using)
+      << Methods[0]->getSourceRange();
+    for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
+      Diag(Methods[I]->getLocStart(), diag::note_also_found)
+        << Methods[I]->getSourceRange();
+  }
   }
-  return MethList.Method;
+  return Methods[0];
 }
 
 ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {

Added: cfe/trunk/test/Modules/Inputs/MethodPoolASub.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/MethodPoolASub.h?rev=172635&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/MethodPoolASub.h (added)
+++ cfe/trunk/test/Modules/Inputs/MethodPoolASub.h Wed Jan 16 12:47:38 2013
@@ -0,0 +1,3 @@
+ at interface A (Sub)
+- (char)method3;
+ at end

Added: cfe/trunk/test/Modules/Inputs/MethodPoolBSub.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/MethodPoolBSub.h?rev=172635&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/MethodPoolBSub.h (added)
+++ cfe/trunk/test/Modules/Inputs/MethodPoolBSub.h Wed Jan 16 12:47:38 2013
@@ -0,0 +1,3 @@
+ at interface B (Sub)
+- (char *)method3;
+ at end

Modified: cfe/trunk/test/Modules/Inputs/module.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/module.map?rev=172635&r1=172634&r2=172635&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/module.map (original)
+++ cfe/trunk/test/Modules/Inputs/module.map Wed Jan 16 12:47:38 2013
@@ -107,9 +107,17 @@
 }
 module MethodPoolA {
   header "MethodPoolA.h"
+
+  explicit module Sub {
+    header "MethodPoolASub.h"
+  }
 }
 module MethodPoolB {
   header "MethodPoolB.h"
+
+  explicit module Sub {
+    header "MethodPoolBSub.h"
+  }
 }
 module import_decl {
   header "import-decl.h"

Modified: cfe/trunk/test/Modules/method_pool.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/method_pool.m?rev=172635&r1=172634&r2=172635&view=diff
==============================================================================
--- cfe/trunk/test/Modules/method_pool.m (original)
+++ cfe/trunk/test/Modules/method_pool.m Wed Jan 16 12:47:38 2013
@@ -28,3 +28,21 @@
 void testMethod2Again(id object) {
   [object method2:1]; // expected-warning{{multiple methods named 'method2:' found}}
 }
+
+void testMethod3(id object) {
+  [object method3]; // expected-warning{{instance method '-method3' not found (return type defaults to 'id')}}
+}
+
+ at import MethodPoolB.Sub;
+
+void testMethod3Again(id object) {
+  char *str = [object method3]; // okay: only found in MethodPoolB.Sub
+}
+
+ at import MethodPoolA.Sub;
+
+void testMethod3AgainAgain(id object) {
+  [object method3]; // expected-warning{{multiple methods named 'method3' found}}
+  // expected-note at 2{{using}}
+  // expected-note at 2{{also found}}
+}





More information about the cfe-commits mailing list