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.
Related
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.
I'm trying to figure out whether to file a bug report against Clang, GCC, or both (I've tested against Clang trunk and GCC 4.7.2: if someone could verify this against GCC trunk that would be helpful):
Basically, the following code three-line file compiles fine with -fsyntax-only, in default and C++11 modes:
class A {
friend void f();
};
Note that there's no prior declaration of f(), but this is explicitly OK.
However, Clang (but not GCC) rejects the following:
class A {
friend void ::f();
};
The error from Clang is "no function named 'f' with type 'void ()' was found in the specified scope", but I can't find any justification in the standard for treating this case differently than the previous one, so I think it's a bug; I might be wrong though (I'm reading from N3242, however, which AFAIK is the last public draft before C++11).
This next example, however, is rejected by GCC rather than Clang:
void f() { }
void g()
{
class A {
friend void ::f();
};
}
The error from GCC is "friend declaration ‘void f()’ in local class without prior declaration", which doesn't seem to make sense since void ::f() should refer to the f() in the global namespace, which is declared. (Never mind that friend-ing a global function from a local class is nonsensical, it doesn't seem to be illegal...)
Finally, this last example is rejected both by Clang and GCC:
void g()
{
class A {
friend void ::f();
};
}
The errors are "friend declaration ‘void f()’ in local class without prior declaration" and "no function named 'f' with type 'void ()' was found in the specified scope", respectively. Now, there does appear to be some justification for rejecting a friend declaration of a previously undeclared function in a local class, from 11.4p11, but the paragraph actually reads:
If a friend declaration appears in a local class (9.8) and the name specified is an unqualified name, a prior
declaration is looked up without considering scopes that are outside the innermost enclosing non-class scope.
For a friend function declaration, if there is no prior declaration, the program is ill-formed...
The illegality of this declaration apparently is based on the second sentence in this paragraph, but it's unclear to me whether the sentence should apply in the case of a qualified name as well, as is used in this case. (Arguably, it could be that the entire paragraph applies to the "local class" case regardless of whether or not an "unqualified name" is used, and the "and the name specified is an unqualified name" clause only applies to the lookup described in the first sentence, but it seems like a stretch...the only reason I'm imagining this as a possibility is because both compilers reject it.)
Anyway, so from what I can tell, all four of these cases (regardless of how sensible they are or not) should be legal; even if not, at least one of Clang and GCC is wrong in the second and third cases. Can anyone find an error in my logic?
The third and fourth cases are admittedly nonsensical; but I can see the second case breaking someone's valid and useful code so I'm somewhat surprised it's never been caught, if it is indeed a bug.
I think this sentence from 8.3/1 is relevant:
When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers (or, in the case of a namespace, of an element of the inline namespace set of that namespace (7.3.1)) or to a specialization thereof; the member shall not merely have been introduced by a using-declaration in the scope of the class or namespace nominated by the nested-name-specifier of the declarator-id.
The paragraph is talking about declarators in general, in any type of declaration. So I think examples 2 and 4 are ill-formed, clang is correct, and gcc is wrong.
(Example 3 might become more realistic if the global declaration were a template function. It might be useful to friend a global function template or a specialization from a local class. And if that's allowed, your example 3 as written might as well be legal for consistency.)
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.