Inline namespaces and ambigous declarations - c++

I'm wondering if this is allowed:
namespace A {
inline namespace B {
int a;
}
int a;
}
void foo() {
A::a = 0; // clang 3.4 compiles, but gcc doesn't
}
Standard says, that
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.
But I can't get it.

It looks like this was a pre clang 3.5 bug and there are two defect reports on this 812 and 861. The resolution is in 861 and adds the following to 3.4.3.2 [namespace.qual] (emphasis mine going forward):
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 [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.
and the also relevant additions:
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 (7.3.3 [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.
It looks like the change was added pre C++11, this text is present in N3337.

Related

Type alias with same name as type

Is it valid C++ ?
#include <iostream>
class Test {
struct Inner {
};
public:
using Inner = struct Inner; // Alias with same name as type
};
int main(int argc, const char * argv[]) {
static_assert(std::is_pod<Test::Inner>::value, "");
return 0;
}
Compile fine with clang but not with GCC / Visual C++ ("Inner is private..." error message)
GCC and Visual C++ are correct.
Indeed you can use using to in effect change the access of a member, e.g.
using Inner_ = Inner;
with
static_assert(std::is_pod<Test::Inner_>::value, "");
in the function.
But in the case where the type alias has the same name as the member, C++ requires that the scope resolution operator looks up the member. So in your case Test::Inner refers to the actual member rather than to the using and compilation should therefore fail as it's private.
See https://en.cppreference.com/w/cpp/language/qualified_lookup, and in particular
Qualified lookup within the scope of a namespace N first considers all
declarations that are located in N and all declarations that are
located in the inline namespace members of N (and, transitively, in
their inline namespace members). If there are no declarations in that
set then it considers declarations in all namespaces named by
using-directives found in N and in all transitive inline namespace
members of N
P1787R6: Declarations and where to find them, merged into C++23 draft, seems to favor Clang's behavior:
[basic.lookup]
In certain contexts, only certain kinds of declarations are included. After any such restriction, any declarations of classes or enumerations are discarded if any other declarations are found. [Note: A type (but not a typedef-name or template) is therefore hidden by any other entity in its scope. — end note] However, if a lookup is type-only, only declarations of types and templates whose specializations are types are considered; furthermore, if declarations of a typedef-name and of the type to which it refers are found, the declaration of the typedef-name is discarded instead of the type declaration.
So the declaration of struct Inner is discarded, because the alias-declaration is found. (One can put Inner into type-only context — Test::struct Inner — and it will refer to the struct Inner declaration, per the second part of the paragraph).

using namespace for function-member definition

I have the following class definition in .h file:
namespace N {
struct S {
S(); // no definition for member here
};
}
And I would like to write definition for class constructor (member in general) in .cpp file. I consider the following two cases:
namespace N {
S::S() { /* definition */ }
}
using namespace N;
S::S() { /* definition */ }
I'm slightly confused why the second is working at all, because never saw this way definition until today. Why the second is working? Some citing from the Standard would be appreciated.
What are the nuances of using one approach instead of the other? Should I prefer the first or the second form?
The reason (2) works is because of these two:
[class.mfct]/4
If the definition of a member function is lexically outside its class
definition, the member function name shall be qualified by its class
name using the ​::​ operator.
[namespace.udir]/2 (emphasis mine)
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, 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 ]
The directive simply lets you name S for the :: operator as if you were inside the N namespace (as you are in (1)). But I wouldn't do that. Scoping is good. Definitions should be scoped too.
In this particular example you have declared only one structure in the namespace and defined the function in a separate .cpp file, so it doesn't matter if you use 1 or 2.
Had you declared any other identifiers in the namespace, then 1 should be preferred over 2 as the using declaration kind of defeats the purpose of having a namespace.

Name lookup in using-declaration via using-directive

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:
Clang (http://melpon.org/wandbox/permlink/c8vl7XbumyyS6vsw): No errors.
GCC (http://melpon.org/wandbox/permlink/immhNeWFCMcCA800): Error: 'i' not declared.
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.
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.
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.

Global unnamed namespace ambiguity vs nested unnamed namespace ambiguity

Consider the following two code snippets:
Snippet A
#include <iostream>
namespace
{
bool foo = false;
}
bool foo = true;
int main()
{
std::cout << foo << std::endl;
}
Snippet B
#include <iostream>
namespace A
{
namespace
{
bool foo = false;
}
bool foo = true;
}
int main()
{
std::cout << A::foo << std::endl;
}
In Snippet A, foo's usage inside int main() is ambiguous, whilst in Snippet B it is not. Why is this the case?
Related: Anonymous Namespace Ambiguity
The behavior of unnamed namespaces is specified in §7.3.1.1 [namespace.unnamed]/p1:
An unnamed-namespace-definition behaves as if it were replaced by
inline_opt namespace unique { /* empty body */ }
using namespace unique ;
namespace unique { namespace-body }
where inline appears if and only if it appears in the
unnamed-namespace-definition, all occurrences of unique in a translation unit are replaced by the same identifier, and this
identifier differs from all other identifiers in the entire program.
In particular, note that the declarations inside the unnamed namespace is made visible in the surrounding scope via a using-directive using namespace unique;.
In Snippet A, foo is unqualified, so the compiler performs unqualified name lookup (§3.4.1 [basic.lookup.unqual]). Relevant here is paragraph 2 of the subclause:
2 The declarations from the namespace nominated by a using-directive
become visible in a namespace enclosing the using-directive; see
7.3.4. For the purpose of the unqualified name lookup rules described in 3.4.1, the declarations from the namespace nominated by the
using-directive are considered members of that enclosing namespace.
Hence, unqualified name lookup finds both declarations of foo, and the name is ambiguous.
In Snippet B, A::foo is qualified, so qualified name lookup rules apply. Since A is a namespace, the applicable subclause is §3.4.3.2 [namespace.qual]. As relevant here, the rule is specified in paragraph 2 of that subclause:
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.
In other words, qualified name lookup considers namespaces nominated by using-directives only if the name is not found in the specified namespace and its inline namespace set. Here, the name foo is found in namespace A, so the unnamed namespace nominated by the using-directive is not considered, and there's no ambiguity.
If you write ::foo instead of foo in Snippet A, then qualified lookup rules would apply instead, and there would once again be no ambiguity.

Unqualified name lookup finds inline namespace member

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
}