Skip to content

Commit

Permalink
[clang][Sema] Fix a CTAD regression after 42239d2
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 28, 2024
1 parent c6a65e4 commit b31ca78
Show file tree
Hide file tree
Showing 4 changed files with 41 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 @@ -345,6 +345,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
14 changes: 13 additions & 1 deletion clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1836,7 +1836,19 @@ 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 *ND = TD->getMostRecentDecl();
// Skip past friend Decls 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.
//
// C++23 N4950 [temp.param]p12
// A default template argument shall not be specified in a friend class
// template declaration.
while (ND->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None &&
ND->getPreviousDecl())
ND = ND->getPreviousDecl();
return cast<TemplateDecl>(ND)->getTemplateParameters();
}

DeclResult Sema::CheckClassTemplate(
Expand Down
24 changes: 24 additions & 0 deletions clang/test/SemaTemplate/concepts-friends.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,3 +478,27 @@ 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 N4950 [temp.param]p12.
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 b31ca78

Please sign in to comment.