Skip to content

Commit e68093b

Browse files
committed
* Fix handling of explicit specifiers
* Prefer a constructor template over a non-template conversion function
1 parent 32e346d commit e68093b

File tree

4 files changed

+46
-9
lines changed

4 files changed

+46
-9
lines changed

clang/include/clang/Sema/Overload.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,9 @@ class Sema;
11991199
llvm::SmallPtrSet<uintptr_t, 16> Functions;
12001200
SmallVector<DeferredTemplateOverloadCandidate, 8> DeferredCandidates;
12011201

1202+
LLVM_PREFERRED_TYPE(bool)
1203+
unsigned HasDeferredTemplateConstructors : 1;
1204+
12021205
// Allocator for ConversionSequenceLists and deferred candidate args.
12031206
// We store the first few of these
12041207
// inline to avoid allocation for small sets.
@@ -1248,7 +1251,8 @@ class Sema;
12481251
public:
12491252
OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK,
12501253
OperatorRewriteInfo RewriteInfo = {})
1251-
: Loc(Loc), Kind(CSK), RewriteInfo(RewriteInfo) {}
1254+
: HasDeferredTemplateConstructors(false), Loc(Loc), Kind(CSK),
1255+
RewriteInfo(RewriteInfo) {}
12521256
OverloadCandidateSet(const OverloadCandidateSet &) = delete;
12531257
OverloadCandidateSet &operator=(const OverloadCandidateSet &) = delete;
12541258
~OverloadCandidateSet() { destroyCandidates(); }
@@ -1260,7 +1264,7 @@ class Sema;
12601264
/// Whether diagnostics should be deferred.
12611265
bool shouldDeferDiags(Sema &S, ArrayRef<Expr *> Args, SourceLocation OpLoc);
12621266

1263-
// Whether the resolution of template candidates should be defered
1267+
// Whether the resolution of template candidates should be deferred
12641268
bool shouldDeferTemplateArgumentDeduction(const LangOptions &Opts) const;
12651269

12661270
/// Determine when this overload candidate will be new to the
@@ -1455,10 +1459,9 @@ class Sema;
14551459
const LangOptions &Opts) const {
14561460
return
14571461
// For user defined conversion we need to check against different
1458-
// combination of CV qualifiers and look at any expicit specifier, so
1462+
// combination of CV qualifiers and look at any explicit specifier, so
14591463
// always deduce template candidates.
1460-
Kind != CSK_InitByUserDefinedConversion &&
1461-
Kind != CSK_InitByConstructor
1464+
Kind != CSK_InitByUserDefinedConversion
14621465
// When doing code completion, we want to see all the
14631466
// viable candidates.
14641467
&& Kind != CSK_CodeCompletion

clang/lib/Sema/SemaOverload.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,7 @@ void OverloadCandidateSet::clear(CandidateSetKind CSK) {
11241124
Candidates.clear();
11251125
Functions.clear();
11261126
Kind = CSK;
1127+
HasDeferredTemplateConstructors = false;
11271128
}
11281129

11291130
namespace {
@@ -7887,6 +7888,11 @@ static bool isNonDependentlyExplicit(FunctionTemplateDecl *FTD) {
78877888
return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).isExplicit();
78887889
}
78897890

7891+
static bool hasDependentExplicit(FunctionTemplateDecl *FTD) {
7892+
return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).getKind() ==
7893+
ExplicitSpecKind::Unresolved;
7894+
}
7895+
78907896
static void AddTemplateOverloadCandidateImmediately(
78917897
Sema &S, OverloadCandidateSet &CandidateSet,
78927898
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
@@ -7978,7 +7984,10 @@ void Sema::AddTemplateOverloadCandidate(
79787984
return;
79797985

79807986
if (ExplicitTemplateArgs ||
7981-
!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts())) {
7987+
!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts()) ||
7988+
(isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl()) &&
7989+
hasDependentExplicit(FunctionTemplate))) {
7990+
79827991
AddTemplateOverloadCandidateImmediately(
79837992
*this, CandidateSet, FunctionTemplate, FoundDecl, ExplicitTemplateArgs,
79847993
Args, SuppressUserConversions, PartialOverloading, AllowExplicit,
@@ -8366,7 +8375,9 @@ void Sema::AddTemplateConversionCandidate(
83668375
if (!CandidateSet.isNewCandidate(FunctionTemplate))
83678376
return;
83688377

8369-
if (!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts())) {
8378+
if (!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts()) ||
8379+
hasDependentExplicit(FunctionTemplate)) {
8380+
83708381
AddTemplateConversionCandidateImmediately(
83718382
*this, CandidateSet, FunctionTemplate, FoundDecl, ActingDC, From,
83728383
ToType, AllowObjCConversionOnExplicit, AllowExplicit,
@@ -11007,6 +11018,8 @@ void OverloadCandidateSet::AddDeferredTemplateCandidate(
1100711018
AllowExplicit,
1100811019
AggregateCandidateDeduction};
1100911020
DeferredCandidates.emplace_back(std::move(C));
11021+
HasDeferredTemplateConstructors |=
11022+
isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl());
1101011023
}
1101111024

1101211025
void OverloadCandidateSet::AddDeferredMethodTemplateCandidate(
@@ -11162,6 +11175,15 @@ void OverloadCandidateSet::PerfectViableFunction(
1116211175
for (auto It = begin(); It != end(); ++It) {
1116311176
if (!It->isPerfectMatch(S.getASTContext()))
1116411177
continue;
11178+
// We found a suitable conversion function
11179+
// but if there is a template constructor in the target class
11180+
// we might prefer that instead.
11181+
if (HasDeferredTemplateConstructors &&
11182+
isa_and_nonnull<CXXConversionDecl>(It->Function)) {
11183+
Best = end();
11184+
break;
11185+
}
11186+
1116511187
if (Best == end()) {
1116611188
Best = It;
1116711189
continue;

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6142,9 +6142,9 @@ FunctionDecl *Sema::getMoreConstrainedFunction(FunctionDecl *FD1,
61426142
assert(!FD1->getDescribedTemplate() && !FD2->getDescribedTemplate() &&
61436143
"not for function templates");
61446144
assert(!FD1->isFunctionTemplateSpecialization() ||
6145-
isa<CXXConversionDecl>(FD1));
6145+
(isa<CXXConversionDecl, CXXConstructorDecl>(FD1)));
61466146
assert(!FD2->isFunctionTemplateSpecialization() ||
6147-
isa<CXXConversionDecl>(FD2));
6147+
(isa<CXXConversionDecl, CXXConstructorDecl>(FD2)));
61486148

61496149
FunctionDecl *F1 = FD1;
61506150
if (FunctionDecl *P = FD1->getTemplateInstantiationPattern(false))

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,18 @@ static_assert(m1.g(0) == 1);
116116
static_assert(Members<int[3]>{}.s(0) == 2);
117117

118118

119+
namespace ConstructorInit{
120+
struct S {
121+
template <typename T>
122+
S(T&&) {}
123+
};
124+
struct Test {
125+
operator S() = delete;
126+
};
127+
128+
static_assert(__is_constructible(S, Test));
129+
}
130+
119131

120132
namespace GH62096 {
121133
template <typename T>

0 commit comments

Comments
 (0)