[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
This commit is contained in:
@@ -925,6 +925,11 @@ class Sema;
|
||||
|
||||
bool TookAddressOfOverload : 1;
|
||||
|
||||
/// Have we matched any packs on the parameter side, versus any non-packs on
|
||||
/// the argument side, in a context where the opposite matching is also
|
||||
/// allowed?
|
||||
bool HasMatchedPackOnParmToNonPackOnArg : 1;
|
||||
|
||||
/// True if the candidate was found using ADL.
|
||||
CallExpr::ADLCallKind IsADLCandidate : 1;
|
||||
|
||||
@@ -999,8 +1004,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++
|
||||
|
||||
@@ -10133,7 +10133,8 @@ public:
|
||||
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.
|
||||
@@ -10168,7 +10169,8 @@ public:
|
||||
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
|
||||
@@ -10214,7 +10216,8 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
/// 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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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.
|
||||
///
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -5179,7 +5179,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,
|
||||
@@ -5394,8 +5395,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;
|
||||
|
||||
@@ -5546,10 +5546,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(
|
||||
@@ -5707,7 +5708,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;
|
||||
|
||||
@@ -7293,7 +7294,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();
|
||||
@@ -7338,8 +7339,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
|
||||
|
||||
@@ -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(
|
||||
@@ -3174,7 +3174,8 @@ 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,
|
||||
/*ArgumentPackIndex=*/0, SugaredBuilder, CanonicalBuilder,
|
||||
Sema::CTAK_Specified, /*PartialOrdering=*/false,
|
||||
/*MatchedPackOnParmToNonPackOnArg=*/nullptr)) {
|
||||
Info.Param = makeTemplateParameter(
|
||||
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
|
||||
@@ -3283,7 +3284,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;
|
||||
|
||||
@@ -3383,10 +3386,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;
|
||||
|
||||
@@ -3451,7 +3454,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;
|
||||
|
||||
@@ -3989,7 +3994,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);
|
||||
@@ -4012,9 +4018,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;
|
||||
|
||||
@@ -4546,7 +4553,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;
|
||||
@@ -4761,7 +4769,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);
|
||||
});
|
||||
@@ -4873,9 +4882,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;
|
||||
@@ -5055,9 +5065,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;
|
||||
@@ -5634,7 +5645,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;
|
||||
@@ -6479,8 +6491,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
|
||||
@@ -6559,7 +6571,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 &&
|
||||
|
||||
@@ -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@-1 {{has different template parameters}}
|
||||
template <class...> struct A {};
|
||||
void test() { f(A<int>()); }
|
||||
// old-error@-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@-1 {{has different template parameters}}
|
||||
};
|
||||
template <class...> struct B {};
|
||||
void test() { A().f(B<int>()); }
|
||||
// old-error@-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@-1 {{different template parameters}}
|
||||
};
|
||||
template <class...> struct B {};
|
||||
// old-note@-1 2{{not viable}}
|
||||
void test() { B<int> b = A(); }
|
||||
// old-error@-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 {};
|
||||
|
||||
Reference in New Issue
Block a user