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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With