Skip to content

Commit 37ef323

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

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 {
@@ -7981,15 +7982,20 @@ void Sema::AddTemplateOverloadCandidate(
79817982
if (!CandidateSet.isNewCandidate(FunctionTemplate, PO))
79827983
return;
79837984

7985+
bool DependentExplicitSpecifier = hasDependentExplicit(FunctionTemplate);
7986+
79847987
if (ExplicitTemplateArgs ||
79857988
!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts()) ||
79867989
(isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl()) &&
7987-
hasDependentExplicit(FunctionTemplate))) {
7990+
DependentExplicitSpecifier)) {
79887991

79897992
AddTemplateOverloadCandidateImmediately(
79907993
*this, CandidateSet, FunctionTemplate, FoundDecl, ExplicitTemplateArgs,
79917994
Args, SuppressUserConversions, PartialOverloading, AllowExplicit,
79927995
IsADLCandidate, PO, AggregateCandidateDeduction);
7996+
7997+
if (DependentExplicitSpecifier)
7998+
CandidateSet.DisableResolutionByPerfectCandidate();
79937999
return;
79948000
}
79958001

@@ -8374,13 +8380,15 @@ void Sema::AddTemplateConversionCandidate(
83748380
return;
83758381

83768382
if (!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts()) ||
8377-
hasDependentExplicit(FunctionTemplate)) {
8378-
8383+
CandidateSet.getKind() ==
8384+
OverloadCandidateSet::CSK_InitByUserDefinedConversion ||
8385+
CandidateSet.getKind() == OverloadCandidateSet::CSK_InitByConstructor) {
83798386
AddTemplateConversionCandidateImmediately(
83808387
*this, CandidateSet, FunctionTemplate, FoundDecl, ActingDC, From,
83818388
ToType, AllowObjCConversionOnExplicit, AllowExplicit,
83828389
AllowResultConversion);
83838390

8391+
CandidateSet.DisableResolutionByPerfectCandidate();
83848392
return;
83858393
}
83868394

@@ -11020,6 +11028,7 @@ void OverloadCandidateSet::AddDeferredTemplateCandidate(
1102011028
Args,
1102111029
IsADLCandidate,
1102211030
PO};
11031+
1102311032
HasDeferredTemplateConstructors |=
1102411033
isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl());
1102511034
}
@@ -11191,19 +11200,19 @@ OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S,
1119111200

1119211201
assert(shouldDeferTemplateArgumentDeduction(S.getLangOpts()) ||
1119311202
DeferredCandidatesCount == 0 &&
11194-
"Unexpected deferred template candidate");
11203+
"Unexpected deferred template candidates");
1119511204

11196-
bool TwoPhaseResolution = DeferredCandidatesCount != 0;
11205+
bool TwoPhaseResolution =
11206+
DeferredCandidatesCount != 0 && !ResolutionByPerfectCandidateIsDisabled;
1119711207

1119811208
if (TwoPhaseResolution) {
1119911209

1120011210
PerfectViableFunction(S, Loc, Best);
1120111211
if (Best != end())
1120211212
return ResultForBestCandidate(Best);
11203-
11204-
InjectNonDeducedTemplateCandidates(S);
1120511213
}
1120611214

11215+
InjectNonDeducedTemplateCandidates(S);
1120711216
return BestViableFunctionImpl(S, Loc, Best);
1120811217
}
1120911218

@@ -11212,8 +11221,10 @@ void OverloadCandidateSet::PerfectViableFunction(
1121211221

1121311222
Best = end();
1121411223
for (auto It = begin(); It != end(); ++It) {
11224+
1121511225
if (!It->isPerfectMatch(S.getASTContext()))
1121611226
continue;
11227+
1121711228
// We found a suitable conversion function
1121811229
// but if there is a template constructor in the target class
1121911230
// we might prefer that instead.
@@ -11238,6 +11249,7 @@ void OverloadCandidateSet::PerfectViableFunction(
1123811249
Best = It;
1123911250
continue;
1124011251
}
11252+
// ambiguous
1124111253
Best = end();
1124211254
break;
1124311255
}

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)