Skip to content

Commit 183fd33

Browse files
committed
* Fix handling of explicit specifiers
* Prefer a constructor template over a non-template conversion function
1 parent 66bd871 commit 183fd33

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 {
@@ -7891,6 +7892,11 @@ static bool isNonDependentlyExplicit(FunctionTemplateDecl *FTD) {
78917892
return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).isExplicit();
78927893
}
78937894

7895+
static bool hasDependentExplicit(FunctionTemplateDecl *FTD) {
7896+
return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).getKind() ==
7897+
ExplicitSpecKind::Unresolved;
7898+
}
7899+
78947900
static void AddTemplateOverloadCandidateImmediately(
78957901
Sema &S, OverloadCandidateSet &CandidateSet,
78967902
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
@@ -7982,7 +7988,10 @@ void Sema::AddTemplateOverloadCandidate(
79827988
return;
79837989

79847990
if (ExplicitTemplateArgs ||
7985-
!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts())) {
7991+
!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts()) ||
7992+
(isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl()) &&
7993+
hasDependentExplicit(FunctionTemplate))) {
7994+
79867995
AddTemplateOverloadCandidateImmediately(
79877996
*this, CandidateSet, FunctionTemplate, FoundDecl, ExplicitTemplateArgs,
79887997
Args, SuppressUserConversions, PartialOverloading, AllowExplicit,
@@ -8370,7 +8379,9 @@ void Sema::AddTemplateConversionCandidate(
83708379
if (!CandidateSet.isNewCandidate(FunctionTemplate))
83718380
return;
83728381

8373-
if (!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts())) {
8382+
if (!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts()) ||
8383+
hasDependentExplicit(FunctionTemplate)) {
8384+
83748385
AddTemplateConversionCandidateImmediately(
83758386
*this, CandidateSet, FunctionTemplate, FoundDecl, ActingDC, From,
83768387
ToType, AllowObjCConversionOnExplicit, AllowExplicit,
@@ -11011,6 +11022,8 @@ void OverloadCandidateSet::AddDeferredTemplateCandidate(
1101111022
AllowExplicit,
1101211023
AggregateCandidateDeduction};
1101311024
DeferredCandidates.emplace_back(std::move(C));
11025+
HasDeferredTemplateConstructors |=
11026+
isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl());
1101411027
}
1101511028

1101611029
void OverloadCandidateSet::AddDeferredMethodTemplateCandidate(
@@ -11166,6 +11179,15 @@ void OverloadCandidateSet::PerfectViableFunction(
1116611179
for (auto It = begin(); It != end(); ++It) {
1116711180
if (!It->isPerfectMatch(S.getASTContext()))
1116811181
continue;
11182+
// We found a suitable conversion function
11183+
// but if there is a template constructor in the target class
11184+
// we might prefer that instead.
11185+
if (HasDeferredTemplateConstructors &&
11186+
isa_and_nonnull<CXXConversionDecl>(It->Function)) {
11187+
Best = end();
11188+
break;
11189+
}
11190+
1116911191
if (Best == end()) {
1117011192
Best = It;
1117111193
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)