[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