[clang] [Clang][Concepts] Fix the constraint equivalence checking for TemplateTypeParmTypes (PR #102131)

Younan Zhang via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 6 05:13:27 PDT 2024


https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/102131

Fixes https://github.com/llvm/llvm-project/issues/101735

(I'll add a release note and some comments later)

>From 0727e47124af564826a22a718a64a1da79e6131d Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Tue, 6 Aug 2024 20:08:43 +0800
Subject: [PATCH] [Clang][Concepts] Fix the constraint equivalence checking for
 TemplateTypeParmTypes

---
 clang/include/clang/Sema/Template.h           |  2 ++
 clang/lib/Sema/SemaConcept.cpp                | 28 +++++++++++++++----
 .../SemaTemplate/concepts-out-of-line-def.cpp | 23 +++++++++++++++
 3 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index d616865afe807..7b3646f0fcc35 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -245,6 +245,8 @@ enum class TemplateSubstitutionKind : char {
                     AssociatedDecl) &&
                "Trying to change incorrect declaration?");
         TemplateArgumentLists[0].Args = Args;
+        TemplateArgumentLists[0].AssociatedDeclAndFinal.setPointer(
+            AssociatedDecl);
       } else {
         --NumRetainedOuterLevels;
         TemplateArgumentLists.push_back({{AssociatedDecl, Final}, Args});
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index d4c9d044985e3..855b145db9586 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -946,7 +946,8 @@ namespace {
 
 static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
     Sema &S, const Sema::TemplateCompareNewDeclInfo &DeclInfo,
-    const Expr *ConstrExpr) {
+    const Expr *ConstrExpr,
+    const Decl *PreferredInnermostAssociatedDecl = nullptr) {
   MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
       DeclInfo.getDecl(), DeclInfo.getLexicalDeclContext(), /*Final=*/false,
       /*Innermost=*/std::nullopt,
@@ -957,6 +958,13 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
   if (MLTAL.getNumSubstitutedLevels() == 0)
     return ConstrExpr;
 
+  if (PreferredInnermostAssociatedDecl)
+    if (MLTAL.getAssociatedDecl(MLTAL.getNumLevels() - 1).first !=
+        PreferredInnermostAssociatedDecl)
+      MLTAL.replaceInnermostTemplateArguments(
+          const_cast<Decl *>(PreferredInnermostAssociatedDecl),
+          MLTAL.getInnermost());
+
   Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/false);
 
   Sema::InstantiatingTemplate Inst(
@@ -1006,15 +1014,25 @@ bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
   // C++ [temp.constr.decl]p4
   if (Old && !New.isInvalid() && !New.ContainsDecl(Old) &&
       Old->getLexicalDeclContext() != New.getLexicalDeclContext()) {
+    const Decl *PreferredInnermostAssociatedDecl = nullptr;
+    if (const NamedDecl *ND = New.getDecl();
+        ND && Old->getDeclContext() == New.getDeclContext() &&
+        Old->getDeclName() == ND->getDeclName() &&
+        Old->getCanonicalDecl() != ND->getCanonicalDecl())
+      PreferredInnermostAssociatedDecl = Old;
     if (const Expr *SubstConstr =
-            SubstituteConstraintExpressionWithoutSatisfaction(*this, Old,
-                                                              OldConstr))
+            SubstituteConstraintExpressionWithoutSatisfaction(
+                *this, Old, OldConstr,
+                /*PreferredInnermostAssociatedDecl=*/
+                PreferredInnermostAssociatedDecl))
       OldConstr = SubstConstr;
     else
       return false;
     if (const Expr *SubstConstr =
-            SubstituteConstraintExpressionWithoutSatisfaction(*this, New,
-                                                              NewConstr))
+            SubstituteConstraintExpressionWithoutSatisfaction(
+                *this, New, NewConstr,
+                /*PreferredInnermostAssociatedDecl=*/
+                PreferredInnermostAssociatedDecl))
       NewConstr = SubstConstr;
     else
       return false;
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 0142efcdc3ee8..333187b0d74ad 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -599,3 +599,26 @@ template <class DerT>
 unsigned long DerivedCollection<DerTs...>::index() {}
 
 } // namespace GH72557
+
+namespace GH101735 {
+
+template <class, class>
+concept True = true;
+
+template <typename T>
+class A {
+  template <typename... Ts>
+  void method(Ts&... ts)
+    requires requires (T t) {
+      { t.method(static_cast<Ts &&>(ts)...) } -> True<void>;
+    };
+};
+
+template <typename T>
+template <typename... Ts>
+void A<T>::method(Ts&... ts)
+  requires requires (T t) {
+    { t.method(static_cast<Ts &&>(ts)...) } -> True<void>;
+  } {}
+
+}



More information about the cfe-commits mailing list