[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