[clang] [Clang][Sema] Improve support for explicit specializations of constrained member functions & member function templates (PR #88963)
Krystian Stasiowski via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 30 13:18:41 PDT 2024
https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/88963
>From 77de225477afd3689b8bf64107e8f3a4eeab85ac Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 16 Apr 2024 13:36:11 -0400
Subject: [PATCH 1/2] [Clang][Sema] Improve support for explicit
specializations of constrained member functions & member function templates
---
clang/lib/Sema/SemaConcept.cpp | 2 +-
clang/lib/Sema/SemaOverload.cpp | 11 ++-
clang/lib/Sema/SemaTemplate.cpp | 44 +++++++++--
clang/lib/Sema/SemaTemplateInstantiate.cpp | 4 +
.../CXX/temp/temp.spec/temp.expl.spec/p8.cpp | 74 +++++++++++++++++++
5 files changed, 124 insertions(+), 11 deletions(-)
create mode 100644 clang/test/CXX/temp/temp.spec/temp.expl.spec/p8.cpp
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index e00c972602829e..7bfec4e11f7aab 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -811,7 +811,7 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
// this may happen while we're comparing two templates' constraint
// equivalence.
LocalInstantiationScope ScopeForParameters(S);
- if (auto *FD = llvm::dyn_cast<FunctionDecl>(DeclInfo.getDecl()))
+ if (auto *FD = DeclInfo.getDecl()->getAsFunction())
for (auto *PVD : FD->parameters())
ScopeForParameters.InstantiatedLocal(PVD, PVD);
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 04cd9e78739d20..6f7aec0b319e3b 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1303,6 +1303,8 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
if (New->isMSVCRTEntryPoint())
return false;
+ NamedDecl *OldDecl = Old;
+ NamedDecl *NewDecl = New;
FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
@@ -1347,6 +1349,8 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
// references to non-instantiated entities during constraint substitution.
// GH78101.
if (NewTemplate) {
+ OldDecl = OldTemplate;
+ NewDecl = NewTemplate;
// C++ [temp.over.link]p4:
// The signature of a function template consists of its function
// signature, its return type and its template parameter list. The names
@@ -1506,13 +1510,14 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
}
}
- if (!UseOverrideRules) {
+ if (!UseOverrideRules &&
+ New->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) {
Expr *NewRC = New->getTrailingRequiresClause(),
*OldRC = Old->getTrailingRequiresClause();
if ((NewRC != nullptr) != (OldRC != nullptr))
return true;
-
- if (NewRC && !SemaRef.AreConstraintExpressionsEqual(Old, OldRC, New, NewRC))
+ if (NewRC &&
+ !SemaRef.AreConstraintExpressionsEqual(OldDecl, OldRC, NewDecl, NewRC))
return true;
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 7f18631c6096d1..49f878f683103b 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -10349,6 +10349,25 @@ bool Sema::CheckFunctionTemplateSpecialization(
return false;
}
+static bool IsMoreConstrainedFunction(Sema &S, FunctionDecl *FD1,
+ FunctionDecl *FD2) {
+ if (FunctionDecl *MF = FD1->getInstantiatedFromMemberFunction())
+ FD1 = MF;
+ if (FunctionDecl *MF = FD2->getInstantiatedFromMemberFunction())
+ FD2 = MF;
+ llvm::SmallVector<const Expr *, 3> AC1, AC2;
+ FD1->getAssociatedConstraints(AC1);
+ FD2->getAssociatedConstraints(AC2);
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (S.IsAtLeastAsConstrained(FD1, AC1, FD2, AC2, AtLeastAsConstrained1))
+ return false;
+ if (S.IsAtLeastAsConstrained(FD2, AC2, FD1, AC1, AtLeastAsConstrained2))
+ return false;
+ if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
+ return false;
+ return AtLeastAsConstrained1;
+}
+
/// Perform semantic analysis for the given non-template member
/// specialization.
///
@@ -10383,15 +10402,26 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
QualType Adjusted = Function->getType();
if (!hasExplicitCallingConv(Adjusted))
Adjusted = adjustCCAndNoReturn(Adjusted, Method->getType());
+ if (!Context.hasSameType(Adjusted, Method->getType()))
+ continue;
+ if (Method->getTrailingRequiresClause()) {
+ ConstraintSatisfaction Satisfaction;
+ if (CheckFunctionConstraints(Method, Satisfaction,
+ /*UsageLoc=*/Member->getLocation(),
+ /*ForOverloadResolution=*/true) ||
+ !Satisfaction.IsSatisfied)
+ continue;
+ if (Instantiation &&
+ !IsMoreConstrainedFunction(*this, Method,
+ cast<CXXMethodDecl>(Instantiation)))
+ continue;
+ }
// This doesn't handle deduced return types, but both function
// declarations should be undeduced at this point.
- if (Context.hasSameType(Adjusted, Method->getType())) {
- FoundInstantiation = *I;
- Instantiation = Method;
- InstantiatedFrom = Method->getInstantiatedFromMemberFunction();
- MSInfo = Method->getMemberSpecializationInfo();
- break;
- }
+ FoundInstantiation = *I;
+ Instantiation = Method;
+ InstantiatedFrom = Method->getInstantiatedFromMemberFunction();
+ MSInfo = Method->getMemberSpecializationInfo();
}
}
} else if (isa<VarDecl>(Member)) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 3a9fd906b7af86..c5e832c97d8a0e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -275,6 +275,10 @@ Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
TemplateArgs->asArray(),
/*Final=*/false);
+ if (RelativeToPrimary &&
+ Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return Response::UseNextDecl(Function);
+
// If this function was instantiated from a specialized member that is
// a function template, we're done.
assert(Function->getPrimaryTemplate() && "No function template?");
diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p8.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p8.cpp
new file mode 100644
index 00000000000000..87e10d10e4b453
--- /dev/null
+++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p8.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+template<typename T>
+concept C = sizeof(T) <= sizeof(long);
+
+template<typename T>
+struct A {
+ template<typename U>
+ void f(U) requires C<U>;
+
+ void g() requires C<T>;
+
+ template<typename U>
+ void h(U) requires C<T>;
+
+ constexpr int i() requires C<T> {
+ return 0;
+ }
+
+ constexpr int i() requires C<T> && true {
+ return 1;
+ }
+
+ template<>
+ void f(char);
+};
+
+template<>
+template<typename U>
+void A<short>::f(U) requires C<U>;
+
+template<>
+template<typename U>
+void A<short>::h(U) requires C<short>;
+
+template<>
+template<>
+void A<int>::f(int);
+
+template<>
+void A<long>::g();
+
+template<>
+constexpr int A<long>::i() {
+ return 2;
+}
+
+static_assert(A<long>().i() == 2);
+
+template<typename T>
+struct D {
+ template<typename U>
+ static constexpr int f(U);
+
+ template<typename U>
+ static constexpr int f(U) requires (sizeof(T) == 1);
+
+ template<>
+ constexpr int f(int) {
+ return 1;
+ }
+};
+
+template<>
+template<typename U>
+constexpr int D<signed char>::f(U) requires (sizeof(signed char) == 1) {
+ return 0;
+}
+
+static_assert(D<char>::f(0) == 1);
+static_assert(D<char[2]>::f(0) == 1);
+static_assert(D<signed char>::f(0) == 1);
+static_assert(D<signed char>::f(0.0) == 0);
>From be79079507ffbd9b29683498f405dc2c32dd8ba7 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 30 Apr 2024 16:14:47 -0400
Subject: [PATCH 2/2] [FOLD] handle friend function template specializations
---
clang/lib/Sema/SemaTemplateInstantiate.cpp | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index c5e832c97d8a0e..07626058c79776 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -276,7 +276,10 @@ Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
/*Final=*/false);
if (RelativeToPrimary &&
- Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ (Function->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization ||
+ (Function->getFriendObjectKind() &&
+ !Function->getPrimaryTemplate()->getFriendObjectKind())))
return Response::UseNextDecl(Function);
// If this function was instantiated from a specialized member that is
More information about the cfe-commits
mailing list