[llvm-branch-commits] [clang] [clang] Implement TTP P0522 pack matching for deduced function template calls. (PR #111457)
Matheus Izvekov via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Oct 9 21:46:41 PDT 2024
https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/111457
>From 1975bae70df78c437d10a361a15aca27f218460e Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Sat, 5 Oct 2024 21:56:51 -0300
Subject: [PATCH] [clang] Implement TTP 'reversed' pack matching for deduced
function template calls.
Clang previously missed implementing P0522 pack matching
for deduced function template calls.
---
clang/docs/ReleaseNotes.rst | 4 ++
clang/include/clang/Sema/Overload.h | 7 +-
clang/include/clang/Sema/Sema.h | 23 ++++---
clang/lib/Sema/SemaLookup.cpp | 1 +
clang/lib/Sema/SemaOverload.cpp | 50 +++++++++------
clang/lib/Sema/SemaTemplate.cpp | 23 +++----
clang/lib/Sema/SemaTemplateDeduction.cpp | 76 ++++++++++++----------
clang/test/SemaTemplate/cwg2398.cpp | 81 ++++++++++++++++++++++++
8 files changed, 193 insertions(+), 72 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 153901fb3b1ed7..71967b1d27fbad 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -151,6 +151,10 @@ C++ Language Changes
- The builtin type alias ``__builtin_common_type`` has been added to improve the
performance of ``std::common_type``.
+- When matching a template to a template template parameter in the context of a deduced
+ function template call, clang now implements ``[temp.arg.template]p3.3``,
+ allowing a pack on the parameter to match a non-pack argument.
+
C++2c Feature Support
^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index c716a25bb673b8..8b7480636c36e7 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -925,6 +925,8 @@ class Sema;
bool TookAddressOfOverload : 1;
+ bool HasMatchedPackOnParmToNonPackOnArg : 1;
+
/// True if the candidate was found using ADL.
CallExpr::ADLCallKind IsADLCandidate : 1;
@@ -999,8 +1001,9 @@ class Sema;
friend class OverloadCandidateSet;
OverloadCandidate()
: IsSurrogate(false), IgnoreObjectArgument(false),
- TookAddressOfOverload(false), IsADLCandidate(CallExpr::NotADL),
- RewriteKind(CRK_None) {}
+ TookAddressOfOverload(false),
+ HasMatchedPackOnParmToNonPackOnArg(false),
+ IsADLCandidate(CallExpr::NotADL), RewriteKind(CRK_None) {}
};
/// OverloadCandidateSet - A set of overload candidates, used in C++
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d99a0c7af4b0ca..5f045860acb7b2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10132,7 +10132,8 @@ class Sema final : public SemaBase {
ADLCallKind IsADLCandidate = ADLCallKind::NotADL,
ConversionSequenceList EarlyConversions = std::nullopt,
OverloadCandidateParamOrder PO = {},
- bool AggregateCandidateDeduction = false);
+ bool AggregateCandidateDeduction = false,
+ bool HasMatchedPackOnParmToNonPackOnArg = false);
/// Add all of the function declarations in the given function set to
/// the overload candidate set.
@@ -10167,7 +10168,8 @@ class Sema final : public SemaBase {
bool SuppressUserConversions = false,
bool PartialOverloading = false,
ConversionSequenceList EarlyConversions = std::nullopt,
- OverloadCandidateParamOrder PO = {});
+ OverloadCandidateParamOrder PO = {},
+ bool HasMatchedPackOnParmToNonPackOnArg = false);
/// Add a C++ member function template as a candidate to the candidate
/// set, using template argument deduction to produce an appropriate member
@@ -10213,7 +10215,8 @@ class Sema final : public SemaBase {
CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
- bool AllowExplicit, bool AllowResultConversion = true);
+ bool AllowExplicit, bool AllowResultConversion = true,
+ bool HasMatchedPackOnParmToNonPackOnArg = false);
/// Adds a conversion function template specialization
/// candidate to the overload set, using template argument deduction
@@ -11637,7 +11640,7 @@ class Sema final : public SemaBase {
SourceLocation RAngleLoc, unsigned ArgumentPackIndex,
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
- CheckTemplateArgumentKind CTAK,
+ CheckTemplateArgumentKind CTAK, bool PartialOrdering,
bool *MatchedPackOnParmToNonPackOnArg);
/// Check that the given template arguments can be provided to
@@ -11720,7 +11723,8 @@ class Sema final : public SemaBase {
/// It returns true if an error occurred, and false otherwise.
bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
TemplateParameterList *Params,
- TemplateArgumentLoc &Arg, bool IsDeduced,
+ TemplateArgumentLoc &Arg,
+ bool PartialOrdering,
bool *MatchedPackOnParmToNonPackOnArg);
void NoteTemplateLocation(const NamedDecl &Decl,
@@ -12232,8 +12236,8 @@ class Sema final : public SemaBase {
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned NumExplicitlySpecified, FunctionDecl *&Specialization,
sema::TemplateDeductionInfo &Info,
- SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = nullptr,
- bool PartialOverloading = false,
+ SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
+ bool PartialOverloading, bool PartialOrdering,
llvm::function_ref<bool()> CheckNonDependent = [] { return false; });
/// Perform template argument deduction from a function call
@@ -12267,7 +12271,8 @@ class Sema final : public SemaBase {
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info,
bool PartialOverloading, bool AggregateDeductionCandidate,
- QualType ObjectType, Expr::Classification ObjectClassification,
+ bool PartialOrdering, QualType ObjectType,
+ Expr::Classification ObjectClassification,
llvm::function_ref<bool(ArrayRef<QualType>)> CheckNonDependent);
/// Deduce template arguments when taking the address of a function
@@ -12422,7 +12427,7 @@ class Sema final : public SemaBase {
bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
TemplateParameterList *PParam, TemplateDecl *PArg, TemplateDecl *AArg,
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
- bool IsDeduced, bool *MatchedPackOnParmToNonPackOnArg);
+ bool PartialOrdering, bool *MatchedPackOnParmToNonPackOnArg);
/// Mark which template parameters are used in a given expression.
///
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 31422c213ac249..60fa195221c938 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -3667,6 +3667,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
if (CheckTemplateArgument(
Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
0, SugaredChecked, CanonicalChecked, CTAK_Specified,
+ /*PartialOrdering=*/false,
/*MatchedPackOnParmToNonPackOnArg=*/nullptr) ||
Trap.hasErrorOccurred())
IsTemplate = false;
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 2cde8131108fbe..f545e9341e1ae6 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -6864,7 +6864,8 @@ void Sema::AddOverloadCandidate(
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions,
ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions,
- OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) {
+ OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction,
+ bool HasMatchedPackOnParmToNonPackOnArg) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
@@ -6883,7 +6884,8 @@ void Sema::AddOverloadCandidate(
AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),
Expr::Classification::makeSimpleLValue(), Args,
CandidateSet, SuppressUserConversions,
- PartialOverloading, EarlyConversions, PO);
+ PartialOverloading, EarlyConversions, PO,
+ HasMatchedPackOnParmToNonPackOnArg);
return;
}
// We treat a constructor like a non-member function, since its object
@@ -6926,6 +6928,8 @@ void Sema::AddOverloadCandidate(
CandidateSet.getRewriteInfo().getRewriteKind(Function, PO);
Candidate.IsADLCandidate = IsADLCandidate;
Candidate.ExplicitCallArguments = Args.size();
+ Candidate.HasMatchedPackOnParmToNonPackOnArg =
+ HasMatchedPackOnParmToNonPackOnArg;
// Explicit functions are not actually candidates at all if we're not
// allowing them in this context, but keep them around so we can point
@@ -7453,16 +7457,13 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType,
}
}
-void
-Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
- CXXRecordDecl *ActingContext, QualType ObjectType,
- Expr::Classification ObjectClassification,
- ArrayRef<Expr *> Args,
- OverloadCandidateSet &CandidateSet,
- bool SuppressUserConversions,
- bool PartialOverloading,
- ConversionSequenceList EarlyConversions,
- OverloadCandidateParamOrder PO) {
+void Sema::AddMethodCandidate(
+ CXXMethodDecl *Method, DeclAccessPair FoundDecl,
+ CXXRecordDecl *ActingContext, QualType ObjectType,
+ Expr::Classification ObjectClassification, ArrayRef<Expr *> Args,
+ OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
+ bool PartialOverloading, ConversionSequenceList EarlyConversions,
+ OverloadCandidateParamOrder PO, bool HasMatchedPackOnParmToNonPackOnArg) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded");
@@ -7493,6 +7494,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
Candidate.TookAddressOfOverload =
CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet;
Candidate.ExplicitCallArguments = Args.size();
+ Candidate.HasMatchedPackOnParmToNonPackOnArg =
+ HasMatchedPackOnParmToNonPackOnArg;
bool IgnoreExplicitObject =
(Method->isExplicitObjectMemberFunction() &&
@@ -7663,8 +7666,8 @@ void Sema::AddMethodTemplateCandidate(
ConversionSequenceList Conversions;
if (TemplateDeductionResult Result = DeduceTemplateArguments(
MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info,
- PartialOverloading, /*AggregateDeductionCandidate=*/false, ObjectType,
- ObjectClassification,
+ PartialOverloading, /*AggregateDeductionCandidate=*/false,
+ /*PartialOrdering=*/false, ObjectType, ObjectClassification,
[&](ArrayRef<QualType> ParamTypes) {
return CheckNonDependentConversions(
MethodTmpl, ParamTypes, Args, CandidateSet, Conversions,
@@ -7702,7 +7705,8 @@ void Sema::AddMethodTemplateCandidate(
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
ActingContext, ObjectType, ObjectClassification, Args,
CandidateSet, SuppressUserConversions, PartialOverloading,
- Conversions, PO);
+ Conversions, PO,
+ Info.hasMatchedPackOnParmToNonPackOnArg());
}
/// Determine whether a given function template has a simple explicit specifier
@@ -7748,6 +7752,7 @@ void Sema::AddTemplateOverloadCandidate(
if (TemplateDeductionResult Result = DeduceTemplateArguments(
FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info,
PartialOverloading, AggregateCandidateDeduction,
+ /*PartialOrdering=*/false,
/*ObjectType=*/QualType(),
/*ObjectClassification=*/Expr::Classification(),
[&](ArrayRef<QualType> ParamTypes) {
@@ -7788,7 +7793,8 @@ void Sema::AddTemplateOverloadCandidate(
Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions,
PartialOverloading, AllowExplicit,
/*AllowExplicitConversions=*/false, IsADLCandidate, Conversions, PO,
- Info.AggregateDeductionCandidateHasMismatchedArity);
+ Info.AggregateDeductionCandidateHasMismatchedArity,
+ Info.hasMatchedPackOnParmToNonPackOnArg());
}
bool Sema::CheckNonDependentConversions(
@@ -7910,7 +7916,8 @@ void Sema::AddConversionCandidate(
CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
- bool AllowExplicit, bool AllowResultConversion) {
+ bool AllowExplicit, bool AllowResultConversion,
+ bool HasMatchedPackOnParmToNonPackOnArg) {
assert(!Conversion->getDescribedFunctionTemplate() &&
"Conversion function templates use AddTemplateConversionCandidate");
QualType ConvType = Conversion->getConversionType().getNonReferenceType();
@@ -7955,6 +7962,8 @@ void Sema::AddConversionCandidate(
Candidate.FinalConversion.setAllToTypes(ToType);
Candidate.Viable = true;
Candidate.ExplicitCallArguments = 1;
+ Candidate.HasMatchedPackOnParmToNonPackOnArg =
+ HasMatchedPackOnParmToNonPackOnArg;
// Explicit functions are not actually candidates at all if we're not
// allowing them in this context, but keep them around so we can point
@@ -8156,7 +8165,8 @@ void Sema::AddTemplateConversionCandidate(
assert(Specialization && "Missing function template specialization?");
AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
CandidateSet, AllowObjCConversionOnExplicit,
- AllowExplicit, AllowResultConversion);
+ AllowExplicit, AllowResultConversion,
+ Info.hasMatchedPackOnParmToNonPackOnArg());
}
void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
@@ -10509,6 +10519,10 @@ bool clang::isBetterOverloadCandidate(
isa<CXXConstructorDecl>(Cand2.Function))
return isa<CXXConstructorDecl>(Cand1.Function);
+ if (Cand1.HasMatchedPackOnParmToNonPackOnArg !=
+ Cand2.HasMatchedPackOnParmToNonPackOnArg)
+ return Cand2.HasMatchedPackOnParmToNonPackOnArg;
+
// -- F1 is a non-template function and F2 is a function template
// specialization, or, if not that,
bool Cand1IsSpecialization = Cand1.Function &&
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index cc9505c0d7338c..530de42586ee61 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5175,7 +5175,8 @@ bool Sema::CheckTemplateArgument(
unsigned ArgumentPackIndex,
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
- CheckTemplateArgumentKind CTAK, bool *MatchedPackOnParmToNonPackOnArg) {
+ CheckTemplateArgumentKind CTAK, bool PartialOrdering,
+ bool *MatchedPackOnParmToNonPackOnArg) {
// Check template type parameters.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted,
@@ -5390,8 +5391,7 @@ bool Sema::CheckTemplateArgument(
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
- if (CheckTemplateTemplateArgument(TempParm, Params, Arg,
- /*IsDeduced=*/CTAK != CTAK_Specified,
+ if (CheckTemplateTemplateArgument(TempParm, Params, Arg, PartialOrdering,
MatchedPackOnParmToNonPackOnArg))
return true;
@@ -5542,10 +5542,11 @@ bool Sema::CheckTemplateArgumentList(
if (ArgIdx < NumArgs) {
// Check the template argument we were given.
- if (CheckTemplateArgument(
- *Param, NewArgs[ArgIdx], Template, TemplateLoc, RAngleLoc,
- SugaredArgumentPack.size(), SugaredConverted, CanonicalConverted,
- CTAK_Specified, MatchedPackOnParmToNonPackOnArg))
+ if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc,
+ RAngleLoc, SugaredArgumentPack.size(),
+ SugaredConverted, CanonicalConverted,
+ CTAK_Specified, /*PartialOrdering=*/false,
+ MatchedPackOnParmToNonPackOnArg))
return true;
CanonicalConverted.back().setIsDefaulted(
@@ -5703,7 +5704,7 @@ bool Sema::CheckTemplateArgumentList(
// Check the default template argument.
if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0,
SugaredConverted, CanonicalConverted,
- CTAK_Specified,
+ CTAK_Specified, /*PartialOrdering=*/false,
/*MatchedPackOnParmToNonPackOnArg=*/nullptr))
return true;
@@ -7287,7 +7288,7 @@ static void DiagnoseTemplateParameterListArityMismatch(
bool Sema::CheckTemplateTemplateArgument(
TemplateTemplateParmDecl *Param, TemplateParameterList *Params,
- TemplateArgumentLoc &Arg, bool IsDeduced,
+ TemplateArgumentLoc &Arg, bool PartialOrdering,
bool *MatchedPackOnParmToNonPackOnArg) {
TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs();
@@ -7332,8 +7333,8 @@ bool Sema::CheckTemplateTemplateArgument(
// A template-argument matches a template template-parameter P when P
// is at least as specialized as the template-argument A.
if (!isTemplateTemplateParameterAtLeastAsSpecializedAs(
- Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced,
- MatchedPackOnParmToNonPackOnArg))
+ Params, Param, Template, DefaultArgs, Arg.getLocation(),
+ PartialOrdering, MatchedPackOnParmToNonPackOnArg))
return true;
// P2113
// C++20[temp.func.order]p2
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index c6fc776462a87f..0788d8c0e8f182 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2955,7 +2955,7 @@ Sema::getIdentityTemplateArgumentLoc(NamedDecl *TemplateParm,
/// fully-converted template arguments.
static bool ConvertDeducedTemplateArgument(
Sema &S, NamedDecl *Param, DeducedTemplateArgument Arg, NamedDecl *Template,
- TemplateDeductionInfo &Info, bool IsDeduced,
+ TemplateDeductionInfo &Info, bool IsDeduced, bool PartialOrdering,
SmallVectorImpl<TemplateArgument> &SugaredOutput,
SmallVectorImpl<TemplateArgument> &CanonicalOutput) {
auto ConvertArg = [&](DeducedTemplateArgument Arg,
@@ -2976,7 +2976,7 @@ static bool ConvertDeducedTemplateArgument(
? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound
: Sema::CTAK_Deduced)
: Sema::CTAK_Specified,
- &MatchedPackOnParmToNonPackOnArg);
+ PartialOrdering, &MatchedPackOnParmToNonPackOnArg);
if (MatchedPackOnParmToNonPackOnArg)
Info.setMatchedPackOnParmToNonPackOnArg();
return Res;
@@ -3062,9 +3062,9 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info,
SmallVectorImpl<TemplateArgument> &SugaredBuilder,
- SmallVectorImpl<TemplateArgument> &CanonicalBuilder,
- LocalInstantiationScope *CurrentInstantiationScope = nullptr,
- unsigned NumAlreadyConverted = 0, bool *IsIncomplete = nullptr) {
+ SmallVectorImpl<TemplateArgument> &CanonicalBuilder, bool PartialOrdering,
+ LocalInstantiationScope *CurrentInstantiationScope,
+ unsigned NumAlreadyConverted, bool *IsIncomplete) {
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
@@ -3107,8 +3107,8 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
// We may have deduced this argument, so it still needs to be
// checked and converted.
if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info,
- IsDeduced, SugaredBuilder,
- CanonicalBuilder)) {
+ IsDeduced, PartialOrdering,
+ SugaredBuilder, CanonicalBuilder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
Info.reset(
@@ -3172,10 +3172,11 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
}
// Check whether we can actually use the default argument.
- if (S.CheckTemplateArgument(
- Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(),
- 0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified,
- /*MatchedPackOnParmToNonPackOnArg=*/nullptr)) {
+ if (S.CheckTemplateArgument(Param, DefArg, TD, TD->getLocation(),
+ TD->getSourceRange().getEnd(), 0,
+ SugaredBuilder, CanonicalBuilder,
+ Sema::CTAK_Specified, /*PartialOrdering=*/false,
+ /*MatchedPackOnParmToNonPackOnArg=*/nullptr)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
// FIXME: These template arguments are temporary. Free them!
@@ -3256,7 +3257,9 @@ FinishTemplateArgumentDeduction(
SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
if (auto Result = ConvertDeducedTemplateArguments(
S, Partial, IsPartialOrdering, Deduced, Info, SugaredBuilder,
- CanonicalBuilder);
+ CanonicalBuilder, IsPartialOrdering,
+ /*CurrentInstantiationScope=*/nullptr, /*NumAlreadyConverted=*/0,
+ /*IsIncomplete=*/nullptr);
Result != TemplateDeductionResult::Success)
return Result;
@@ -3356,10 +3359,10 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction(
// explicitly specified, template argument deduction fails.
SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
if (auto Result = ConvertDeducedTemplateArguments(
- S, Template, /*IsDeduced*/ PartialOrdering, Deduced, Info,
- SugaredBuilder, CanonicalBuilder,
+ S, Template, /*IsDeduced=*/PartialOrdering, Deduced, Info,
+ SugaredBuilder, CanonicalBuilder, PartialOrdering,
/*CurrentInstantiationScope=*/nullptr,
- /*NumAlreadyConverted=*/0U);
+ /*NumAlreadyConverted=*/0U, /*IsIncomplete=*/nullptr);
Result != TemplateDeductionResult::Success)
return Result;
@@ -3424,7 +3427,9 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction(
SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
if (auto Result = ConvertDeducedTemplateArguments(
S, TD, /*IsDeduced=*/false, Deduced, Info, SugaredBuilder,
- CanonicalBuilder);
+ CanonicalBuilder, /*PartialOrdering=*/false,
+ /*CurrentInstantiationScope=*/nullptr, /*NumAlreadyConverted=*/0,
+ /*IsIncomplete=*/nullptr);
Result != TemplateDeductionResult::Success)
return Result;
@@ -3962,7 +3967,8 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
unsigned NumExplicitlySpecified, FunctionDecl *&Specialization,
TemplateDeductionInfo &Info,
SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
- bool PartialOverloading, llvm::function_ref<bool()> CheckNonDependent) {
+ bool PartialOverloading, bool PartialOrdering,
+ llvm::function_ref<bool()> CheckNonDependent) {
// Unevaluated SFINAE context.
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
@@ -3985,9 +3991,10 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
bool IsIncomplete = false;
SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
if (auto Result = ConvertDeducedTemplateArguments(
- *this, FunctionTemplate, /*IsDeduced*/ true, Deduced, Info,
- SugaredBuilder, CanonicalBuilder, CurrentInstantiationScope,
- NumExplicitlySpecified, PartialOverloading ? &IsIncomplete : nullptr);
+ *this, FunctionTemplate, /*IsDeduced=*/true, Deduced, Info,
+ SugaredBuilder, CanonicalBuilder, PartialOrdering,
+ CurrentInstantiationScope, NumExplicitlySpecified,
+ PartialOverloading ? &IsIncomplete : nullptr);
Result != TemplateDeductionResult::Success)
return Result;
@@ -4504,7 +4511,8 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
FunctionDecl *&Specialization, TemplateDeductionInfo &Info,
bool PartialOverloading, bool AggregateDeductionCandidate,
- QualType ObjectType, Expr::Classification ObjectClassification,
+ bool PartialOrdering, QualType ObjectType,
+ Expr::Classification ObjectClassification,
llvm::function_ref<bool(ArrayRef<QualType>)> CheckNonDependent) {
if (FunctionTemplate->isInvalidDecl())
return TemplateDeductionResult::Invalid;
@@ -4719,7 +4727,8 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
runWithSufficientStackSpace(Info.getLocation(), [&] {
Result = FinishTemplateArgumentDeduction(
FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info,
- &OriginalCallArgs, PartialOverloading, [&, CallingCtx]() {
+ &OriginalCallArgs, PartialOverloading, PartialOrdering,
+ [&, CallingCtx]() {
ContextRAII SavedContext(*this, CallingCtx);
return CheckNonDependent(ParamTypesForArgChecking);
});
@@ -4831,9 +4840,10 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
TemplateDeductionResult Result;
runWithSufficientStackSpace(Info.getLocation(), [&] {
- Result = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
- NumExplicitlySpecified,
- Specialization, Info);
+ Result = FinishTemplateArgumentDeduction(
+ FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info,
+ /*OriginalCallArgs=*/nullptr, /*PartialOverloading=*/false,
+ /*PartialOrdering=*/true);
});
if (Result != TemplateDeductionResult::Success)
return Result;
@@ -5013,9 +5023,10 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
FunctionDecl *ConversionSpecialized = nullptr;
TemplateDeductionResult Result;
runWithSufficientStackSpace(Info.getLocation(), [&] {
- Result = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0,
- ConversionSpecialized, Info,
- &OriginalCallArgs);
+ Result = FinishTemplateArgumentDeduction(
+ ConversionTemplate, Deduced, 0, ConversionSpecialized, Info,
+ &OriginalCallArgs, /*PartialOverloading=*/false,
+ /*PartialOrdering=*/false);
});
Specialization = cast_or_null<CXXConversionDecl>(ConversionSpecialized);
return Result;
@@ -5592,7 +5603,8 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction(
SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
if (auto Result = ConvertDeducedTemplateArguments(
S, FTD, /*IsDeduced=*/true, Deduced, Info, SugaredBuilder,
- CanonicalBuilder, /*CurrentInstantiationScope=*/nullptr,
+ CanonicalBuilder, /*PartialOrdering=*/true,
+ /*CurrentInstantiationScope=*/nullptr,
/*NumAlreadyConverted=*/0, &IsIncomplete);
Result != TemplateDeductionResult::Success)
return Result;
@@ -6437,8 +6449,8 @@ bool Sema::isMoreSpecializedThanPrimary(
bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
TemplateParameterList *P, TemplateDecl *PArg, TemplateDecl *AArg,
- const DefaultArguments &DefaultArgs, SourceLocation ArgLoc, bool IsDeduced,
- bool *MatchedPackOnParmToNonPackOnArg) {
+ const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
+ bool PartialOrdering, bool *MatchedPackOnParmToNonPackOnArg) {
// C++1z [temp.arg.template]p4: (DR 150)
// A template template-parameter P is at least as specialized as a
// template template-argument A if, given the following rewrite to two
@@ -6517,7 +6529,7 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
switch (::DeduceTemplateArguments(
*this, A, AArgs, PArgs, Info, Deduced,
/*NumberOfArgumentsMustMatch=*/false, /*PartialOrdering=*/true,
- IsDeduced ? PackFold::ArgumentToParameter : PackFold::Both,
+ PartialOrdering ? PackFold::ArgumentToParameter : PackFold::Both,
/*HasDeducedAnyParam=*/nullptr)) {
case clang::TemplateDeductionResult::Success:
if (MatchedPackOnParmToNonPackOnArg &&
diff --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp
index 56091e84cf4e95..3825239de4a285 100644
--- a/clang/test/SemaTemplate/cwg2398.cpp
+++ b/clang/test/SemaTemplate/cwg2398.cpp
@@ -405,6 +405,87 @@ namespace packs {
} // namespace t4
} // namespace packs
+namespace fun_tmpl_call {
+ namespace match_func {
+ template <template <class> class TT> void f(TT<int>) {};
+ // old-note at -1 {{has different template parameters}}
+ template <class...> struct A {};
+ void test() { f(A<int>()); }
+ // old-error at -1 {{no matching function for call to 'f'}}
+ } // namespace match_func
+ namespace order_func_nonpack {
+ template <template <class> class TT> void f(TT<int>) {}
+ template <template <class...> class TT> void f(TT<int>) = delete;
+
+ template <class> struct A {};
+ void test() { f(A<int>()); }
+ } // namespace order_func_nonpack
+ namespace order_func_pack {
+ template <template <class> class TT> void f(TT<int>) = delete;
+ template <template <class...> class TT> void f(TT<int>) {}
+
+ template <class...> struct A {};
+ void test() { f(A<int>()); }
+ } // namespace order_func_pack
+ namespace match_method {
+ struct A {
+ template <template <class> class TT> void f(TT<int>) {};
+ // old-note at -1 {{has different template parameters}}
+ };
+ template <class...> struct B {};
+ void test() { A().f(B<int>()); }
+ // old-error at -1 {{no matching member function for call to 'f'}}
+ } // namespace t2
+ namespace order_method_nonpack {
+ struct A {
+ template <template <class> class TT> void f(TT<int>) {}
+ template <template <class...> class TT> void f(TT<int>) = delete;
+ };
+ template <class> struct B {};
+ void test() { A().f(B<int>()); }
+ } // namespace order_method_nonpack
+ namespace order_method_pack {
+ struct A {
+ template <template <class> class TT> void f(TT<int>) = delete;
+ template <template <class...> class TT> void f(TT<int>) {}
+ };
+ template <class...> struct B {};
+ void test() { A().f(B<int>()); }
+ } // namespace order_method_pack
+ namespace match_conv {
+ struct A {
+ template <template <class> class TT> operator TT<int>() { return {}; }
+ // old-note at -1 {{different template parameters}}
+ };
+ template <class...> struct B {};
+ // old-note at -1 2{{not viable}}
+ void test() { B<int> b = A(); }
+ // old-error at -1 {{no viable conversion from 'A' to 'B<int>'}}
+ } // namespace match_conv
+ namespace order_conv_nonpack {
+ struct A {
+ template <template <class> class TT> operator TT<int>() { return {}; };
+ template <template <class...> class TT> operator TT<int>() = delete;
+ };
+ template <class> struct B {};
+ void test() { B<int> b = A(); }
+ } // namespace order_conv_nonpack
+ namespace order_conv_pack {
+ struct A {
+ template <template <class> class TT> operator TT<int>() = delete;
+ template <template <class...> class TT> operator TT<int>() { return {}; }
+ };
+ template <class...> struct B {};
+ void test() { B<int> b = A(); }
+ } // namespace order_conv_pack
+ namespace regression1 {
+ template <template <class, class...> class TT, class T1, class... T2s>
+ void f(TT<T1, T2s...>) {}
+ template <class> struct A {};
+ void test() { f(A<int>()); }
+ } // namespace regression1
+} // namespace fun_tmpl_packs
+
namespace partial {
namespace t1 {
template<template<class... T1s> class TT1> struct A {};
More information about the llvm-branch-commits
mailing list