зеркало из https://github.com/microsoft/clang-1.git
When checking a template argument list against a template containing
a parameter pack, check the parameter pack against each of the template arguments it corresponds to, then pack the converted arguments into a template argument pack. Allows us to use variadic class templates so long as instantiation isn't required, e.g., template<typename... Types> struct Tuple; Tuple<int, float> *t2; git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122251 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
87dd697dcc
Коммит
14be16b939
|
@ -2377,30 +2377,40 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
|||
// a template-id shall match the type and form specified for the
|
||||
// corresponding parameter declared by the template in its
|
||||
// template-parameter-list.
|
||||
llvm::SmallVector<TemplateArgument, 2> ArgumentPack;
|
||||
TemplateParameterList::iterator Param = Params->begin(),
|
||||
ParamEnd = Params->end();
|
||||
unsigned ArgIdx = 0;
|
||||
for (TemplateParameterList::iterator Param = Params->begin(),
|
||||
ParamEnd = Params->end();
|
||||
Param != ParamEnd; ++Param, ++ArgIdx) {
|
||||
while (Param != ParamEnd) {
|
||||
if (ArgIdx > NumArgs && PartialTemplateArgs)
|
||||
break;
|
||||
|
||||
// If we have a template parameter pack, check every remaining template
|
||||
// argument against that template parameter pack.
|
||||
// FIXME: Variadic templates are unimplemented
|
||||
if ((*Param)->isTemplateParameterPack()) {
|
||||
Diag(TemplateLoc, diag::err_variadic_templates_unsupported);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ArgIdx < NumArgs) {
|
||||
// Check the template argument we were given.
|
||||
if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template,
|
||||
TemplateLoc, RAngleLoc, Converted))
|
||||
return true;
|
||||
|
||||
if ((*Param)->isTemplateParameterPack()) {
|
||||
// The template parameter was a template parameter pack, so take the
|
||||
// deduced argument and place it on the argument pack. Note that we
|
||||
// stay on the same template parameter so that we can deduce more
|
||||
// arguments.
|
||||
ArgumentPack.push_back(Converted.back());
|
||||
Converted.pop_back();
|
||||
} else {
|
||||
// Move to the next template parameter.
|
||||
++Param;
|
||||
}
|
||||
++ArgIdx;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we have a template parameter pack with no more corresponding
|
||||
// arguments, just break out now and we'll fill in the argument pack below.
|
||||
if ((*Param)->isTemplateParameterPack())
|
||||
break;
|
||||
|
||||
// We have a default template argument that we will use.
|
||||
TemplateArgumentLoc Arg;
|
||||
|
||||
|
@ -2475,8 +2485,31 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
|||
if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc,
|
||||
RAngleLoc, Converted))
|
||||
return true;
|
||||
|
||||
// Move to the next template parameter and argument.
|
||||
++Param;
|
||||
++ArgIdx;
|
||||
}
|
||||
|
||||
|
||||
// Form argument packs for each of the parameter packs remaining.
|
||||
while (Param != ParamEnd) {
|
||||
if ((*Param)->isTemplateParameterPack()) {
|
||||
// The parameter pack takes the contents of the current argument pack,
|
||||
// which we built up earlier.
|
||||
if (ArgumentPack.empty()) {
|
||||
Converted.push_back(TemplateArgument(0, 0));
|
||||
} else {
|
||||
TemplateArgument *PackedArgs
|
||||
= new (Context) TemplateArgument [ArgumentPack.size()];
|
||||
std::copy(ArgumentPack.begin(), ArgumentPack.end(), PackedArgs);
|
||||
Converted.push_back(TemplateArgument(PackedArgs, ArgumentPack.size()));
|
||||
ArgumentPack.clear();
|
||||
}
|
||||
}
|
||||
|
||||
++Param;
|
||||
}
|
||||
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
|
||||
|
||||
template<class ...Types> struct Tuple;
|
||||
|
||||
Tuple<> *t0;
|
||||
Tuple<int> *t1;
|
||||
Tuple<int, char> *t2a;
|
||||
Tuple<int, float> *t2b = t2a; // expected-error{{cannot initialize a variable of type 'Tuple<int, float> *' with an lvalue of type 'Tuple<int, char> *'}}
|
||||
Tuple<int, float, double> *t3;
|
Загрузка…
Ссылка в новой задаче