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

David Blaikie dblaikie at gmail.com
Tue Mar 19 19:13:16 PDT 2013


On Tue, Mar 19, 2013 at 6:53 PM, John McCall <rjmccall at apple.com> wrote:
> 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

AKA PR15496

Thanks for the fix, John!

- David

>
> 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();
> +    }
> +  };
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list