Consider this code:
struct foo{};
int main() {
foo::foo a;
}
I would expect this to be well-formed, declaring a variable of type foo by the rule in [class]/2 (N4140, emphasis mine):
A class-name is inserted into the scope in which it is declared immediately after the class-name is seen.
The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.
For purposes of access checking, the injected-class-name is treated as if it were a public member name.
clang 3.6.0 agrees with me, compiling the above code with no applicable warnings with -Wall -pedantic.
gcc 5.2.0 disagrees, providing the following error message:
main.cpp: In function 'int main()':
main.cpp:5:5: error: 'foo::foo' names the constructor, not the type
foo::foo a;
The above holds no matter how deep the nesting of injected class names, e.g. foo::foo::foo::foo.
Is there a rule which forces that construct to be interpreted as a constructor in that context, or is this agcc bug? Or am I interpreting the standards quote incorrectly?
It appears that clang is wrong in this case. The relevant exception I was looking for is in [class.qual]/2:
2 In a lookup in which function names are not ignored and the nested-name-specifier nominates a class C:
(2.1)
if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C, or
[...]
the name is instead considered to name the constructor of class C.
The standard has a near-equivalent (non-normative, obviously) example:
struct A { A(); };
struct B: public A { B(); };
A::A() { }
B::B() { }
B::A ba;// object of type A
A::A a;// error, A::A is not a type name
struct A::A a2;// object of type A
However, clang actually issues a correct diagnostic in this case:
error: qualified reference to 'A' is a constructor name rather than a type wherever a constructor can be declared
Perhaps clang interprets the line In a lookup in which function names are not ignored as In a lookup in which a constructor declaration is valid, but that doesn't seem to be a correct interpretation.
There is an existing bug for this in the clang bugzilla.
Relevant, but not an answer: The GCC people discussed exactly this for years and figured that it should not be accepted. They explicitly made this an error in GCC 4.5 and newer - in 4.4.7 it was accepted.
BTW: You probably want to use Clang's -Weverything instead of -Wall -pedantic when investigating such stuff.
I think this is the subject of language defect #147
which contains this example
class B { };
class A: public B {
A::B ab; // B is the inherited injected B
A::A aa; // Error: A::A is the constructor
};
At least gcc seems to believe that. :-)
Related
In this code:
typedef int foo;
struct S
{
foo foo;
};
int main() {}
all versions of clang -std=c++14 accept this code, however all versions of g++ -std=c++14 report:
5 : error: declaration of 'foo S::foo' [-fpermissive]
foo foo;
^
1 : error: changes meaning of 'foo' from 'typedef int foo' [-fpermissive]
Is the code correct?
The code is wrong. typedef is a new name for a existing type. So you can not create a variable with a type's name like foo foo; is equal to int int.
g++ -std=c++14 is the correct one.
Also refer this question
According to the C++ standard, declaring a variable with the same name as a type is correct code in general, but invalid code within a class definition. The class case is specific, because names declared in a class definition are visible within the whole class definition, before and after the point of declaration of that name. In other scopes (global, namespace, function, ...) declared names are visible only after the point of declaration.
For the example given in the question: If you have another reference to foo before the member declaration foo foo;,
struct S { foo another_member; foo foo; };
to which foo should it refer? To the type or the member foo? In this case it would be possible to deduce from the context that the type is meant, but the C++ standard probably avoided complexity for treating corner cases.
But foo foo; is valid code outside of class definitions: Additionally to the excerpt from section [dcl.spec], which Serge Ballesta already citied in his answer, section [dcl.decl] is useful in this context. It gives a valid example for this case (in older versions of the C++ standard text in a note below the text, in later versions as part of the main text) - here from the N3242 draft (final draft for C++11):
A declaration with several declarators is usually equivalent to the corresponding sequence of declarations each with a single declarator. That is
T D1, D2, ... Dn;
is usually equvalent to
T D1; T D2; ... T Dn;
where T is a decl-specifier-seq and each Di is an init-declarator.
The exception occurs when a name introduced by one of the declarators
hides a type name used by the decl-specifiers, so that when the same
decl-specifiers are used in a subsequent declaration, they do not have
the same meaning, as in
struct S ... ;
S S, T; // declare two instances of struct S
which is not equivalent to
struct S ... ;
S S;
S T; // error
The excerpt from section [dcl.spec] is useful as well, as it describes, when a name in a declaration of a variable is interpreted as type name and when as the variable name (long quote is given in Serge Ballesta's answer):
... it is interpreted as part of the decl-specifier-seq if and only if
...
The relevant section for the class' case, which is given in the original question, is [basic.scope.class]:
... A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in
the completed scope of S. No diagnostic is required for a violation of this rule. ...
This means that the code of the original question is invalid, but the compiler does not need to give an error. So both clang and gcc behave correctly (according to the C++ standard).
I would say CLang is correct here - even if I would never use this.
C++ 14 draft N4296 says in 7.1 Specifiers [dcl.spec] 3
If a type-name is encountered while parsing a decl-specifier-seq, it is interpreted as part of the decl-specifier-
seq if and only if there is no previous type-specifier other than a cv-qualifier in the decl-specifier-seq. The
sequence shall be self-consistent as described below. [ Example:
typedef char* Pc;
static Pc; // error: name missing
Here, the declaration static Pc is ill-formed because no name was specified for the static variable of type Pc.
To get a variable called Pc, a type-specifier (other than const or volatile) has to be present to indicate that
the typedef-name Pc is the name being (re)declared, rather than being part of the decl-specifier sequence.
For another example,
void f(const Pc); // void f(char* const) (not const char*)
void g(const int Pc); // void g(const int)
(emphasize mine)
Even if an example is not normative, it let think that for the writers of C++ specification, a variable can redeclare the name of a typedef.
But g++ is simply more conservative what looks more reasonable. If I ever see such a construct in production code, the programmer would soon learn not to do it again, even I the compiler accepted it...
This code
int clash;
struct Foo {
decltype(clash) clash;
};
compiles silently on clang, but fails to compile on gcc giving the errors
error: declaration of 'int Foo::clash' [-fpermissive]
error: changes meaning of 'clash' from 'int clash' [-fpermissive]
It seems that 2 ingredients are required for the error to arise:
The shadowing must be done by a class member (no problem if it's a function's local scope).
decltype([shadowed name]) must be used in the shadowing scope before the declaration of [shadowing name].
My question is twofold:
Is gcc justified in rejecting this code?
Where does it say so in the standard?
gcc is correct the program is ill-formed, although this particular violation does not require a diagnostic so clang does not have to provide one.
If we look at the C++11 standard(The closest draft would be N3337) section 3.3.7 Class scope it says:
A name N used in a class S shall refer to the same declaration in its
context and when re-evaluated in the completed scope of S. No
diagnostic is required for a violation of this rule.
and the next rule says:
If reordering member declarations in a class yields an alternate valid
program under (1) and (2), the program is ill-formed, no diagnostic is
required.
It makes sense we would want to prevent situations where reordering the declarations in a class give a different program. It is curious whether these two rules are redundant or not.
The section also provides the following example:
enum { i = 1 };
class X {
char v[i]; // error: i refers to ::i
// but when reevaluated is X::i
int f() { return sizeof(c); } // OK: X::c
char c;
enum { i = 2 };
};
and if we try this example with gcc (see it live), we get an almost identical error to one your code produces:
error: declaration of 'i' [-fpermissive]
enum { i = 2 };
^
error: changes meaning of 'i' from '<anonymous enum> i' [-fpermissive]
enum { i = 1 };
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Why are redundant scope qualifications supported by the compiler, and is it legal?
I wouldn't expect this to compile but it does. Could this be a compiler bug, or does it have some correct meaning?
$ g++ -c scopes.cpp
$ cat scopes.cpp
class Log {
public:
Log() { }
static void fn() { }
};
void test() {
Log::Log::Log::Log::Log::Log::fn();
}
$ g++ --version
g++ (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3
Yes, it's legal. A class's name is inserted into its own namespace, which is called the injected-class-name. From C++03 §9/2:
[...] The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.
For purposes of access checking, the injected-class-name is treated as if it were a public member name.
Note that Log::Log names the class constructor, which is only allowed in certain contexts, but as long as you end the chain of Log::Log::... with something other than Log (such as fn), then it doesn't name the constructor. Specifically, §3.4.3.1/1a says:
If the nested-name-specifier nominates a class C, and the name specified after the nested-name-specifier,
when looked up in C, is the injected-class-name of C (clause 9), the name is instead considered to name the
constructor of class C. Such a constructor name shall be used only in the declarator-id of a constructor definition
that appears outside of the class definition.
I accidentally happened to find this in one of the source codes I was looking at. So, I'm giving a similar smaller example here.
In the file test.h:
#include<iostream>
class test{
int i;
public:
test(){}
//More functions here
};
In the file test.cpp:
#include "test.h"
int main()
{
test test1;
test::test test2;
test::test::test test3;
return 0;
}
First of all, is there a reason to declare test2 that way? Secondly, this code compiles just fine in g++ version 4.4.3 and lower versions. Is there something in the C++ standard, saying, scope resolution operators are ignored when there is no need to resolve scope?
This code is not valid.
It was a bug in g++ that it accepted the code. See "g++ does not treat injected class name correctly." The bug was resolved as fixed in 2009, so it should be fixed in any recent version of g++.
To clarify the situation, as specified in §9/2:
A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name. For purposes of access checking, the injected-class-name is treated as if it were a public member name.
However, as specified in §3.4.3.1/1:
If the nested-name-specifier of a qualified-id nominates a class, the name specified after the nested-namespecifier is looked up in the scope of the class (10.2), except for the cases listed below.
[ ... §3.4.3.1/2]:
In a lookup in which the constructor is an acceptable lookup result and the nested-name-specifier nominates a class C:
— if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C (Clause 9) [ ... ] the name is instead considered to name the constructor of class C.
[ ... example: ]
struct A { A(); };
[ ... ]
A::A a; // error, A::A is not a type name
struct A::A a2; // object of type A
What I read in the C++ standard about injected class names contradicts (as I see it) with the behavior of a sample program I will present shortly. Here's what I read:
From 3.4 (paragraph 3)
The injected-class-name of a class (clause 9) is also considered to be
a member of that class for the purposes of name hiding and lookup.
From 9 (paragraph 2)
A class-name is inserted into the scope in which it is declared
immediately after the class-name is seen. The class-name is also
inserted into the scope of the class itself; this is known as the
injected-class-name. For purposes of access checking, the
injected-class-name is treated as if it were a public member name.
From these I understand that the following is a well-formed translation unit and it compiles successfully.
#include <vector>
class X: std::vector<int>
{
vector mem;
};
However, I would suppose that the following should have produced an error, but it doesn't
#include <vector>
class X: std::vector<int>, std::vector<char>
{
vector mem; //compiles OK... mem is apparently std::vector<int>
};
Since the name vector is injected into both std::vector<int> and std::vector<char> as as if a public member name, then it should be inherited by X and therefore the name vector in X should be ambiguous. Am I missing something?
P.S. I am using MSVC9.0
I found it! It's right there in the standard! I was right! It should be ambiguous!
Clause 14.6.1 Paragraph
A lookup that finds an injected-class-name (10.2) can result in an
ambiguity in certain cases (for example, if it is found in more than
one base class). If all of the injected-class-names that are found
refer to specializations of the same class template, and if the name
is followed by a template-argument-list, the reference refers to the
class template itself and not a specialization thereof, and is not
ambiguous. [Example:
template <class T> struct Base { };
template <class T> struct Derived: Base<int>, Base<char>
{
typename Derived::Base b; // error: ambiguous typename
Derived::Base<double> d; // OK
};
—end example]
Bottom line: This is yet another Microsoft compiler BUG. Disabling language extensions doesn't help either.
No, you are not missing anything, and your compiler seems to behave buggy. You can see how gcc handles it here: http://ideone.com/MI9gz
Its error message is:
prog.cpp:4:4: error: reference to 'vector' is ambiguous
/usr/lib/gcc/i686-pc-linux-gnu/4.5.1/../../../../include/c++/4.5.1/bits/stl_vector.h:171:5: error: candidates are: class std::vector<char> std::vector<char>::vector
/usr/lib/gcc/i686-pc-linux-gnu/4.5.1/../../../../include/c++/4.5.1/bits/stl_vector.h:171:5: error: class std::vector<int> std::vector<int>::vector