Date: Sat, 29 Jun 2024 19:53:29 -0400
On Sat, Jun 29, 2024 at 8:35 AM Federico Kircheis via Std-Discussion <
std-discussion_at_[hidden]> wrote:
> Hello to everyone,
>
> I am failing to understand if following code is really invalid.
> I've looked at the standard, but I am missing where the relevant
> information is.
>
The entities found when searching for a name in a namespace scope are not
always the same as the entities which are members of that namespace (and
have names). The differences come up with using-declarations,
using-directives, friend declarations, extern variables in block scope, and
this situation: function declarations in block scope.
The relevant rule in C++20 and earlier was [basic.link]/7:
> (6) The name of a function declared in block scope and the name of a
> variable declared by a block scope extern declaration have linkage. ...
(7) When a block scope declaration of an entity with linkage is not found
> to refer to some other declaration, then that entity is a member of the
> innermost enclosing namespace. However such a declaration does not
> introduce the member name in its namespace scope.
C++23 revised the all scope and name lookup language to be more precise.
The same rule is now found in [dcl.meaning.general]/(3.5):
> If the declaration inhabits a block scope *S* and declares a function
> ([dcl.fct]) or uses the extern specifier, the declaration shall not be
> attached to a named module ([module.unit]); its target scope is the
> innermost enclosing namespace scope, but the name is bound in *S*.
[Example 3:
namespace X {
void p() {
q(); // error: q not yet declared
extern void q(); // q is a member of namespace X
extern void r(); // r is a member of namespace X
}
void middle() {
q(); // error: q not found
>
}
void q() { /* ... */ } // definition of X::q
}
-- end example]
Here "target scope" determines whether a declaration is a member of a
namespace or a class or neither ([basic.scope.scope]/2). A name "bound" in
a scope influences the name lookup rules: [basic.lookup.general]/3 defines
"single search" in terms of "bound" names, [class.member.lookup]/1 defines
a "search in a scope" in terms of "single search". In particular for your
examples, the qualified-id ::a::bar requires that the name "bar" was bound
in namespace "a" or in an inline namespace of "a", or can be found via a
using-directive ([namespace.qual]), but it was not.
-- Andrew Schepler
Those snippets compile fine
>
> 1)
> ~~~~
> namespace a {
> int bar(int);
> int foo() {
> return ::a::bar(12);
> }
> int bar(int) {
> return 1;
> }
> }
> ~~~~
> 2)
> ~~~~
> namespace a {
> int foo() {
> int bar(int);
> return bar(12);
> }
> int bar(int) {
> return 1;
> }
> }
> ~~~~
>
> but this one does not(!)
>
> 3)
> ~~~~
> namespace a {
> int foo() {
> int bar(int);
> return ::a::bar(12);
> }
> int bar(int) {
> return 1;
> }
> }
> ~~~~
>
> both gcc and clang suggest that "'bar' is not a member of 'a'" / that
> there is "no member named 'bar' in namespace 'a'" (replacing "::a" with
> "a" does not change the outcome).
>
> Since the function in namespace a is called (even if there is a bar
> function in the global namescope), I am failing to understand why it
> should not be possible to qualify the function call with the namespace.
>
> Especially if there is a function at global scope, removing the forward
> declaration changes the behavior of the program.
>
>
> ~~~~
> int bar(int){
> return 0;
> }
>
> namespace a {
> int foo() {
> // if removed, the line after this comment calls ::bar,
> // and not ::a::bar
> // Since the function call is not qualified,
> // someone might even think it it already calling ::bar
> int bar(int num);
> return bar(12);
> }
> }
> ~~~~
>
> Best
>
> Federico
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>
std-discussion_at_[hidden]> wrote:
> Hello to everyone,
>
> I am failing to understand if following code is really invalid.
> I've looked at the standard, but I am missing where the relevant
> information is.
>
The entities found when searching for a name in a namespace scope are not
always the same as the entities which are members of that namespace (and
have names). The differences come up with using-declarations,
using-directives, friend declarations, extern variables in block scope, and
this situation: function declarations in block scope.
The relevant rule in C++20 and earlier was [basic.link]/7:
> (6) The name of a function declared in block scope and the name of a
> variable declared by a block scope extern declaration have linkage. ...
(7) When a block scope declaration of an entity with linkage is not found
> to refer to some other declaration, then that entity is a member of the
> innermost enclosing namespace. However such a declaration does not
> introduce the member name in its namespace scope.
C++23 revised the all scope and name lookup language to be more precise.
The same rule is now found in [dcl.meaning.general]/(3.5):
> If the declaration inhabits a block scope *S* and declares a function
> ([dcl.fct]) or uses the extern specifier, the declaration shall not be
> attached to a named module ([module.unit]); its target scope is the
> innermost enclosing namespace scope, but the name is bound in *S*.
[Example 3:
namespace X {
void p() {
q(); // error: q not yet declared
extern void q(); // q is a member of namespace X
extern void r(); // r is a member of namespace X
}
void middle() {
q(); // error: q not found
>
}
void q() { /* ... */ } // definition of X::q
}
-- end example]
Here "target scope" determines whether a declaration is a member of a
namespace or a class or neither ([basic.scope.scope]/2). A name "bound" in
a scope influences the name lookup rules: [basic.lookup.general]/3 defines
"single search" in terms of "bound" names, [class.member.lookup]/1 defines
a "search in a scope" in terms of "single search". In particular for your
examples, the qualified-id ::a::bar requires that the name "bar" was bound
in namespace "a" or in an inline namespace of "a", or can be found via a
using-directive ([namespace.qual]), but it was not.
-- Andrew Schepler
Those snippets compile fine
>
> 1)
> ~~~~
> namespace a {
> int bar(int);
> int foo() {
> return ::a::bar(12);
> }
> int bar(int) {
> return 1;
> }
> }
> ~~~~
> 2)
> ~~~~
> namespace a {
> int foo() {
> int bar(int);
> return bar(12);
> }
> int bar(int) {
> return 1;
> }
> }
> ~~~~
>
> but this one does not(!)
>
> 3)
> ~~~~
> namespace a {
> int foo() {
> int bar(int);
> return ::a::bar(12);
> }
> int bar(int) {
> return 1;
> }
> }
> ~~~~
>
> both gcc and clang suggest that "'bar' is not a member of 'a'" / that
> there is "no member named 'bar' in namespace 'a'" (replacing "::a" with
> "a" does not change the outcome).
>
> Since the function in namespace a is called (even if there is a bar
> function in the global namescope), I am failing to understand why it
> should not be possible to qualify the function call with the namespace.
>
> Especially if there is a function at global scope, removing the forward
> declaration changes the behavior of the program.
>
>
> ~~~~
> int bar(int){
> return 0;
> }
>
> namespace a {
> int foo() {
> // if removed, the line after this comment calls ::bar,
> // and not ::a::bar
> // Since the function call is not qualified,
> // someone might even think it it already calling ::bar
> int bar(int num);
> return bar(12);
> }
> }
> ~~~~
>
> Best
>
> Federico
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>
Received on 2024-06-29 23:53:42