[cfe-dev] Extern ref from method defined outside its namespace

John McCall rjmccall at apple.com
Thu Dec 20 11:53:58 PST 2012


On Dec 20, 2012, at 11:20 AM, "Robinson, Paul" <Paul.Robinson at am.sony.com> wrote:
> Here's a case where Clang and GCC both do the same thing but I don't see
> why it is correct.
> 
> --------------------------------------
> namespace aaa {
>  class Klass {
>  public:
>    Klass() {}
>    void Method();
>  };
> }
> 
> class Klass2 {
> public:
>  void Method() {}
> };
> 
> Klass2 k2;
> 
> using namespace aaa;
> 
> void Klass::Method() {
>  extern Klass2 k2; // <-- refers to what name?
>  k2.Method();
> }
> 
> int main() {
>  Klass k;
>  k.Method();
>  return 0;
> }
> --------------------------------------
> So "k2" is defined in the global namespace and has external linkage.
> "using namespace aaa;" unpeels aaa and makes Klass available in the
> global namespace.
> This means the definition of "Klass::Method" actually refers to
> "aaa::Klass::Method". So far so good.
> 
> If I omit the "extern Klass2 k2;" then the reference to k2.Method
> correctly finds k2 in the global namespace.
> 
> But, adding the "extern" declaration causes Clang to treat "k2" as
> a reference to "aaa::k2" rather than "::k2".  I think that's wrong.
> 
> 3.5 [basic.link] p6
> The name of a function declared in block scope and the name of a variable
> declared by a block scope "extern" declaration have linkage. If there is
> a visible declaration of an entity with linkage having the same name and
> type, ignoring entities declared outside the innermost enclosing namespace
> scope, the block scope declaration declares that same entity and receives
> the linkage of the previous declaration.
> 
> Clearly ::k2 is visible for normal unqualified lookup, because if we omit
> the "extern" declaration the compiler is able to see it.
> The "using namespace aaa;" doesn't introduce a namespace scope, so the
> method definition's innermost enclosing namespace scope would be the
> global namespace, which is where ::k2 lives.
> 
> I don't see that the member-function definition of Klass::Method would
> implicitly open a scope for namespace aaa.  Therefore, the global
> namespace is still the innermost enclosing namespace scope of this
> method's definition.
> 
> If we had this:
> 
> namespace aaa {
>  void Klass::Method() {
>    extern Klass2 k2;
>    k2.Method();
>  }
> }
> then sure, "k2" would be "aaa::k2" by the innermost-enclosing-namespace
> rule.  But we don't have that here, AFAICT.

Within an out-of-line declaration, the enclosing namespace is the
original namespace of the entity, not the lexical namespace.

C++11 [namespace.def]p6:
  The enclosing namespaces of a declaration are those namespaces in
  which the declaration lexically appears, except for a redeclaration of a
  namespace member outside its original namespace (e.g., a definition
  as specified in 7.3.1.2). Such a redeclaration has the same enclosing
  namespaces as the original declaration.

John.



More information about the cfe-dev mailing list