[cfe-dev] Specializing friend template functions?

Richard Smith richard at metafoo.co.uk
Mon Dec 8 11:02:33 PST 2014


On Sat, Dec 6, 2014 at 5:35 AM, Mario Lang <mlang at delysid.org> wrote:

> Richard Smith <richard at metafoo.co.uk> writes:
>
> > 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.)
>
> I wonder why name-lookup doesn't find anything.  At least non-templated
> free friend functions have always worked that way.


That's not the case; try this:

struct S {
  friend void f(int);
};
void g() { f(0); } // error, undeclared identifier 'f'


> Or is this a GCC
> extension I am not aware of?
>
> class d {
>   ...
>   friend bool operator==(d, d) { ... }
> };
> // here, d{} == d{} is found
>

There's a special lookup rule used for function calls that allows it to
find declarations that are not in scope; see
http://en.wikipedia.org/wiki/Argument-dependent_name_lookup. This only
applies to function calls, and not, for instance, to explicit
specializations.


> [...]
>
> >> 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.
>
> Guessed that.
>
> > The AST dump looks fine to me for this case, though.
>
> Note friend template<class> vs template<class> friend.
>

Right, the AST pretty-printing is obviously producing ill-formed code. But
the AST dump looks fine.


> The original code was:
>
> >> class c { template<class> friend bool f(c) { return false; } };
>
> and ast-print switched that around to:
>
> >>     friend template <class > bool f(c)     {
>
> which fails to compile on gcc and clang.
>
> --
> CYa,
>   ⡍⠁⠗⠊⠕
>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20141208/69042899/attachment.html>


More information about the cfe-dev mailing list