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.
Related
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'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.
Is the following program well-formed or ill-formed according to the c++ standard?
namespace X { int i; }
namespace Y { using X::i; }
int main() { using X::i; using Y::i; }
I'm getting different results with different compilers:
MSVS: Compiles ( http://webcompiler.cloudapp.net/ )
Clang: Compiles ( http://melpon.org/wandbox/permlink/KloDufJ5h1DalK4v )
GCC: Compile error ( http://melpon.org/wandbox/permlink/IKuuQGE1THofuUTr )
I don't want to fix this program to make it compile on GCC. I just want to know what the c++ standard says about this and why the three compilers behave differently. Also I want to if this is a result of a bug in any of these compilers.
The program should not compile because it declares X::i twice in the same block scope.
C++14 §7.3.3/10:
” A using-declaration is a declaration and can therefore be used repeatedly where (and only where) multiple
declarations are allowed. [Example:
namespace A {
int i;
}
namespace A1 {
using A::i;
using A::i; // OK: double declaration
}
void f() {
using A::i;
using A::i; // error: double declaration
}
Edit: The non-normative comment quoted above, and which I thought answered the question, was there originally in C++98 and has survived through Technical Corrigendum 1 (C++03), C++11 and C++14. But apparently it's wrong. Richard Smith in his answer cites core issue 36 about it, first raised by Andrew Koenig on 2nd August 1998 (less than a month after ANSI approval of the first standard), which apparently means that a known incorrect comment can survive three revisions of the standard.
Citing the core issue itself about that:
C++ Standard Core Language Active Issues, issue 36:
” Notes from 04/00 meeting:
The core language working group was unable to come to consensus over what kind of declaration a using-declaration should emulate. In a straw poll, 7 members favored allowing using-declarations wherever a non-definition declaration could appear, while 4 preferred to allow multiple using-eclarations only in namespace scope (the rationale being that the permission for multiple using-declarations is primarily to support its use in multiple header files, which are seldom included anywhere other than namespace scope). John Spicer pointed out that friend declarations can appear multiple times in class scope and asked if using-declarations would have the same property under the "like a declaration" resolution.
As a result of the lack of agreement, the issue was returned to "open" status.
The general discussion of multiple declarations of the same name is in §3.3.1/4 in both C++98 and C++14. As far as I can see the C++14 text is verbatim identical to the original C++98 text. And by itself it allows declaring the same name multiple times in the same declarative region in a number of cases, one of which is that all the declarations refer to the same entity:
C++14 §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). [Note: A
namespace name or a class template name must be unique in its declarative region (7.3.2, Clause 14). —end note]
However, the wording here only says what is not directly invalid. A declaration can be disallowed by other rules even if it's not disallowed by this one. For example, there is such a restriction for class member declarations:
C++14 §9.2/1:
” […] A member shall not be declared twice in the member-
specification, except that a nested class or member class template can be declared and then later defined,
and except that an enumeration can be introduced with an opaque-enum-declaration and later redeclared
with an enum-specifier.
I fail to find such a restriction that supports the apparently incorrect comment in C++14 §7.3.3/10 quoted at the start above, i.e. I fail to find any special treatment of block scopes or namespace scopes, and so a tentative conclusion (keeping in mind the comment's survival in spite of being contested already in 1998) is that the contested comment actually is wrong and that this question's code, where two declarations in the same declarative region refer to the same entity, is valid and should be accepted by all compilers.
Clang and MSVC are correct; this code is valid. As Alf notes, [namespace.udecl] (7.3.3)/10 says
A using-declaration is a declaration and can therefore be used repeatedly where (and only where) multiple declarations are allowed.
However, there is no restriction on multiple declarations of the same entity in block scope, so the original example is valid. A corresponding case not involving using-declarations is:
int n;
void f() {
extern int n;
extern int n;
}
This is valid (and is accepted by GCC, EDG, Clang, and MSVC), therefore (by the above-quoted rule) the original example is also valid.
It is worth noting that the example in [namespace.udecl] (7.3.3)/10 contains an error. It says:
namespace A {
int i;
}
void f() {
using A::i;
using A::i; // error: double declaration
}
... but the comment is not correct; there is no error on the second declaration. See the discussion in core issue 36. I've removed the example from the standard so that it won't confuse more people.
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.