[clang] [clang][Sema] Fix a CTAD regression after 42239d2e9 (PR #86914)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 29 08:12:32 PDT 2024
https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/86914
>From b31ca786d937dc180ad02042132596b2e5f3710f Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Thu, 28 Mar 2024 14:13:12 +0800
Subject: [PATCH 1/2] [clang][Sema] Fix a CTAD regression after 42239d2e9
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 https://github.com/llvm/llvm-project/issues/86769
---
clang/docs/ReleaseNotes.rst | 3 +++
clang/lib/Sema/SemaTemplate.cpp | 14 +++++++++++-
clang/test/SemaTemplate/concepts-friends.cpp | 24 ++++++++++++++++++++
clang/test/SemaTemplate/ctad.cpp | 2 +-
4 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7fbe2fec6ca065..ed0996bd3d30c0 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 005529a53270c3..14fabe36eee794 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -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(
diff --git a/clang/test/SemaTemplate/concepts-friends.cpp b/clang/test/SemaTemplate/concepts-friends.cpp
index 255b0858917fb6..31840309f1ec86 100644
--- a/clang/test/SemaTemplate/concepts-friends.cpp
+++ b/clang/test/SemaTemplate/concepts-friends.cpp
@@ -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);
+
+}
diff --git a/clang/test/SemaTemplate/ctad.cpp b/clang/test/SemaTemplate/ctad.cpp
index 388ed7d4cced18..ec144d4f44ba8c 100644
--- a/clang/test/SemaTemplate/ctad.cpp
+++ b/clang/test/SemaTemplate/ctad.cpp
@@ -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);
-};
+}
>From 6acd29424d9a8c3febea004a68401439d5b7e5a0 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Fri, 29 Mar 2024 22:51:09 +0800
Subject: [PATCH 2/2] Expand comments
---
clang/lib/Sema/SemaTemplate.cpp | 30 +++++++++++++++++++-----------
1 file changed, 19 insertions(+), 11 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 14fabe36eee794..4eca7d79897676 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1836,19 +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.
- 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
+ Decl *D = TD->getMostRecentDecl();
+ // N3337 [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();
+ //
+ // 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(
More information about the cfe-commits
mailing list