Local extern variable declaration with using-directive in the nearest enclosing scope - c++

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.

[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.

Related

Is it valid to use extern in a local scope to unshadow a global variable?

Is this extern declaration in a nested local scope a valid and defined way to bring the global a back into the scope?
int a = 1; // may be in another file
void main() {
int a = 2; // hides the global
{
cout << a << endl; // prints 2
cout << ::a << endl; // obviously 1
extern int a;
cout << a << endl; // also prints 1
}
}
This is a valid use of extern, though an obscure one. According to the C++20 standard ([basic.link]/6):
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 such a declaration is attached to a named module, the program is
ill-formed. If there is a visible declaration of an entity with linkage, ignoring entities declared outside the
innermost enclosing namespace scope, such that the block scope declaration would be a (possibly ill-formed)
redeclaration if the two declarations appeared in the same declarative region, 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. If, within a translation unit, the same entity is declared with both internal and
external linkage, the program is ill-formed.
In the OP's example, the block-scope declaration extern int a; fails to find a matching declaration with linkage, because the local declaration int a = 2; which has no linkage hides the global declaration int a = 1; which has external linkage. Therefore, extern int a; defaults to external linkage. Also see paragraph 7:
When a block scope declaration of an entity with linkage is not found to refer to some other declaration,
then that entity is a member of the innermost enclosing namespace. However such a declaration does not
introduce the member name in its namespace scope.
Therefore, extern int a; declares a as a member of the nearest enclosing namespace, which is the global namespace. This means it's the same entity as the previously declared global a, since both declare a variable with the same name in the same namespace with linkage. In other words, it gives you a way to refer to the global variable within the block.
This use of extern was inherited from C, but it is obscure even in C. Its use should generally be avoided in favour of ::a.

does c++ allows hoisting or is it compiler specific ? even if

So i was looking through various questions to prepare for my interview that's up tomorrow and came across extern keyword, i understand that extern keyword specifies to allocate memory for a variable which is part of another program(dont know where to use) but the real doubt is,
#include<iostream>
using std::cout;
int main()
{
extern int a;
cout<<a;
return 0;
}
int a=20;
output:
20
i wonder how this works? even if hoisting works in c++ , i know a bit of JS hoisting like even if the declaration of a as int a is done first and assignment is done later , the output is ought to be a value a garbage value....
For this block scope declaration
extern int a;
the compiler searches a previous declaration of the name a in the global namespace that to determine whether it has external or internal linkage. If the compiler does not find the previous declaration it thinks that the variable a refers to a variable defined in the global namespace with external linkage.
And indeed there is a definition of the variable in the global namespace
int a=20;
So the two declarations refer to the same object defined in the global namespace.
From the C++ 17 Standard (6.5 Program and linkage)
2 A name is said to have linkage when it might denote the same object,
reference, function, type, template, namespace or value as a name
introduced by a declaration in another scope:
and
6 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. 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. If, within a translation unit, the
same entity is declared with both internal and external linkage, the
program is ill-formed.
That is a declaration in a block scope with the storage class specifier extern does not define a new object. It refers to an object with the same name defined in the enclosing namespace with an internal or external linkage.

Trying to understand §3.3.1/4 [duplicate]

This question already has answers here:
Can a variable be declared both static and extern?
(4 answers)
Closed 8 years ago.
Apparently from §3.3.1/4, this snippet doesn't compile because it contains two different entities with the same name A in the global namespace, extern int A; and static int A = 101;. That is, one has external and the other has internal linkage.
live example
#include <iostream>
extern int A;
static int A = 101;
class A{};
int main()
{
std::cout << A << '\n';
}
Why then, does this code compile?
#include <iostream>
static int A = 101;
extern int A;
class A{};
int main()
{
std::cout << A << '\n';
}
Edit
I think the accepted answer for the question, of which this one is considered a dup, basically says that in the second snippet, variable A still has internal linkage, despite the extern declaration. But this is in disagreement with paragraph §3.5/4 that I mentioned below in a comment to #dyp.
§3.5/4:
An unnamed namespace or a namespace declared directly or indirectly
within an unnamed namespace has internal linkage. All other namespaces
have external linkage. A name having namespace scope that has not been
given internal linkage above has the same linkage as the enclosing
namespace if it is the name of
— a variable; or
...
Edit 1:
The OP uses §3.5/6 to justify his answer to the other question.
§3.5/6 (emphasis mine):
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. 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.
It's clear this answer doesn't apply to the snippets shown on my question, as the declarations of the variable A are not block scope declarations.
Edit 2:
This issue with "ready" status says that §7.1.1/7 should be deleted because it's false.
The extern specifier does not require that the name has external linkage.
The first example
extern int A; is a declaration of a name A with external linkage - but the external linkage is implied since it's a declaration at namespace scope (outside of an unnamed namespace).
static int A; declares a name with internal linkage.
The two declarations disagree about the linkage, hence the error.
The second example
Here, we first declare static int A;, i.e. a name A with internal linkage.
The declaration extern int A; doesn't declare A with external linkage, it merely redeclares a name that is found via name lookup.
[dcl.stc]/7
The linkages implied by successive declarations for a given entity
shall agree. That is, within a given scope, each declaration declaring
the same variable name or the same overloading of a function name
shall imply the same linkage. Each function in a given set of
overloaded functions can have a different linkage, however.
[ Example:
static char* f(); // f() has internal linkage
char* f() // f() still has internal linkage
{ /* ... */ }
char* g(); // g() has external linkage
static char* g() // error: inconsistent linkage
{ /* ... */ }
// [left out some examples with `inline`]
static void n();
inline void n(); // internal linkage
static int a; // a has internal linkage
int a; // error: two definitions
static int b; // b has internal linkage
extern int b; // b still has internal linkage
int c; // c has external linkage
static int c; // error: inconsistent linkage
extern int d; // d has external linkage
static int d; // error: inconsistent linkage
-- end example ]

Example of entity declared in a anonymous namespace that has external linkage

Given the statements below (emphasis mine) in §3.5/4 and in the Note [94] in §7.3.1.1/1, I'd like to have one single example of an entity declared in a unnamed namespace that has external linkage.
§3.5/4
An unnamed namespace or a namespace declared directly or indirectly
within an unnamed namespace has internal linkage. All other namespaces
have external linkage. A name having namespace scope that has not been
given internal linkage above has the same linkage as the enclosing
namespace if it is the name of
a variable; or
a function; or
a named class (Clause 9), or an unnamed class defined in a typedef declaration in which the class has the typedef name for linkage
purposes (7.1.3); or
a named enumeration (7.2), or an unnamed enumeration defined in a typedef declaration in which the enumeration has the typedef name for
linkage purposes (7.1.3); or
an enumerator belonging to an enumeration with linkage; or
a template.
Note [94] on §7.3.1.1/1:
Although entities in an unnamed namespace might have external linkage,
they are effectively qualified by a name unique to their translation
unit and therefore can never be seen from any other translation unit.
You are looking at a defect in the standard.
The change that makes unnamed namespace members have internal linkage happened fairly late in the C++11 standardization process, in November 2010 (CWG issue 1113). As a result, a number of places in the standard needs to be changed, but weren't. One of which is the footnote you quoted.
CWG issue 1603, currently in "ready" status (read: the resolution is likely to be adopted at the next committee meeting), will fix this and a number of other issues related to giving internal linkage to unnamed namespace members.
It's a good question because it's difficult to demonstrate. We can take advantage of other rules in the C++ Standard to show that a variable in an anonymous namespace can have external linkage.
Templating on an int* with external linkage will succeed while templating on an int* with internal linkage will fail.
#include <iostream>
namespace {
// not externally linked, won't compile
// const int i = 5;
// external linkage, compiles
extern int i;
int i = 5;
}
template<int* int_ptr>
struct temp_on_extern_linked_int {
temp_on_extern_linked_int() {
std::cout << *int_ptr << std::endl;
}
};
int main() {
temp_on_extern_linked_int<&i>();
}
As shown the program compiles and runs.
$ g++-4.8 main.cpp -o main
$ ./main
5
Uncommenting the other definition of i causes the compile to fail.
$ g++-4.8 main.cpp -o main
main.cpp: In function 'int main()':
main.cpp:17:30: error: '& {anonymous}::i' is not a valid template argument of
type 'int*' because '{anonymous}::i' does not have external linkage
temp_on_extern_linked_int<&i>();
^
The compiler is quite helpful. It explicitly states that because i doesn't have external linkage the compile failed.
The commented definition of i has internal linkage because it is qualified const without extern. (§3.4.6)
Variables at namespace scope that are declared const and not extern have internal linkage.
Part of the trick is not compiling as C++11.
Why did C++03 require template parameters to have external linkage?
For example
#include <iostream>
namespace
{
extern int x = 10;
void f( int y )
{
extern int x;
std::cout << x + y << std::endl;
}
}
int main()
{
int y = 15;
f( y );
return 0;
}
According to the C++ Standard
6 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. 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

Declaration into the different declarative region

What part of the standard describes how entity does determine for the declared name? For instance
int foo(){ return 1; }
int main()
{
int foo(); //I know that this foo denotes the "global" foo.
}
How it's occuring?
In the C++11 standard, section 3.5p6 states
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.