[clang] [Clang] Check constraints for an explicit instantiation of a member function (PR #104438)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 15 12:37:50 PDT 2024
https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/104438
>From e3f210f4105d9eef5f34af893b5af81ac94e250b Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 15 Aug 2024 15:46:43 +0200
Subject: [PATCH] [Clang] Check constraints for an explicit instantiation of a
member function
Fixes #46029
Because there may be multiple constrained function of the same type,
we need to perform overload resolution to find the best viable function
to specialize.
---
clang/docs/ReleaseNotes.rst | 3 +-
.../clang/Basic/DiagnosticSemaKinds.td | 2 +
clang/lib/Sema/SemaTemplate.cpp | 64 +++++++++++++++----
.../explicit-instantiation-cxx20.cpp | 40 ++++++++++++
4 files changed, 95 insertions(+), 14 deletions(-)
create mode 100644 clang/test/SemaTemplate/explicit-instantiation-cxx20.cpp
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f5696d6ce15dc7..a7d49460b4bb5d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -73,7 +73,7 @@ C++ Specific Potentially Breaking Changes
template <> // error: extraneous template head
template <typename T>
void f();
-
+
ABI Changes in This Version
---------------------------
@@ -254,6 +254,7 @@ Bug Fixes to C++ Support
specialization of a conversion function template.
- Correctly diagnose attempts to use a concept name in its own definition;
A concept name is introduced to its scope sooner to match the C++ standard. (#GH55875)
+- Correctly check constraints of explicit instantiations of member functions. (#GH46029)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index da2f939067bfab..d5225783115892 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5663,6 +5663,8 @@ def err_explicit_instantiation_internal_linkage : Error<
def err_explicit_instantiation_not_known : Error<
"explicit instantiation of %0 does not refer to a function template, "
"variable template, member function, member class, or static data member">;
+def err_explicit_instantiation_no_candidate : Error<
+ "no candidate for explicit instantiation of %0">;
def note_explicit_instantiation_here : Note<
"explicit instantiation refers here">;
def err_explicit_instantiation_data_member_not_instantiated : Error<
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 25585f683752ac..0afe6064bab185 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -10124,8 +10124,9 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// instantiated from the member definition associated with its class
// template.
UnresolvedSet<8> TemplateMatches;
- FunctionDecl *NonTemplateMatch = nullptr;
- TemplateSpecCandidateSet FailedCandidates(D.getIdentifierLoc());
+ OverloadCandidateSet NonTemplateMatches(D.getBeginLoc(),
+ OverloadCandidateSet::CSK_Normal);
+ TemplateSpecCandidateSet FailedTemplateCandidates(D.getIdentifierLoc());
for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
P != PEnd; ++P) {
NamedDecl *Prev = *P;
@@ -10137,9 +10138,18 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (Method->getPrimaryTemplate()) {
TemplateMatches.addDecl(Method, P.getAccess());
} else {
- // FIXME: Can this assert ever happen? Needs a test.
- assert(!NonTemplateMatch && "Multiple NonTemplateMatches");
- NonTemplateMatch = Method;
+ OverloadCandidate &C = NonTemplateMatches.addCandidate();
+ C.FoundDecl = P.getPair();
+ C.Function = Method;
+ C.Viable = true;
+ ConstraintSatisfaction S;
+ if (Method->getTrailingRequiresClause() &&
+ (CheckFunctionConstraints(Method, S, D.getIdentifierLoc(),
+ /*ForOverloadResolution=*/true) ||
+ !S.IsSatisfied)) {
+ C.Viable = false;
+ C.FailureKind = ovl_fail_constraints_not_satisfied;
+ }
}
}
}
@@ -10149,16 +10159,16 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (!FunTmpl)
continue;
- TemplateDeductionInfo Info(FailedCandidates.getLocation());
+ TemplateDeductionInfo Info(FailedTemplateCandidates.getLocation());
FunctionDecl *Specialization = nullptr;
if (TemplateDeductionResult TDK = DeduceTemplateArguments(
FunTmpl, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr), R,
Specialization, Info);
TDK != TemplateDeductionResult::Success) {
// Keep track of almost-matches.
- FailedCandidates.addCandidate()
- .set(P.getPair(), FunTmpl->getTemplatedDecl(),
- MakeDeductionFailureInfo(Context, TDK, Info));
+ FailedTemplateCandidates.addCandidate().set(
+ P.getPair(), FunTmpl->getTemplatedDecl(),
+ MakeDeductionFailureInfo(Context, TDK, Info));
(void)TDK;
continue;
}
@@ -10172,7 +10182,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
CUDA().IdentifyTarget(Specialization,
/* IgnoreImplicitHDAttr = */ true) !=
CUDA().IdentifyTarget(D.getDeclSpec().getAttributes())) {
- FailedCandidates.addCandidate().set(
+ FailedTemplateCandidates.addCandidate().set(
P.getPair(), FunTmpl->getTemplatedDecl(),
MakeDeductionFailureInfo(
Context, TemplateDeductionResult::CUDATargetMismatch, Info));
@@ -10182,12 +10192,40 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
TemplateMatches.addDecl(Specialization, P.getAccess());
}
- FunctionDecl *Specialization = NonTemplateMatch;
+ FunctionDecl *Specialization = nullptr;
+ if (!NonTemplateMatches.empty()) {
+ unsigned Msg = 0;
+ OverloadCandidateDisplayKind DisplayKind;
+ OverloadCandidateSet::iterator Best;
+ switch (NonTemplateMatches.BestViableFunction(*this, D.getIdentifierLoc(),
+ Best)) {
+ case OR_Success:
+ case OR_Deleted:
+ Specialization = cast<FunctionDecl>(Best->Function);
+ break;
+ case OR_Ambiguous:
+ Msg = diag::err_explicit_instantiation_ambiguous;
+ DisplayKind = OCD_AmbiguousCandidates;
+ break;
+ case OR_No_Viable_Function:
+ Msg = diag::err_explicit_instantiation_no_candidate;
+ DisplayKind = OCD_AllCandidates;
+ break;
+ }
+ if (Msg) {
+ PartialDiagnostic Diag = PDiag(Msg) << Name;
+ NonTemplateMatches.NoteCandidates(
+ PartialDiagnosticAt(D.getIdentifierLoc(), Diag), *this, DisplayKind,
+ {});
+ return true;
+ }
+ }
+
if (!Specialization) {
// Find the most specialized function template specialization.
UnresolvedSetIterator Result = getMostSpecialized(
- TemplateMatches.begin(), TemplateMatches.end(), FailedCandidates,
- D.getIdentifierLoc(),
+ TemplateMatches.begin(), TemplateMatches.end(),
+ FailedTemplateCandidates, D.getIdentifierLoc(),
PDiag(diag::err_explicit_instantiation_not_known) << Name,
PDiag(diag::err_explicit_instantiation_ambiguous) << Name,
PDiag(diag::note_explicit_instantiation_candidate));
diff --git a/clang/test/SemaTemplate/explicit-instantiation-cxx20.cpp b/clang/test/SemaTemplate/explicit-instantiation-cxx20.cpp
new file mode 100644
index 00000000000000..423aa3a39bd855
--- /dev/null
+++ b/clang/test/SemaTemplate/explicit-instantiation-cxx20.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
+
+template<class T>
+concept C = true;
+
+template<class T>
+concept D = C<T> && true;
+
+template<typename T>
+struct a {
+ void no_candidate() requires(false) {}
+ // expected-note at -1 {{candidate function not viable: constraints not satisfied}} \
+ // expected-note at -1 {{because 'false' evaluated to false}}
+ void no_candidate() requires(false && false) {}
+ // expected-note at -1 {{candidate function not viable: constraints not satisfied}} \
+ // expected-note at -1 {{because 'false' evaluated to false}}
+
+ void subsumes();
+ void subsumes() requires C<T>;
+ void subsumes() requires D<T> {};
+
+ void ok() requires false;
+ void ok() requires true {};
+
+ void ok2() requires false;
+ void ok2(){};
+
+ void ambiguous() requires true;
+ // expected-note at -1 {{candidate function}}
+ void ambiguous() requires C<T>;
+ // expected-note at -1 {{candidate function}}
+};
+template void a<int>::no_candidate();
+// expected-error at -1 {{no candidate for explicit instantiation of 'no_candidate'}}
+
+template void a<int>::ambiguous();
+// expected-error at -1 {{partial ordering for explicit instantiation of 'ambiguous' is ambiguous}}
+
+template void a<int>::ok();
+template void a<int>::ok2();
More information about the cfe-commits
mailing list