Skip to content

Commit 9967287

Browse files
committed
Disable resolution by perfect match when
- We find a template conversion candidate - A constructor with a dependent explicit specifier
1 parent a687000 commit 9967287

File tree

3 files changed

+35
-9
lines changed

3 files changed

+35
-9
lines changed

clang/include/clang/Sema/Overload.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,9 +1206,11 @@ class Sema;
12061206
llvm::SmallPtrSet<uintptr_t, 16> Functions;
12071207

12081208
DeferredTemplateOverloadCandidate *FirstDeferredCandidate;
1209-
unsigned DeferredCandidatesCount : 8 * sizeof(unsigned) - 1;
1209+
unsigned DeferredCandidatesCount : 8 * sizeof(unsigned) - 2;
12101210
LLVM_PREFERRED_TYPE(bool)
12111211
unsigned HasDeferredTemplateConstructors : 1;
1212+
LLVM_PREFERRED_TYPE(bool)
1213+
unsigned ResolutionByPerfectCandidateIsDisabled : 1;
12121214

12131215
// Allocator for ConversionSequenceLists and deferred candidate args.
12141216
// We store the first few of these
@@ -1274,7 +1276,8 @@ class Sema;
12741276
OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK,
12751277
OperatorRewriteInfo RewriteInfo = {})
12761278
: FirstDeferredCandidate(nullptr), DeferredCandidatesCount(0),
1277-
HasDeferredTemplateConstructors(false), Loc(Loc), Kind(CSK),
1279+
HasDeferredTemplateConstructors(false),
1280+
ResolutionByPerfectCandidateIsDisabled(false), Loc(Loc), Kind(CSK),
12781281
RewriteInfo(RewriteInfo) {}
12791282
OverloadCandidateSet(const OverloadCandidateSet &) = delete;
12801283
OverloadCandidateSet &operator=(const OverloadCandidateSet &) = delete;
@@ -1387,6 +1390,10 @@ class Sema;
13871390

13881391
void InjectNonDeducedTemplateCandidates(Sema &S);
13891392

1393+
void DisableResolutionByPerfectCandidate() {
1394+
ResolutionByPerfectCandidateIsDisabled = true;
1395+
}
1396+
13901397
/// Find the best viable function on this overload set, if it exists.
13911398
OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc,
13921399
OverloadCandidateSet::iterator& Best);

clang/lib/Sema/SemaOverload.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,7 @@ void OverloadCandidateSet::clear(CandidateSetKind CSK) {
11271127
FirstDeferredCandidate = nullptr;
11281128
DeferredCandidatesCount = 0;
11291129
HasDeferredTemplateConstructors = false;
1130+
ResolutionByPerfectCandidateIsDisabled = false;
11301131
}
11311132

11321133
namespace {
@@ -7985,15 +7986,20 @@ void Sema::AddTemplateOverloadCandidate(
79857986
if (!CandidateSet.isNewCandidate(FunctionTemplate, PO))
79867987
return;
79877988

7989+
bool DependentExplicitSpecifier = hasDependentExplicit(FunctionTemplate);
7990+
79887991
if (ExplicitTemplateArgs ||
79897992
!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts()) ||
79907993
(isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl()) &&
7991-
hasDependentExplicit(FunctionTemplate))) {
7994+
DependentExplicitSpecifier)) {
79927995

79937996
AddTemplateOverloadCandidateImmediately(
79947997
*this, CandidateSet, FunctionTemplate, FoundDecl, ExplicitTemplateArgs,
79957998
Args, SuppressUserConversions, PartialOverloading, AllowExplicit,
79967999
IsADLCandidate, PO, AggregateCandidateDeduction);
8000+
8001+
if (DependentExplicitSpecifier)
8002+
CandidateSet.DisableResolutionByPerfectCandidate();
79978003
return;
79988004
}
79998005

@@ -8378,13 +8384,15 @@ void Sema::AddTemplateConversionCandidate(
83788384
return;
83798385

83808386
if (!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts()) ||
8381-
hasDependentExplicit(FunctionTemplate)) {
8382-
8387+
CandidateSet.getKind() ==
8388+
OverloadCandidateSet::CSK_InitByUserDefinedConversion ||
8389+
CandidateSet.getKind() == OverloadCandidateSet::CSK_InitByConstructor) {
83838390
AddTemplateConversionCandidateImmediately(
83848391
*this, CandidateSet, FunctionTemplate, FoundDecl, ActingDC, From,
83858392
ToType, AllowObjCConversionOnExplicit, AllowExplicit,
83868393
AllowResultConversion);
83878394

8395+
CandidateSet.DisableResolutionByPerfectCandidate();
83888396
return;
83898397
}
83908398

@@ -11024,6 +11032,7 @@ void OverloadCandidateSet::AddDeferredTemplateCandidate(
1102411032
Args,
1102511033
IsADLCandidate,
1102611034
PO};
11035+
1102711036
HasDeferredTemplateConstructors |=
1102811037
isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl());
1102911038
}
@@ -11195,19 +11204,19 @@ OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S,
1119511204

1119611205
assert(shouldDeferTemplateArgumentDeduction(S.getLangOpts()) ||
1119711206
DeferredCandidatesCount == 0 &&
11198-
"Unexpected deferred template candidate");
11207+
"Unexpected deferred template candidates");
1119911208

11200-
bool TwoPhaseResolution = DeferredCandidatesCount != 0;
11209+
bool TwoPhaseResolution =
11210+
DeferredCandidatesCount != 0 && !ResolutionByPerfectCandidateIsDisabled;
1120111211

1120211212
if (TwoPhaseResolution) {
1120311213

1120411214
PerfectViableFunction(S, Loc, Best);
1120511215
if (Best != end())
1120611216
return ResultForBestCandidate(Best);
11207-
11208-
InjectNonDeducedTemplateCandidates(S);
1120911217
}
1121011218

11219+
InjectNonDeducedTemplateCandidates(S);
1121111220
return BestViableFunctionImpl(S, Loc, Best);
1121211221
}
1121311222

@@ -11216,8 +11225,10 @@ void OverloadCandidateSet::PerfectViableFunction(
1121611225

1121711226
Best = end();
1121811227
for (auto It = begin(); It != end(); ++It) {
11228+
1121911229
if (!It->isPerfectMatch(S.getASTContext()))
1122011230
continue;
11231+
1122111232
// We found a suitable conversion function
1122211233
// but if there is a template constructor in the target class
1122311234
// we might prefer that instead.
@@ -11242,6 +11253,7 @@ void OverloadCandidateSet::PerfectViableFunction(
1124211253
Best = It;
1124311254
continue;
1124411255
}
11256+
// ambiguous
1124511257
Best = end();
1124611258
break;
1124711259
}

clang/test/SemaCXX/overload-resolution-deferred-templates.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,13 @@ struct StringRef {
150150

151151
}
152152

153+
template <class> struct tuple {};
154+
struct BonkersBananas {
155+
template <class T> operator T();
156+
template <class = void> explicit operator tuple<int>() = delete;
157+
};
158+
static_assert(!__is_constructible(tuple<int>, BonkersBananas));
159+
153160
namespace GH62096 {
154161
template <typename T>
155162
struct Oops {

0 commit comments

Comments
 (0)