1

Is this program well-formed according to the c++ standard?

namespace X { int i = 1; }

using namespace X;

int main() {
    extern int i;
    i = 2;
}

I get different results with different compilers:

  • GCC and Clang gives a linker error: Undefined reference to i.

  • Visual c++ accepts the program.

Supremum
  • 542
  • 7
  • 23
  • [Clang](http://melpon.org/wandbox/permlink/mXZcZBUJ0hugmhU5) and [GCC](http://melpon.org/wandbox/permlink/HI7rh3yNLZoNmgJf) accept the program. Which versions are you using? – David G Jul 18 '15 at 17:46
  • The latest possible version here: http://melpon.org/wandbox – Supremum Jul 18 '15 at 17:47
  • I had an error in the example. I have fixed it now. Now both GCC and Clang gives a compilation error (undefined reference to i). – Supremum Jul 18 '15 at 17:49
  • I meant linker error instead of compiler error in my previous comment. – Supremum Jul 18 '15 at 18:51

1 Answers1

4

[basic.link]/p6:

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. If there is more than one such matching entity, the program is ill-formed. Otherwise, if no matching entity is found, the block scope entity receives external linkage.

X::i was declared outside the innermost enclosing namespace of the extern declaration (i.e the global namespace) so it is ignored. This means no declaration was found for i and therefore extern int i is a declaration of a new variable named i with external linkage.

Your program will compile, but will not link if the block-scope i is odr-used.

David G
  • 94,763
  • 41
  • 167
  • 253
  • Doesn't [namespace.udir]p2 ( http://eel.is/c++draft/namespace.udir#2 ) apply here? – Supremum Jul 18 '15 at 18:22
  • 1
    @Supremum That was my concern as well, but I think from this note from [basic.scope.pdecl]/p11, "Function declarations at block scope and variable declarations with the `extern` specifier at block scope refer to declarations that are members of an enclosing namespace", `X::i` appears as if it was declared in the global namespace but it is not a member, which makes it excluded from the lookup. I'm a little shaky in this area though so maybe someone more knowledgeable will come around with something definitive. – David G Jul 18 '15 at 18:36
  • Hmm... Yes X::i is clearly not a member the global namespace since it is not declared there, but according to [namespace.udir]p2 name-lookup should behave like it was declared there, and therefore was a member of the global namespace. However I think that applying [basic.link]/p6 is not a name-lookup. Therefore I think you are right about that we should get linker error here. Does this mean that visual c++ have a bug for not reporting the linker error? – Supremum Jul 18 '15 at 18:49
  • 1
    @Supremum Yes, I think VC++ has a bug here. – David G Jul 18 '15 at 18:54
  • @0x499602D2 I would have thought that changing ```using namespace X;``` to ```using X::i;``` would compile. It too fails, even though [this answer](https://stackoverflow.com/questions/42388431/function-hiding-and-using-declaration-in-c) seems to indicate that a using declaration amounts to a declaration of in the same region for that entity. I don't understand why it still fails then since they declaration is obviously visible. – Colin Hicks Jan 27 '21 at 16:58