Skip to content

Commit 0330d3b

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

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 {
@@ -7989,15 +7990,20 @@ void Sema::AddTemplateOverloadCandidate(
79897990
if (!CandidateSet.isNewCandidate(FunctionTemplate, PO))
79907991
return;
79917992

7993+
bool DependentExplicitSpecifier = hasDependentExplicit(FunctionTemplate);
7994+
79927995
if (ExplicitTemplateArgs ||
79937996
!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts()) ||
79947997
(isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl()) &&
7995-
hasDependentExplicit(FunctionTemplate))) {
7998+
DependentExplicitSpecifier)) {
79967999

79978000
AddTemplateOverloadCandidateImmediately(
79988001
*this, CandidateSet, FunctionTemplate, FoundDecl, ExplicitTemplateArgs,
79998002
Args, SuppressUserConversions, PartialOverloading, AllowExplicit,
80008003
IsADLCandidate, PO, AggregateCandidateDeduction);
8004+
8005+
if (DependentExplicitSpecifier)
8006+
CandidateSet.DisableResolutionByPerfectCandidate();
80018007
return;
80028008
}
80038009

@@ -8382,13 +8388,15 @@ void Sema::AddTemplateConversionCandidate(
83828388
return;
83838389

83848390
if (!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts()) ||
8385-
hasDependentExplicit(FunctionTemplate)) {
8386-
8391+
CandidateSet.getKind() ==
8392+
OverloadCandidateSet::CSK_InitByUserDefinedConversion ||
8393+
CandidateSet.getKind() == OverloadCandidateSet::CSK_InitByConstructor) {
83878394
AddTemplateConversionCandidateImmediately(
83888395
*this, CandidateSet, FunctionTemplate, FoundDecl, ActingDC, From,
83898396
ToType, AllowObjCConversionOnExplicit, AllowExplicit,
83908397
AllowResultConversion);
83918398

8399+
CandidateSet.DisableResolutionByPerfectCandidate();
83928400
return;
83938401
}
83948402

@@ -11028,6 +11036,7 @@ void OverloadCandidateSet::AddDeferredTemplateCandidate(
1102811036
Args,
1102911037
IsADLCandidate,
1103011038
PO};
11039+
1103111040
HasDeferredTemplateConstructors |=
1103211041
isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl());
1103311042
}
@@ -11199,19 +11208,19 @@ OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S,
1119911208

1120011209
assert(shouldDeferTemplateArgumentDeduction(S.getLangOpts()) ||
1120111210
DeferredCandidatesCount == 0 &&
11202-
"Unexpected deferred template candidate");
11211+
"Unexpected deferred template candidates");
1120311212

11204-
bool TwoPhaseResolution = DeferredCandidatesCount != 0;
11213+
bool TwoPhaseResolution =
11214+
DeferredCandidatesCount != 0 && !ResolutionByPerfectCandidateIsDisabled;
1120511215

1120611216
if (TwoPhaseResolution) {
1120711217

1120811218
PerfectViableFunction(S, Loc, Best);
1120911219
if (Best != end())
1121011220
return ResultForBestCandidate(Best);
11211-
11212-
InjectNonDeducedTemplateCandidates(S);
1121311221
}
1121411222

11223+
InjectNonDeducedTemplateCandidates(S);
1121511224
return BestViableFunctionImpl(S, Loc, Best);
1121611225
}
1121711226

@@ -11220,8 +11229,10 @@ void OverloadCandidateSet::PerfectViableFunction(
1122011229

1122111230
Best = end();
1122211231
for (auto It = begin(); It != end(); ++It) {
11232+
1122311233
if (!It->isPerfectMatch(S.getASTContext()))
1122411234
continue;
11235+
1122511236
// We found a suitable conversion function
1122611237
// but if there is a template constructor in the target class
1122711238
// we might prefer that instead.
@@ -11246,6 +11257,7 @@ void OverloadCandidateSet::PerfectViableFunction(
1124611257
Best = It;
1124711258
continue;
1124811259
}
11260+
// ambiguous
1124911261
Best = end();
1125011262
break;
1125111263
}

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)