Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 5b38d71

Browse files
committed
[c++1z] Synthesize implicit deduction guides from constructors on demand. Rank
such guides below explicit ones, and ensure that references to the class's template parameters are not treated as forwarding references. We make a few tweaks to the wording in the current standard: 1) The constructor parameter list is copied faithfully to the deduction guide, without losing default arguments or a varargs ellipsis (which the standard wording loses by omission). 2) If the class template declares no constructors, we add a T() -> T<...> guide (which will only ever work if T has default arguments for all non-pack template parameters). 3) If the class template declares nothing that looks like a copy or move constructor, we add a T(T<...>) -> T<...> guide. #2 and #3 follow from the "pretend we had a class type with these constructors" philosophy for deduction guides. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@295007 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 515451d commit 5b38d71

File tree

14 files changed

+564
-134
lines changed

14 files changed

+564
-134
lines changed

include/clang/AST/ASTContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,6 +1357,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
13571357
ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
13581358
const IdentifierInfo *Name, ArrayRef<TemplateArgument> Args) const;
13591359

1360+
TemplateArgument getInjectedTemplateArg(NamedDecl *ParamDecl);
1361+
13601362
/// Get a template argument list with one argument per template parameter
13611363
/// in a template parameter list, such as for the injected class name of
13621364
/// a class template.

include/clang/AST/DeclTemplate.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,6 +1482,7 @@ class TemplateTemplateParmDecl final
14821482

14831483
using TemplateParmPosition::getDepth;
14841484
using TemplateParmPosition::getPosition;
1485+
using TemplateParmPosition::setPosition;
14851486
using TemplateParmPosition::getIndex;
14861487

14871488
/// \brief Whether this template template parameter is a template

include/clang/Sema/Sema.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6759,6 +6759,11 @@ class Sema {
67596759
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
67606760
bool Diagnose = true);
67616761

6762+
/// \brief Declare implicit deduction guides for a class template if we've
6763+
/// not already done so.
6764+
void DeclareImplicitDeductionGuides(TemplateDecl *Template,
6765+
SourceLocation Loc);
6766+
67626767
QualType DeduceTemplateSpecializationFromInitializer(
67636768
TypeSourceInfo *TInfo, const InitializedEntity &Entity,
67646769
const InitializationKind &Kind, MultiExprArg Init);

lib/AST/ASTContext.cpp

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3872,42 +3872,45 @@ ASTContext::getDependentTemplateSpecializationType(
38723872
return QualType(T, 0);
38733873
}
38743874

3875+
TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) {
3876+
TemplateArgument Arg;
3877+
if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
3878+
QualType ArgType = getTypeDeclType(TTP);
3879+
if (TTP->isParameterPack())
3880+
ArgType = getPackExpansionType(ArgType, None);
3881+
3882+
Arg = TemplateArgument(ArgType);
3883+
} else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
3884+
Expr *E = new (*this) DeclRefExpr(
3885+
NTTP, /*enclosing*/false,
3886+
NTTP->getType().getNonLValueExprType(*this),
3887+
Expr::getValueKindForType(NTTP->getType()), NTTP->getLocation());
3888+
3889+
if (NTTP->isParameterPack())
3890+
E = new (*this) PackExpansionExpr(DependentTy, E, NTTP->getLocation(),
3891+
None);
3892+
Arg = TemplateArgument(E);
3893+
} else {
3894+
auto *TTP = cast<TemplateTemplateParmDecl>(Param);
3895+
if (TTP->isParameterPack())
3896+
Arg = TemplateArgument(TemplateName(TTP), Optional<unsigned>());
3897+
else
3898+
Arg = TemplateArgument(TemplateName(TTP));
3899+
}
3900+
3901+
if (Param->isTemplateParameterPack())
3902+
Arg = TemplateArgument::CreatePackCopy(*this, Arg);
3903+
3904+
return Arg;
3905+
}
3906+
38753907
void
38763908
ASTContext::getInjectedTemplateArgs(const TemplateParameterList *Params,
38773909
SmallVectorImpl<TemplateArgument> &Args) {
38783910
Args.reserve(Args.size() + Params->size());
38793911

3880-
for (NamedDecl *Param : *Params) {
3881-
TemplateArgument Arg;
3882-
if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
3883-
QualType ArgType = getTypeDeclType(TTP);
3884-
if (TTP->isParameterPack())
3885-
ArgType = getPackExpansionType(ArgType, None);
3886-
3887-
Arg = TemplateArgument(ArgType);
3888-
} else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
3889-
Expr *E = new (*this) DeclRefExpr(
3890-
NTTP, /*enclosing*/false,
3891-
NTTP->getType().getNonLValueExprType(*this),
3892-
Expr::getValueKindForType(NTTP->getType()), NTTP->getLocation());
3893-
3894-
if (NTTP->isParameterPack())
3895-
E = new (*this) PackExpansionExpr(DependentTy, E, NTTP->getLocation(),
3896-
None);
3897-
Arg = TemplateArgument(E);
3898-
} else {
3899-
auto *TTP = cast<TemplateTemplateParmDecl>(Param);
3900-
if (TTP->isParameterPack())
3901-
Arg = TemplateArgument(TemplateName(TTP), Optional<unsigned>());
3902-
else
3903-
Arg = TemplateArgument(TemplateName(TTP));
3904-
}
3905-
3906-
if (Param->isTemplateParameterPack())
3907-
Arg = TemplateArgument::CreatePackCopy(*this, Arg);
3908-
3909-
Args.push_back(Arg);
3910-
}
3912+
for (NamedDecl *Param : *Params)
3913+
Args.push_back(getInjectedTemplateArg(Param));
39113914
}
39123915

39133916
QualType ASTContext::getPackExpansionType(QualType Pattern,

lib/Sema/SemaInit.cpp

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8242,45 +8242,27 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
82428242
return QualType();
82438243
}
82448244

8245+
// Can't deduce from dependent arguments.
8246+
if (Expr::hasAnyTypeDependentArguments(Inits))
8247+
return Context.DependentTy;
8248+
82458249
// FIXME: Perform "exact type" matching first, per CWG discussion?
82468250
// Or implement this via an implied 'T(T) -> T' deduction guide?
82478251

82488252
// FIXME: Do we need/want a std::initializer_list<T> special case?
82498253

8254+
// Look up deduction guides, including those synthesized from constructors.
8255+
//
82508256
// C++1z [over.match.class.deduct]p1:
82518257
// A set of functions and function templates is formed comprising:
8252-
bool HasDefaultConstructor = false;
8253-
SmallVector<DeclAccessPair, 16> CtorsAndGuides;
8254-
CXXRecordDecl *Primary = Template->getTemplatedDecl();
8255-
bool Complete = isCompleteType(TSInfo->getTypeLoc().getEndLoc(),
8256-
Context.getTypeDeclType(Primary));
8257-
if (Complete) {
8258-
for (NamedDecl *D : LookupConstructors(Template->getTemplatedDecl())) {
8259-
// - For each constructor of the class template designated by the
8260-
// template-name, a function template [...]
8261-
auto Info = getConstructorInfo(D);
8262-
if (!Info.Constructor || Info.Constructor->isInvalidDecl())
8263-
continue;
8264-
8265-
// FIXME: Synthesize a deduction guide.
8266-
8267-
if (Info.Constructor->isDefaultConstructor())
8268-
HasDefaultConstructor = true;
8269-
}
8270-
}
8271-
8258+
// - For each constructor of the class template designated by the
8259+
// template-name, a function template [...]
82728260
// - For each deduction-guide, a function or function template [...]
82738261
DeclarationNameInfo NameInfo(
82748262
Context.DeclarationNames.getCXXDeductionGuideName(Template),
82758263
TSInfo->getTypeLoc().getEndLoc());
82768264
LookupResult Guides(*this, NameInfo, LookupOrdinaryName);
82778265
LookupQualifiedName(Guides, Template->getDeclContext());
8278-
for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
8279-
auto *FD = dyn_cast<FunctionDecl>(*I);
8280-
if (FD && FD->getMinRequiredArguments() == 0)
8281-
HasDefaultConstructor = true;
8282-
CtorsAndGuides.push_back(I.getPair());
8283-
}
82848266

82858267
// FIXME: Do not diagnose inaccessible deduction guides. The standard isn't
82868268
// clear on this, but they're not found by name so access does not apply.
@@ -8307,8 +8289,8 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
83078289
auto tryToResolveOverload =
83088290
[&](bool OnlyListConstructors) -> OverloadingResult {
83098291
Candidates.clear();
8310-
for (DeclAccessPair Pair : CtorsAndGuides) {
8311-
NamedDecl *D = Pair.getDecl()->getUnderlyingDecl();
8292+
for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
8293+
NamedDecl *D = (*I)->getUnderlyingDecl();
83128294
if (D->isInvalidDecl())
83138295
continue;
83148296

@@ -8357,10 +8339,11 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
83578339
bool SuppressUserConversions = Kind.isCopyInit();
83588340

83598341
if (TD)
8360-
AddTemplateOverloadCandidate(TD, Pair, /*ExplicitArgs*/ nullptr, Inits,
8361-
Candidates, SuppressUserConversions);
8342+
AddTemplateOverloadCandidate(TD, I.getPair(), /*ExplicitArgs*/ nullptr,
8343+
Inits, Candidates,
8344+
SuppressUserConversions);
83628345
else
8363-
AddOverloadCandidate(FD, Pair, Inits, Candidates,
8346+
AddOverloadCandidate(FD, I.getPair(), Inits, Candidates,
83648347
SuppressUserConversions);
83658348
}
83668349
return Candidates.BestViableFunction(*this, Kind.getLocation(), Best);
@@ -8371,7 +8354,21 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
83718354
// C++11 [over.match.list]p1, per DR1467: for list-initialization, first
83728355
// try initializer-list constructors.
83738356
if (ListInit) {
8374-
if (ListInit->getNumInits() || !HasDefaultConstructor)
8357+
bool TryListConstructors = true;
8358+
8359+
// Try list constructors unless the list is empty and the class has one or
8360+
// more default constructors, in which case those constructors win.
8361+
if (!ListInit->getNumInits()) {
8362+
for (NamedDecl *D : Guides) {
8363+
auto *FD = dyn_cast<FunctionDecl>(D->getUnderlyingDecl());
8364+
if (FD && FD->getMinRequiredArguments() == 0) {
8365+
TryListConstructors = false;
8366+
break;
8367+
}
8368+
}
8369+
}
8370+
8371+
if (TryListConstructors)
83758372
Result = tryToResolveOverload(/*OnlyListConstructor*/true);
83768373
// Then unwrap the initializer list and try again considering all
83778374
// constructors.
@@ -8393,13 +8390,18 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
83938390
Candidates.NoteCandidates(*this, OCD_ViableCandidates, Inits);
83948391
return QualType();
83958392

8396-
case OR_No_Viable_Function:
8393+
case OR_No_Viable_Function: {
8394+
CXXRecordDecl *Primary =
8395+
cast<ClassTemplateDecl>(Template)->getTemplatedDecl();
8396+
bool Complete =
8397+
isCompleteType(Kind.getLocation(), Context.getTypeDeclType(Primary));
83978398
Diag(Kind.getLocation(),
83988399
Complete ? diag::err_deduced_class_template_ctor_no_viable
83998400
: diag::err_deduced_class_template_incomplete)
8400-
<< TemplateName << !CtorsAndGuides.empty();
8401+
<< TemplateName << !Guides.empty();
84018402
Candidates.NoteCandidates(*this, OCD_AllCandidates, Inits);
84028403
return QualType();
8404+
}
84038405

84048406
case OR_Deleted: {
84058407
Diag(Kind.getLocation(), diag::err_deduced_class_template_deleted)

lib/Sema/SemaLookup.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,7 @@ static bool isImplicitlyDeclaredMemberFunctionName(DeclarationName Name) {
774774
/// that need to be declared in the given declaration context, do so.
775775
static void DeclareImplicitMemberFunctionsWithName(Sema &S,
776776
DeclarationName Name,
777+
SourceLocation Loc,
777778
const DeclContext *DC) {
778779
if (!DC)
779780
return;
@@ -816,6 +817,10 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
816817
}
817818
break;
818819

820+
case DeclarationName::CXXDeductionGuideName:
821+
S.DeclareImplicitDeductionGuides(Name.getCXXDeductionGuideTemplate(), Loc);
822+
break;
823+
819824
default:
820825
break;
821826
}
@@ -828,7 +833,8 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
828833

829834
// Lazily declare C++ special member functions.
830835
if (S.getLangOpts().CPlusPlus)
831-
DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), DC);
836+
DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), R.getNameLoc(),
837+
DC);
832838

833839
// Perform lookup into this declaration context.
834840
DeclContext::lookup_result DR = DC->lookup(R.getLookupName());
@@ -1041,7 +1047,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
10411047
if (isImplicitlyDeclaredMemberFunctionName(Name)) {
10421048
for (Scope *PreS = S; PreS; PreS = PreS->getParent())
10431049
if (DeclContext *DC = PreS->getEntity())
1044-
DeclareImplicitMemberFunctionsWithName(*this, Name, DC);
1050+
DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
10451051
}
10461052

10471053
// Implicitly declare member functions with the name we're looking for, if in

lib/Sema/SemaOverload.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8991,6 +8991,14 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
89918991
// C++14 [over.match.best]p1 section 2 bullet 3.
89928992
}
89938993

8994+
// -- F1 is generated from a deduction-guide and F2 is not
8995+
if (Cand1.Function && Cand2.Function && Cand1.Function->isDeductionGuide() &&
8996+
Cand1.Function->isImplicit() != Cand2.Function->isImplicit()) {
8997+
assert(Cand2.Function->isDeductionGuide() &&
8998+
"comparing deduction guide with non-deduction-guide");
8999+
return Cand2.Function->isImplicit();
9000+
}
9001+
89949002
// -- F1 is a non-template function and F2 is a function template
89959003
// specialization, or, if not that,
89969004
bool Cand1IsSpecialization = Cand1.Function &&

0 commit comments

Comments
 (0)