-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Description
Consider (https://godbolt.org/z/brf4183r8):
template <typename T>
struct TS {
struct Nested {};
};
struct S {
template <typename T>
friend struct TS<T>::Nested;
};This valid, if horrible, friend declaration, roughly speaking, has the effect of making TS<T>::Nested a friend of S for each specialisation of TS—whether implicit or explicit—that contains a declaration of some struct Nested. [temp.friend]p5
We do not and seemingly have never supported this feature properly (there are FIXMEs about this from 2013). When we encounter such a declaration, we print
<source>:8:26: warning: dependent nested name specifier 'TS<T>::' for friend class declaration is not
supported; turning off access control for 'S' [-Wunsupported-friend]
8 | friend struct TS<T>::Nested;
| ~~~~~~~^
and disable access checking entirely for S (yes, that means anyone can now access any private members of S). GCC and MSVC both seem to support this feature properly, though EDG doesn’t (see the godbolt link above).
There is an AST node in Clang, FriendTemplateDecl, that seems to have been intended for this exact use case, but it is currently unused: we can serialise it, traverse it, and print it, but we only create it in exactly one place and never use it again after that; instantiating would theoretically raise an error, but I don’t think it’s currently possible to get to that code path.
If someone wants to look into working on this: from what I can tell, a good starting point would be to search for references to setUnsupportedFriend. In at least one of these places, we seem to be creating a regular FriendDecl for this, which should probably be a FriendTemplateDecl, but I haven’t looked into this too much...