Skip to content

Commit 0f6ed4c

Browse files
authored
[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 d3bc9cc commit 0f6ed4c

File tree

4 files changed

+51
-2
lines changed

4 files changed

+51
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,9 @@ Bug Fixes in This Version
357357
- Fixes an assertion failure on invalid code when trying to define member
358358
functions in lambdas.
359359

360+
- Fixed a regression in CTAD that a friend declaration that befriends itself may cause
361+
incorrect constraint substitution. (#GH86769).
362+
360363
Bug Fixes to Compiler Builtins
361364
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
362365

clang/lib/Sema/SemaTemplate.cpp

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

18421862
DeclResult Sema::CheckClassTemplate(

clang/test/SemaTemplate/concepts-friends.cpp

Lines changed: 26 additions & 0 deletions
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 N3337 [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

Lines changed: 1 addition & 1 deletion
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)