r177473 - Don't look outside the innermost enclosing namespace when

John McCall rjmccall at apple.com
Tue Mar 19 18:53:00 PDT 2013


Author: rjmccall
Date: Tue Mar 19 20:53:00 2013
New Revision: 177473

URL: http://llvm.org/viewvc/llvm-project?rev=177473&view=rev
Log:
Don't look outside the innermost enclosing namespace when
performing unqualified lookup for a friend class declaration.

rdar://13393749

Modified:
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=177473&r1=177472&r2=177473&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Mar 19 20:53:00 2013
@@ -9467,6 +9467,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned
     // shouldn't be diagnosing.
     LookupName(Previous, S);
 
+    // When declaring or defining a tag, ignore ambiguities introduced
+    // by types using'ed into this scope.
     if (Previous.isAmbiguous() && 
         (TUK == TUK_Definition || TUK == TUK_Declaration)) {
       LookupResult::Filter F = Previous.makeFilter();
@@ -9476,6 +9478,27 @@ Decl *Sema::ActOnTag(Scope *S, unsigned
           F.erase();
       }
       F.done();
+    }
+
+    // C++11 [namespace.memdef]p3:
+    //   If the name in a friend declaration is neither qualified nor
+    //   a template-id and the declaration is a function or an
+    //   elaborated-type-specifier, the lookup to determine whether
+    //   the entity has been previously declared shall not consider
+    //   any scopes outside the innermost enclosing namespace.
+    //
+    // Does it matter that this should be by scope instead of by
+    // semantic context?
+    if (!Previous.empty() && TUK == TUK_Friend) {
+      DeclContext *EnclosingNS = SearchDC->getEnclosingNamespaceContext();
+      LookupResult::Filter F = Previous.makeFilter();
+      while (F.hasNext()) {
+        NamedDecl *ND = F.next();
+        DeclContext *DC = ND->getDeclContext()->getRedeclContext();
+        if (DC->isFileContext() && !EnclosingNS->Encloses(ND->getDeclContext()))
+          F.erase();
+      }
+      F.done();
     }
     
     // Note:  there used to be some attempt at recovery here.

Modified: cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp?rev=177473&r1=177472&r2=177473&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp Tue Mar 19 20:53:00 2013
@@ -91,3 +91,104 @@ namespace test5 {
   template void f<int>(int);
   template void f<long>(long); //expected-note {{instantiation}}
 }
+
+// rdar://13393749
+namespace test6 {
+  class A;
+  namespace ns {
+    class B {
+      static void foo(); // expected-note {{implicitly declared private here}}
+      friend union A;
+    };
+
+    union A {
+      void test() {
+        B::foo();
+      }
+    };
+  }
+
+  class A {
+    void test() {
+      ns::B::foo(); // expected-error {{'foo' is a private member of 'test6::ns::B'}}
+    }
+  };
+}
+
+// We seem to be following a correct interpretation with these, but
+// the standard could probably be a bit clearer.
+namespace test7a {
+  namespace ns {
+    class A;
+  }
+
+  using namespace ns;
+  class B {
+    static void foo();
+    friend class A;
+  };
+
+  class ns::A {
+    void test() {
+      B::foo();
+    }
+  };
+}
+namespace test7b {
+  namespace ns {
+    class A;
+  }
+
+  using ns::A;
+  class B {
+    static void foo();
+    friend class A;
+  };
+
+  class ns::A {
+    void test() {
+      B::foo();
+    }
+  };
+}
+namespace test7c {
+  namespace ns1 {
+    class A;
+  }
+
+  namespace ns2 {
+    // ns1::A appears as if declared in test7c according to [namespace.udir]p2.
+    // I think that means we aren't supposed to find it.
+    using namespace ns1;
+    class B {
+      static void foo(); // expected-note {{implicitly declared private here}}
+      friend class A;
+    };
+  }
+
+  class ns1::A {
+    void test() {
+      ns2::B::foo(); // expected-error {{'foo' is a private member of 'test7c::ns2::B'}}
+    }
+  };
+}
+namespace test7d {
+  namespace ns1 {
+    class A;
+  }
+
+  namespace ns2 {
+    // Honor the lexical context of a using-declaration, though.
+    using ns1::A;
+    class B {
+      static void foo();
+      friend class A;
+    };
+  }
+
+  class ns1::A {
+    void test() {
+      ns2::B::foo();
+    }
+  };
+}





More information about the cfe-commits mailing list