C++11 3.3.1p4 - Declarations in same declarative region? - c++

In C++ std 3.3.1p4:
Given a set of declarations in a single declarative region, each of which specifies the same unqualified name, they shall all refer to the same entity.
In the following, aren't the two int declarations in the same declarative region, specify the same unqualified name, and refer to two different entities?
int main()
{
int i;
{
int i;
}
}
How does the quote not apply and render this ill-formed?
If the quote doesn't apply to this, what does it apply to?
(Note that the declarative region of the first i does include the second i as demonstrated in the example in 3.3.1p2.)

They are not in the same single declarative region. The declarative region of the inner i is limited to within the innermost braces.
In fact 3.3.1/2 has code remarkably similar to your own:
int j = 24;
int main() {
int i = j, j;
j = 42;
}
In that, the j used to set i is the 24 one but the scope of that outer j stops after the , and restarts at the }. Those two j variables are distinct despite the fact they're in the file declarative region for the same reasons as your example: the re are two declarative regions.
Since there is not a single declarative region, scope takes control. C++11 3.3.1/1 states (my bold):
Every name is introduced in some portion of program text called a declarative region, which is the largest part of the program in which that name is valid, that is, in which that name may be used as an unqualified name to refer to the same entity. In general, each particular name is valid only within some possibly discontiguous portion of program text called its scope.
The scope of a declaration is the same as its potential scope unless the potential scope contains another declaration of the same name. In that case, the potential scope of the declaration in the inner (contained) declarative region is excluded from the scope of the declaration in the outer (containing) declarative region.
It's the possibly discontiguous that's important here, the inner i (in your example) "descopes", or hides, the outer i even though the outer declarative region may enclose the inner one.

Related

why a structured binding does not potentially conflict with a variable

The newest standard has been modified to add the content of P1787. One rule about two declarations that potentially conflict is:
Two declarations potentially conflict if they correspond and cause their shared name to denote different entities ([basic.link]).
I don't know the meaning of wording "different entities" here. Does it mean these entities that has different kinds or mean that they are different entities determined by basic.link#8? The entities have these kinds:
An entity is a value, object, reference, structured binding, function, enumerator, type, class member, bit-field, template, template specialization, namespace, or pack.
Such for a example,
void fun(); //#1
extern int fun; //#2
int main(){}
If the wording "different entities" means the former, then #1 denotes a function and #2 denotes a variable, they're different kind of entities. And such two declaration are in the same scope, Hence they are ill-formed per:
The program is ill-formed if, in any scope, a name is bound to two declarations that potentially conflict and one precedes the other
However, if the differenct entities should be determined by [basic.link#8] instead of determing it according to kind of entities. Then, it also makes sense. Because, per [basic.link#8]
Two declarations of entities declare the same entity if, considering declarations of unnamed types to introduce their names for linkage purposes, if any ([dcl.typedef], [dcl.enum]), they correspond ([basic.scope.scope]), have the same target scope that is not a function or template parameter scope, and either
they appear in the same translation unit, or
they both declare names with module linkage and are attached to the same module, or
they both declare names with external linkage.
Since they're corresponding and have the same target scope, and also bullet 1 or bullet 3 is satisfied. So, #1 and #2 are the same entity. However, they violate the following rule:
For any two declarations of an entity E:
If one declares E to be a variable or function, the other shall declare E as one of the same type.
So, Regardless of how to understand "different entities", the first example is always ill-formed. These compilers indeed give a right dignosis.
However, consider the second example
#include <iostream>
struct D{
int m;
};
auto [x] = D{0}; //#1
void show(){
std::cout<<&x<<"\n";
}
int main(){
extern int x; //#2
std::cout<<&x<<"\n";
}
GCC prints the same address. Instead, Clang reports a link error.
Similarly, if "different entities" is the former opinion. Then #1 is a structured binding while #2 is a variable. According to this rule:
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.
So, such two declarations has the same target scope. Hence, they should potentially conflict. If "different entities" is determined by [basic.link]. According to [basic.link#8], they are the same entity. However, it also violates
If one declares E to be a variable or function, the other shall declare E as one of the same type.
So, anyhow, the second example should be ill-formed. Why GCC gives the result that such two entity has the same address. Rather, Clang only gives a link error?
In addition, Is it necessary to add a precondition for [basic.link#8], that is, two entities should be first have the same kind?

what are lookup rules when a name occured before function's declarator-id?

#include <iostream>
typedef int Name;
Name func(int){
return 0;
}
int main(){
}
Consider the above code, I can't find a bullet in [basic.lookup.unqual] that can interpret how to lookup Name for definition of func. I will cite some potential rules here:
A name used in global scope, outside of any function, class or user-declared namespace, shall be declared before its use in global scope.
A name used in a user-declared namespace outside of the definition of any function or class shall be declared before its use in that namespace or before its use in a namespace enclosing its namespace.
In the definition of a function that is a member of namespace N, a name used after the function's declarator-id shall be declared before its use in the block in which it is used or in one of its enclosing blocks ([stmt.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
Please note the emphasized parts, it seems that my case does not satisfy these bullets, because Function definitions have the form
function-definition:
attribute-specifier-seq(opt) decl-specifier-seq(opt) declarator virt-specifier-seq(opt) function-body
Let me analyze the first bullet. It says outside of any function,but according to the Function definitions rule, I think that Name is within the function(definition), bullet 1 isn't satisfied. Bullet 2 is similar with that of bullet 1. Bullet 3 says that the name used after the function's declarator-id, in my case, the Name is used before the function's declarator-id. So what's the rule about this case to find the unqualified name Name?
My confusions:
In my example ,the Name,func ,(int) and { return 0;}(function body) are all parts of that function definition,So:
what is outside of any function,such as the func in my example,where's area of outside of that function?
what is outside of the definition of any function,such as the func definition in my example,where's area of outside of the definition of that function?
I think that Name is within the function(definition), bullet 1 isn't satisfied.
Bullet 1 didn't say "function(definition)". It said "outside of any function". It doesn't specify declaration or definition; merely "outside of any function".
Since being inside or outside of a "function" is not a defined concept, it must be read as plain English. Is a function prototype "outside of the function"? Visually speaking, there's nothing special about a function prototype that is suggestive of an inside/outside distinction. By contrast, the function body's block scope does suggest an inside/outside distinction.
The intent of the text of course is quite obvious; it's talking about the function body. The rule equates "function", "class" and "namespace", all of which have a block that defines scoping for names. That is the most logical place for any inside/outside distinction, so it seems pretty obvious that it's saying that the global scope consists of everything that isn't in the scope of a function body, the scope of a class definition, or the scope of a namespace body.
So this can be easily handled with an editorial change.
Note that the committee recognizes the wording of this section (among others in that area) as somewhat defective, and there's a proposal for rewriting it into something more coherent in C++23. The new wording from the proposal completely rewrites this section.

Why does c++'s namespace scope also include file scope(in c)?

C(ISO/IEC 9899:2011) has no concept of namespace, when referring global variable's scope, the standard use file scope:
Every other identifier has scope determined by the placement of its declaration (in a declarator or type specifier). If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope, which terminates at the end of the translation unit. If the declarator or type specifier that declares the identifier appears inside a block or within the list of parameter declarations in a function definition, the identifier has block scope, which terminates at the end of the associated block. If the declarator or type specifier that declares the identifier appears within the list of parameter declarations in a function prototype (not part of a function definition), the identifier has function prototype scope, which terminates at the end of the function declarator. If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.
However, in c++(at least ISO/IEC 14882:2011), file scope is never used and use namespace scope instead:
The declarative region of a namespace-definition is its namespace-body. Entities declared in a namespace-body are said to be members of the namespace, and names introduced by these declarations into the declarative region of the namespace are said to be member names of the namespace. A namespace member name has namespace scope. Its potential scope includes its namespace from the name's point of declaration onwards; and for each using-directive ([namespace.udir]) that nominates the member's namespace, the member's potential scope includes that portion of the potential scope of the using-directive that follows the member's point of declaration.
As we know, c++ is inspired a lot from C, so many definitions of terms also derive from c, though they are virtually two different languages now. IMO, there should be a reason that c++ use namespace scope instead of file scope, but I don't know. What's behind it?
The C++ standard doesn't mention file scope because it isn't trying to explain things in C terms. It defines and uses its own terms. In this case, it is under the definition of namespaces:
[basic.namespace]
2 The outermost declarative region of a translation unit is a
namespace; see [basic.scope.namespace].
This declarative region, in C++ terms, is the equivalent of C's file scope. The C++ standard uses these definitions because it intends to support namespace declarations, that allow us to partition this scope into smaller pieces.
C has no such feature, so it speaks only of things at file scope as the its outermost scope, because said definition is enough.
You're asking about file scope, not function scope.
The reason that C++ instead talks about namespace scope, is that it has namespaces. C doesn't. So of course C wouldn't have namespace scope.
C and C++ are different languages. C++ doesn't change things to "not be C", it changes things because its designers consider the changes to make the language inherently "better", either directly, or by consequence of the existence of some C++-only feature that in turn makes the language "better" than C.

How is the following passage from the standard to be interpreted?

§3.3.6/1 (C++11)
The declarative region of a namespace-definition is its namespace-body. The potential scope denoted by
an original-namespace-name is the concatenation of the declarative regions established by each of the
namespace-definitions in the same declarative region with that original-namespace-name....
The definition of a declarative region is as follows (§3.3.1/1):
Every name is introduced in some portion of program text called a declarative region, which is the largest part
of the program in which that name is valid, that is, in which that name may be used as an unqualified name
to refer to the same entity. ...
The two taken together would seem to imply that the name of a namespace can only be used (unqualified) inside the namespace body itself. But, clearly, this is false. So what does it mean for the declarative region of a namespace definition to be the body, when the name of the namespace can in fact be used (unqualified) outside the namespace body?
Also, I just don't understand this at all (re-quoted from above):
The potential scope denoted by
an original-namespace-name is the concatenation of the declarative regions established by each of the
namespace-definitions in the same declarative region with that original-namespace-name.
The standard is not talking about what you think...
I think your confusion lies with the fact that you are mistakingly assuming that the text is about the namespace name itself, when the standard is really talking about names introduced inside the namespace in question.
What about the quoted thing that "just doesn't make sense"?
The potential scope denoted by an original-namespace-name is the concatenation of the declarative regions established by each of the namespace-definitions in the same declarative region with that original-namespace-name.
The above might be easiest to describe with an example:
.--- namespace definition
| .--- original-namespace-name
v v
namespace N { <-------------------------------.
int x = 0; <---+--- declarative region (1)
} <-------------------------------------------'
.--- another namespace definition of `N`
| .--- original-namespace-name
v v
namespace N { <-------------------------------.
int y = x; <---+--- declarative region (2)
} <-------------------------------------------'
Note: The potential scope of int x is both (1) and (2), ie. "concatenation of the declarative regions" introduced.
In the example we have two namespace-definitions for the original-namespace-name N, we also have two declarative regions, but the "potential scope" inside the namespace named N is both (1), and (2).
As long as the namespace definitions themselves are in the same declarative region, and share the same original-namespace-name, they refer to the same namespace.
Introducing another such namespace definition will just add more room to the potential scope (by appending another declarative region) of the variables previously declared inside it.
potential scope, and declarative region; what are they?
a declarative region is the part of a program where a name can be referred to without being qualified.
The potential scope is the scope in which a name is potentially valid, it's the entire scope in which the name could refer to the same entity.
3.3.1p1 Declarative regions and scope [basic.scope.declarative]
Every name is introduced in some portion of program text called a declarative region, which is the largest part of the program in which that name is valid, that is, in which the name may be used as an unqualified name to refer to the same entity.
In general, each particular name is valid only within some possible discontiguous portion of program text called its scope. To determine the scope of a declaration, it is sometimes conventient to refer to the potential scope of a declaration.
The scope of a declaration is the same as its potential scope unless the potential scope contains another declaration of the same name. In that case the potential scope of the declaration in the inner (contained) declarative region is excluded from the scope of the declaration in the outer (containing) declarative region.

Use of extern in block scope

clang, gcc and VS2013 all complain about redefinition of w in main(), but I couldn't find in the Standard anything disallowing this.
namespace N {
extern int j;
int j;
}
int main()
{
extern int w;
int w;
}
These paragraphs say something about the use of an extern declaration in block scope, but they don't seem to justify the error message:
§3.3.1/4
Given a set of declarations in a single declarative region, ...
[ Note: These restrictions apply to the declarative region into which
a name is introduced, which is not necessarily the same as the region
in which the declaration occurs. In particular,
elaborated-type-specifiers (7.1.6.3) and friend declarations (11.3)
may introduce a (possibly not visible) name into an enclosing
namespace; these restrictions apply to that region. Local extern
declarations (3.5) may introduce a name into the declarative region
where the declaration appears and also introduce a (possibly not
visible) name into an enclosing namespace; these restrictions apply to
both regions. —end note ]
§3.3.2/10
[ Note: Friend declarations refer to functions or classes that are
members of the nearest enclosing namespace, but they do not introduce
new names into that namespace (7.3.1.2). Function declarations at
block scope and variable declarations with the extern specifier at
block scope refer to declarations that are members of an enclosing
namespace, but they do not introduce new names into that scope. —end
note ]
I believe this is mostly covered by §3.5/6.
In particular:
The name of a function declared in block scope and the name of a variable declared by a block scope extern declaration have linkage. If there is a visible declaration of an entity with linkage having the same name and type, ignoring entities declared outside the innermost enclosing namespace scope, the block scope declaration declares that same entity and receives the linkage of the previous declaration. If there is more than one such matching entity, the program is ill-formed. Otherwise, if no matching entity is found, the block scope entity
receives external linkage.
So, the extern int w; declares a w that has linkage (external linkage, in this case, since no matching entity is visible at that point).
Then you attempt to define a local w which has no linkage (by §3.5/8).
That gives two declarations of the same name at the same scope, but with different linkages. That's prohibited by §3.3.1/4:
Given a set of declarations in a single declarative region, each of which specifies the same unqualified name,
they shall all refer to the same entity, or all refer to functions and function templates; or
exactly one declaration shall declare a class name or enumeration name that is not a typedef name
and the other declarations shall all refer to the same variable or enumerator, or all refer to functions and function templates; in this case the class name or enumeration name is hidden (3.3.10).
Neither refers to a function, function template, class name, or enumeration name, so none of these "escape clauses" applies. The two declarations must refer to the same entity, which must have both external linkage and no linkage. Since that's impossible, the code is ill-formed.
Here is my interpretation: In §3.3.1/3 the standard says:
The names declared by a declaration are introduced into the scope in which the declaration occurs, except that the presence of a friend specifier (11.3), certain uses of the elaborated-type-specifier (7.1.6.3), and using-directives (7.3.4) alter this general behavior.
As extern declarations are not listed as exception, the name is introduced in the block scope, which is why you get the error when you try to redeclare it.
The paragraph you quoted says
but they do not introduce new names into that scope.
which is a bit ambiguous, as both block scope and namespace scope are mentioned. The standard would contradict itself if it referred to block scope, so I assume that namespace scope is meant.