[cfe-dev] Specializing friend template functions?

Mario Lang mlang at delysid.org
Fri Dec 5 03:55:53 PST 2014


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.
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.

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.

Or am I just babbling along, and everyone knows about this one already?

-- 
CYa,
  ⡍⠁⠗⠊⠕




More information about the cfe-dev mailing list