When trying to compile the following (simplified) code for multiple platforms, I found that it was failing on some, namely IBM’s xlC_r. Further investigation has found that it also fails on comeau and clang. It compiles successfully with g++ and Solaris’s CC.
Here is the code:
int main()
{
int a1[1];
bool a2[1];
for (int *it = a1, *end = a1+1; it != end; ++it) {
//...
bool *jt = a2, *end = a2+1;
//...
}
}
xlC_r error:
"main.cpp", line 8.25: 1540-0400 (S) "end" has a conflicting declaration.
"main.cpp", line 6.25: 1540-0425 (I) "end" is defined on line 6 of "main.cpp".
clang error:
main.cpp:8:25: error: redefinition of 'end' with a different type
bool *jt = a2, *end = a2+1;
^
main.cpp:6:25: note: previous definition is here
for (int *it = a1, *end = a1+1; it != end; ++it) {
^
comeau error:
"ComeauTest.c", line 8: error: "end", declared in for-loop initialization, may not
be redeclared in this scope
bool *jt = a2, *end = a2+1;
^
The question is why is this an error?
Looking through the 2003 standard, it says the following (6.5.3):
The for statement
for ( for-init-statement; condition; expression ) statement
is equivalent to
{
for-init-statement;
while ( condition ) {
statement;
expression;
}
}
except that names declared in the for-init-statement are in the same
declarative-region as those declared in condition
Here there are no names declared in condition.
Further, it says (6.5.1):
When the condition of a while statement is a declaration, the scope
of the variable that is declared extends from its point of declaration
(3.3.1) to the end of the while statement. A while statement of the form
while (T t = x) statement
is equivalent to
label:
{
T t = x;
if (t) {
statement;
goto label;
}
}
Again, I’m not sure this is relevant, as there is no declaration in the condition. So given the equivalent re-write from 6.5.3, my code should be the same as:
int main()
{
int a1[1];
bool a2[1];
{
int *it = a1, *end = a1+1;
while (it != end) {
//...
bool *jt = a2, *end = a2+1;
//...
++it;
}
}
}
Which obviously would allow end to be re-declared.
The standard is somewhat ambiguous. The code you quote as being equivalent to a
whileloop implies that there is an inner scope where declarations inside the loop could hide declarations in the condition; however the standard also says (quoting C++11, since I don’t have C++03 handy):which between them imply that the names can’t be redeclared.
Older (pre-1998) versions of the language put declarations in the for-init-statement into the declarative region outside the loop. This meant that your code would be valid, but this wouldn’t: