Improve the checking of deduced template arguments stored within template argument packs when finishing template argument deduction for a function template

llvm-svn: 122843
This commit is contained in:
Douglas Gregor 2011-01-04 22:13:36 +00:00
parent 87f457057f
commit aaa6a908ac
2 changed files with 96 additions and 40 deletions

View File

@ -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<TemplateArgument> &Output) {
if (Arg.getKind() == TemplateArgument::Pack) {
// This is a template argument pack, so check each of its arguments against
// the template parameter.
llvm::SmallVector<TemplateArgument, 2> 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<TemplateArgument, 4> 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<NonTypeTemplateParmDecl>(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<NamedDecl *>(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;
}

View File

@ -0,0 +1,25 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
namespace DeductionForInstantiation {
template<unsigned I, typename ...Types>
struct X { };
template<typename ...Types>
void f0(X<sizeof...(Types), Types&...>) { }
// 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<float>(X<1, float&>);
template void f0<double>(X<1, double&>);
// Two explicitly-specialized arguments
template void f0<char, unsigned char>(X<2, char&, unsigned char&>);
template void f0<signed char, char>(X<2, signed char&, char&>);
// FIXME: Extension of explicitly-specified arguments
// template void f0<short, int>(X<3, short&, int&, long&>);
}