This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115e. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-11-11


861. Unintended ambiguity in inline namespace lookup

Section: 6.5.5.3  [namespace.qual]     Status: CD2     Submitter: Michael Wong     Date: 7 April, 2009

[Voted into WP at March, 2010 meeting as part of document N3079.]

The algorithm for namespace-qualified lookup is given in 6.5.5.3 [namespace.qual] paragraph 2:

Given X::m (where X is a user-declared namespace), or given ::m (where X is the global namespace), let S be the set of all declarations of m in X and in the transitive closure of all namespaces nominated by using-directives in X and its used namespaces, except that using-directives that nominate non-inline namespaces (9.8.2 [namespace.def]) are ignored in any namespace, including X, directly containing one or more declarations of m.

Consider the following example:

    namespace A {
        inline namespace B {
            namespace C {
                int i;
            }
            using namespace C;
        }
        int i;
    }

    int j = A::i;     // ambiguous

The transitive closure includes B because it is inline, and it includes C because there is no declaration of i in B. As a result, A::i finds both the i declared in A and the one declared in C, and the lookup is ambiguous.

This result is apparently unintended.

Proposed resolution (November, 2009):

  1. Change 9.8.2 [namespace.def] paragraph 9 as follows:

  2. These properties are transitive: if a namespace N contains an inline namespace M, which in turn contains an inline namespace O, then the members of O can be used as though they were members of M or N. The transitive closure of all inline namespaces in N is the inline namespace set of N. The set of namespaces consisting of the innermost non-inline namespace enclosing an inline namespace O, together with any intervening inline namespaces, is the enclosing namespace set of O.
  3. Insert a new paragraph before 6.5.5.3 [namespace.qual] paragraph 2 and change the existing paragraph 2 as follows:

  4. 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 (9.8.2 [namespace.def]). 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 non-inline 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), let S be the set of all declarations of m in X and in the transitive closure of all namespaces nominated by using-directives in X and its used namespaces, except that using-directives that nominate non-inline namespaces (9.8.2 [namespace.def]) are ignored in any namespace, including X, directly containing one or more declarations of m. No namespace is searched more than once in the lookup of a name. If if S(X,m) is the empty set, the program is ill-formed. Otherwise, if S(X,m) has exactly one member, or if the context of the reference is a using-declaration (9.9 [namespace.udecl]), S(X,m) is the required set of declarations of m. Otherwise if the use of m is not one that allows a unique declaration to be chosen from S(X,m), the program is ill-formed. [Example:...