Factor out checking of template arguments after deduction into a separate

function. (This change would also allow us to handle default template arguments
in partial specializations if the standard ever permits them.)

llvm-svn: 290225
This commit is contained in:
Richard Smith 2016-12-21 01:10:31 +00:00
parent d9af48a931
commit 1f5be4d5b6
1 changed files with 135 additions and 148 deletions

View File

@ -2214,6 +2214,130 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
return ConvertArg(Arg, 0);
}
// FIXME: This should not be a template, but
// ClassTemplatePartialSpecializationDecl sadly does not derive from
// TemplateDecl.
template<typename TemplateDeclT>
static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
Sema &S, TemplateDeclT *Template,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info, SmallVectorImpl<TemplateArgument> &Builder,
LocalInstantiationScope *CurrentInstantiationScope = nullptr,
unsigned NumAlreadyConverted = 0, bool PartialOverloading = false) {
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
NamedDecl *Param = TemplateParams->getParam(I);
if (!Deduced[I].isNull()) {
if (I < NumAlreadyConverted) {
// We have already fully type-checked and converted this
// argument, because it was explicitly-specified. Just record the
// presence of this argument.
Builder.push_back(Deduced[I]);
// We may have had explicitly-specified template arguments for a
// template parameter pack (that may or may not have been extended
// via additional deduced arguments).
if (Param->isParameterPack() && CurrentInstantiationScope) {
if (CurrentInstantiationScope->getPartiallySubstitutedPack() ==
Param) {
// Forget the partially-substituted pack; its substitution is now
// complete.
CurrentInstantiationScope->ResetPartiallySubstitutedPack();
}
}
continue;
}
// We have deduced this argument, so it still needs to be
// checked and converted.
if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info,
isa<FunctionTemplateDecl>(Template),
Builder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
return Sema::TDK_SubstitutionFailure;
}
continue;
}
// C++0x [temp.arg.explicit]p3:
// A trailing template parameter pack (14.5.3) not otherwise deduced will
// be deduced to an empty sequence of template arguments.
// FIXME: Where did the word "trailing" come from?
if (Param->isTemplateParameterPack()) {
// We may have had explicitly-specified template arguments for this
// template parameter pack. If so, our empty deduction extends the
// explicitly-specified set (C++0x [temp.arg.explicit]p9).
const TemplateArgument *ExplicitArgs;
unsigned NumExplicitArgs;
if (CurrentInstantiationScope &&
CurrentInstantiationScope->getPartiallySubstitutedPack(
&ExplicitArgs, &NumExplicitArgs) == Param) {
Builder.push_back(TemplateArgument(
llvm::makeArrayRef(ExplicitArgs, NumExplicitArgs)));
// Forget the partially-substituted pack; its substitution is now
// complete.
CurrentInstantiationScope->ResetPartiallySubstitutedPack();
} else {
// Go through the motions of checking the empty argument pack against
// the parameter pack.
DeducedTemplateArgument DeducedPack(TemplateArgument::getEmptyPack());
if (ConvertDeducedTemplateArgument(
S, Param, DeducedPack, Template, Info,
isa<FunctionTemplateDecl>(Template), Builder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
return Sema::TDK_SubstitutionFailure;
}
}
continue;
}
// Substitute into the default template argument, if available.
bool HasDefaultArg = false;
TemplateDecl *TD = dyn_cast<TemplateDecl>(Template);
if (!TD) {
assert(isa<ClassTemplatePartialSpecializationDecl>(Template));
return Sema::TDK_Incomplete;
}
TemplateArgumentLoc DefArg = S.SubstDefaultTemplateArgumentIfAvailable(
TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, Builder,
HasDefaultArg);
// If there was no default argument, deduction is incomplete.
if (DefArg.getArgument().isNull()) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
if (PartialOverloading) break;
return HasDefaultArg ? Sema::TDK_SubstitutionFailure
: Sema::TDK_Incomplete;
}
// Check whether we can actually use the default argument.
if (S.CheckTemplateArgument(Param, DefArg, TD, TD->getLocation(),
TD->getSourceRange().getEnd(), 0, Builder,
Sema::CTAK_Specified)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
// FIXME: These template arguments are temporary. Free them!
Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
return Sema::TDK_SubstitutionFailure;
}
// If we get here, we successfully used the default template argument.
}
return Sema::TDK_Success;
}
/// Complete template argument deduction for a class template partial
/// specialization.
static Sema::TemplateDeductionResult
@ -2232,25 +2356,9 @@ FinishTemplateArgumentDeduction(Sema &S,
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
SmallVector<TemplateArgument, 4> Builder;
TemplateParameterList *PartialParams = Partial->getTemplateParameters();
for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) {
NamedDecl *Param = PartialParams->getParam(I);
if (Deduced[I].isNull()) {
Info.Param = makeTemplateParameter(Param);
return Sema::TDK_Incomplete;
}
// We have deduced this argument, so it still needs to be
// checked and converted.
if (ConvertDeducedTemplateArgument(S, Param, Deduced[I],
Partial, Info, false,
Builder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
return Sema::TDK_SubstitutionFailure;
}
}
if (auto Result = ConvertDeducedTemplateArguments(S, Partial, Deduced,
Info, Builder))
return Result;
// Form the template argument list from the deduced template arguments.
TemplateArgumentList *DeducedArgumentList
@ -2372,24 +2480,9 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
SmallVector<TemplateArgument, 4> Builder;
TemplateParameterList *PartialParams = Partial->getTemplateParameters();
for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) {
NamedDecl *Param = PartialParams->getParam(I);
if (Deduced[I].isNull()) {
Info.Param = makeTemplateParameter(Param);
return Sema::TDK_Incomplete;
}
// We have deduced this argument, so it still needs to be
// checked and converted.
if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Partial,
Info, false, Builder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
return Sema::TDK_SubstitutionFailure;
}
}
if (auto Result = ConvertDeducedTemplateArguments(S, Partial, Deduced,
Info, Builder))
return Result;
// Form the template argument list from the deduced template arguments.
TemplateArgumentList *DeducedArgumentList = TemplateArgumentList::CreateCopy(
@ -2819,9 +2912,6 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
TemplateDeductionInfo &Info,
SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
bool PartialOverloading) {
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
// Unevaluated SFINAE context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
SFINAETrap Trap(*this);
@ -2842,114 +2932,11 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
SmallVector<TemplateArgument, 4> Builder;
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
NamedDecl *Param = TemplateParams->getParam(I);
if (!Deduced[I].isNull()) {
if (I < NumExplicitlySpecified) {
// We have already fully type-checked and converted this
// argument, because it was explicitly-specified. Just record the
// presence of this argument.
Builder.push_back(Deduced[I]);
// We may have had explicitly-specified template arguments for a
// template parameter pack (that may or may not have been extended
// via additional deduced arguments).
if (Param->isParameterPack() && CurrentInstantiationScope) {
if (CurrentInstantiationScope->getPartiallySubstitutedPack() ==
Param) {
// Forget the partially-substituted pack; its substitution is now
// complete.
CurrentInstantiationScope->ResetPartiallySubstitutedPack();
}
}
continue;
}
// We have deduced this argument, so it still needs to be
// checked and converted.
if (ConvertDeducedTemplateArgument(*this, Param, Deduced[I],
FunctionTemplate, Info,
true, Builder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
return TDK_SubstitutionFailure;
}
continue;
}
// C++0x [temp.arg.explicit]p3:
// A trailing template parameter pack (14.5.3) not otherwise deduced will
// be deduced to an empty sequence of template arguments.
// FIXME: Where did the word "trailing" come from?
if (Param->isTemplateParameterPack()) {
// We may have had explicitly-specified template arguments for this
// template parameter pack. If so, our empty deduction extends the
// explicitly-specified set (C++0x [temp.arg.explicit]p9).
const TemplateArgument *ExplicitArgs;
unsigned NumExplicitArgs;
if (CurrentInstantiationScope &&
CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs,
&NumExplicitArgs)
== Param) {
Builder.push_back(TemplateArgument(
llvm::makeArrayRef(ExplicitArgs, NumExplicitArgs)));
// Forget the partially-substituted pack; its substitution is now
// complete.
CurrentInstantiationScope->ResetPartiallySubstitutedPack();
} else {
// Go through the motions of checking the empty argument pack against
// the parameter pack.
DeducedTemplateArgument DeducedPack(TemplateArgument::getEmptyPack());
if (ConvertDeducedTemplateArgument(*this, Param, DeducedPack,
FunctionTemplate, Info, true,
Builder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
return TDK_SubstitutionFailure;
}
}
continue;
}
// Substitute into the default template argument, if available.
bool HasDefaultArg = false;
TemplateArgumentLoc DefArg
= SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate,
FunctionTemplate->getLocation(),
FunctionTemplate->getSourceRange().getEnd(),
Param,
Builder, HasDefaultArg);
// If there was no default argument, deduction is incomplete.
if (DefArg.getArgument().isNull()) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
if (PartialOverloading) break;
return HasDefaultArg ? TDK_SubstitutionFailure : TDK_Incomplete;
}
// Check whether we can actually use the default argument.
if (CheckTemplateArgument(Param, DefArg,
FunctionTemplate,
FunctionTemplate->getLocation(),
FunctionTemplate->getSourceRange().getEnd(),
0, Builder,
CTAK_Specified)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
// FIXME: These template arguments are temporary. Free them!
Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
return TDK_SubstitutionFailure;
}
// If we get here, we successfully used the default template argument.
}
if (auto Result = ConvertDeducedTemplateArguments(
*this, FunctionTemplate, Deduced, Info, Builder,
CurrentInstantiationScope, NumExplicitlySpecified,
PartialOverloading))
return Result;
// Form the template argument list from the deduced template arguments.
TemplateArgumentList *DeducedArgumentList