Consider the following program. Is it well-formed or not according to the c++ standard (references to relevant parts of the standard needed):
namespace X { extern int i; }
namespace N { using X::i; }
int N::i = 1;
int main() {}
I'm getting different results for different compilers. I'm trying to figure out for what compiler I should file a bug report for:
Clang: Gives the following compiler error: No member named 'i' in namespace 'N'
GCC and Visual C++ compiles it without errors.
For comparison the following gives compiler error with all three compilers:
namespace X { void f(); }
namespace N { using X::f; }
void N::f() {};
int main() {}
Current working draft N4527, [8.3p1]:
[...] When the declarator-id is qualified, the declaration shall refer to a
previously declared member of the class or namespace to which the
qualifier refers (or, in the case of a namespace, of an element of the
inline namespace set of that namespace (7.3.1)) or to a specialization
thereof; the member shall not merely have been introduced by a
using-declaration in the scope of the class or namespace nominated by
the nested-name-specifier of the declarator-id. [...]
So, definitely ill-formed; GCC and MSVC are wrong.
Related
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.
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.
Assume the following code:
namespace test
{
namespace detail
{
}
inline namespace v1
{
namespace detail
{
void foo()
{
}
}
}
}
int main()
{
test::detail::foo();
}
As we can see, this code compiles with Clang; not with GCC, however - GCC complains that the reference to namespace detail is ambiguous:
main.cpp:20:11: error: reference to 'detail' is ambiguous
test::detail::foo();
^
main.cpp:4:5: note: candidates are: namespace test::detail { }
{
^
main.cpp:10:9: note: namespace test::v1::detail { }
{
^
Which compiler does the correct thing here?
GCC is correct:
Members of an inline namespace can be used in most respects as though they were members of the enclosing namespace. Specifically, the inline namespace and its enclosing namespace are both added to the set of associated namespaces used in argument-dependent lookup (3.4.2) whenever one of them is, and a using-directive that names the namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace (7.3.1.1). Furthermore, each member of the inline namespace can subsequently be explicitly instantiated (14.7.2) or explicitly specialized (14.7.3) as though it were a member of the enclosing namespace. Finally, looking up a name in the enclosing namespace via explicit qualification (3.4.3.2) will include members of the inline namespace brought in by the using-directive even if there are declarations of that name in the enclosing namespace.
(This is at 7.3.1/8 in old n3337 numbering)
I believe you're seeing Clang bug #10361.
GCC is correct.
N3797 states that,
and a using- directive (
7.3.4 ) that names the inline namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace (
7.3.1.1 ).
Thus, test::detail is not the same namespace as test::v1::detail, so the lookup of test::detail is ambiguous. The Standard is exceptionally clear that the lookup of test::detail should include test::v1::detail, there are many quotes in this section to support this, but nothing to state that they should be considered the same namespace.
Arguably, I would say that Clang's behaviour is superior, but GCC's is correct.
I've written the following code:
#include <iostream>
inline namespace M
{
int j=42;
}
int main(){ std::cout << j << "\n"; } //j is unqualified name here.
//Hence, unqualified name lookup rules will be applied.
//This implies that member of inline namespace shall not be considered.
//But it is not true
And it works fine. But I'm expected that the that program is ill-formed. It is because the Standard said (N3797, sec. 7.3.1/7):
Finally, looking up a name in the enclosing namespace via explicit
qualification (3.4.3.2) will include members of the inline namespace
brought in by the using-directive even if there are declarations of
that name in the enclosing namespace.
Also the section 3.4.1/6 does not said anything about involving of inline namespace in the unqualified name lookup:
A name used in the definition of a function following the function’s
declarator-id 28 that is a member of namespace N (where, only for the
purpose of exposition, N could represent the global scope) shall be
declared before its use in the block in which it is used or in one of
its enclosing blocks (6.3) 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.
It is a g++ bug or I understood that rules incorrectly?
There's no bug..
No, it's not a bug in neither g++ (or clang++) which has the behavior described, the compiler is supposed to find j.
inline namespace N {
int j;
}
int main () {
int a = j; // legal, `j` == `N::j`
}
What does the Standard say?
You are missing a very important section of the standard, namely 7.3.1§8, where it states that the enclosing namespace of an inline namespace implicitly has a using directive that refers to the inline namespace.
[7.3.1]p8 namespace definition [namespace.def]
Members of an inline namespace can be used in most respects as thought they were members of the enclosing namespace. Specifically, the inline namespace and its enclosing namespace are both added to the set of associated namespaces used in argument-dependent lookup (3.4.2) whenever one of them is, and a using-directive (7.3.4) that names the inline namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace (7.3.1.1).
Elaboration
This means that our previous example is semantically equivalent to the below, where we have introduced a using-directive to bring the names from our nested namespace into the global namespace:
inline namespace N {
int j;
}
using namespace N; // the implicit using-directive
int main () {
int a = j; // legal
}
namespace M{
void f();
void M::f(){}
}
int main(){}
The above code gives error like so:
"ComeauTest.c", line 3: error:
qualified name is not allowed in
namespace member
declaration
void M::f(){}
And
G++ also gives error.
But
VS2010 compiles fine.
My questions are:
a) What is the expected behavior?
b) $7.3.1.2 does not seem to talk about this restriction. Which portion of the Standard guides the behavior of such code?
Which portion of the Standard guides the behavior of such code?
C++03 Section $8.3 says
A declarator-id shall not be qualified except for the definition of a member function (9.3) or static data member (9.4) out-side of its class, the definition or explicit instantiation of a function or variable member of a namespace out-side of its namespace, or the definition of a previously declared explicit specialization outside of its name-space, or the declaration of a friend function that is a member of another class or namespace (11.4).
So your code is ill-formed.
However in discussing issue 548 the CWG agreed that the prohibition of qualified declarators inside their namespace should be lifted1.
1 : Active Issue 482
7.3.1.2-2 talks specifically about this:
Members of a named namespace can also be defined outside that namespace by explicit qualification (3.4.3.2) of the name being defined, provided that the entity being defined was already declared in the namespace and the definition appears after the point of declaration in a namespace that encloses the declaration’s namespace.
M::f is considered a outside of namespace definition.