Consider the following program (see live demo here).
#include <stdio.h>
int main(void)
{
int ; // Missing variable name
puts("Surprise");
}
My compiler, gcc 4.8.1, gives the below warning:
[Warning] useless type name in empty declaration [enabled by default]
Why does it compile fine? Shouldn't I get a compiler error? g++ 4.8.1 gives the following error when I compile it as a C++ program:
[Error] declaration does not declare anything [-fpermissive]
The C standard says
A declaration other than a static_assert declaration shall declare at least a declarator (other than the parameters of a function or the members of a structure or union), a tag, or the members of an enumeration.
C++ says
In a simple-declaration, the optional init-declarator-list can be omitted only when declaring a class (Clause 9) or enumeration.
A violation of this in either language requires a diagnostic. The standards do not talk about compiler errors or warnings. A warning is a diagnostic.
Your code is illegal (i.e. erroneous, ill-formed, constraint-violating) in both C and C++. The reason you get a "warning" in one language and "error" in another is just a quirk of your compiler and your compiler setup. After all, neither language really formally differentiates between "warnings" and "errors". GCC under its default settings just happens to be more permissive in C mode (mostly for historical reasons).
Use -pedantic-errors in GCC, and you will get an "error" in C code as well. (Note that -pedantic-errors does not simply blindly turn all "warnings" into "errors". It attempts to report only actual constraint violations as "errors".)
The syntax of declaration is defined as (omitting init-declarator-list and init-declarator):
C11 6.7 Declarations
declaration:
declaration-specifiers init-declarator-list opt ;
static_assert-declaration
declaration-specifiers:
storage-class-specifier declaration-specifiers opt
type-specifier declaration-specifiers opt
type-qualifier declaration-specifiers opt
function-specifier declaration-specifiers opt
alignment-specifier declaration-specifiers opt
Note that declaration-specifiers is defined recursively, but each with an opt indicates it's optional.
Also, the following clause 6 states:
The declaration specifiers consist of a sequence of specifiers that indicate the linkage,
storage duration, and part of the type of the entities that the declarators denote. The initdeclarator-list is a comma-separated sequence of declarators, each of which may have additional type information, or an initializer, or both. The declarators contain the identifiers (if any) being declared.
Note the words if any.
Related
I'm having a question about N4842.
For 9.2.7 The inline specifier, there is
"If the inline specifier is used in a friend function declaration, that declaration shall be a definition or the function shall have previously been declared inline."
in fifth paragraph.
But no error has occurred by the following code.
struct X{
friend inline void f();
};
void f(){} // no error
Why is not there error?
Please teach me.
Seems like a compiler bug, which I was able to reproduce on all big 3 compilers. Standard verbiage here is very explicit:
10.1.6/5 (latest draft):
If the inline specifier is used in a friend function declaration, that
declaration shall be a definition or the function shall have
previously been declared inline.
4.1/1:
The set of diagnosable rules consists of all syntactic and semantic
rules in this International Standard except for those rules containing
an explicit notation that “no diagnostic is required” or which are
described as resulting in “undefined behavior”.
...
(2.2) — If a program contains a violation of any diagnosable rule or
an occurrence of a construct described in this International Standard
as “conditionally-supported” when the implementation does not support
that construct, a conforming implementation shall issue at least one
diagnostic message.
Since the rule is not marked as 'no diagnostic is required', failure to provide one is a compiler bug. If you feeling strongly about it, you can file a bugreport.
By mistake, I wrote something along the lines of constexpr bool{};, and while GCC and Clang rejected this, MSVC was more than happy to compile it (see Godbolt). From my understanding, functions (and thus constructors) evaluated at compile time cannot have side effects, therefore this can never have any effect, but is it indeed ill-formed?
(In my experience, MSVC tends to be wrong, but in this specific case I didn’t find where the standard forbids this.)
That's just not valid syntax. It is "forbidden" by the standard by virtue of not being a possible grammar production.
A declaration such as
constexpr bool b{};
is a simple-declaration and has the syntax decl-specifier-seq init-declarator-list(opt) ; (see C++17 [dcl.dcl]/1). The keyword constexpr is a decl-specifier, and so is bool (although only some decl-specifiers have an effect on the type; bool does, but constexpr does not).
The rest of the declaration, b{}, is an init-declarator, which consists of a declarator plus an optional initializer, which in this case is {}. (See [dcl.decl]/1.) The declarator is b. In general, a declarator must contain an identifier such as b. See [dcl.decl]/4.
There is a similar grammar production called an abstract-declarator which lacks an identifier (See [dcl.name]/1). Abstract declarators are allowed in particular contexts, such as when writing down a type-id, or in a parameter-declaration-clause (function parameters are allowed to be unnamed). However, an init-declarator must contain a declarator, not an abstract-declarator.
There is no other grammar production that would match constexpr bool{}; either.
Consider the following program (see live demo here).
#include <stdio.h>
int main(void)
{
int ; // Missing variable name
puts("Surprise");
}
My compiler, gcc 4.8.1, gives the below warning:
[Warning] useless type name in empty declaration [enabled by default]
Why does it compile fine? Shouldn't I get a compiler error? g++ 4.8.1 gives the following error when I compile it as a C++ program:
[Error] declaration does not declare anything [-fpermissive]
The C standard says
A declaration other than a static_assert declaration shall declare at least a declarator (other than the parameters of a function or the members of a structure or union), a tag, or the members of an enumeration.
C++ says
In a simple-declaration, the optional init-declarator-list can be omitted only when declaring a class (Clause 9) or enumeration.
A violation of this in either language requires a diagnostic. The standards do not talk about compiler errors or warnings. A warning is a diagnostic.
Your code is illegal (i.e. erroneous, ill-formed, constraint-violating) in both C and C++. The reason you get a "warning" in one language and "error" in another is just a quirk of your compiler and your compiler setup. After all, neither language really formally differentiates between "warnings" and "errors". GCC under its default settings just happens to be more permissive in C mode (mostly for historical reasons).
Use -pedantic-errors in GCC, and you will get an "error" in C code as well. (Note that -pedantic-errors does not simply blindly turn all "warnings" into "errors". It attempts to report only actual constraint violations as "errors".)
The syntax of declaration is defined as (omitting init-declarator-list and init-declarator):
C11 6.7 Declarations
declaration:
declaration-specifiers init-declarator-list opt ;
static_assert-declaration
declaration-specifiers:
storage-class-specifier declaration-specifiers opt
type-specifier declaration-specifiers opt
type-qualifier declaration-specifiers opt
function-specifier declaration-specifiers opt
alignment-specifier declaration-specifiers opt
Note that declaration-specifiers is defined recursively, but each with an opt indicates it's optional.
Also, the following clause 6 states:
The declaration specifiers consist of a sequence of specifiers that indicate the linkage,
storage duration, and part of the type of the entities that the declarators denote. The initdeclarator-list is a comma-separated sequence of declarators, each of which may have additional type information, or an initializer, or both. The declarators contain the identifiers (if any) being declared.
Note the words if any.
I compiled these codes in MSVC:
int a=sizeof(struct{char c;});
and
int b=((struct{char c;} *)0,0);
and
printf("%p",(struct{char c;} *)0);
As C codes, they can pass compiling, with a warning (warning c4116: unnamed type definition in parentheses. If you give a name, it's "warning c4115: "Whatever" : named type definition in parentheses");
As C++ codes, they are compiled with a bunch of errors.
My questions are:
1. In C, are type definitions in parentheses valid? Why do I get that warning?
2. In C++, are type definitions in parentheses valid?
EDIT :
3. Why?
In C, sizeof can be applied to any type-name that is not an incomplete type (6.5.3.4p1); a struct-or-union-specifier that contains a struct declaration list (6.7.2.1p1) is a type-specifier and thus a type-name. MSVC's warning is there for two reasons: first, because some older compilers (or a C++ compiler used as a C compiler) might not support this usage, and second, because it's unusual and might not be what you intended.
In C++, sizeof can be applied to a type-id; a class-specifier is a type-specifier and thus a type-id, but a class specifier that defines a class (or an enum specifier that defines an enumeration) can only appear in a class declaration or a using declaration (7.1.6p3). This is probably because C++ classes can have linkage and allowing them to appear in general expressions (not just definitions) would complicate this.
In C:
sizeof(struct{char c;})
and
sizeof((struct{char c;} *)0,0)
are both valid expressions. An implementation is free to issue an additional informational diagnostic messages for valid C code.
My understanding, for a long time now, was that a C++ translation unit, after the preprocessor has run, is a sequence of declarations (let me remind that any definition is also a declaration).
Many people have argued with this statement but no one has ever given a counterexample. But I myself found this example which troubles me:
int x; //declaration
; // ??? EMPTY DECLARATION?
int main() //dec
{ //la
} //ration
This compiles fine with MSVC and online comeau. I know the standard defines an empty statement but I never heard of an empty declaration. So, I see three options:
My understanding is correct and the standard defines an empty declaration
My understanding is correct but the standard doesn't define empty declarations and the above translation is ill-formed
My understanding is incorrect, i.e. a C++ TU is not a sequence of declarations
Please help me dissolve my doubts. Thanks
Your understanding is correct and the standard (or at least Stroustrup) does define an empty declaration.
EDIT: It seems this answer is wrong (there's a semantic rule on the standard - but not on the book, as far as I can tell - that prohibits both decl-specified-seq and init-declarator-list of being empty at the same time). See Charles Bailey's answer.
n "The C++ Programming Language", appendix A, section A.4:
A program is a collection of translation-units (...). A translation-unit, often called a source file, is a sequence of declarations:
translation-unit:
declaration-seq_opt
opt means the production is optional. In this rule, it means an empty translation unit is valid.
Section A.7:
declaration-seq:
declaration
declaration-seq declaration
declaration:
block-declaration
(...)
block-declaration:
simple-declaration
(...)
simple-declaration:
decl-specified-seq_opt init-declarator-list_opt ;
So declaration-seq is a sequence of at least one declaration. A declaration can, amongst other things, be a block-declaration, which in turn produces simple-declaration. As both the decl-specified-seq and init-declarator-list non-literals are optional, ; is a valid declaration.
An empty-declaration is allowed in (the current draft of) C++0x at file scope (and namespace scope and other places where a declaration is allowed) and it is just a semicolon. It is a standalone grammatical entity.
In C++03 a lone semicolon is not allowed where only a declaration is expected. Although it might appear that a simple-declaration might be able to reduce to just a semicolon an explicit rule disallows this.
7 [dcl.dcl] / 3
In a simple-declaration, the optional init-declarator-list can be omitted only when declaring a class (clause 9) or enumeration (7.2), that is, when the decl-specifier-seq contains either a class-specifier, an elaborated-type-specifier with a class-key (9.1), or an enum-specifier.
In short this implies that the init-declarator-list can be omitted only when the decl-specifier-seq is not omitted.