[cfe-commits] r146563 - in /cfe/trunk: include/clang/Sema/Lookup.h lib/Sema/SemaLookup.cpp test/Modules/Inputs/decl.h test/Modules/Inputs/def.h test/Modules/Inputs/module.map test/Modules/decldef.mm

Douglas Gregor dgregor at apple.com
Wed Dec 14 08:03:29 PST 2011


Author: dgregor
Date: Wed Dec 14 10:03:29 2011
New Revision: 146563

URL: http://llvm.org/viewvc/llvm-project?rev=146563&view=rev
Log:
When name lookup comes across a declaration that is in a module that
is not visible, look for any previous declarations of that entity that
might be visible.

Added:
    cfe/trunk/test/Modules/Inputs/decl.h   (with props)
    cfe/trunk/test/Modules/Inputs/def.h   (with props)
    cfe/trunk/test/Modules/decldef.mm
Modified:
    cfe/trunk/include/clang/Sema/Lookup.h
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/test/Modules/Inputs/module.map

Modified: cfe/trunk/include/clang/Sema/Lookup.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Lookup.h?rev=146563&r1=146562&r2=146563&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Lookup.h (original)
+++ cfe/trunk/include/clang/Sema/Lookup.h Wed Dec 14 10:03:29 2011
@@ -266,23 +266,36 @@
     return Paths;
   }
 
-  /// \brief Tests whether the given declaration is acceptable.
-  bool isAcceptableDecl(NamedDecl *D) const {
-    if (!D->isInIdentifierNamespace(IDNS))
-      return false;
-    
+  /// \brief Determine whether the given declaration is visible to the
+  /// program.
+  static bool isVisible(NamedDecl *D) {
     // So long as this declaration is not module-private or was parsed as
-    // part of this translation unit (i.e., in the module), we're allowed to
-    // find it.
+    // part of this translation unit (i.e., in the module), it's visible.
     if (!D->isModulePrivate() || !D->isFromASTFile())
       return true;
-
+    
     // FIXME: We should be allowed to refer to a module-private name from 
     // within the same module, e.g., during template instantiation.
     // This requires us know which module a particular declaration came from.
     return false;
   }
-
+  
+  /// \brief Retrieve the accepted (re)declaration of the given declaration,
+  /// if there is one.
+  NamedDecl *getAcceptableDecl(NamedDecl *D) const {
+    if (!D->isInIdentifierNamespace(IDNS))
+      return 0;
+    
+    if (isVisible(D))
+      return D;
+    
+    return getAcceptableDeclSlow(D);
+  }
+  
+private:
+  NamedDecl *getAcceptableDeclSlow(NamedDecl *D) const;
+public:
+  
   /// \brief Returns the identifier namespace mask for this lookup.
   unsigned getIdentifierNamespace() const {
     return IDNS;

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=146563&r1=146562&r2=146563&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Wed Dec 14 10:03:29 2011
@@ -321,6 +321,12 @@
   delete Paths;
 }
 
+static NamedDecl *getVisibleDecl(NamedDecl *D);
+
+NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
+  return getVisibleDecl(D);
+}
+
 /// Resolves the result kind of this lookup.
 void LookupResult::resolveKind() {
   unsigned N = Decls.size();
@@ -649,7 +655,7 @@
   DeclContext::lookup_const_iterator I, E;
   for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
     NamedDecl *D = *I;
-    if (R.isAcceptableDecl(D)) {
+    if ((D = R.getAcceptableDecl(D))) {
       R.addDecl(D);
       Found = true;
     }
@@ -875,9 +881,9 @@
     // Check whether the IdResolver has anything in this scope.
     bool Found = false;
     for (; I != IEnd && S->isDeclScope(*I); ++I) {
-      if (R.isAcceptableDecl(*I)) {
+      if (NamedDecl *ND = R.getAcceptableDecl(*I)) {
         Found = true;
-        R.addDecl(*I);
+        R.addDecl(ND);
       }
     }
     if (Found) {
@@ -926,8 +932,8 @@
                 if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable(
                                                  Name.getAsIdentifierInfo(),
                                                              ClassDeclared)) {
-                  if (R.isAcceptableDecl(Ivar)) {
-                    R.addDecl(Ivar);
+                  if (NamedDecl *ND = R.getAcceptableDecl(Ivar)) {
+                    R.addDecl(ND);
                     R.resolveKind();
                     return true;
                   }
@@ -977,13 +983,13 @@
     // Check whether the IdResolver has anything in this scope.
     bool Found = false;
     for (; I != IEnd && S->isDeclScope(*I); ++I) {
-      if (R.isAcceptableDecl(*I)) {
+      if (NamedDecl *ND = R.getAcceptableDecl(*I)) {
         // We found something.  Look for anything else in our scope
         // with this same name and in an acceptable identifier
         // namespace, so that we can construct an overload set if we
         // need to.
         Found = true;
-        R.addDecl(*I);
+        R.addDecl(ND);
       }
     }
 
@@ -1047,6 +1053,40 @@
   return !R.empty();
 }
 
+/// \brief Retrieve the previous declaration of D.
+static NamedDecl *getPreviousDeclaration(NamedDecl *D) {
+  if (TagDecl *TD = dyn_cast<TagDecl>(D))
+    return TD->getPreviousDeclaration();
+  if (VarDecl *VD = dyn_cast<VarDecl>(D))
+    return VD->getPreviousDeclaration();
+  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+    return FD->getPreviousDeclaration();
+  if (RedeclarableTemplateDecl *RTD = dyn_cast<RedeclarableTemplateDecl>(D))
+    return RTD->getPreviousDeclaration();
+  
+  return 0;
+}
+
+/// \brief Retrieve the visible declaration corresponding to D, if any.
+///
+/// This routine determines whether the declaration D is visible in the current
+/// module, with the current imports. If not, it checks whether any
+/// redeclaration of D is visible, and if so, returns that declaration.
+/// 
+/// \returns D, or a visible previous declaration of D, whichever is more recent
+/// and visible. If no declaration of D is visible, returns null.
+static NamedDecl *getVisibleDecl(NamedDecl *D) {
+  if (LookupResult::isVisible(D))
+    return D;
+  
+  while ((D = getPreviousDeclaration(D))) {
+    if (LookupResult::isVisible(D))
+      return D;
+  }
+  
+  return 0;
+}
+
 /// @brief Perform unqualified name lookup starting from a given
 /// scope.
 ///
@@ -1125,10 +1165,11 @@
         
         // If this declaration is module-private and it came from an AST
         // file, we can't see it.
-        if ((*I)->isModulePrivate() && (*I)->isFromASTFile())
+        NamedDecl *D = getVisibleDecl(*I);
+        if (!D)
           continue;
-            
-        R.addDecl(*I);
+                
+        R.addDecl(D);
 
         if ((*I)->getAttr<OverloadableAttr>()) {
           // If this declaration has the "overloadable" attribute, we
@@ -1145,7 +1186,10 @@
           for (++LastI; LastI != IEnd; ++LastI) {
             if (!S->isDeclScope(*LastI))
               break;
-            R.addDecl(*LastI);
+            
+            D = getVisibleDecl(*LastI);
+            if (D)
+              R.addDecl(D);
           }
         }
 
@@ -2712,7 +2756,7 @@
                                  DEnd = CurCtx->decls_end();
          D != DEnd; ++D) {
       if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) {
-        if (Result.isAcceptableDecl(ND)) {
+        if ((ND = Result.getAcceptableDecl(ND))) {
           Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
           Visited.add(ND);
         }
@@ -2723,17 +2767,16 @@
                PEnd = ForwardProto->protocol_end();
              P != PEnd;
              ++P) {
-          if (Result.isAcceptableDecl(*P)) {
-            Consumer.FoundDecl(*P, Visited.checkHidden(*P), Ctx, InBaseClass);
-            Visited.add(*P);
+          if (NamedDecl *ND = Result.getAcceptableDecl(*P)) {
+            Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
+            Visited.add(ND);
           }
         }
       } else if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) {
           ObjCInterfaceDecl *IFace = Class->getForwardInterfaceDecl();
-          if (Result.isAcceptableDecl(IFace)) {
-            Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), Ctx,
-                               InBaseClass);
-            Visited.add(IFace);
+          if (NamedDecl *ND = Result.getAcceptableDecl(IFace)) {
+            Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
+            Visited.add(ND);
           }
       }
       
@@ -2873,7 +2916,7 @@
     for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
          D != DEnd; ++D) {
       if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
-        if (Result.isAcceptableDecl(ND)) {
+        if ((ND = Result.getAcceptableDecl(ND))) {
           Consumer.FoundDecl(ND, Visited.checkHidden(ND), 0, false);
           Visited.add(ND);
         }

Added: cfe/trunk/test/Modules/Inputs/decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/decl.h?rev=146563&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/decl.h (added)
+++ cfe/trunk/test/Modules/Inputs/decl.h Wed Dec 14 10:03:29 2011
@@ -0,0 +1,2 @@
+ at class A;
+typedef struct B B;

Propchange: cfe/trunk/test/Modules/Inputs/decl.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/Modules/Inputs/decl.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/Modules/Inputs/decl.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/Modules/Inputs/def.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/def.h?rev=146563&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/def.h (added)
+++ cfe/trunk/test/Modules/Inputs/def.h Wed Dec 14 10:03:29 2011
@@ -0,0 +1,7 @@
+ at interface A
+ at end
+
+struct B {
+  int b1;
+};
+

Propchange: cfe/trunk/test/Modules/Inputs/def.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/Modules/Inputs/def.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/Modules/Inputs/def.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/Modules/Inputs/module.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/module.map?rev=146563&r1=146562&r2=146563&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/module.map (original)
+++ cfe/trunk/test/Modules/Inputs/module.map Wed Dec 14 10:03:29 2011
@@ -36,3 +36,8 @@
 module redeclarations_left { header "redeclarations_left.h" }
 module redeclarations_right { header "redeclarations_right.h" }
 module load_failure { header "load_failure.h" }
+
+module decldef {
+  explicit module Decl { header "decl.h" }
+  explicit module Def { header "def.h" }
+}
\ No newline at end of file

Added: cfe/trunk/test/Modules/decldef.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/decldef.mm?rev=146563&view=auto
==============================================================================
--- cfe/trunk/test/Modules/decldef.mm (added)
+++ cfe/trunk/test/Modules/decldef.mm Wed Dec 14 10:03:29 2011
@@ -0,0 +1,17 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -I %S/Inputs -fmodule-cache-path %t %s -verify
+
+__import_module__ decldef;
+A *a1; // expected-error{{unknown type name 'A'}}
+B *b1; // expected-error{{unknown type name 'B'}}
+
+__import_module__ decldef.Decl;
+
+// FIXME: No link between @interface (which we can't see) and @class
+// (which we can).
+// A *a2;
+B *b;
+
+void testB() {
+  B b; // FIXME: Should error, because we can't see the definition.
+}





More information about the cfe-commits mailing list