Skip to content

Commit 4dadf42

Browse files
authored
[clang] Implement TTP P0522 pack matching for deduced function template calls. (#111457)
Clang previously missed implementing P0522 pack matching for deduced function template calls. Fixes #111363
1 parent 224519b commit 4dadf42

File tree

7 files changed

+189
-69
lines changed

7 files changed

+189
-69
lines changed

clang/include/clang/Sema/Overload.h

+8-2
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,11 @@ class Sema;
925925

926926
bool TookAddressOfOverload : 1;
927927

928+
/// Have we matched any packs on the parameter side, versus any non-packs on
929+
/// the argument side, in a context where the opposite matching is also
930+
/// allowed?
931+
bool HasMatchedPackOnParmToNonPackOnArg : 1;
932+
928933
/// True if the candidate was found using ADL.
929934
CallExpr::ADLCallKind IsADLCandidate : 1;
930935

@@ -999,8 +1004,9 @@ class Sema;
9991004
friend class OverloadCandidateSet;
10001005
OverloadCandidate()
10011006
: IsSurrogate(false), IgnoreObjectArgument(false),
1002-
TookAddressOfOverload(false), IsADLCandidate(CallExpr::NotADL),
1003-
RewriteKind(CRK_None) {}
1007+
TookAddressOfOverload(false),
1008+
HasMatchedPackOnParmToNonPackOnArg(false),
1009+
IsADLCandidate(CallExpr::NotADL), RewriteKind(CRK_None) {}
10041010
};
10051011

10061012
/// OverloadCandidateSet - A set of overload candidates, used in C++

clang/include/clang/Sema/Sema.h

+14-9
Original file line numberDiff line numberDiff line change
@@ -10133,7 +10133,8 @@ class Sema final : public SemaBase {
1013310133
ADLCallKind IsADLCandidate = ADLCallKind::NotADL,
1013410134
ConversionSequenceList EarlyConversions = std::nullopt,
1013510135
OverloadCandidateParamOrder PO = {},
10136-
bool AggregateCandidateDeduction = false);
10136+
bool AggregateCandidateDeduction = false,
10137+
bool HasMatchedPackOnParmToNonPackOnArg = false);
1013710138

1013810139
/// Add all of the function declarations in the given function set to
1013910140
/// the overload candidate set.
@@ -10168,7 +10169,8 @@ class Sema final : public SemaBase {
1016810169
bool SuppressUserConversions = false,
1016910170
bool PartialOverloading = false,
1017010171
ConversionSequenceList EarlyConversions = std::nullopt,
10171-
OverloadCandidateParamOrder PO = {});
10172+
OverloadCandidateParamOrder PO = {},
10173+
bool HasMatchedPackOnParmToNonPackOnArg = false);
1017210174

1017310175
/// Add a C++ member function template as a candidate to the candidate
1017410176
/// set, using template argument deduction to produce an appropriate member
@@ -10214,7 +10216,8 @@ class Sema final : public SemaBase {
1021410216
CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
1021510217
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
1021610218
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
10217-
bool AllowExplicit, bool AllowResultConversion = true);
10219+
bool AllowExplicit, bool AllowResultConversion = true,
10220+
bool HasMatchedPackOnParmToNonPackOnArg = false);
1021810221

1021910222
/// Adds a conversion function template specialization
1022010223
/// candidate to the overload set, using template argument deduction
@@ -11637,7 +11640,7 @@ class Sema final : public SemaBase {
1163711640
SourceLocation RAngleLoc, unsigned ArgumentPackIndex,
1163811641
SmallVectorImpl<TemplateArgument> &SugaredConverted,
1163911642
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
11640-
CheckTemplateArgumentKind CTAK,
11643+
CheckTemplateArgumentKind CTAK, bool PartialOrdering,
1164111644
bool *MatchedPackOnParmToNonPackOnArg);
1164211645

1164311646
/// Check that the given template arguments can be provided to
@@ -11720,7 +11723,8 @@ class Sema final : public SemaBase {
1172011723
/// It returns true if an error occurred, and false otherwise.
1172111724
bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
1172211725
TemplateParameterList *Params,
11723-
TemplateArgumentLoc &Arg, bool IsDeduced,
11726+
TemplateArgumentLoc &Arg,
11727+
bool PartialOrdering,
1172411728
bool *MatchedPackOnParmToNonPackOnArg);
1172511729

1172611730
void NoteTemplateLocation(const NamedDecl &Decl,
@@ -12232,8 +12236,8 @@ class Sema final : public SemaBase {
1223212236
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
1223312237
unsigned NumExplicitlySpecified, FunctionDecl *&Specialization,
1223412238
sema::TemplateDeductionInfo &Info,
12235-
SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = nullptr,
12236-
bool PartialOverloading = false,
12239+
SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
12240+
bool PartialOverloading, bool PartialOrdering,
1223712241
llvm::function_ref<bool()> CheckNonDependent = [] { return false; });
1223812242

1223912243
/// Perform template argument deduction from a function call
@@ -12267,7 +12271,8 @@ class Sema final : public SemaBase {
1226712271
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
1226812272
FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info,
1226912273
bool PartialOverloading, bool AggregateDeductionCandidate,
12270-
QualType ObjectType, Expr::Classification ObjectClassification,
12274+
bool PartialOrdering, QualType ObjectType,
12275+
Expr::Classification ObjectClassification,
1227112276
llvm::function_ref<bool(ArrayRef<QualType>)> CheckNonDependent);
1227212277

1227312278
/// Deduce template arguments when taking the address of a function
@@ -12422,7 +12427,7 @@ class Sema final : public SemaBase {
1242212427
bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
1242312428
TemplateParameterList *PParam, TemplateDecl *PArg, TemplateDecl *AArg,
1242412429
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
12425-
bool IsDeduced, bool *MatchedPackOnParmToNonPackOnArg);
12430+
bool PartialOrdering, bool *MatchedPackOnParmToNonPackOnArg);
1242612431

1242712432
/// Mark which template parameters are used in a given expression.
1242812433
///

clang/lib/Sema/SemaLookup.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -3667,6 +3667,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
36673667
if (CheckTemplateArgument(
36683668
Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
36693669
0, SugaredChecked, CanonicalChecked, CTAK_Specified,
3670+
/*PartialOrdering=*/false,
36703671
/*MatchedPackOnParmToNonPackOnArg=*/nullptr) ||
36713672
Trap.hasErrorOccurred())
36723673
IsTemplate = false;

clang/lib/Sema/SemaOverload.cpp

+32-18
Original file line numberDiff line numberDiff line change
@@ -6864,7 +6864,8 @@ void Sema::AddOverloadCandidate(
68646864
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
68656865
bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions,
68666866
ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions,
6867-
OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) {
6867+
OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction,
6868+
bool HasMatchedPackOnParmToNonPackOnArg) {
68686869
const FunctionProtoType *Proto
68696870
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
68706871
assert(Proto && "Functions without a prototype cannot be overloaded");
@@ -6883,7 +6884,8 @@ void Sema::AddOverloadCandidate(
68836884
AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),
68846885
Expr::Classification::makeSimpleLValue(), Args,
68856886
CandidateSet, SuppressUserConversions,
6886-
PartialOverloading, EarlyConversions, PO);
6887+
PartialOverloading, EarlyConversions, PO,
6888+
HasMatchedPackOnParmToNonPackOnArg);
68876889
return;
68886890
}
68896891
// We treat a constructor like a non-member function, since its object
@@ -6926,6 +6928,8 @@ void Sema::AddOverloadCandidate(
69266928
CandidateSet.getRewriteInfo().getRewriteKind(Function, PO);
69276929
Candidate.IsADLCandidate = IsADLCandidate;
69286930
Candidate.ExplicitCallArguments = Args.size();
6931+
Candidate.HasMatchedPackOnParmToNonPackOnArg =
6932+
HasMatchedPackOnParmToNonPackOnArg;
69296933

69306934
// Explicit functions are not actually candidates at all if we're not
69316935
// allowing them in this context, but keep them around so we can point
@@ -7453,16 +7457,13 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType,
74537457
}
74547458
}
74557459

7456-
void
7457-
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
7458-
CXXRecordDecl *ActingContext, QualType ObjectType,
7459-
Expr::Classification ObjectClassification,
7460-
ArrayRef<Expr *> Args,
7461-
OverloadCandidateSet &CandidateSet,
7462-
bool SuppressUserConversions,
7463-
bool PartialOverloading,
7464-
ConversionSequenceList EarlyConversions,
7465-
OverloadCandidateParamOrder PO) {
7460+
void Sema::AddMethodCandidate(
7461+
CXXMethodDecl *Method, DeclAccessPair FoundDecl,
7462+
CXXRecordDecl *ActingContext, QualType ObjectType,
7463+
Expr::Classification ObjectClassification, ArrayRef<Expr *> Args,
7464+
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
7465+
bool PartialOverloading, ConversionSequenceList EarlyConversions,
7466+
OverloadCandidateParamOrder PO, bool HasMatchedPackOnParmToNonPackOnArg) {
74667467
const FunctionProtoType *Proto
74677468
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
74687469
assert(Proto && "Methods without a prototype cannot be overloaded");
@@ -7493,6 +7494,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
74937494
Candidate.TookAddressOfOverload =
74947495
CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet;
74957496
Candidate.ExplicitCallArguments = Args.size();
7497+
Candidate.HasMatchedPackOnParmToNonPackOnArg =
7498+
HasMatchedPackOnParmToNonPackOnArg;
74967499

74977500
bool IgnoreExplicitObject =
74987501
(Method->isExplicitObjectMemberFunction() &&
@@ -7663,8 +7666,8 @@ void Sema::AddMethodTemplateCandidate(
76637666
ConversionSequenceList Conversions;
76647667
if (TemplateDeductionResult Result = DeduceTemplateArguments(
76657668
MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info,
7666-
PartialOverloading, /*AggregateDeductionCandidate=*/false, ObjectType,
7667-
ObjectClassification,
7669+
PartialOverloading, /*AggregateDeductionCandidate=*/false,
7670+
/*PartialOrdering=*/false, ObjectType, ObjectClassification,
76687671
[&](ArrayRef<QualType> ParamTypes) {
76697672
return CheckNonDependentConversions(
76707673
MethodTmpl, ParamTypes, Args, CandidateSet, Conversions,
@@ -7702,7 +7705,8 @@ void Sema::AddMethodTemplateCandidate(
77027705
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
77037706
ActingContext, ObjectType, ObjectClassification, Args,
77047707
CandidateSet, SuppressUserConversions, PartialOverloading,
7705-
Conversions, PO);
7708+
Conversions, PO,
7709+
Info.hasMatchedPackOnParmToNonPackOnArg());
77067710
}
77077711

77087712
/// Determine whether a given function template has a simple explicit specifier
@@ -7748,6 +7752,7 @@ void Sema::AddTemplateOverloadCandidate(
77487752
if (TemplateDeductionResult Result = DeduceTemplateArguments(
77497753
FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info,
77507754
PartialOverloading, AggregateCandidateDeduction,
7755+
/*PartialOrdering=*/false,
77517756
/*ObjectType=*/QualType(),
77527757
/*ObjectClassification=*/Expr::Classification(),
77537758
[&](ArrayRef<QualType> ParamTypes) {
@@ -7788,7 +7793,8 @@ void Sema::AddTemplateOverloadCandidate(
77887793
Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions,
77897794
PartialOverloading, AllowExplicit,
77907795
/*AllowExplicitConversions=*/false, IsADLCandidate, Conversions, PO,
7791-
Info.AggregateDeductionCandidateHasMismatchedArity);
7796+
Info.AggregateDeductionCandidateHasMismatchedArity,
7797+
Info.hasMatchedPackOnParmToNonPackOnArg());
77927798
}
77937799

77947800
bool Sema::CheckNonDependentConversions(
@@ -7910,7 +7916,8 @@ void Sema::AddConversionCandidate(
79107916
CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
79117917
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
79127918
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
7913-
bool AllowExplicit, bool AllowResultConversion) {
7919+
bool AllowExplicit, bool AllowResultConversion,
7920+
bool HasMatchedPackOnParmToNonPackOnArg) {
79147921
assert(!Conversion->getDescribedFunctionTemplate() &&
79157922
"Conversion function templates use AddTemplateConversionCandidate");
79167923
QualType ConvType = Conversion->getConversionType().getNonReferenceType();
@@ -7955,6 +7962,8 @@ void Sema::AddConversionCandidate(
79557962
Candidate.FinalConversion.setAllToTypes(ToType);
79567963
Candidate.Viable = true;
79577964
Candidate.ExplicitCallArguments = 1;
7965+
Candidate.HasMatchedPackOnParmToNonPackOnArg =
7966+
HasMatchedPackOnParmToNonPackOnArg;
79587967

79597968
// Explicit functions are not actually candidates at all if we're not
79607969
// allowing them in this context, but keep them around so we can point
@@ -8156,7 +8165,8 @@ void Sema::AddTemplateConversionCandidate(
81568165
assert(Specialization && "Missing function template specialization?");
81578166
AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
81588167
CandidateSet, AllowObjCConversionOnExplicit,
8159-
AllowExplicit, AllowResultConversion);
8168+
AllowExplicit, AllowResultConversion,
8169+
Info.hasMatchedPackOnParmToNonPackOnArg());
81608170
}
81618171

81628172
void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
@@ -10509,6 +10519,10 @@ bool clang::isBetterOverloadCandidate(
1050910519
isa<CXXConstructorDecl>(Cand2.Function))
1051010520
return isa<CXXConstructorDecl>(Cand1.Function);
1051110521

10522+
if (Cand1.HasMatchedPackOnParmToNonPackOnArg !=
10523+
Cand2.HasMatchedPackOnParmToNonPackOnArg)
10524+
return Cand2.HasMatchedPackOnParmToNonPackOnArg;
10525+
1051210526
// -- F1 is a non-template function and F2 is a function template
1051310527
// specialization, or, if not that,
1051410528
bool Cand1IsSpecialization = Cand1.Function &&

clang/lib/Sema/SemaTemplate.cpp

+12-11
Original file line numberDiff line numberDiff line change
@@ -5179,7 +5179,8 @@ bool Sema::CheckTemplateArgument(
51795179
unsigned ArgumentPackIndex,
51805180
SmallVectorImpl<TemplateArgument> &SugaredConverted,
51815181
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
5182-
CheckTemplateArgumentKind CTAK, bool *MatchedPackOnParmToNonPackOnArg) {
5182+
CheckTemplateArgumentKind CTAK, bool PartialOrdering,
5183+
bool *MatchedPackOnParmToNonPackOnArg) {
51835184
// Check template type parameters.
51845185
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
51855186
return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted,
@@ -5394,8 +5395,7 @@ bool Sema::CheckTemplateArgument(
53945395

53955396
case TemplateArgument::Template:
53965397
case TemplateArgument::TemplateExpansion:
5397-
if (CheckTemplateTemplateArgument(TempParm, Params, Arg,
5398-
/*IsDeduced=*/CTAK != CTAK_Specified,
5398+
if (CheckTemplateTemplateArgument(TempParm, Params, Arg, PartialOrdering,
53995399
MatchedPackOnParmToNonPackOnArg))
54005400
return true;
54015401

@@ -5546,10 +5546,11 @@ bool Sema::CheckTemplateArgumentList(
55465546

55475547
if (ArgIdx < NumArgs) {
55485548
// Check the template argument we were given.
5549-
if (CheckTemplateArgument(
5550-
*Param, NewArgs[ArgIdx], Template, TemplateLoc, RAngleLoc,
5551-
SugaredArgumentPack.size(), SugaredConverted, CanonicalConverted,
5552-
CTAK_Specified, MatchedPackOnParmToNonPackOnArg))
5549+
if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc,
5550+
RAngleLoc, SugaredArgumentPack.size(),
5551+
SugaredConverted, CanonicalConverted,
5552+
CTAK_Specified, /*PartialOrdering=*/false,
5553+
MatchedPackOnParmToNonPackOnArg))
55535554
return true;
55545555

55555556
CanonicalConverted.back().setIsDefaulted(
@@ -5707,7 +5708,7 @@ bool Sema::CheckTemplateArgumentList(
57075708
// Check the default template argument.
57085709
if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0,
57095710
SugaredConverted, CanonicalConverted,
5710-
CTAK_Specified,
5711+
CTAK_Specified, /*PartialOrdering=*/false,
57115712
/*MatchedPackOnParmToNonPackOnArg=*/nullptr))
57125713
return true;
57135714

@@ -7293,7 +7294,7 @@ static void DiagnoseTemplateParameterListArityMismatch(
72937294

72947295
bool Sema::CheckTemplateTemplateArgument(
72957296
TemplateTemplateParmDecl *Param, TemplateParameterList *Params,
7296-
TemplateArgumentLoc &Arg, bool IsDeduced,
7297+
TemplateArgumentLoc &Arg, bool PartialOrdering,
72977298
bool *MatchedPackOnParmToNonPackOnArg) {
72987299
TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
72997300
auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs();
@@ -7338,8 +7339,8 @@ bool Sema::CheckTemplateTemplateArgument(
73387339
// A template-argument matches a template template-parameter P when P
73397340
// is at least as specialized as the template-argument A.
73407341
if (!isTemplateTemplateParameterAtLeastAsSpecializedAs(
7341-
Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced,
7342-
MatchedPackOnParmToNonPackOnArg))
7342+
Params, Param, Template, DefaultArgs, Arg.getLocation(),
7343+
PartialOrdering, MatchedPackOnParmToNonPackOnArg))
73437344
return true;
73447345
// P2113
73457346
// C++20[temp.func.order]p2

0 commit comments

Comments
 (0)