How does unqualified name lookup work when using using-declarations? - c++

Is this ill-formed or well-formed according to the c++ standard?
namespace M { struct i {}; }
namespace N { static int i = 1; }
using M::i;
using N::i;
int main() { sizeof (i); }
Clang rejects it and GCC accepts it.
According to [namespace.udir-6] (http://eel.is/c++draft/basic.namespace#namespace.udir-6):
If name lookup finds a declaration for a name in two different
namespaces, and the declarations do not declare the same entity and do
not declare functions, the use of the name is ill-formed.
How should we interpret this? Remember that each using-declaration are declaring a name by [namespace.udecl]p1 (http://eel.is/c++draft/namespace.udecl#1):
A using-declaration introduces a name into the declarative region in
which the using-declaration appears.
using-declaration:
using typenameopt nested-name-specifier unqualified-id ;
The member name specified in a using-declaration is declared in the
declarative region in which the using-declaration appears. [ Note:
Only the specified name is so declared; specifying an enumeration name
in a using-declaration does not declare its enumerators in the
using-declaration's declarative region. — end note ] If a
using-declaration names a constructor ([class.qual]), it implicitly
declares a set of constructors in the class in which the
using-declaration appears ([class.inhctor]); otherwise the name
specified in a using-declaration is a synonym for a set of
declarations in another namespace or class.
So we have 4 declarations of the name i.
Which of these does unqualified name lookup of i in sizeof(i) find?
Does it only find using M::i; and using N::i; which are both in the same namespace (the global namespace) so the program is well-formed?
Or does it only find struct i {}; and static int i = 1; which are in different namespaces so the program is ill-formed?
Or do we have some other alternative?

bogdan already has to the answer, but to build on why your intuition is incorrect, you cited:
If name lookup finds a declaration for a name in two different namespaces, and the declarations do not declare the same entity and do not declare functions, the use of the name is ill-formed.
But in the example, we have:
namespace M {
struct i {}; // declares M::i, entity class type
}
namespace N {
static int i = 1; // declares N::i, entity variable
}
using M::i; // declares ::i, synonym of M::i
using N::i; // declares ::i, synonym of N::i
// hides (*) the other ::i
int main() {
sizeof (i);
}
To elaborate on (*), we have two declaration of i in the global namespace ::. From [basic.scope.hiding]:
A class name (9.1) or enumeration name (7.2) can be hidden by the name of a variable, data member,
function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data
member, function, or enumerator are declared in the same scope (in any order) with the same name, the
class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is
visible.
So with the two is in the same scope, the class is hidden (irrespective of the ordering of the using-declarations!), and sizeof(i) refers to the ::i that is the synonym of N::i. Both is were in the same namespace (::), which is why your quote doesn't apply. This differs from your earlier question, where you had using-directives instead:
using namespace M;
using namespace N;
There i would be found in two different namespaces, referring to two different non-function entities. Hence, the error. Here, Clang is wrong and GCC is correct.

N4527 [7.3.3p13]:
Since a using-declaration is a declaration, the restrictions on
declarations of the same name in the same declarative region (3.3)
also apply to using-declarations. [ Example:
namespace A {
int x;
}
namespace B {
int i;
struct g { };
struct x { };
void f(int);
void f(double);
void g(char); // OK: hides struct g
}
void func() {
int i;
using B::i; // error: i declared twice
void f(char);
using B::f; // OK: each f is a function
f(3.5); // calls B::f(double)
using B::g;
g(’a’); // calls B::g(char)
struct g g1; // g1 has class type B::g
using B::x;
using A::x; // OK: hides struct B::x
x = 99; // assigns to A::x
struct x x1; // x1 has class type B::x
}
—end example ]
Note the using-declarations for the two different xs - it's the same case as your example.
Your first quote is referring to using-directives, not using-declarations.
Unqualified name lookup for the i in sizeof(i) finds the is in the global namespace. Since they are declarations in the same scope, according to [3.3.10p2] (quote below), the variable i hides the struct.
A class name (9.1) or enumeration name (7.2) can be hidden by the name
of a variable, data member, function, or enumerator declared in the
same scope. If a class or enumeration name and a variable, data
member, function, or enumerator are declared in the same scope (in any
order) with the same name, the class or enumeration name is hidden
wherever the variable, data member, function, or enumerator name is
visible.
So, the code is well-formed and Clang is wrong to reject it.
MSVC (12 and 14) accepts the example.
Basically, think of the name introduced by a using-declaration as just another name for some entity, which is also named somewhere else (the place designated by the nested-name-specifier of the qualified-id in the using-declaration). This is different from what a using-directive does; I tend to think of using-directives as "name lookup tweaks".

Related

Same name in typedef and using from a namespace

Sample code:
struct X { void f() {} };
typedef X A;
namespace N {
struct A { void g() {} };
};
using N::A;
int main()
{
A a;
a.f();
}
This code compiles correctly, and A a; creates an X, not a N::A.
What rule in the standard covers this behaviour? I was expecting an error that A a; would be ambiguous. If I name the first struct A instead of X and remove the typedef, then I do get such an error. (g++ 8.3)
According to [namespace.udecl]/1 using N::A introduces the unqualified A into the declarative region in which the using declaration appears.
... the unqualified-id is declared in the declarative region in which the using-declaration appears as a synonym for each declaration introduced by the using-declarator.
So the ambiguity is covered jointly by [namespace.udecl]/13
Since a using-declaration is a declaration, the restrictions on declarations of the same name in the same declarative region also apply to using-declarations.
and [basic.scope.declarative]/4
Given a set of declarations in a single declarative region, each of
which specifies the same unqualified name,
they shall all refer to the same entity, or all refer to functions and function templates; or
exactly one declaration shall declare a class name or enumeration name that is not a typedef name and the other declarations shall all refer to the same variable, non-static data member, or enumerator, or all refer to functions and function templates; in this case the class name or enumeration name is hidden.
The typedef declaration and the using declaration in the OP don't fill either bullet, so the pair of declarations in the same declarative region is ill-formed.

The difference between declaring a name, introducing a name, and declaring an entity

From the C++11 standard, §7.3.3[namespace.udecl]/1:
A using-declaration introduces a name into the declarative region in which the using-declaration appears.
using-declaration:
using typenameopt nested-name-specifier unqualified-id ;
using :: unqualified-id ;
The member name specified in a using-declaration is declared in the declarative region in which the using-declaration appears.
What do they mean by the name being declared in the declarative region where the using-declaration occurs?
Does this mean the same as introducing that name into the declarative region where the using-declaration occurs?
Also is there a difference between declaring a name and declaring the entity that the name denotes?
Example:
namespace N { static int i = 1; } /* Declares an entity denoted by
the name i in the declarative region of the namespace N.
Introduces the name into the declarative region of the namespace N.
Declares the name i in the declarative region of the namespace N? */
using N::i; /* Declares the name i in the declarative region of the
global namespace. Also introduces that name into the declarative
region of the global namespace? Also declares the entity that the
name i denotes? */
From first principles, an entity is, from [basic]
a value, object, reference, function, enumerator, type, class member, bit-field, template, template
specialization, namespace, parameter pack, or this. [...] Every name that denotes an entity is introduced by a declaration.
Declarations declare things. To be declared means that it was introduced by a declaration, from [basic.scope.declarative]
Every name is introduced in some portion of program text called a declarative region, which is the largest part
of the program in which that name is valid, that is, in which that name may be used as an unqualified name
to refer to the same entity.
The names declared by a declaration are introduced into the scope in which the declaration occurs, except
that the presence of a friend specifier (11.3), certain uses of the elaborated-type-specifier (7.1.6.3), and
using-directives (7.3.4) alter this general behavior.
None of those exceptions are relevant here, since we're talking about using-declarations and not using-directives. Let me alter your example somewhat so as to avoid the global namespace:
namespace N { // + declarative region #1
// |
static int i; // | introduces a name into this region
// | this declaration introduces an entity
} // +
So to start with, N::i is an entity that is declared in namespace N and introduced into the scope of N. Now, let's add a using-declaration:
namespace B { // + declarative region #2
// |
using N::i; // | declaration introduces a name i
// | but this is not an entity
} // +
From [namespace.udecl], we have:
If a using-declaration names a constructor (3.4.3.1), it implicitly declares a set of constructors in the
class in which the using-declaration appears (12.9); otherwise the name specified in a using-declaration is a
synonym for a set of declarations in another namespace or class.
The using-declaration using N::i does not name a constructor, so rather than having the name i be a new entity, it is instead a synonym for N::i.
So basically, both is are names introduced in and declared in their respective namespaces. In N, i declares an entity with static linkage, but in B, i declares a synonym to that entity - not a new entity.
What do they mean by the name being declared in the declarative region
where the using-declaration occurs?
I'll try and answer this with an example of my understanding of it (Refer to my comments in the depicted code):
// "namespace X {}" introduces a declarative region of the namespace X
namespace X {
//The name SomeObject is now introduced into the declarative region X
// It is only visible in that declarative region
using Y::SomeObject;
}//Declarative region X ENDS here
// SomeObject NOT visible here
Below is an example where the (compiler) error makes it clear where the name is not visible:
#include <iostream>
namespace A
{
struct X{};
}
namespace B
{
struct X{};
}
namespace C
{
using A::X;
void foo(X){}
}
namespace D
{
using B::X;
void foo(X){}
}
void foo(X){} //FAILS TO COMPILE - DELIBERATE!!!
int main()
{
return 0;
}

Interpretation of [basic.scope.hiding]p2 when unqualified name lookup involves using-directives

There are two types of name hiding in c++:
1) Normal name hiding: [basic.scope.hiding]p1 (http://eel.is/c++draft/basic.scope.hiding#1):
A name can be hidden by an explicit declaration of that same name in a
nested declarative region or derived class ([class.member.lookup]).
2) The special type of name hiding in [basic.scope.hiding]p2 (http://eel.is/c++draft/basic.scope.hiding#2):
A class name ([class.name]) or enumeration name ([dcl.enum]) can be
hidden by the name of a variable, data member, function, or enumerator
declared in the same scope. If a class or enumeration name and a
variable, data member, function, or enumerator are declared in the
same scope (in any order) with the same name, the class or enumeration
name is hidden wherever the variable, data member, function, or
enumerator name is visible.
I'm interested to know about how name hiding interacts with using-directives when unqualified name lookup is performed.
For the first type of name hiding the behaviour is quite clear. This is because [basic.scope.hiding]p1 has been reformulated in terms of the rules in the section [basic.lookup.unqual] (http://eel.is/c++draft/basic.lookup.unqual)
The same has not been done for the second type of name hiding. So the following question now arises:
*) How should this second type of name hiding interact with unqualified name lookup that involves using-directives?
Looking elsewhere in the standard I find [namespace.udir]p2 (http://eel.is/c++draft/namespace.udir#2) and I think this is key to answering this question:
A using-directive specifies that the names in the nominated namespace
can be used in the scope in which the using-directive appears after
the using-directive. During unqualified name lookup
([basic.lookup.unqual]), the names appear as if they were declared in
the nearest enclosing namespace which contains both the
using-directive and the nominated namespace. [ Note: In this context,
“contains” means “contains directly or indirectly”. — end note ]
Applying the as if part of this rule to [basic.scope.hiding]p1 gives consistency with the rules in the section [basic.lookup.unqual]. This application is also consistent with [basic.scope.hiding]p4 (http://eel.is/c++draft/basic.scope.hiding#4) So this looks promising.
Because of this I think we can answer the question *) by similarly applying the as if part of [namespace.udir]p2 to [basic.scope.hiding]p2. This application is also consistent with [basic.scope.hiding]p4. I think this is also the most natural and least complex interpretation of the c++ standard.
The problem however is that Clang and GCC does not make the same interpretation as me. For example:
namespace N { static int i = 1; }
namespace M { struct i {}; }
using namespace M;
using namespace N;
int main() { sizeof(i); }
According to my interpretation this program should be well-formed and i should be looked up as the integer variable. Both Clang and GCC disagree with this by giving a name lookup ambiguity.
In the case of Clang this more complex interpretation leads to the following bug:
namespace N { static int i = 1; }
namespace M { struct i {}; }
namespace P {
using N::i;
using M::i;
}
namespace Q { using M::i; }
using namespace P;
using namespace Q;
int main() { sizeof (i); }
Gives no errors, but change
using namespace P;
using namespace Q;
into
using namespace Q;
using namespace P;
and we get name-lookup ambiguity error. GCC is at least consistent here.
Did I interpret the c++ standard correctly?
The key phrases here I believe are:
A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived
class (10.2).
A class name (9.1) or enumeration name (7.2) can be hidden by the name of a variable, data member,
function, or enumerator declared in the same scope.
In this example:
namespace N { static int i = 1; }
namespace M { struct i {}; }
using namespace M;
using namespace N;
int main() { sizeof(i); }
Both is are declared in different, non-nested scopes, so there is no hiding. Name lookup finds them as if they were declared in ::, but that's not what the rule for hiding stipulates.
Otherwise, we have, from [basic.lookup]:
Name lookup shall
find an unambiguous declaration for the name (see 10.2). Name lookup may associate more than one declaration
with a name if it finds the name to be a function name;
There is no unambiguous declaration in ::, so this code is ill-formed and the error is correct. The same is true for the other example, so the fact that there is some using-declaration ordering for which clang compiles it is a bug.
While this is non-normative, there is an example in [namespace.udir] that makes this interpretation clear:
[ Note: In particular,
the name of a variable, function or enumerator does not hide the name of a class or enumeration declared
in a different namespace. For example,
namespace A {
class X { };
extern "C" int g();
extern "C++" int h();
}
namespace B {
void X(int);
extern "C" int g();
extern "C++" int h(int);
}
using namespace A;
using namespace B;
void f() {
X(1); // error: name X found in two namespaces
g(); // OK: name g refers to the same entity
h(); // OK: overload resolution selects A::h
}
—end note ]
namespace N { static int i = 1; }
namespace M { struct i {}; }
using namespace M;
using namespace N;
int main() { sizeof(i); }
This is ill-formed. §7.3.4/6:
If name lookup finds a declaration for a name in two different
namespaces, and the declarations do not declare the same entity and do
not declare functions, the use of the name is ill-formed.
The same applies to your second example. Note that the name hiding rule that applies in e.g.
struct A {} A;
…doesn't apply in your case, as the two is are declared in distinct scopes. Also,
During unqualified name lookup ([basic.lookup.unqual]), the names
appear as if they were declared in the nearest enclosing namespace
which contains both the using-directive and the nominated namespace.
Is irrelevant as well since any ambiguity that name lookup produces, as in your examples with i, is dealt with after lookup - here in e.g. the aforementioned §7.3.4/6.

Unnamed and Named Namespace Resolution

Should a reference to a name that exists in both an unnamed namespace and the local named namespace result in a error for ambiguity or is the resolution well-defined? I'm seeing the following work fine on G++ and Clang, less well on MSVC.
namespace Foo
{
class Bar
{
public:
int x;
};
}
namespace
{
class Bar
{
public:
int y;
};
}
namespace Foo
{
void tester()
{
Bar b;
}
}
int main()
{
Foo::tester();
return 0;
}
GCC and Clang are right. Within Foo::tester, an unqualified use of Bar unambiguously refers to Foo::Bar.
Unqualified lookup is specified by C++11 3.4.1/1:
the scopes are searched for a declaration in the order listed in each of the
respective categories; name lookup ends as soon as a declaration is found for the name.
The scopes searched for the use of a name in a function are listed in 3.4.1/6:
A name used in the definition of a function [...] that is a member of namespace N [...] shall be declared before its use in the block [...] or, shall be declared before its use in namespace N or, if N is a nested namespace, shall be declared before its use in one of N’s enclosing namespaces.
In this case, the function is a member of Foo, so Foo is searched before the enclosing (global) namespace, which includes the unnamed namespace. Foo::Bar is found there, and lookup ends.

Class member qualified name lookup

Consider the following code snippet:
class A
{
int b[A::a]; //1, error
void foo(){ int b = A::a; } //2, ok
static const int a = 5;
}
Clause 3.4.3.1/1 (Qualified name lookup, class members) said:
If the nested-name-specifier of a qualified-id nominates a class, the
name specified after the nested-name-specifier is looked up in the
scope of the class (10.2)
This implies that the name a after the nested-name-specifier both in //1 and in //2 will be looked up in the class scope.
Clause 10.2 (Member name lookup) said:
10.2/2
The following steps define the result of name lookup for a member name
f in a class scope C.
10.2/3
The lookup set for f in C, called S(f, C)...
S(f, C) is calculated as follows:
10.2/4
If C contains a declaration of the name f, the declaration set
contains every declaration of f declared in C that satisfies the
requirements of the language construct in which the lookup occurs.
The following is unclear for me:
From the quotes I cited implies that for both //1 and //2 the same member lookup rules shall be applied. But actually its a different. Why is my reasoning wrong?
Note: I know about unqualified name lookup rules into the class scope. And I understood that behavior in the following code snippet:
class A
{
int b[a]; //error
void foo(){ int b = a; } //ok
static const int a = 5;
}
It is because that behavior described in the sections 3.4.1/7 and 3.4.1/8 (Unqualified name lookup).
The error is because when int b[A::a]; is being processed, A does not yet have a symbol a. At that point of compilation, A is still incomplete because we have not reached the closing } of the class definition yet. The compiler doesn't "look ahead" to see if future lines of source code contain a definition of a.
You can see this by reversing the order of the lines:
class A
{
static const int a = 5;
int b[A::a]; // OK
};
The function definition does not have the same problem because inline function bodies are not compiled until after compilation of the class definition. (Sorry, I don't have standard references handy for this)
The member declaration int b[A::a]; is not in the potential scope of A::a (3.3.7p1), while the body of void A::foo() is in the potential scope (3.3.7p1b1):
1) The potential scope of a name declared in a class consists not only of the declarative region following the name's point of declaration, but also of all function bodies, brace-or-equal-initializers of non-static data members, and default arguments in that class (including such things in nested classes).
3.4.3.1p1 references the potential scope rule in a note:
[...] [ Note: A class member can be referred to using a qualified-id at any point in its potential scope (3.3.7). — end note ] [...]
Of course, notes are non-normative, so the conclusion must be that the potential scope rule is implied by other material in the standard. I believe this other material is specifically 3.3.2p5:
After the point of declaration of a class member, the member name can be looked up in the scope of its class. [...]
By implication, prior to the point of declaration of that class member, that member name cannot be looked up in the scope of that class.