Skip to content

Commit 6bb5a0b

Browse files
authored
[Clang] Check constraints for an explicit instantiation of a member function (#104438)
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. Fixes #46029
1 parent 7d60f46 commit 6bb5a0b

File tree

4 files changed

+95
-14
lines changed

4 files changed

+95
-14
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ C++ Specific Potentially Breaking Changes
7373
template <> // error: extraneous template head
7474
template <typename T>
7575
void f();
76-
76+
7777
ABI Changes in This Version
7878
---------------------------
7979

@@ -273,6 +273,7 @@ Bug Fixes to C++ Support
273273
- Properly reject defaulted copy/move assignment operators that have a non-reference explicit object parameter.
274274
- Clang now properly handles the order of attributes in `extern` blocks. (#GH101990).
275275
- Fixed an assertion failure by preventing null explicit object arguments from being deduced. (#GH102025).
276+
- Correctly check constraints of explicit instantiations of member functions. (#GH46029)
276277

277278
Bug Fixes to AST Handling
278279
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5667,6 +5667,8 @@ def err_explicit_instantiation_internal_linkage : Error<
56675667
def err_explicit_instantiation_not_known : Error<
56685668
"explicit instantiation of %0 does not refer to a function template, "
56695669
"variable template, member function, member class, or static data member">;
5670+
def err_explicit_instantiation_no_candidate : Error<
5671+
"no viable candidate for explicit instantiation of %0">;
56705672
def note_explicit_instantiation_here : Note<
56715673
"explicit instantiation refers here">;
56725674
def err_explicit_instantiation_data_member_not_instantiated : Error<

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10124,8 +10124,9 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
1012410124
// instantiated from the member definition associated with its class
1012510125
// template.
1012610126
UnresolvedSet<8> TemplateMatches;
10127-
FunctionDecl *NonTemplateMatch = nullptr;
10128-
TemplateSpecCandidateSet FailedCandidates(D.getIdentifierLoc());
10127+
OverloadCandidateSet NonTemplateMatches(D.getBeginLoc(),
10128+
OverloadCandidateSet::CSK_Normal);
10129+
TemplateSpecCandidateSet FailedTemplateCandidates(D.getIdentifierLoc());
1012910130
for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
1013010131
P != PEnd; ++P) {
1013110132
NamedDecl *Prev = *P;
@@ -10137,9 +10138,18 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
1013710138
if (Method->getPrimaryTemplate()) {
1013810139
TemplateMatches.addDecl(Method, P.getAccess());
1013910140
} else {
10140-
// FIXME: Can this assert ever happen? Needs a test.
10141-
assert(!NonTemplateMatch && "Multiple NonTemplateMatches");
10142-
NonTemplateMatch = Method;
10141+
OverloadCandidate &C = NonTemplateMatches.addCandidate();
10142+
C.FoundDecl = P.getPair();
10143+
C.Function = Method;
10144+
C.Viable = true;
10145+
ConstraintSatisfaction S;
10146+
if (Method->getTrailingRequiresClause() &&
10147+
(CheckFunctionConstraints(Method, S, D.getIdentifierLoc(),
10148+
/*ForOverloadResolution=*/true) ||
10149+
!S.IsSatisfied)) {
10150+
C.Viable = false;
10151+
C.FailureKind = ovl_fail_constraints_not_satisfied;
10152+
}
1014310153
}
1014410154
}
1014510155
}
@@ -10149,16 +10159,16 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
1014910159
if (!FunTmpl)
1015010160
continue;
1015110161

10152-
TemplateDeductionInfo Info(FailedCandidates.getLocation());
10162+
TemplateDeductionInfo Info(FailedTemplateCandidates.getLocation());
1015310163
FunctionDecl *Specialization = nullptr;
1015410164
if (TemplateDeductionResult TDK = DeduceTemplateArguments(
1015510165
FunTmpl, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr), R,
1015610166
Specialization, Info);
1015710167
TDK != TemplateDeductionResult::Success) {
1015810168
// Keep track of almost-matches.
10159-
FailedCandidates.addCandidate()
10160-
.set(P.getPair(), FunTmpl->getTemplatedDecl(),
10161-
MakeDeductionFailureInfo(Context, TDK, Info));
10169+
FailedTemplateCandidates.addCandidate().set(
10170+
P.getPair(), FunTmpl->getTemplatedDecl(),
10171+
MakeDeductionFailureInfo(Context, TDK, Info));
1016210172
(void)TDK;
1016310173
continue;
1016410174
}
@@ -10172,7 +10182,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
1017210182
CUDA().IdentifyTarget(Specialization,
1017310183
/* IgnoreImplicitHDAttr = */ true) !=
1017410184
CUDA().IdentifyTarget(D.getDeclSpec().getAttributes())) {
10175-
FailedCandidates.addCandidate().set(
10185+
FailedTemplateCandidates.addCandidate().set(
1017610186
P.getPair(), FunTmpl->getTemplatedDecl(),
1017710187
MakeDeductionFailureInfo(
1017810188
Context, TemplateDeductionResult::CUDATargetMismatch, Info));
@@ -10182,12 +10192,40 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
1018210192
TemplateMatches.addDecl(Specialization, P.getAccess());
1018310193
}
1018410194

10185-
FunctionDecl *Specialization = NonTemplateMatch;
10195+
FunctionDecl *Specialization = nullptr;
10196+
if (!NonTemplateMatches.empty()) {
10197+
unsigned Msg = 0;
10198+
OverloadCandidateDisplayKind DisplayKind;
10199+
OverloadCandidateSet::iterator Best;
10200+
switch (NonTemplateMatches.BestViableFunction(*this, D.getIdentifierLoc(),
10201+
Best)) {
10202+
case OR_Success:
10203+
case OR_Deleted:
10204+
Specialization = cast<FunctionDecl>(Best->Function);
10205+
break;
10206+
case OR_Ambiguous:
10207+
Msg = diag::err_explicit_instantiation_ambiguous;
10208+
DisplayKind = OCD_AmbiguousCandidates;
10209+
break;
10210+
case OR_No_Viable_Function:
10211+
Msg = diag::err_explicit_instantiation_no_candidate;
10212+
DisplayKind = OCD_AllCandidates;
10213+
break;
10214+
}
10215+
if (Msg) {
10216+
PartialDiagnostic Diag = PDiag(Msg) << Name;
10217+
NonTemplateMatches.NoteCandidates(
10218+
PartialDiagnosticAt(D.getIdentifierLoc(), Diag), *this, DisplayKind,
10219+
{});
10220+
return true;
10221+
}
10222+
}
10223+
1018610224
if (!Specialization) {
1018710225
// Find the most specialized function template specialization.
1018810226
UnresolvedSetIterator Result = getMostSpecialized(
10189-
TemplateMatches.begin(), TemplateMatches.end(), FailedCandidates,
10190-
D.getIdentifierLoc(),
10227+
TemplateMatches.begin(), TemplateMatches.end(),
10228+
FailedTemplateCandidates, D.getIdentifierLoc(),
1019110229
PDiag(diag::err_explicit_instantiation_not_known) << Name,
1019210230
PDiag(diag::err_explicit_instantiation_ambiguous) << Name,
1019310231
PDiag(diag::note_explicit_instantiation_candidate));
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
2+
3+
template<class T>
4+
concept C = true;
5+
6+
template<class T>
7+
concept D = C<T> && true;
8+
9+
template<typename T>
10+
struct a {
11+
void no_candidate() requires(false) {}
12+
// expected-note@-1 {{candidate function not viable: constraints not satisfied}} \
13+
// expected-note@-1 {{because 'false' evaluated to false}}
14+
void no_candidate() requires(false && false) {}
15+
// expected-note@-1 {{candidate function not viable: constraints not satisfied}} \
16+
// expected-note@-1 {{because 'false' evaluated to false}}
17+
18+
void subsumes();
19+
void subsumes() requires C<T>;
20+
void subsumes() requires D<T> {};
21+
22+
void ok() requires false;
23+
void ok() requires true {};
24+
25+
void ok2() requires false;
26+
void ok2(){};
27+
28+
void ambiguous() requires true;
29+
// expected-note@-1 {{candidate function}}
30+
void ambiguous() requires C<T>;
31+
// expected-note@-1 {{candidate function}}
32+
};
33+
template void a<int>::no_candidate();
34+
// expected-error@-1 {{no viable candidate for explicit instantiation of 'no_candidate'}}
35+
36+
template void a<int>::ambiguous();
37+
// expected-error@-1 {{partial ordering for explicit instantiation of 'ambiguous' is ambiguous}}
38+
39+
template void a<int>::ok();
40+
template void a<int>::ok2();

0 commit comments

Comments
 (0)