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.)
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.
I have looked around quite a bit and have not found whether or not C++ attributes should be in the header or the implementation or both. For example:
file.h
[[nodiscard]] std::future<int> get_data();
file.cpp
[[nodiscard]] std::future<int> get_data() { return ...; }
Should both have the attribute or only one? The examples provided by cppreference are all functions with no forward declaration.
To be effective, the attribute needs to be applied to the declaration (i.e., in the header). If a call is being compiled, and the declaration the compiler has seen lacks the attribute, the compiler normally won't be able to issue a diagnostic based on the attribute (since it hasn't seen it).
§[dcl.attr.nodiscard]/1:
The attribute-token nodiscard may be applied to the declarator-id in a function declaration or to the declaration of a class or enumeration.
The same basic notion applies to most other attributes as well, but a few belong in the implementation--most obviously the [[fallthrough]] attribute, which goes at the end of a case in a switch statement, so it has to be located where the switch statement itself is.
The [[noreturn]] attribute is a little bit more specific. It directly requires that if a function is declared more than once, the first declaration the compiler sees for that function must have the [[noreturn]] attribute. If the compiler sees a [[noreturn]] attribute on a function that has previously been declared without it, the code is ill-formed (but no diagnostic is required if the two declarations were in separate translation units).
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.
namespace A{
int i;
}
int main(){
using A::i;
using A::i;
}
VS2010 - compiles fine
gcc (ideone) - compiles fine
Comeau - gives error ""ComeauTest.c", line 10: error: "i" has already been declared in the current scope
using A::i;"
$7.3.3/8 - "A using-declaration is a
declaration and can therefore be used
repeatedly where (and only where)
multiple declarations are allowed."
The example right there indicates that the code is indeed ill-formed.
So, is this a bug in GCC and VS2010?
EDIT 2:
Remove the multiple using directives as it was unrelated to the query on hand.
The example you refer to is known to be inconsistent. The committee hasn't yet fixed this.
So, is this a bug in GCC and VS2010?
I don't think it's a bug in either of GCC/VS2010/Clang or Comeau. It appears to be a bug in the C++ Standard. In these cases, compile writers have to make up their mind on what is most viable. If you remove the example in question, then 3.3/4 states the example is valid: "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 ...".
The question arises, as discussed in the linked issue, what 7.3.3/8 refers to when it says "declarations", which the committee didn't reach consensus about. And so, until then 3.3/4 applies for GCC/VS2010 and Clang, while Comeau chooses to use some other semantics.
Yes you are right. This is indeed a bug in g++, MSVC++ and Clang. Comeau has got it correct.
As you said 7.3.3/8 says
A using-declaration is a declaration and can therefore be used repeatedly where (and only where) multiple declarations are allowed
The following code snippet is also given.
void f()
{
using A::i;
using A::i; //error: double declaration
}
Similarly your code is ill-formed too.
namespace A{
int i;
}
int main(){
using A::i;
using A::i;
}
VS2010 - compiles fine
gcc (ideone) - compiles fine
Comeau - gives error ""ComeauTest.c", line 10: error: "i" has already been declared in the current scope
using A::i;"
$7.3.3/8 - "A using-declaration is a
declaration and can therefore be used
repeatedly where (and only where)
multiple declarations are allowed."
The example right there indicates that the code is indeed ill-formed.
So, is this a bug in GCC and VS2010?
EDIT 2:
Remove the multiple using directives as it was unrelated to the query on hand.
The example you refer to is known to be inconsistent. The committee hasn't yet fixed this.
So, is this a bug in GCC and VS2010?
I don't think it's a bug in either of GCC/VS2010/Clang or Comeau. It appears to be a bug in the C++ Standard. In these cases, compile writers have to make up their mind on what is most viable. If you remove the example in question, then 3.3/4 states the example is valid: "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 ...".
The question arises, as discussed in the linked issue, what 7.3.3/8 refers to when it says "declarations", which the committee didn't reach consensus about. And so, until then 3.3/4 applies for GCC/VS2010 and Clang, while Comeau chooses to use some other semantics.
Yes you are right. This is indeed a bug in g++, MSVC++ and Clang. Comeau has got it correct.
As you said 7.3.3/8 says
A using-declaration is a declaration and can therefore be used repeatedly where (and only where) multiple declarations are allowed
The following code snippet is also given.
void f()
{
using A::i;
using A::i; //error: double declaration
}
Similarly your code is ill-formed too.