зеркало из https://github.com/microsoft/clang-1.git
Implicitly expand argument packs when performing template argument
deduction. Unify all of the looping over template arguments for deduction purposes into a single place, where argument pack expansion occurs; this is also the hook for deducing from pack expansions, which itself is not yet implemented. For now, at least we can handle a basic "count" metafunction written with variadics. See the new test for the formulation that works. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122418 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
250704bc52
Коммит
20a55e2515
|
@ -1861,12 +1861,15 @@ def err_pack_expansion_length_conflict : Error<
|
|||
"pack expansion contains parameter packs %0 and %1 that have different "
|
||||
"lengths (%2 vs. %3)">;
|
||||
|
||||
// Unsupported variadic templates features
|
||||
def err_pack_expansion_unsupported : Error<
|
||||
"clang does not yet support %select{non-type|template}0 pack expansions">;
|
||||
def err_pack_expansion_instantiation_unsupported : Error<
|
||||
"clang cannot yet instantiate pack expansions">;
|
||||
def err_pack_expansion_mismatch_unsupported : Error<
|
||||
"clang cannot yet instantiate pack expansions with mismatched pack levels">;
|
||||
def err_pack_expansion_deduction : Error<
|
||||
"clang cannot yet perform template argument deduction for a pack expansion">;
|
||||
|
||||
def err_unexpected_typedef : Error<
|
||||
"unexpected type name %0: expected expression">;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "clang/Sema/Sema.h"
|
||||
#include "clang/Sema/DeclSpec.h"
|
||||
#include "clang/Sema/SemaDiagnostic.h" // FIXME: temporary!
|
||||
#include "clang/Sema/Template.h"
|
||||
#include "clang/Sema/TemplateDeduction.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
|
@ -82,6 +83,14 @@ DeduceTemplateArguments(Sema &S,
|
|||
TemplateDeductionInfo &Info,
|
||||
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced);
|
||||
|
||||
static Sema::TemplateDeductionResult
|
||||
DeduceTemplateArguments(Sema &S,
|
||||
TemplateParameterList *TemplateParams,
|
||||
const TemplateArgument *Params, unsigned NumParams,
|
||||
const TemplateArgument *Args, unsigned NumArgs,
|
||||
TemplateDeductionInfo &Info,
|
||||
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced);
|
||||
|
||||
/// \brief If the given expression is of a form that permits the deduction
|
||||
/// of a non-type template parameter, return the declaration of that
|
||||
/// non-type template parameter.
|
||||
|
@ -301,16 +310,13 @@ DeduceTemplateArguments(Sema &S,
|
|||
|
||||
// Perform template argument deduction on each template
|
||||
// argument.
|
||||
// FIXME: This "min" function isn't going to work in general. We should
|
||||
// probably pass down a flag that allows too few/too many arguments.
|
||||
unsigned NumArgs = std::min(SpecArg->getNumArgs(), Param->getNumArgs());
|
||||
for (unsigned I = 0; I != NumArgs; ++I)
|
||||
if (Sema::TemplateDeductionResult Result
|
||||
= DeduceTemplateArguments(S, TemplateParams,
|
||||
Param->getArg(I),
|
||||
SpecArg->getArg(I),
|
||||
Info, Deduced))
|
||||
return Result;
|
||||
|
||||
return Sema::TDK_Success;
|
||||
return DeduceTemplateArguments(S, TemplateParams,
|
||||
Param->getArgs(), NumArgs,
|
||||
SpecArg->getArgs(), NumArgs,
|
||||
Info, Deduced);
|
||||
}
|
||||
|
||||
// If the argument type is a class template specialization, we
|
||||
|
@ -334,20 +340,12 @@ DeduceTemplateArguments(Sema &S,
|
|||
Info, Deduced))
|
||||
return Result;
|
||||
|
||||
unsigned NumArgs = Param->getNumArgs();
|
||||
const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs();
|
||||
if (NumArgs != ArgArgs.size())
|
||||
return Sema::TDK_NonDeducedMismatch;
|
||||
|
||||
for (unsigned I = 0; I != NumArgs; ++I)
|
||||
if (Sema::TemplateDeductionResult Result
|
||||
= DeduceTemplateArguments(S, TemplateParams,
|
||||
Param->getArg(I),
|
||||
ArgArgs.get(I),
|
||||
Info, Deduced))
|
||||
return Result;
|
||||
|
||||
return Sema::TDK_Success;
|
||||
// Perform template argument deduction for the template arguments.
|
||||
return DeduceTemplateArguments(S, TemplateParams,
|
||||
Param->getArgs(), Param->getNumArgs(),
|
||||
SpecArg->getTemplateArgs().data(),
|
||||
SpecArg->getTemplateArgs().size(),
|
||||
Info, Deduced);
|
||||
}
|
||||
|
||||
/// \brief Determines whether the given type is an opaque type that
|
||||
|
@ -664,6 +662,7 @@ DeduceTemplateArguments(Sema &S,
|
|||
|
||||
for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) {
|
||||
// Check argument types.
|
||||
// FIXME: Variadic templates.
|
||||
if (Sema::TemplateDeductionResult Result
|
||||
= DeduceTemplateArguments(S, TemplateParams,
|
||||
FunctionProtoParam->getArgType(I),
|
||||
|
@ -917,14 +916,81 @@ DeduceTemplateArguments(Sema &S,
|
|||
return Sema::TDK_Success;
|
||||
}
|
||||
case TemplateArgument::Pack:
|
||||
// FIXME: Variadic templates
|
||||
assert(0 && "FIXME: Implement!");
|
||||
break;
|
||||
llvm_unreachable("Argument packs should be expanded by the caller!");
|
||||
}
|
||||
|
||||
return Sema::TDK_Success;
|
||||
}
|
||||
|
||||
/// \brief Determine whether there is a template argument to be used for
|
||||
/// deduction.
|
||||
///
|
||||
/// This routine "expands" argument packs in-place, overriding its input
|
||||
/// parameters so that \c Args[ArgIdx] will be the available template argument.
|
||||
///
|
||||
/// \returns true if there is another template argument (which will be at
|
||||
/// \c Args[ArgIdx]), false otherwise.
|
||||
static bool hasTemplateArgumentForDeduction(const TemplateArgument *&Args,
|
||||
unsigned &ArgIdx,
|
||||
unsigned &NumArgs) {
|
||||
if (ArgIdx == NumArgs)
|
||||
return false;
|
||||
|
||||
const TemplateArgument &Arg = Args[ArgIdx];
|
||||
if (Arg.getKind() != TemplateArgument::Pack)
|
||||
return true;
|
||||
|
||||
assert(ArgIdx == NumArgs - 1 && "Pack not at the end of argument list?");
|
||||
Args = Arg.pack_begin();
|
||||
NumArgs = Arg.pack_size();
|
||||
ArgIdx = 0;
|
||||
return ArgIdx < NumArgs;
|
||||
}
|
||||
|
||||
static Sema::TemplateDeductionResult
|
||||
DeduceTemplateArguments(Sema &S,
|
||||
TemplateParameterList *TemplateParams,
|
||||
const TemplateArgument *Params, unsigned NumParams,
|
||||
const TemplateArgument *Args, unsigned NumArgs,
|
||||
TemplateDeductionInfo &Info,
|
||||
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
|
||||
unsigned ArgIdx = 0, ParamIdx = 0;
|
||||
for (; hasTemplateArgumentForDeduction(Params, ParamIdx, NumParams);
|
||||
++ParamIdx) {
|
||||
if (!Params[ParamIdx].isPackExpansion()) {
|
||||
// The simple case: deduce template arguments by matching P and A.
|
||||
|
||||
// Check whether we have enough arguments.
|
||||
if (!hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs))
|
||||
return Sema::TDK_TooFewArguments;
|
||||
|
||||
// Perform deduction for this P/A pair.
|
||||
if (Sema::TemplateDeductionResult Result
|
||||
= DeduceTemplateArguments(S, TemplateParams,
|
||||
Params[ParamIdx], Args[ArgIdx],
|
||||
Info, Deduced))
|
||||
return Result;
|
||||
|
||||
// Move to the next argument.
|
||||
++ArgIdx;
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME: Variadic templates.
|
||||
// The parameter is a pack expansion, so we'll
|
||||
// need to repeatedly unify arguments against the parameter, capturing
|
||||
// the bindings for each expanded parameter pack.
|
||||
S.Diag(Info.getLocation(), diag::err_pack_expansion_deduction);
|
||||
return Sema::TDK_TooManyArguments;
|
||||
}
|
||||
|
||||
// If there is an argument remaining, then we had too many arguments.
|
||||
if (hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs))
|
||||
return Sema::TDK_TooManyArguments;
|
||||
|
||||
return Sema::TDK_Success;
|
||||
}
|
||||
|
||||
static Sema::TemplateDeductionResult
|
||||
DeduceTemplateArguments(Sema &S,
|
||||
TemplateParameterList *TemplateParams,
|
||||
|
@ -932,15 +998,10 @@ DeduceTemplateArguments(Sema &S,
|
|||
const TemplateArgumentList &ArgList,
|
||||
TemplateDeductionInfo &Info,
|
||||
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
|
||||
assert(ParamList.size() == ArgList.size());
|
||||
for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
|
||||
if (Sema::TemplateDeductionResult Result
|
||||
= DeduceTemplateArguments(S, TemplateParams,
|
||||
ParamList[I], ArgList[I],
|
||||
Info, Deduced))
|
||||
return Result;
|
||||
}
|
||||
return Sema::TDK_Success;
|
||||
return DeduceTemplateArguments(S, TemplateParams,
|
||||
ParamList.data(), ParamList.size(),
|
||||
ArgList.data(), ArgList.size(),
|
||||
Info, Deduced);
|
||||
}
|
||||
|
||||
/// \brief Determine whether two template arguments are the same.
|
||||
|
@ -1087,6 +1148,7 @@ FinishTemplateArgumentDeduction(Sema &S,
|
|||
// When the argument is an expression, check the expression result
|
||||
// against the actual template parameter to get down to the canonical
|
||||
// template argument.
|
||||
// FIXME: Variadic templates.
|
||||
Expr *InstExpr = InstArg.getAsExpr();
|
||||
if (NonTypeTemplateParmDecl *NTTP
|
||||
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
|
||||
|
@ -1301,6 +1363,8 @@ Sema::SubstituteExplicitTemplateArguments(
|
|||
//
|
||||
// Take all of the explicitly-specified arguments and put them into the
|
||||
// set of deduced template arguments.
|
||||
//
|
||||
// FIXME: Variadic templates?
|
||||
Deduced.reserve(TemplateParams->size());
|
||||
for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I)
|
||||
Deduced.push_back(ExplicitArgumentList->get(I));
|
||||
|
@ -1394,6 +1458,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
|
|||
// 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);
|
||||
if (!Deduced[I].isNull()) {
|
||||
if (I < NumExplicitlySpecified) {
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
|
||||
|
||||
template<typename Head, typename ...Tail>
|
||||
struct count {
|
||||
static const unsigned value = 1 + count<Tail...>::value;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct count<T> {
|
||||
static const unsigned value = 1;
|
||||
};
|
||||
|
||||
int check1[count<int>::value == 1? 1 : -1];
|
||||
int check2[count<float, double>::value == 2? 1 : -1];
|
||||
int check3[count<char, signed char, unsigned char>::value == 3? 1 : -1];
|
||||
|
||||
|
Загрузка…
Ссылка в новой задаче