This is an archive of the discontinued LLVM Phabricator instance.

Repair redeclaration chain of friend template functions.
AbandonedPublic

Authored by sepavloff on Apr 20 2016, 11:28 AM.

Details

Reviewers
None
Summary

When friend template function is parsed, it obtains wrong type. For
instance, in the code:

template<typename T1> void func(T1 *x);
template<typename T> struct C1 {

template<typename T1> void func(T1 *x);

};

the friend function func gets canonical type 'void (template-param-1-0)',
while type of the same function declared at file level is
'void (template-param-0-0)'. As a result, these two declarations are not
connected into redeclaration chain.

It occurs because beginning of template friend is parsed in the same way
as a declaration of member template. So template parameters get canonical
types as for a member template. Whether the declaration is a friend or
not can be determined only after declspec is parsed. It is too late, and
use of token look ahead is impractical to determine how parameters should
be handled. Type parameters should be fixed after friend declaration is
seen. They require shift of template parameter depth downward. It the
example above the shift would convert the type 'void (template-param-1-0)'
into 'void (template-param-0-0)'. However this change cannot be made for
all instances of template parameter, because friend function body may use
befriending class parameters as well, after the shift they would have the
same canonical representation as the friend function template parameters.

The fix implements update of canonical representation of friend template
function type. It allows to build up redeclaration chain correctly and
still does not break body of the friend function.

Diff Detail

Event Timeline

sepavloff updated this revision to Diff 54396.Apr 20 2016, 11:28 AM
sepavloff retitled this revision from to Repair redeclaration chain of friend template functions..
sepavloff updated this object.
sepavloff added a reviewer: rsmith.
sepavloff added a subscriber: cfe-commits.
rsmith edited edge metadata.Apr 20 2016, 1:57 PM

Sorry, I don't think this approach can work. Consider:

template<typename T> struct X {
  template<typename U> friend void f(T);
  template<typename U> friend void f(U);
};

These two friend declarations declare different friend function templates, but this transformation would incorrectly make them have the same type and be redeclarations of each other.

I think the right thing here is to just accept that a friend function template declared within a class template will not be part of the corresponding redeclaration chain. But that's fine, so long as we don't try to inject the function template into the surrounding scope -- when we come to instantiate the class template, the instantiated friend function template will have the right type and will be part of the relevant redeclaration chain.

sepavloff removed a subscriber: cfe-commits.
sepavloff abandoned this revision.Jul 10 2017, 9:38 AM

D21508 implements other solution.