https://github.com/zyn0217 updated 
https://github.com/llvm/llvm-project/pull/102587

>From 62218a472c88764472ffba69ceca1825686fe1b9 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7...@gmail.com>
Date: Fri, 9 Aug 2024 16:32:30 +0800
Subject: [PATCH 1/2] [Clang][Concepts] Fix a constraint comparison regression
 for out-of-line ClassTemplateDecls

---
 clang/docs/ReleaseNotes.rst                   |  2 ++
 clang/lib/Sema/SemaConcept.cpp                | 11 ++++++----
 .../SemaTemplate/concepts-out-of-line-def.cpp | 21 +++++++++++++++++++
 3 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0f1a4c1851911d..cb92ba25d1633f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -186,6 +186,8 @@ Bug Fixes to C++ Support
   substitutions in concepts, so it doesn't incorrectly complain of missing
   module imports in those situations. (#GH60336)
 - Fix init-capture packs having a size of one before being instantiated. 
(#GH63677)
+- Clang now properly compares constraints on an out of line class template
+  declaration definition. (#GH102320)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index d4c9d044985e34..2871f78868aea7 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -948,7 +948,7 @@ static const Expr 
*SubstituteConstraintExpressionWithoutSatisfaction(
     Sema &S, const Sema::TemplateCompareNewDeclInfo &DeclInfo,
     const Expr *ConstrExpr) {
   MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
-      DeclInfo.getDecl(), DeclInfo.getLexicalDeclContext(), /*Final=*/false,
+      DeclInfo.getDecl(), DeclInfo.getDeclContext(), /*Final=*/false,
       /*Innermost=*/std::nullopt,
       /*RelativeToPrimary=*/true,
       /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true,
@@ -971,9 +971,12 @@ static const Expr 
*SubstituteConstraintExpressionWithoutSatisfaction(
   // this may happen while we're comparing two templates' constraint
   // equivalence.
   LocalInstantiationScope ScopeForParameters(S);
-  if (auto *FD = DeclInfo.getDecl()->getAsFunction())
-    for (auto *PVD : FD->parameters())
-      ScopeForParameters.InstantiatedLocal(PVD, PVD);
+  if (const NamedDecl *D = DeclInfo.getDecl()) {
+    const FunctionDecl *FD = D->getAsFunction();
+    if (FD)
+      for (auto *PVD : FD->parameters())
+        ScopeForParameters.InstantiatedLocal(PVD, PVD);
+  }
 
   std::optional<Sema::CXXThisScopeRAII> ThisScope;
 
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp 
b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 0142efcdc3ee86..5ea1ff79e572bc 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -599,3 +599,24 @@ template <class DerT>
 unsigned long DerivedCollection<DerTs...>::index() {}
 
 } // namespace GH72557
+
+namespace GH102320 {
+
+template <class, class>
+concept Constrained = true;
+
+template <class T> class C {
+  template <Constrained<T>> class D;
+  template <class U>
+    requires Constrained<T, U>
+  class E;
+};
+
+template <class T> template <Constrained<T>> class C<T>::D {};
+
+template <class T>
+template <class U>
+  requires Constrained<T, U>
+class C<T>::E {};
+
+} // namespace GH102320

>From 23bc9374b19b138a767fb8c7cd3d06b23433e699 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7...@gmail.com>
Date: Sat, 10 Aug 2024 12:09:00 +0800
Subject: [PATCH 2/2] Don't visit out-of-line specializations

---
 clang/lib/Sema/SemaConcept.cpp                | 35 +++++++++++++++----
 .../SemaTemplate/concepts-out-of-line-def.cpp | 15 ++++++++
 2 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 2871f78868aea7..900d3d1616cbe2 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -947,12 +947,35 @@ namespace {
 static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
     Sema &S, const Sema::TemplateCompareNewDeclInfo &DeclInfo,
     const Expr *ConstrExpr) {
+  const NamedDecl *ND = DeclInfo.getDecl();
+  // ND would be absent when we are parsing a template parameter header, and 
the
+  // template it pertains to is thus unavaliable. We collect the surrounding
+  // template arguments for evaluating constraints, starting from the current
+  // semantic context, in order for out-of-line constrained declarations to be
+  // properly evaluated.
+  //
+  //   template <class T>
+  //   class A {
+  //     template <C<T>> class B;
+  //   };
+  //
+  //   template <class T> template <C<T> U> class A<T>::B {};
+  //
+  //   (This is the case when comparing `template <C<T> U>` against its primary
+  //   template parameter list `template <C<T>>`.)
+  //
+  // Parent specializations are also ignored because fully specialized parents
+  // of the out-of-line declaration don't contribute to the depth of templates.
+  //
+  //   template <> template <C<void> U> class A<void>::B {};
+  //   (U rests in the depth of 0.)
+  //
   MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
-      DeclInfo.getDecl(), DeclInfo.getDeclContext(), /*Final=*/false,
+      ND, DeclInfo.getDeclContext(), /*Final=*/false,
       /*Innermost=*/std::nullopt,
       /*RelativeToPrimary=*/true,
       /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true,
-      /*SkipForSpecialization*/ false);
+      /*SkipForSpecialization=*/!ND);
 
   if (MLTAL.getNumSubstitutedLevels() == 0)
     return ConstrExpr;
@@ -962,7 +985,7 @@ static const Expr 
*SubstituteConstraintExpressionWithoutSatisfaction(
   Sema::InstantiatingTemplate Inst(
       S, DeclInfo.getLocation(),
       Sema::InstantiatingTemplate::ConstraintNormalization{},
-      const_cast<NamedDecl *>(DeclInfo.getDecl()), SourceRange{});
+      const_cast<NamedDecl *>(ND), SourceRange{});
   if (Inst.isInvalid())
     return nullptr;
 
@@ -971,12 +994,10 @@ static const Expr 
*SubstituteConstraintExpressionWithoutSatisfaction(
   // this may happen while we're comparing two templates' constraint
   // equivalence.
   LocalInstantiationScope ScopeForParameters(S);
-  if (const NamedDecl *D = DeclInfo.getDecl()) {
-    const FunctionDecl *FD = D->getAsFunction();
-    if (FD)
+  if (ND)
+    if (const FunctionDecl *FD = ND->getAsFunction())
       for (auto *PVD : FD->parameters())
         ScopeForParameters.InstantiatedLocal(PVD, PVD);
-  }
 
   std::optional<Sema::CXXThisScopeRAII> ThisScope;
 
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp 
b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 5ea1ff79e572bc..c3eadaa3ceaf27 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -619,4 +619,19 @@ template <class U>
   requires Constrained<T, U>
 class C<T>::E {};
 
+#if 0
+// FIXME: Is it conforming? Only Clang rejects it in every released version.
+template <>
+template <Constrained<int> T>
+class C<int>::D<T> {};
+#endif
+
+template <>
+template <Constrained<int>>
+class C<int>::D {};
+
+template <>
+template <class T> requires Constrained<int, T>
+class C<int>::E {};
+
 } // namespace GH102320

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to