From 1f5be4d5b6d7205e88a65f96cbbbf7cf943c0295 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 21 Dec 2016 01:10:31 +0000 Subject: [PATCH] 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 --- clang/lib/Sema/SemaTemplateDeduction.cpp | 283 +++++++++++++++---------------- 1 file changed, 135 insertions(+), 148 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index dc96d3f..06a2def 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -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 +static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( + Sema &S, TemplateDeclT *Template, + SmallVectorImpl &Deduced, + TemplateDeductionInfo &Info, SmallVectorImpl &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(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(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(Template); + if (!TD) { + assert(isa(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(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(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 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 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 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 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(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(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 -- 2.7.4