[cfe-dev] Specializing friend template functions?

Richard Smith richard at metafoo.co.uk
Fri Dec 5 14:06:06 PST 2014


On Fri, Dec 5, 2014 at 3:55 AM, Mario Lang <mlang at delysid.org> wrote:

> Hi.
>
> I sort of have a suspicion that this might be a known issue, but I
> haven't found anything so far.  The code below compiles just fine with
> GCC, but Clang complains:
>
> ---<snip>---
> class c { template<class> friend bool f(c) { return false; } };
> template<> bool f<int>(c) { return true; }
>
> int main(){}
> ---<snip>---
>
> cl.cc:2:1: error: extraneous 'template<>' in declaration of variable 'f'
> template<> bool f<int>(c) { return true; }
> ^~~~~~~~~~
> cl.cc:2:17: error: redefinition of 'f' as different kind of symbol
> template<> bool f<int>(c) { return true; }
>                 ^
> cl.cc:1:39: note: previous definition is here
> class c { template<class> friend bool f(c) { return false; } };
>                                       ^
>
> As I am not an expert on the standard at all, the first question that
> comes to mind is: is this actually legal?  Given how inline friend
> functions usually work, I have a feeling it should be legal.
>

I don't think this is legal. For an explicit specialization to be valid,
name lookup must find the template being explicitly specialized. Name
lookup for 'f' after the definition of 'c' does not find anything, so the
declaration appears to be ill-formed. (See [temp.names]p2 and p3.)

Clang at least compiles it if the friend template function is not
> defined inline, like this:
>
> class c { template<class> friend bool f(c); };
> template<class> bool f(c) { return false; }
> template<> bool f<int>(c) { return true; }
>
> In any case, while the error message hints at what is going on
> internally, I think it could be improved.  If this is legal, there
> shouldn't be an error, of course.  And if it is not, we could actually
> let the user know that what they are trying isn't about to work, instead
> of claiming that we are looking at a variable definition, which is quite
> misleading methinks.
>

I completely agree that we should diagnose this better.

Secondly, looking at the AST for the code with the offending
> specialisation commented out, I get:
>
> |-CXXRecordDecl 0x3123330 <cl.cc:1:1, col:62> col:7 class c definition
> | |-CXXRecordDecl 0x3123440 <col:1, col:7> col:7 implicit referenced class
> c
> | `-FriendDecl 0x3167120 <col:11, col:60> col:39
> |   `-FunctionTemplateDecl 0x31670b0 parent 0x3122980 <col:11, col:60>
> col:39 f
> |     |-TemplateTypeParmDecl 0x31234d0 <col:20> col:20 class
> |     `-FunctionDecl 0x3167000 parent 0x3122980 <col:27, col:60> col:39 f
> '_Bool (class c)'
> |       |-ParmVarDecl 0x3123590 <col:41> col:42 'class c'
> |       `-CompoundStmt 0x31671c0 <col:44, col:60>
> |         `-ReturnStmt 0x31671a0 <col:46, col:53>
> |           `-CXXBoolLiteralExpr 0x3167188 <col:53> '_Bool' false
>
> So the FunctionTemplateDecl looks fine, but AST print is a bit messy:
>
> class c {
>     friend template <class > bool f(c)     {
>         return false;
>     }
>
> ;
> };
> int main() {
> }
>
> Note, the extra semicolon (likely harmless) and the swapped 'friend'
> keyword position.  I don't know if 'friend' can be switched around like
> this, but GCC *and* clang actually fail to compile that.
>
> I guess the AST printer doesn't really require to always produce valid
> source code (or does it), but this AST print seems to hint at some gaps
> in AST handling around FriendDecl and nested TemplateFunctionDecl.
>

We don't guarantee that the AST printer always produces valid code. The AST
dump looks fine to me for this case,  though.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20141205/05f50e74/attachment.html>


More information about the cfe-dev mailing list