From aaa6a908acc365b0c1d8a130799f2ff5a276ffd4 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 4 Jan 2011 22:13:36 +0000 Subject: [PATCH] Improve the checking of deduced template arguments stored within template argument packs when finishing template argument deduction for a function template llvm-svn: 122843 --- clang/lib/Sema/SemaTemplateDeduction.cpp | 111 +++++++++++------- .../temp.decls/temp.variadic/deduction.cpp | 25 ++++ 2 files changed, 96 insertions(+), 40 deletions(-) create mode 100644 clang/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 99b6daceed92..82693dd228d6 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1677,6 +1677,55 @@ getTrivialTemplateArgumentLoc(Sema &S, return TemplateArgumentLoc(); } +/// \brief Convert the given deduced template argument and add it to the set of +/// fully-converted template arguments. +static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, + DeducedTemplateArgument Arg, + FunctionTemplateDecl *FunctionTemplate, + QualType NTTPType, + TemplateDeductionInfo &Info, + llvm::SmallVectorImpl &Output) { + if (Arg.getKind() == TemplateArgument::Pack) { + // This is a template argument pack, so check each of its arguments against + // the template parameter. + llvm::SmallVector PackedArgsBuilder; + for (TemplateArgument::pack_iterator PA = Arg.pack_begin(), + PAEnd = Arg.pack_end(); + PA != PAEnd; ++PA) { + DeducedTemplateArgument InnerArg(*PA); + InnerArg.setDeducedFromArrayBound(Arg.wasDeducedFromArrayBound()); + if (ConvertDeducedTemplateArgument(S, Param, InnerArg, FunctionTemplate, + NTTPType, Info, PackedArgsBuilder)) + return true; + } + + // Create the resulting argument pack. + TemplateArgument *PackedArgs = 0; + if (!PackedArgsBuilder.empty()) { + PackedArgs = new (S.Context) TemplateArgument[PackedArgsBuilder.size()]; + std::copy(PackedArgsBuilder.begin(), PackedArgsBuilder.end(), PackedArgs); + } + Output.push_back(TemplateArgument(PackedArgs, PackedArgsBuilder.size())); + return false; + } + + // Convert the deduced template argument into a template + // argument that we can check, almost as if the user had written + // the template argument explicitly. + TemplateArgumentLoc ArgLoc = getTrivialTemplateArgumentLoc(S, Arg, NTTPType, + Info.getLocation()); + + // Check the template argument, converting it as necessary. + return S.CheckTemplateArgument(Param, ArgLoc, + FunctionTemplate, + FunctionTemplate->getLocation(), + FunctionTemplate->getSourceRange().getEnd(), + Output, + Arg.wasDeducedFromArrayBound() + ? Sema::CTAK_DeducedFromArrayBound + : Sema::CTAK_Deduced); +} + /// \brief Finish template argument deduction for a function template, /// checking the deduced template arguments for completeness and forming /// the function template specialization. @@ -1708,9 +1757,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. llvm::SmallVector Builder; - for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { - // FIXME: Variadic templates. Unwrap argument packs? - NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I); + for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { + NamedDecl *Param = TemplateParams->getParam(I); if (!Deduced[I].isNull()) { if (I < NumExplicitlySpecified) { @@ -1730,49 +1778,32 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, QualType NTTPType; if (NonTypeTemplateParmDecl *NTTP = dyn_cast(Param)) { - if (Deduced[I].getKind() == TemplateArgument::Declaration) { - NTTPType = NTTP->getType(); - if (NTTPType->isDependentType()) { - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Builder.data(), Builder.size()); - NTTPType = SubstType(NTTPType, - MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), - NTTP->getDeclName()); - if (NTTPType.isNull()) { - Info.Param = makeTemplateParameter(Param); - // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(Context, - Builder.data(), - Builder.size())); - return TDK_SubstitutionFailure; - } + NTTPType = NTTP->getType(); + if (NTTPType->isDependentType()) { + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Builder.data(), Builder.size()); + NTTPType = SubstType(NTTPType, + MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), + NTTP->getDeclName()); + if (NTTPType.isNull()) { + Info.Param = makeTemplateParameter(Param); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(Context, + Builder.data(), + Builder.size())); + return TDK_SubstitutionFailure; } } } - // Convert the deduced template argument into a template - // argument that we can check, almost as if the user had written - // the template argument explicitly. - TemplateArgumentLoc Arg = getTrivialTemplateArgumentLoc(*this, - Deduced[I], - NTTPType, - Info.getLocation()); - - // Check the template argument, converting it as necessary. - if (CheckTemplateArgument(Param, Arg, - FunctionTemplate, - FunctionTemplate->getLocation(), - FunctionTemplate->getSourceRange().getEnd(), - Builder, - Deduced[I].wasDeducedFromArrayBound() - ? CTAK_DeducedFromArrayBound - : CTAK_Deduced)) { - Info.Param = makeTemplateParameter( - const_cast(TemplateParams->getParam(I))); + if (ConvertDeducedTemplateArgument(*this, Param, Deduced[I], + FunctionTemplate, NTTPType, Info, + Builder)) { + Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(), - Builder.size())); + Builder.size())); return TDK_SubstitutionFailure; } diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp new file mode 100644 index 000000000000..f26b656be959 --- /dev/null +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +namespace DeductionForInstantiation { + template + struct X { }; + + template + void f0(X) { } + + // No explicitly-specified arguments + template void f0(X<0>); + template void f0(X<1, int&>); + template void f0(X<2, int&, short&>); + + // One explicitly-specified argument + template void f0(X<1, float&>); + template void f0(X<1, double&>); + + // Two explicitly-specialized arguments + template void f0(X<2, char&, unsigned char&>); + template void f0(X<2, signed char&, char&>); + + // FIXME: Extension of explicitly-specified arguments + // template void f0(X<3, short&, int&, long&>); +}