Skip to content

Commit

Permalink
[clang][Sema] Fix a CTAD regression after 42239d2 (llvm#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 llvm#86769
  • Loading branch information
zyn0217 committed Mar 29, 2024
1 parent a385a91 commit 997ea41
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 2 deletions.
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,10 @@ Bug Fixes to C++ Support
- Fix a crash when an unresolved overload set is encountered on the RHS of a ``.*`` operator.
(`#53815 <https://github.com/llvm/llvm-project/issues/53815>`_)

- Fixed a regression in CTAD that a friend declaration that befriends itself may cause
incorrect constraint substitution.
(`#86769 <https://github.com/llvm/llvm-project/issues/86769>`_)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed an import failure of recursive friend class template.
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 @@ -1830,7 +1830,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 [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 [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 997ea41

Please sign in to comment.