Name lookup in using-declaration via using-directive
Asked Answered
E

2

6

Is the following program well-formed or ill-formed according to the c++ standard?

namespace N { int i; }
using namespace N;
using ::i;
int main() {}

I get different results with different compilers:

Is this program well-formed or ill-formed according to the c++ standard? References to the c++ standard needed.

I'm trying to figure out for which compiler I should file a bug.

Egotism answered 25/7, 2015 at 16:49 Comment(0)
P
5

Well-formed.

The using-directive doesn't introduce the name i in the global namespace, but it is used during lookup. The using-declaration uses qualified lookup to find i; qualified lookup in the presence of using-directives is specified in [3.4.3.2 p1, p2] (quotes from N4527, the current working draft):

If the nested-name-specifier of a qualified-id nominates a namespace (including the case where the nested-name-specifier is ::, i.e., nominating the global namespace), the name specified after the nested-name-specifier is looked up in the scope of the namespace. [...]

For a namespace X and name m, the namespace-qualified lookup set S(X,m) is defined as follows: Let S'(X,m) be the set of all declarations of m in X and the inline namespace set of X (7.3.1). If S'(X,m) is not empty, S(X,m) is S'(X,m); otherwise, S(X,m) is the union of S(Ni,m) for all namespaces Ni nominated by using-directives in X and its inline namespace set.

So, for qualified lookup, the first step is to look for declarations of i made directly in the namespace indicated by the nested-name-specifier (:: in this case). There are no such declarations, so lookup then proceeds to the second step, which is to form the set of all declarations of i found by qualified lookup in all namespaces nominated by using-directives in the global namespace. That set is comprised of N::i, which is the result of name lookup, and is introduced as a name in global namespace by the using declaration.

I find it worth noting (although pretty obvious) that this definition of qualified lookup is recursive: using the notation in the quote, qualified lookup in each namespace Ni will first look for declarations made directly in Ni, then, if none is found, will in turn proceed to look in the namespaces nominated by using-directives in Ni, and so on.


For what it's worth, MSVC accepts the code as well.

Psychophysics answered 25/7, 2015 at 17:12 Comment(1)
I reported the bug to GCC now: gcc.gnu.org/bugzilla/show_bug.cgi?id=67008Egotism
P
4

GCC is wrong. Qualified name lookup does consider N::i; §3.4.3.2/2 & /3:

For a namespace X and name m, the namespace-qualified lookup set S(X, m) is defined as follows: Let S'(X, m) be the set of all declarations of m in X and the inline namespace set of X (7.3.1). If S'(X, m) is not empty, S(X, m) is S'(X, m); otherwise, S(X, m) is the union of S(Ni, m) for all namespaces Ni nominated by using-directives in X and its inline namespace set.

Given X::m (where X is a user-declared namespace), or given ::m (where X is the global namespace), […] if S(X, m) has exactly one member, or if the context of the reference is a using-declaration (7.3.3), S(X, m) is the required set of declarations of m.

There is only one namespace nominated by a using-directive in your program: N. It's therefore included in the union and ::i is resolved to N::i.

Note that GCC is inconsistent with its lookup: Using ::i in another context is fine.

namespace N { int i; }
using namespace N;

int main() {
    ::i = 5;
}

This compiles. The only difference that a using-declaration makes as a context is shown in the above quote and does not affect the established conclusion.

Pearl answered 25/7, 2015 at 17:12 Comment(1)
@Psychophysics Well, I saw this question really late (like a few minutes ago only), so I was lucky to get first ;-)Pearl

© 2022 - 2024 — McMap. All rights reserved.