Skip to content

Commit 358b4a4

Browse files
committed
[clang] Implement TTP 'reversed' pack matching for deduced function template calls.
Clang previously missed implementing P0522 pack matching for deduced function template calls.
1 parent 159aacb commit 358b4a4

File tree

7 files changed

+187
-67
lines changed

7 files changed

+187
-67
lines changed

clang/include/clang/Sema/Overload.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,11 @@ class Sema;
930930
LLVM_PREFERRED_TYPE(bool)
931931
unsigned TookAddressOfOverload : 1;
932932

933+
/// Have we matched any packs on the parameter side, versus any non-packs on
934+
/// the argument side, in a context where the opposite matching is also
935+
/// allowed?
936+
bool HasMatchedPackOnParmToNonPackOnArg : 1;
937+
933938
/// True if the candidate was found using ADL.
934939
LLVM_PREFERRED_TYPE(CallExpr::ADLCallKind)
935940
unsigned IsADLCandidate : 1;
@@ -1006,6 +1011,7 @@ class Sema;
10061011
OverloadCandidate()
10071012
: IsSurrogate(false), IgnoreObjectArgument(false),
10081013
TookAddressOfOverload(false),
1014+
HasMatchedPackOnParmToNonPackOnArg(false),
10091015
IsADLCandidate(llvm::to_underlying(CallExpr::NotADL)),
10101016
RewriteKind(CRK_None) {}
10111017
};

clang/include/clang/Sema/Sema.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10169,7 +10169,8 @@ class Sema final : public SemaBase {
1016910169
ADLCallKind IsADLCandidate = ADLCallKind::NotADL,
1017010170
ConversionSequenceList EarlyConversions = {},
1017110171
OverloadCandidateParamOrder PO = {},
10172-
bool AggregateCandidateDeduction = false);
10172+
bool AggregateCandidateDeduction = false,
10173+
bool HasMatchedPackOnParmToNonPackOnArg = false);
1017310174

1017410175
/// Add all of the function declarations in the given function set to
1017510176
/// the overload candidate set.
@@ -10204,7 +10205,8 @@ class Sema final : public SemaBase {
1020410205
bool SuppressUserConversions = false,
1020510206
bool PartialOverloading = false,
1020610207
ConversionSequenceList EarlyConversions = {},
10207-
OverloadCandidateParamOrder PO = {});
10208+
OverloadCandidateParamOrder PO = {},
10209+
bool HasMatchedPackOnParmToNonPackOnArg = false);
1020810210

1020910211
/// Add a C++ member function template as a candidate to the candidate
1021010212
/// set, using template argument deduction to produce an appropriate member
@@ -10250,7 +10252,8 @@ class Sema final : public SemaBase {
1025010252
CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
1025110253
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
1025210254
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
10253-
bool AllowExplicit, bool AllowResultConversion = true);
10255+
bool AllowExplicit, bool AllowResultConversion = true,
10256+
bool HasMatchedPackOnParmToNonPackOnArg = false);
1025410257

1025510258
/// Adds a conversion function template specialization
1025610259
/// candidate to the overload set, using template argument deduction
@@ -11678,7 +11681,7 @@ class Sema final : public SemaBase {
1167811681
SourceLocation RAngleLoc, unsigned ArgumentPackIndex,
1167911682
SmallVectorImpl<TemplateArgument> &SugaredConverted,
1168011683
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
11681-
CheckTemplateArgumentKind CTAK,
11684+
CheckTemplateArgumentKind CTAK, bool PartialOrdering,
1168211685
bool *MatchedPackOnParmToNonPackOnArg);
1168311686

1168411687
/// Check that the given template arguments can be provided to
@@ -11761,7 +11764,8 @@ class Sema final : public SemaBase {
1176111764
/// It returns true if an error occurred, and false otherwise.
1176211765
bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
1176311766
TemplateParameterList *Params,
11764-
TemplateArgumentLoc &Arg, bool IsDeduced,
11767+
TemplateArgumentLoc &Arg,
11768+
bool PartialOrdering,
1176511769
bool *MatchedPackOnParmToNonPackOnArg);
1176611770

1176711771
void NoteTemplateLocation(const NamedDecl &Decl,
@@ -12273,8 +12277,8 @@ class Sema final : public SemaBase {
1227312277
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
1227412278
unsigned NumExplicitlySpecified, FunctionDecl *&Specialization,
1227512279
sema::TemplateDeductionInfo &Info,
12276-
SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = nullptr,
12277-
bool PartialOverloading = false,
12280+
SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
12281+
bool PartialOverloading, bool PartialOrdering,
1227812282
llvm::function_ref<bool()> CheckNonDependent = [] { return false; });
1227912283

1228012284
/// Perform template argument deduction from a function call
@@ -12308,7 +12312,8 @@ class Sema final : public SemaBase {
1230812312
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
1230912313
FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info,
1231012314
bool PartialOverloading, bool AggregateDeductionCandidate,
12311-
QualType ObjectType, Expr::Classification ObjectClassification,
12315+
bool PartialOrdering, QualType ObjectType,
12316+
Expr::Classification ObjectClassification,
1231212317
llvm::function_ref<bool(ArrayRef<QualType>)> CheckNonDependent);
1231312318

1231412319
/// Deduce template arguments when taking the address of a function
@@ -12463,7 +12468,7 @@ class Sema final : public SemaBase {
1246312468
bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
1246412469
TemplateParameterList *PParam, TemplateDecl *PArg, TemplateDecl *AArg,
1246512470
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
12466-
bool IsDeduced, bool *MatchedPackOnParmToNonPackOnArg);
12471+
bool PartialOrdering, bool *MatchedPackOnParmToNonPackOnArg);
1246712472

1246812473
/// Mark which template parameters are used in a given expression.
1246912474
///

clang/lib/Sema/SemaLookup.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3676,6 +3676,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
36763676
if (CheckTemplateArgument(
36773677
Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
36783678
0, SugaredChecked, CanonicalChecked, CTAK_Specified,
3679+
/*PartialOrdering=*/false,
36793680
/*MatchedPackOnParmToNonPackOnArg=*/nullptr) ||
36803681
Trap.hasErrorOccurred())
36813682
IsTemplate = false;

clang/lib/Sema/SemaOverload.cpp

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6917,7 +6917,8 @@ void Sema::AddOverloadCandidate(
69176917
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
69186918
bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions,
69196919
ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions,
6920-
OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) {
6920+
OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction,
6921+
bool HasMatchedPackOnParmToNonPackOnArg) {
69216922
const FunctionProtoType *Proto
69226923
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
69236924
assert(Proto && "Functions without a prototype cannot be overloaded");
@@ -6936,7 +6937,8 @@ void Sema::AddOverloadCandidate(
69366937
AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),
69376938
Expr::Classification::makeSimpleLValue(), Args,
69386939
CandidateSet, SuppressUserConversions,
6939-
PartialOverloading, EarlyConversions, PO);
6940+
PartialOverloading, EarlyConversions, PO,
6941+
HasMatchedPackOnParmToNonPackOnArg);
69406942
return;
69416943
}
69426944
// We treat a constructor like a non-member function, since its object
@@ -6979,6 +6981,8 @@ void Sema::AddOverloadCandidate(
69796981
CandidateSet.getRewriteInfo().getRewriteKind(Function, PO);
69806982
Candidate.IsADLCandidate = llvm::to_underlying(IsADLCandidate);
69816983
Candidate.ExplicitCallArguments = Args.size();
6984+
Candidate.HasMatchedPackOnParmToNonPackOnArg =
6985+
HasMatchedPackOnParmToNonPackOnArg;
69826986

69836987
// Explicit functions are not actually candidates at all if we're not
69846988
// allowing them in this context, but keep them around so we can point
@@ -7521,16 +7525,13 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType,
75217525
}
75227526
}
75237527

7524-
void
7525-
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
7526-
CXXRecordDecl *ActingContext, QualType ObjectType,
7527-
Expr::Classification ObjectClassification,
7528-
ArrayRef<Expr *> Args,
7529-
OverloadCandidateSet &CandidateSet,
7530-
bool SuppressUserConversions,
7531-
bool PartialOverloading,
7532-
ConversionSequenceList EarlyConversions,
7533-
OverloadCandidateParamOrder PO) {
7528+
void Sema::AddMethodCandidate(
7529+
CXXMethodDecl *Method, DeclAccessPair FoundDecl,
7530+
CXXRecordDecl *ActingContext, QualType ObjectType,
7531+
Expr::Classification ObjectClassification, ArrayRef<Expr *> Args,
7532+
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
7533+
bool PartialOverloading, ConversionSequenceList EarlyConversions,
7534+
OverloadCandidateParamOrder PO, bool HasMatchedPackOnParmToNonPackOnArg) {
75347535
const FunctionProtoType *Proto
75357536
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
75367537
assert(Proto && "Methods without a prototype cannot be overloaded");
@@ -7561,6 +7562,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
75617562
Candidate.TookAddressOfOverload =
75627563
CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet;
75637564
Candidate.ExplicitCallArguments = Args.size();
7565+
Candidate.HasMatchedPackOnParmToNonPackOnArg =
7566+
HasMatchedPackOnParmToNonPackOnArg;
75647567

75657568
bool IgnoreExplicitObject =
75667569
(Method->isExplicitObjectMemberFunction() &&
@@ -7731,8 +7734,8 @@ void Sema::AddMethodTemplateCandidate(
77317734
ConversionSequenceList Conversions;
77327735
if (TemplateDeductionResult Result = DeduceTemplateArguments(
77337736
MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info,
7734-
PartialOverloading, /*AggregateDeductionCandidate=*/false, ObjectType,
7735-
ObjectClassification,
7737+
PartialOverloading, /*AggregateDeductionCandidate=*/false,
7738+
/*PartialOrdering=*/false, ObjectType, ObjectClassification,
77367739
[&](ArrayRef<QualType> ParamTypes) {
77377740
return CheckNonDependentConversions(
77387741
MethodTmpl, ParamTypes, Args, CandidateSet, Conversions,
@@ -7770,7 +7773,8 @@ void Sema::AddMethodTemplateCandidate(
77707773
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
77717774
ActingContext, ObjectType, ObjectClassification, Args,
77727775
CandidateSet, SuppressUserConversions, PartialOverloading,
7773-
Conversions, PO);
7776+
Conversions, PO,
7777+
Info.hasMatchedPackOnParmToNonPackOnArg());
77747778
}
77757779

77767780
/// Determine whether a given function template has a simple explicit specifier
@@ -7816,6 +7820,7 @@ void Sema::AddTemplateOverloadCandidate(
78167820
if (TemplateDeductionResult Result = DeduceTemplateArguments(
78177821
FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info,
78187822
PartialOverloading, AggregateCandidateDeduction,
7823+
/*PartialOrdering=*/false,
78197824
/*ObjectType=*/QualType(),
78207825
/*ObjectClassification=*/Expr::Classification(),
78217826
[&](ArrayRef<QualType> ParamTypes) {
@@ -7856,7 +7861,8 @@ void Sema::AddTemplateOverloadCandidate(
78567861
Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions,
78577862
PartialOverloading, AllowExplicit,
78587863
/*AllowExplicitConversions=*/false, IsADLCandidate, Conversions, PO,
7859-
Info.AggregateDeductionCandidateHasMismatchedArity);
7864+
Info.AggregateDeductionCandidateHasMismatchedArity,
7865+
Info.hasMatchedPackOnParmToNonPackOnArg());
78607866
}
78617867

78627868
bool Sema::CheckNonDependentConversions(
@@ -7978,7 +7984,8 @@ void Sema::AddConversionCandidate(
79787984
CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
79797985
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
79807986
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
7981-
bool AllowExplicit, bool AllowResultConversion) {
7987+
bool AllowExplicit, bool AllowResultConversion,
7988+
bool HasMatchedPackOnParmToNonPackOnArg) {
79827989
assert(!Conversion->getDescribedFunctionTemplate() &&
79837990
"Conversion function templates use AddTemplateConversionCandidate");
79847991
QualType ConvType = Conversion->getConversionType().getNonReferenceType();
@@ -8023,6 +8030,8 @@ void Sema::AddConversionCandidate(
80238030
Candidate.FinalConversion.setAllToTypes(ToType);
80248031
Candidate.Viable = true;
80258032
Candidate.ExplicitCallArguments = 1;
8033+
Candidate.HasMatchedPackOnParmToNonPackOnArg =
8034+
HasMatchedPackOnParmToNonPackOnArg;
80268035

80278036
// Explicit functions are not actually candidates at all if we're not
80288037
// allowing them in this context, but keep them around so we can point
@@ -8224,7 +8233,8 @@ void Sema::AddTemplateConversionCandidate(
82248233
assert(Specialization && "Missing function template specialization?");
82258234
AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
82268235
CandidateSet, AllowObjCConversionOnExplicit,
8227-
AllowExplicit, AllowResultConversion);
8236+
AllowExplicit, AllowResultConversion,
8237+
Info.hasMatchedPackOnParmToNonPackOnArg());
82288238
}
82298239

82308240
void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
@@ -10576,6 +10586,10 @@ bool clang::isBetterOverloadCandidate(
1057610586
isa<CXXConstructorDecl>(Cand2.Function))
1057710587
return isa<CXXConstructorDecl>(Cand1.Function);
1057810588

10589+
if (Cand1.HasMatchedPackOnParmToNonPackOnArg !=
10590+
Cand2.HasMatchedPackOnParmToNonPackOnArg)
10591+
return Cand2.HasMatchedPackOnParmToNonPackOnArg;
10592+
1057910593
// -- F1 is a non-template function and F2 is a function template
1058010594
// specialization, or, if not that,
1058110595
bool Cand1IsSpecialization = Cand1.Function &&

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5204,7 +5204,8 @@ bool Sema::CheckTemplateArgument(
52045204
unsigned ArgumentPackIndex,
52055205
SmallVectorImpl<TemplateArgument> &SugaredConverted,
52065206
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
5207-
CheckTemplateArgumentKind CTAK, bool *MatchedPackOnParmToNonPackOnArg) {
5207+
CheckTemplateArgumentKind CTAK, bool PartialOrdering,
5208+
bool *MatchedPackOnParmToNonPackOnArg) {
52085209
// Check template type parameters.
52095210
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
52105211
return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted,
@@ -5419,8 +5420,7 @@ bool Sema::CheckTemplateArgument(
54195420

54205421
case TemplateArgument::Template:
54215422
case TemplateArgument::TemplateExpansion:
5422-
if (CheckTemplateTemplateArgument(TempParm, Params, Arg,
5423-
/*IsDeduced=*/CTAK != CTAK_Specified,
5423+
if (CheckTemplateTemplateArgument(TempParm, Params, Arg, PartialOrdering,
54245424
MatchedPackOnParmToNonPackOnArg))
54255425
return true;
54265426

@@ -5571,10 +5571,11 @@ bool Sema::CheckTemplateArgumentList(
55715571

55725572
if (ArgIdx < NumArgs) {
55735573
// Check the template argument we were given.
5574-
if (CheckTemplateArgument(
5575-
*Param, NewArgs[ArgIdx], Template, TemplateLoc, RAngleLoc,
5576-
SugaredArgumentPack.size(), SugaredConverted, CanonicalConverted,
5577-
CTAK_Specified, MatchedPackOnParmToNonPackOnArg))
5574+
if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc,
5575+
RAngleLoc, SugaredArgumentPack.size(),
5576+
SugaredConverted, CanonicalConverted,
5577+
CTAK_Specified, /*PartialOrdering=*/false,
5578+
MatchedPackOnParmToNonPackOnArg))
55785579
return true;
55795580

55805581
CanonicalConverted.back().setIsDefaulted(
@@ -5732,7 +5733,7 @@ bool Sema::CheckTemplateArgumentList(
57325733
// Check the default template argument.
57335734
if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0,
57345735
SugaredConverted, CanonicalConverted,
5735-
CTAK_Specified,
5736+
CTAK_Specified, /*PartialOrdering=*/false,
57365737
/*MatchedPackOnParmToNonPackOnArg=*/nullptr))
57375738
return true;
57385739

@@ -7325,7 +7326,7 @@ static void DiagnoseTemplateParameterListArityMismatch(
73257326

73267327
bool Sema::CheckTemplateTemplateArgument(
73277328
TemplateTemplateParmDecl *Param, TemplateParameterList *Params,
7328-
TemplateArgumentLoc &Arg, bool IsDeduced,
7329+
TemplateArgumentLoc &Arg, bool PartialOrdering,
73297330
bool *MatchedPackOnParmToNonPackOnArg) {
73307331
TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
73317332
auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs();
@@ -7370,8 +7371,8 @@ bool Sema::CheckTemplateTemplateArgument(
73707371
// A template-argument matches a template template-parameter P when P
73717372
// is at least as specialized as the template-argument A.
73727373
if (!isTemplateTemplateParameterAtLeastAsSpecializedAs(
7373-
Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced,
7374-
MatchedPackOnParmToNonPackOnArg))
7374+
Params, Param, Template, DefaultArgs, Arg.getLocation(),
7375+
PartialOrdering, MatchedPackOnParmToNonPackOnArg))
73757376
return true;
73767377
// P2113
73777378
// C++20[temp.func.order]p2

0 commit comments

Comments
 (0)