forked from OSchip/llvm-project
Initial implementation of function parameter packs. This implementation allows:
1) Declaration of function parameter packs 2) Instantiation of function parameter packs within function types. 3) Template argument deduction of function parameter packs when matching two function types. We're missing all of the important template-instantiation logic for function template definitions, along with template argument deduction from the argument list of a function call, so don't even think of trying to use these for real yet. llvm-svn: 122926
This commit is contained in:
parent
260acf32ee
commit
5499af4ef9
|
@ -1877,8 +1877,6 @@ def err_sizeof_pack_no_pack_name : Error<
|
|||
// Unsupported variadic templates features
|
||||
def err_pack_expansion_mismatch_unsupported : Error<
|
||||
"clang cannot yet instantiate pack expansions with mismatched pack levels">;
|
||||
def err_function_parameter_pack_unsupported : Error<
|
||||
"clang does not yet support function parameter packs">;
|
||||
|
||||
def err_unexpected_typedef : Error<
|
||||
"unexpected type name %0: expected expression">;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "clang/AST/OperationKinds.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/ExternalASTSource.h"
|
||||
#include "clang/AST/TypeLoc.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "clang/Basic/TemplateKinds.h"
|
||||
#include "clang/Basic/TypeTraits.h"
|
||||
|
@ -3879,6 +3880,10 @@ public:
|
|||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
SourceLocation Loc, DeclarationName Entity);
|
||||
|
||||
TypeSourceInfo *SubstType(TypeLoc TL,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
SourceLocation Loc, DeclarationName Entity);
|
||||
|
||||
TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
SourceLocation Loc,
|
||||
|
|
|
@ -4986,12 +4986,6 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
|
|||
<< D.getCXXScopeSpec().getRange();
|
||||
D.getCXXScopeSpec().clear();
|
||||
}
|
||||
|
||||
// FIXME: Variadic templates.
|
||||
if (D.hasEllipsis()) {
|
||||
Diag(D.getEllipsisLoc(), diag::err_function_parameter_pack_unsupported);
|
||||
D.setInvalidType();
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we have a valid name
|
||||
|
|
|
@ -84,6 +84,15 @@ DeduceTemplateArguments(Sema &S,
|
|||
TemplateDeductionInfo &Info,
|
||||
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced);
|
||||
|
||||
static Sema::TemplateDeductionResult
|
||||
DeduceTemplateArguments(Sema &S,
|
||||
TemplateParameterList *TemplateParams,
|
||||
QualType Param,
|
||||
QualType Arg,
|
||||
TemplateDeductionInfo &Info,
|
||||
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
|
||||
unsigned TDF);
|
||||
|
||||
static Sema::TemplateDeductionResult
|
||||
DeduceTemplateArguments(Sema &S,
|
||||
TemplateParameterList *TemplateParams,
|
||||
|
@ -469,6 +478,209 @@ static bool IsPossiblyOpaquelyQualifiedType(QualType T) {
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief Retrieve the depth and index of an unexpanded parameter pack.
|
||||
static std::pair<unsigned, unsigned>
|
||||
getDepthAndIndex(UnexpandedParameterPack UPP) {
|
||||
if (const TemplateTypeParmType *TTP
|
||||
= UPP.first.dyn_cast<const TemplateTypeParmType *>())
|
||||
return std::make_pair(TTP->getDepth(), TTP->getIndex());
|
||||
|
||||
NamedDecl *ND = UPP.first.get<NamedDecl *>();
|
||||
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
|
||||
return std::make_pair(TTP->getDepth(), TTP->getIndex());
|
||||
|
||||
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
|
||||
return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
|
||||
|
||||
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
|
||||
return std::make_pair(TTP->getDepth(), TTP->getIndex());
|
||||
}
|
||||
|
||||
/// \brief Helper function to build a TemplateParameter when we don't
|
||||
/// know its type statically.
|
||||
static TemplateParameter makeTemplateParameter(Decl *D) {
|
||||
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D))
|
||||
return TemplateParameter(TTP);
|
||||
else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
|
||||
return TemplateParameter(NTTP);
|
||||
|
||||
return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
|
||||
}
|
||||
|
||||
/// \brief Deduce the template arguments by comparing the list of parameter
|
||||
/// types to the list of argument types, as in the parameter-type-lists of
|
||||
/// function types (C++ [temp.deduct.type]p10).
|
||||
///
|
||||
/// \param S The semantic analysis object within which we are deducing
|
||||
///
|
||||
/// \param TemplateParams The template parameters that we are deducing
|
||||
///
|
||||
/// \param Params The list of parameter types
|
||||
///
|
||||
/// \param NumParams The number of types in \c Params
|
||||
///
|
||||
/// \param Args The list of argument types
|
||||
///
|
||||
/// \param NumArgs The number of types in \c Args
|
||||
///
|
||||
/// \param Info information about the template argument deduction itself
|
||||
///
|
||||
/// \param Deduced the deduced template arguments
|
||||
///
|
||||
/// \param TDF bitwise OR of the TemplateDeductionFlags bits that describe
|
||||
/// how template argument deduction is performed.
|
||||
///
|
||||
/// \returns the result of template argument deduction so far. Note that a
|
||||
/// "success" result means that template argument deduction has not yet failed,
|
||||
/// but it may still fail, later, for other reasons.
|
||||
static Sema::TemplateDeductionResult
|
||||
DeduceTemplateArguments(Sema &S,
|
||||
TemplateParameterList *TemplateParams,
|
||||
const QualType *Params, unsigned NumParams,
|
||||
const QualType *Args, unsigned NumArgs,
|
||||
TemplateDeductionInfo &Info,
|
||||
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
|
||||
unsigned TDF) {
|
||||
// FIXME: Fast-path check with NumParams != NumArgs and there are no
|
||||
// pack expansions around.
|
||||
|
||||
// C++0x [temp.deduct.type]p10:
|
||||
// Similarly, if P has a form that contains (T), then each parameter type
|
||||
// Pi of the respective parameter-type- list of P is compared with the
|
||||
// corresponding parameter type Ai of the corresponding parameter-type-list
|
||||
// of A. [...]
|
||||
unsigned ArgIdx = 0, ParamIdx = 0;
|
||||
for (; ParamIdx != NumParams; ++ParamIdx) {
|
||||
// Check argument types.
|
||||
const PackExpansionType *Expansion
|
||||
= dyn_cast<PackExpansionType>(Params[ParamIdx]);
|
||||
if (!Expansion) {
|
||||
// Simple case: compare the parameter and argument types at this point.
|
||||
|
||||
// Make sure we have an argument.
|
||||
if (ArgIdx >= NumArgs)
|
||||
return Sema::TDK_TooFewArguments;
|
||||
|
||||
if (Sema::TemplateDeductionResult Result
|
||||
= DeduceTemplateArguments(S, TemplateParams,
|
||||
Params[ParamIdx],
|
||||
Args[ArgIdx],
|
||||
Info, Deduced, TDF))
|
||||
return Result;
|
||||
|
||||
++ArgIdx;
|
||||
continue;
|
||||
}
|
||||
|
||||
// C++0x [temp.deduct.type]p10:
|
||||
// If the parameter-declaration corresponding to Pi is a function
|
||||
// parameter pack, then the type of its declarator- id is compared with
|
||||
// each remaining parameter type in the parameter-type-list of A. Each
|
||||
// comparison deduces template arguments for subsequent positions in the
|
||||
// template parameter packs expanded by the function parameter pack.
|
||||
|
||||
// Compute the set of template parameter indices that correspond to
|
||||
// parameter packs expanded by the pack expansion.
|
||||
llvm::SmallVector<unsigned, 2> PackIndices;
|
||||
QualType Pattern = Expansion->getPattern();
|
||||
{
|
||||
llvm::BitVector SawIndices(TemplateParams->size());
|
||||
llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
|
||||
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
|
||||
unsigned Depth, Index;
|
||||
llvm::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
|
||||
if (Depth == 0 && !SawIndices[Index]) {
|
||||
SawIndices[Index] = true;
|
||||
PackIndices.push_back(Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?");
|
||||
|
||||
// Save the deduced template arguments for each parameter pack expanded
|
||||
// by this pack expansion, then clear out the deduction.
|
||||
llvm::SmallVector<DeducedTemplateArgument, 2>
|
||||
SavedPacks(PackIndices.size());
|
||||
for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
|
||||
SavedPacks[I] = Deduced[PackIndices[I]];
|
||||
Deduced[PackIndices[I]] = DeducedTemplateArgument();
|
||||
}
|
||||
|
||||
// Keep track of the deduced template arguments for each parameter pack
|
||||
// expanded by this pack expansion (the outer index) and for each
|
||||
// template argument (the inner SmallVectors).
|
||||
llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2>
|
||||
NewlyDeducedPacks(PackIndices.size());
|
||||
bool HasAnyArguments = false;
|
||||
for (; ArgIdx < NumArgs; ++ArgIdx) {
|
||||
HasAnyArguments = true;
|
||||
|
||||
// Deduce template arguments from the pattern.
|
||||
if (Sema::TemplateDeductionResult Result
|
||||
= DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx],
|
||||
Info, Deduced))
|
||||
return Result;
|
||||
|
||||
// Capture the deduced template arguments for each parameter pack expanded
|
||||
// by this pack expansion, add them to the list of arguments we've deduced
|
||||
// for that pack, then clear out the deduced argument.
|
||||
for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
|
||||
DeducedTemplateArgument &DeducedArg = Deduced[PackIndices[I]];
|
||||
if (!DeducedArg.isNull()) {
|
||||
NewlyDeducedPacks[I].push_back(DeducedArg);
|
||||
DeducedArg = DeducedTemplateArgument();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build argument packs for each of the parameter packs expanded by this
|
||||
// pack expansion.
|
||||
for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
|
||||
if (HasAnyArguments && NewlyDeducedPacks[I].empty()) {
|
||||
// We were not able to deduce anything for this parameter pack,
|
||||
// so just restore the saved argument pack.
|
||||
Deduced[PackIndices[I]] = SavedPacks[I];
|
||||
continue;
|
||||
}
|
||||
|
||||
DeducedTemplateArgument NewPack;
|
||||
|
||||
if (NewlyDeducedPacks[I].empty()) {
|
||||
// If we deduced an empty argument pack, create it now.
|
||||
NewPack = DeducedTemplateArgument(TemplateArgument(0, 0));
|
||||
} else {
|
||||
TemplateArgument *ArgumentPack
|
||||
= new (S.Context) TemplateArgument [NewlyDeducedPacks[I].size()];
|
||||
std::copy(NewlyDeducedPacks[I].begin(), NewlyDeducedPacks[I].end(),
|
||||
ArgumentPack);
|
||||
NewPack
|
||||
= DeducedTemplateArgument(TemplateArgument(ArgumentPack,
|
||||
NewlyDeducedPacks[I].size()),
|
||||
NewlyDeducedPacks[I][0].wasDeducedFromArrayBound());
|
||||
}
|
||||
|
||||
DeducedTemplateArgument Result
|
||||
= checkDeducedTemplateArguments(S.Context, SavedPacks[I], NewPack);
|
||||
if (Result.isNull()) {
|
||||
Info.Param
|
||||
= makeTemplateParameter(TemplateParams->getParam(PackIndices[I]));
|
||||
Info.FirstArg = SavedPacks[I];
|
||||
Info.SecondArg = NewPack;
|
||||
return Sema::TDK_Inconsistent;
|
||||
}
|
||||
|
||||
Deduced[PackIndices[I]] = Result;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we don't have any extra arguments.
|
||||
if (ArgIdx < NumArgs)
|
||||
return Sema::TDK_TooManyArguments;
|
||||
|
||||
return Sema::TDK_Success;
|
||||
}
|
||||
|
||||
/// \brief Deduce the template arguments by comparing the parameter type and
|
||||
/// the argument type (C++ [temp.deduct.type]).
|
||||
///
|
||||
|
@ -740,9 +952,6 @@ DeduceTemplateArguments(Sema &S,
|
|||
FunctionProtoArg->getTypeQuals())
|
||||
return Sema::TDK_NonDeducedMismatch;
|
||||
|
||||
if (FunctionProtoParam->getNumArgs() != FunctionProtoArg->getNumArgs())
|
||||
return Sema::TDK_NonDeducedMismatch;
|
||||
|
||||
if (FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic())
|
||||
return Sema::TDK_NonDeducedMismatch;
|
||||
|
||||
|
@ -754,18 +963,12 @@ DeduceTemplateArguments(Sema &S,
|
|||
Info, Deduced, 0))
|
||||
return Result;
|
||||
|
||||
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),
|
||||
FunctionProtoArg->getArgType(I),
|
||||
Info, Deduced, 0))
|
||||
return Result;
|
||||
}
|
||||
|
||||
return Sema::TDK_Success;
|
||||
return DeduceTemplateArguments(S, TemplateParams,
|
||||
FunctionProtoParam->arg_type_begin(),
|
||||
FunctionProtoParam->getNumArgs(),
|
||||
FunctionProtoArg->arg_type_begin(),
|
||||
FunctionProtoArg->getNumArgs(),
|
||||
Info, Deduced, 0);
|
||||
}
|
||||
|
||||
case Type::InjectedClassName: {
|
||||
|
@ -1045,35 +1248,6 @@ static bool hasTemplateArgumentForDeduction(const TemplateArgument *&Args,
|
|||
return ArgIdx < NumArgs;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the depth and index of an unexpanded parameter pack.
|
||||
static std::pair<unsigned, unsigned>
|
||||
getDepthAndIndex(UnexpandedParameterPack UPP) {
|
||||
if (const TemplateTypeParmType *TTP
|
||||
= UPP.first.dyn_cast<const TemplateTypeParmType *>())
|
||||
return std::make_pair(TTP->getDepth(), TTP->getIndex());
|
||||
|
||||
NamedDecl *ND = UPP.first.get<NamedDecl *>();
|
||||
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
|
||||
return std::make_pair(TTP->getDepth(), TTP->getIndex());
|
||||
|
||||
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
|
||||
return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
|
||||
|
||||
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
|
||||
return std::make_pair(TTP->getDepth(), TTP->getIndex());
|
||||
}
|
||||
|
||||
/// \brief Helper function to build a TemplateParameter when we don't
|
||||
/// know its type statically.
|
||||
static TemplateParameter makeTemplateParameter(Decl *D) {
|
||||
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D))
|
||||
return TemplateParameter(TTP);
|
||||
else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
|
||||
return TemplateParameter(NTTP);
|
||||
|
||||
return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
|
||||
}
|
||||
|
||||
/// \brief Determine whether the given set of template arguments has a pack
|
||||
/// expansion that is not the last template argument.
|
||||
static bool hasPackExpansionBeforeEnd(const TemplateArgument *Args,
|
||||
|
|
|
@ -1052,6 +1052,36 @@ TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
|
|||
return Instantiator.TransformType(T);
|
||||
}
|
||||
|
||||
TypeSourceInfo *Sema::SubstType(TypeLoc TL,
|
||||
const MultiLevelTemplateArgumentList &Args,
|
||||
SourceLocation Loc,
|
||||
DeclarationName Entity) {
|
||||
assert(!ActiveTemplateInstantiations.empty() &&
|
||||
"Cannot perform an instantiation without some context on the "
|
||||
"instantiation stack");
|
||||
|
||||
if (TL.getType().isNull())
|
||||
return 0;
|
||||
|
||||
if (!TL.getType()->isDependentType() &&
|
||||
!TL.getType()->isVariablyModifiedType()) {
|
||||
// FIXME: Make a copy of the TypeLoc data here, so that we can
|
||||
// return a new TypeSourceInfo. Inefficient!
|
||||
TypeLocBuilder TLB;
|
||||
TLB.pushFullCopy(TL);
|
||||
return TLB.getTypeSourceInfo(Context, TL.getType());
|
||||
}
|
||||
|
||||
TemplateInstantiator Instantiator(*this, Args, Loc, Entity);
|
||||
TypeLocBuilder TLB;
|
||||
TLB.reserve(TL.getFullDataSize());
|
||||
QualType Result = Instantiator.TransformType(TLB, TL);
|
||||
if (Result.isNull())
|
||||
return 0;
|
||||
|
||||
return TLB.getTypeSourceInfo(Context, Result);
|
||||
}
|
||||
|
||||
/// Deprecated form of the above.
|
||||
QualType Sema::SubstType(QualType T,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
|
@ -1122,8 +1152,34 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
|
|||
ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
||||
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
|
||||
TypeSourceInfo *NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(),
|
||||
OldParm->getDeclName());
|
||||
TypeSourceInfo *NewDI = 0;
|
||||
|
||||
bool WasParameterPack = false;
|
||||
bool IsParameterPack = false;
|
||||
TypeLoc OldTL = OldDI->getTypeLoc();
|
||||
if (isa<PackExpansionTypeLoc>(OldTL)) {
|
||||
PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(OldTL);
|
||||
WasParameterPack = true;
|
||||
|
||||
// We have a function parameter pack. Substitute into the pattern of the
|
||||
// expansion.
|
||||
NewDI = SubstType(ExpansionTL.getPatternLoc(), TemplateArgs,
|
||||
OldParm->getLocation(), OldParm->getDeclName());
|
||||
if (!NewDI)
|
||||
return 0;
|
||||
|
||||
if (NewDI->getType()->containsUnexpandedParameterPack()) {
|
||||
// We still have unexpanded parameter packs, which means that
|
||||
// our function parameter is still a function parameter pack.
|
||||
// Therefore, make its type a pack expansion type.
|
||||
NewDI = CheckPackExpansion(NewDI, ExpansionTL.getEllipsisLoc());
|
||||
IsParameterPack = true;
|
||||
}
|
||||
} else {
|
||||
NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(),
|
||||
OldParm->getDeclName());
|
||||
}
|
||||
|
||||
if (!NewDI)
|
||||
return 0;
|
||||
|
||||
|
@ -1153,7 +1209,11 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
|
|||
|
||||
NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
|
||||
|
||||
CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);
|
||||
// FIXME: When OldParm is a parameter pack and NewParm is not a parameter
|
||||
// pack, we actually have a set of instantiated locations. Maintain this set!
|
||||
if (!WasParameterPack || IsParameterPack)
|
||||
CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);
|
||||
|
||||
// FIXME: OldParm may come from a FunctionProtoType, in which case CurContext
|
||||
// can be anything, is this right ?
|
||||
NewParm->setDeclContext(CurContext);
|
||||
|
|
|
@ -3396,34 +3396,128 @@ bool TreeTransform<Derived>::
|
|||
FunctionProtoType *T = TL.getTypePtr();
|
||||
|
||||
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) {
|
||||
ParmVarDecl *OldParm = TL.getArg(i);
|
||||
if (ParmVarDecl *OldParm = TL.getArg(i)) {
|
||||
if (OldParm->isParameterPack()) {
|
||||
// We have a function parameter pack that may need to be expanded.
|
||||
llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
|
||||
QualType NewType;
|
||||
ParmVarDecl *NewParm;
|
||||
|
||||
if (OldParm) {
|
||||
NewParm = getDerived().TransformFunctionTypeParam(OldParm);
|
||||
// Find the parameter packs that could be expanded.
|
||||
SourceLocation EllipsisLoc;
|
||||
SourceRange PatternRange;
|
||||
if (OldParm->getTypeSourceInfo()) {
|
||||
TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc();
|
||||
PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(TL);
|
||||
TypeLoc Pattern = ExpansionTL.getPatternLoc();
|
||||
EllipsisLoc = ExpansionTL.getEllipsisLoc();
|
||||
PatternRange = Pattern.getSourceRange();
|
||||
SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
|
||||
} else {
|
||||
SemaRef.collectUnexpandedParameterPacks(
|
||||
cast<PackExpansionType>(OldParm->getType())->getPattern(),
|
||||
Unexpanded);
|
||||
EllipsisLoc = OldParm->getLocation();
|
||||
}
|
||||
|
||||
// Determine whether we should expand the parameter packs.
|
||||
bool ShouldExpand = false;
|
||||
unsigned NumExpansions = 0;
|
||||
if (getDerived().TryExpandParameterPacks(EllipsisLoc, PatternRange,
|
||||
Unexpanded.data(),
|
||||
Unexpanded.size(),
|
||||
ShouldExpand, NumExpansions)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ShouldExpand) {
|
||||
// Expand the function parameter pack into multiple, separate
|
||||
// parameters.
|
||||
for (unsigned I = 0; I != NumExpansions; ++I) {
|
||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
|
||||
ParmVarDecl *NewParm
|
||||
= getDerived().TransformFunctionTypeParam(OldParm);
|
||||
if (!NewParm)
|
||||
return true;
|
||||
|
||||
PTypes.push_back(NewParm->getType());
|
||||
PVars.push_back(NewParm);
|
||||
}
|
||||
|
||||
// We're done with the pack expansion.
|
||||
continue;
|
||||
}
|
||||
|
||||
// We'll substitute the parameter now without expanding the pack
|
||||
// expansion.
|
||||
}
|
||||
|
||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
|
||||
ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm);
|
||||
if (!NewParm)
|
||||
return true;
|
||||
NewType = NewParm->getType();
|
||||
|
||||
PTypes.push_back(NewParm->getType());
|
||||
PVars.push_back(NewParm);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Deal with the possibility that we don't have a parameter
|
||||
// declaration for this parameter.
|
||||
} else {
|
||||
NewParm = 0;
|
||||
|
||||
QualType OldType = T->getArgType(i);
|
||||
NewType = getDerived().TransformType(OldType);
|
||||
if (NewType.isNull())
|
||||
QualType OldType = T->getArgType(i);
|
||||
bool IsPackExpansion = false;
|
||||
if (const PackExpansionType *Expansion
|
||||
= dyn_cast<PackExpansionType>(OldType)) {
|
||||
// We have a function parameter pack that may need to be expanded.
|
||||
QualType Pattern = Expansion->getPattern();
|
||||
llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
|
||||
|
||||
// Determine whether we should expand the parameter packs.
|
||||
bool ShouldExpand = false;
|
||||
unsigned NumExpansions = 0;
|
||||
if (getDerived().TryExpandParameterPacks(TL.getBeginLoc(), SourceRange(),
|
||||
Unexpanded.data(),
|
||||
Unexpanded.size(),
|
||||
ShouldExpand, NumExpansions)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ShouldExpand) {
|
||||
// Expand the function parameter pack into multiple, separate
|
||||
// parameters.
|
||||
for (unsigned I = 0; I != NumExpansions; ++I) {
|
||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
|
||||
QualType NewType = getDerived().TransformType(Pattern);
|
||||
if (NewType.isNull())
|
||||
return true;
|
||||
|
||||
PTypes.push_back(NewType);
|
||||
PVars.push_back(0);
|
||||
}
|
||||
|
||||
// We're done with the pack expansion.
|
||||
continue;
|
||||
}
|
||||
|
||||
// We'll substitute the parameter now without expanding the pack
|
||||
// expansion.
|
||||
OldType = Expansion->getPattern();
|
||||
IsPackExpansion = true;
|
||||
}
|
||||
|
||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
|
||||
QualType NewType = getDerived().TransformType(OldType);
|
||||
if (NewType.isNull())
|
||||
return true;
|
||||
|
||||
if (IsPackExpansion)
|
||||
NewType = getSema().Context.getPackExpansionType(NewType);
|
||||
|
||||
PTypes.push_back(NewType);
|
||||
PVars.push_back(NewParm);
|
||||
PVars.push_back(0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
// When it is part of a parameter-declaration-clause, the parameter
|
||||
// pack is a function parameter pack.
|
||||
template<typename ...Types>
|
||||
void f0(Types ...args); // FIXME: temporary expected-error{{clang does not yet support function parameter packs}}
|
||||
void f0(Types ...args);
|
||||
|
||||
template<typename ...Types>
|
||||
void f1(const Types &...args); // FIXME: temporary expected-error{{clang does not yet support function parameter packs}}
|
||||
void f1(const Types &...args);
|
||||
|
||||
// [ Note: Otherwise, the parameter-declaration is part of a
|
||||
// template-parameter-list and the parameter pack is a template
|
||||
|
|
|
@ -20,8 +20,8 @@ template<typename T> struct is_same<T, T> {
|
|||
|
||||
template<typename T, typename ...Types>
|
||||
struct X0 {
|
||||
typedef identity<T(Types...)> function_pack_1; // expected-error{{clang does not yet support function parameter packs}}
|
||||
typedef identity<T(Types......)> variadic_function_pack_1; // expected-error{{clang does not yet support function parameter packs}}
|
||||
typedef identity<T(Types...)> function_pack_1;
|
||||
typedef identity<T(Types......)> variadic_function_pack_1;
|
||||
typedef identity<T(T...)> variadic_1;
|
||||
typedef tuple<T(Types, ...)...> template_arg_expansion_1;
|
||||
};
|
||||
|
|
|
@ -231,3 +231,27 @@ namespace TemplateTemplateApply {
|
|||
tuple<int&, int*, int const>>::value? 1 : -1];
|
||||
|
||||
}
|
||||
|
||||
namespace FunctionTypes {
|
||||
template<typename FunctionType>
|
||||
struct Arity;
|
||||
|
||||
template<typename R, typename ...Types>
|
||||
struct Arity<R(Types...)> {
|
||||
static const unsigned value = sizeof...(Types);
|
||||
};
|
||||
|
||||
template<typename R, typename ...Types>
|
||||
struct Arity<R(Types......)> {
|
||||
static const unsigned value = sizeof...(Types);
|
||||
};
|
||||
|
||||
template<typename R, typename T1, typename T2, typename T3, typename T4>
|
||||
struct Arity<R(T1, T2, T3, T4)>; // expected-note{{template is declared here}}
|
||||
|
||||
int check0[Arity<int()>::value == 0? 1 : -1];
|
||||
int check1[Arity<int(float, double)>::value == 2? 1 : -1];
|
||||
int check2[Arity<int(float...)>::value == 1? 1 : -1];
|
||||
int check3[Arity<int(float, double, long double...)>::value == 3? 1 : -1];
|
||||
Arity<int(float, double, long double, char)> check4; // expected-error{{implicit instantiation of undefined template 'FunctionTypes::Arity<int (float, double, long double, char)>'}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue