Skip to content

Commit

Permalink
[clang][Sema] Fix a CTAD regression after 42239d2 (#86914)
Browse files Browse the repository at this point in the history
The most recent declaration of a template as a friend can introduce a
different template parameter depth compared to what we anticipate from a
CTAD guide.

Fixes #86769
  • Loading branch information
zyn0217 committed Mar 29, 2024
1 parent d3bc9cc commit 0f6ed4c
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 2 deletions.
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,9 @@ Bug Fixes in This Version
- Fixes an assertion failure on invalid code when trying to define member
functions in lambdas.

- Fixed a regression in CTAD that a friend declaration that befriends itself may cause
incorrect constraint substitution. (#GH86769).

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
22 changes: 21 additions & 1 deletion clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1836,7 +1836,27 @@ static TemplateParameterList *GetTemplateParameterList(TemplateDecl *TD) {
// Make sure we get the template parameter list from the most
// recent declaration, since that is the only one that is guaranteed to
// have all the default template argument information.
return cast<TemplateDecl>(TD->getMostRecentDecl())->getTemplateParameters();
Decl *D = TD->getMostRecentDecl();
// C++11 N3337 [temp.param]p12:
// A default template argument shall not be specified in a friend class
// template declaration.
//
// Skip past friend *declarations* because they are not supposed to contain
// default template arguments. Moreover, these declarations may introduce
// template parameters living in different template depths than the
// corresponding template parameters in TD, causing unmatched constraint
// substitution.
//
// FIXME: Diagnose such cases within a class template:
// template <class T>
// struct S {
// template <class = void> friend struct C;
// };
// template struct S<int>;
while (D->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None &&
D->getPreviousDecl())
D = D->getPreviousDecl();
return cast<TemplateDecl>(D)->getTemplateParameters();
}

DeclResult Sema::CheckClassTemplate(
Expand Down
26 changes: 26 additions & 0 deletions clang/test/SemaTemplate/concepts-friends.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,3 +478,29 @@ template <Concept> class Foo {
};

} // namespace FriendOfFriend

namespace GH86769 {

template <typename T>
concept X = true;

template <X T> struct Y {
Y(T) {}
template <X U> friend struct Y;
template <X U> friend struct Y;
template <X U> friend struct Y;
};

template <class T>
struct Z {
// FIXME: This is ill-formed per C++11 N3337 [temp.param]p12:
// A default template argument shall not be specified in a friend class
// template declaration.
template <X U = void> friend struct Y;
};

template struct Y<int>;
template struct Z<int>;
Y y(1);

}
2 changes: 1 addition & 1 deletion clang/test/SemaTemplate/ctad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ X x;
template<class T, class B> struct Y { Y(T); };
template<class T, class B=void> struct Y ;
Y y(1);
};
}

0 comments on commit 0f6ed4c

Please sign in to comment.