Skip to content

Commit b8b812d

Browse files
committed
* Fix handling of explicit specifiers
* Prefer a constructor template over a non-template conversion function
1 parent 4adae26 commit b8b812d

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 {
@@ -7883,6 +7884,11 @@ static bool isNonDependentlyExplicit(FunctionTemplateDecl *FTD) {
78837884
return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).isExplicit();
78847885
}
78857886

7887+
static bool hasDependentExplicit(FunctionTemplateDecl *FTD) {
7888+
return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).getKind() ==
7889+
ExplicitSpecKind::Unresolved;
7890+
}
7891+
78867892
static void AddTemplateOverloadCandidateImmediately(
78877893
Sema &S, OverloadCandidateSet &CandidateSet,
78887894
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
@@ -7974,7 +7980,10 @@ void Sema::AddTemplateOverloadCandidate(
79747980
return;
79757981

79767982
if (ExplicitTemplateArgs ||
7977-
!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts())) {
7983+
!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts()) ||
7984+
(isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl()) &&
7985+
hasDependentExplicit(FunctionTemplate))) {
7986+
79787987
AddTemplateOverloadCandidateImmediately(
79797988
*this, CandidateSet, FunctionTemplate, FoundDecl, ExplicitTemplateArgs,
79807989
Args, SuppressUserConversions, PartialOverloading, AllowExplicit,
@@ -8362,7 +8371,9 @@ void Sema::AddTemplateConversionCandidate(
83628371
if (!CandidateSet.isNewCandidate(FunctionTemplate))
83638372
return;
83648373

8365-
if (!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts())) {
8374+
if (!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts()) ||
8375+
hasDependentExplicit(FunctionTemplate)) {
8376+
83668377
AddTemplateConversionCandidateImmediately(
83678378
*this, CandidateSet, FunctionTemplate, FoundDecl, ActingDC, From,
83688379
ToType, AllowObjCConversionOnExplicit, AllowExplicit,
@@ -11003,6 +11014,8 @@ void OverloadCandidateSet::AddDeferredTemplateCandidate(
1100311014
AllowExplicit,
1100411015
AggregateCandidateDeduction};
1100511016
DeferredCandidates.emplace_back(std::move(C));
11017+
HasDeferredTemplateConstructors |=
11018+
isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl());
1100611019
}
1100711020

1100811021
void OverloadCandidateSet::AddDeferredMethodTemplateCandidate(
@@ -11158,6 +11171,15 @@ void OverloadCandidateSet::PerfectViableFunction(
1115811171
for (auto It = begin(); It != end(); ++It) {
1115911172
if (!It->isPerfectMatch(S.getASTContext()))
1116011173
continue;
11174+
// We found a suitable conversion function
11175+
// but if there is a template constructor in the target class
11176+
// we might prefer that instead.
11177+
if (HasDeferredTemplateConstructors &&
11178+
isa_and_nonnull<CXXConversionDecl>(It->Function)) {
11179+
Best = end();
11180+
break;
11181+
}
11182+
1116111183
if (Best == end()) {
1116211184
Best = It;
1116311185
continue;

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6204,9 +6204,9 @@ FunctionDecl *Sema::getMoreConstrainedFunction(FunctionDecl *FD1,
62046204
assert(!FD1->getDescribedTemplate() && !FD2->getDescribedTemplate() &&
62056205
"not for function templates");
62066206
assert(!FD1->isFunctionTemplateSpecialization() ||
6207-
isa<CXXConversionDecl>(FD1));
6207+
(isa<CXXConversionDecl, CXXConstructorDecl>(FD1)));
62086208
assert(!FD2->isFunctionTemplateSpecialization() ||
6209-
isa<CXXConversionDecl>(FD2));
6209+
(isa<CXXConversionDecl, CXXConstructorDecl>(FD2)));
62106210

62116211
FunctionDecl *F1 = FD1;
62126212
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)