Skip to content

Commit 76c7219

Browse files
zyn0217tstellar
authored andcommitted
[clang][Sema] Fix a CTAD regression after 42239d2 (#86914)
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
1 parent e0f0c46 commit 76c7219

File tree

4 files changed

+52
-2
lines changed

4 files changed

+52
-2
lines changed

clang/docs/ReleaseNotes.rst

+4
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,10 @@ Bug Fixes to C++ Support
11061106
- Fix a crash when an unresolved overload set is encountered on the RHS of a ``.*`` operator.
11071107
(`#53815 <https://github.com/llvm/llvm-project/issues/53815>`_)
11081108

1109+
- Fixed a regression in CTAD that a friend declaration that befriends itself may cause
1110+
incorrect constraint substitution.
1111+
(`#86769 <https://github.com/llvm/llvm-project/issues/86769>`_)
1112+
11091113
Bug Fixes to AST Handling
11101114
^^^^^^^^^^^^^^^^^^^^^^^^^
11111115
- Fixed an import failure of recursive friend class template.

clang/lib/Sema/SemaTemplate.cpp

+21-1
Original file line numberDiff line numberDiff line change
@@ -1830,7 +1830,27 @@ static TemplateParameterList *GetTemplateParameterList(TemplateDecl *TD) {
18301830
// Make sure we get the template parameter list from the most
18311831
// recent declaration, since that is the only one that is guaranteed to
18321832
// have all the default template argument information.
1833-
return cast<TemplateDecl>(TD->getMostRecentDecl())->getTemplateParameters();
1833+
Decl *D = TD->getMostRecentDecl();
1834+
// C++11 [temp.param]p12:
1835+
// A default template argument shall not be specified in a friend class
1836+
// template declaration.
1837+
//
1838+
// Skip past friend *declarations* because they are not supposed to contain
1839+
// default template arguments. Moreover, these declarations may introduce
1840+
// template parameters living in different template depths than the
1841+
// corresponding template parameters in TD, causing unmatched constraint
1842+
// substitution.
1843+
//
1844+
// FIXME: Diagnose such cases within a class template:
1845+
// template <class T>
1846+
// struct S {
1847+
// template <class = void> friend struct C;
1848+
// };
1849+
// template struct S<int>;
1850+
while (D->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None &&
1851+
D->getPreviousDecl())
1852+
D = D->getPreviousDecl();
1853+
return cast<TemplateDecl>(D)->getTemplateParameters();
18341854
}
18351855

18361856
DeclResult Sema::CheckClassTemplate(

clang/test/SemaTemplate/concepts-friends.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -478,3 +478,29 @@ template <Concept> class Foo {
478478
};
479479

480480
} // namespace FriendOfFriend
481+
482+
namespace GH86769 {
483+
484+
template <typename T>
485+
concept X = true;
486+
487+
template <X T> struct Y {
488+
Y(T) {}
489+
template <X U> friend struct Y;
490+
template <X U> friend struct Y;
491+
template <X U> friend struct Y;
492+
};
493+
494+
template <class T>
495+
struct Z {
496+
// FIXME: This is ill-formed per C++11 [temp.param]p12:
497+
// A default template argument shall not be specified in a friend class
498+
// template declaration.
499+
template <X U = void> friend struct Y;
500+
};
501+
502+
template struct Y<int>;
503+
template struct Z<int>;
504+
Y y(1);
505+
506+
}

clang/test/SemaTemplate/ctad.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,4 @@ X x;
5353
template<class T, class B> struct Y { Y(T); };
5454
template<class T, class B=void> struct Y ;
5555
Y y(1);
56-
};
56+
}

0 commit comments

Comments
 (0)