Strange code that compiles with g++
The following code compiles successfully with g++ 4.8.1:
int main()
{
int(*)();
}
It looks like a simple declaration of a pointer to function:
int(*f)();
It doesn't compile with clang 3.4 and vc++ 2013.
Is it a compiler bug or one of dark places of the standard?
List of similar strange code pieces which compile fine with g++ 4.8.1 (updated):
int(*)();
int(*);
int(*){};
int(*());
Live example with these strange code pieces.
Update 1: @Ali added some interesting information in the comments:
All 4 cases give a compile error with clang 3.5 trunk (202594) and compile fine with gcc 4.9 trunk (20140302). The behavior is the same with
-std=c++98 -pedantic
, except forint(*){};
which is understandable; extended initializer lists only available with-std=c++11
.
Update 2: As @CantChooseUsernames noted in his answer they still compile fine even with initialization and no assembly is generated for them by g++ (neither with nor without initialization) even without any enabled optimization:
int(*)() = 0;
int(*) = 0;
int(*){} = 0;
int(*()) = 0;
Live example with initializations.
Update 3: I was really surprised to find that int(*)() = "Hello, world!";
compiles fine, too (while int(*p)() = "Hello, world!";
doesn't compile, of course).
Update 4: It is fantastic but int(*){} = Hello, world!;
compiles fine. And the following extremely strange piece of code, too: int(*){}() = -+*/%&|^~.,:!?$()[]{};
(live example).
Update 5: As @zwol noted in his comment
This and a number of related syntactic problems are being tracked as gcc bug 68265.
According to the C++ Standard (p. #6 of section 7 Declarations)
6 Each init-declarator in the init-declarator-list contains exactly one declarator-id, which is the name declared by that init-declarator and hence one of the names declared by the declaration
So it is simply a compiler bug.
The valid code could look as for example (apart from the function pointer declaration showed by you) though I can not compile it with my MS VC++ 2010.
int(*p){};
It seems that the compiler you are using for testing allows declarations without a declarator-id.
Also take into account the following paragraph of section 8.1 Type names
1 To specify type conversions explicitly, and as an argument of sizeof, alignof, new, or typeid, the name of a type shall be specified. This can be done with a type-id, which is syntactically a declaration for a variable or function of that type that omits the name of the entity.
I am not sure how much this helps, but I tried the following (clang 3.3, g++ 4.8.1):
using P = int(*)();
using Q = int*;
P; // warning only
Q; // warning only
int(*)(); // error (but only in clang)
int*; // error
int(*p)(); // ok
int *q; // ok
On the other hand, everything compiles fine in g++ 4.8.2 and 4.9.0. I have no clang 3.4, unfortunately.
Very roughly, a declaration [iso section 7] consists of the following parts in order:
- optional prefix specifiers (e.g.
static
,virtual
) - base type (e.g.
const double
,vector<int>
) - declarator (e.g.
n
,*p
,a[7]
,f(int)
) - optional suffix function specifiers (e.g.
const
,noexcept
) - optional initializer or function body (e.g.
= {1,2,3}
or{ return 0; }
Now, a declarator roughly consists of a name and optionally some declarator operators [iso 8/4].
Prefix operators, e.g.:
-
*
(pointer) -
*const
(constant pointer) -
&
(lvalue reference) -
&&
(rvalue reference) -
auto
(function return type, when trailing)
Postfix operators, e.g.:
-
[]
(array) -
()
(function) -
->
(function trailing return type)
The above operators were designed to reflect their use in expressions. Postfix operators bind tighter than prefix, and parentheses can be used to change their order: int *f()
is a function returning a pointer to int
, whereas int (*f)()
is a pointer to a function returning int
.
Maybe I am wrong, but I think these operators cannot be in the declaration without the name. So when we write int *q;
, then int
is the base type, and *q
is the declarator consisting of prefix operator *
followed by name q
. But int *;
cannot appear by itself.
On the other hand, when we define using Q = int*;
, then declaration Q;
is fine by itself because Q
is the base type. Of course, because we are not declaring anything, we may get an error or a warning depending on compiler options, but this is a different error.
The above are just my understanding. What the standard (e.g. N3337) says is [iso 8.3/1]:
Each declarator contains exactly one declarator-id; it names the identifier that is declared. An unqualified-id occurring in a declarator-id shall be a simple identifier except for the declaration of some special functions (12.3 [user-defined conversions], 12.4 [destructors], 13.5 [overloaded operators]) and for the declaration of template specializations or partial specializations (14.7).
(notes in square brackets are mine). So I understand int(*)();
should be invalid and I cannot say why it has different behaviour in clang and different versions of g++.
You can use this: http://gcc.godbolt.org/ to view the assembly..
int main()
{
int(*)() = 0;
return 0;
}
Generates:
main:
pushq %rbp
movq %rsp, %rbp
movl $0, %eax
popq %rbp
ret
Which is equivalent to: int main() {return 0;}
So even with NO optimization, gcc just doesn't generate assembly for it.. Should it give a warning or error? I have no clue but it doesn't care or do anything for the unnamed func pointer.
However:
int main()
{
int (*p)() = 0;
return 0;
}
With no optimization will generate:
main:
pushq %rbp
movq %rsp, %rbp
movq $0, -8(%rbp)
movl $0, %eax
popq %rbp
ret
which allocates 8 bytes on the stack..