Check in a new template argument list builder that should work better for variadic templates.

llvm-svn: 73937
This commit is contained in:
Anders Carlsson 2009-06-23 01:26:57 +00:00
parent e2170edfbb
commit 5947ddfb55
4 changed files with 174 additions and 146 deletions

View File

@ -469,10 +469,6 @@ public:
/// occur in a non-dependent, canonical template argument list.
TemplateArgument(Expr *E);
/// \brief Construct a template argument pack.
TemplateArgument(SourceLocation Loc, TemplateArgument *Args,
unsigned NumArgs, bool CopyArgs);
/// \brief Copy constructor for a template argument.
TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
if (Kind == Integral) {
@ -587,6 +583,9 @@ public:
/// \brief Retrieve the location where the template argument starts.
SourceLocation getLocation() const { return StartLoc; }
/// \brief Construct a template argument pack.
void setArgumentPack(TemplateArgument *Args, unsigned NumArgs, bool CopyArgs);
/// \brief Used to insert TemplateArguments into FoldingSets.
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(Kind);
@ -622,47 +621,51 @@ public:
/// \brief A helper class for making template argument lists.
class TemplateArgumentListBuilder {
/// FlatArgs - contains the template arguments in flat form.
llvm::SmallVector<TemplateArgument, 16> FlatArgs;
llvm::SmallVector<TemplateArgument, 16> StructuredArgs;
ASTContext &Context;
TemplateArgument *StructuredArgs;
unsigned MaxStructuredArgs;
unsigned NumStructuredArgs;
TemplateArgument *FlatArgs;
unsigned MaxFlatArgs;
unsigned NumFlatArgs;
bool AddingToPack;
unsigned PackBeginIndex;
/// isAddingFromParameterPack - Returns whether we're adding arguments from
/// a parameter pack.
bool isAddingFromParameterPack() const {
return PackBeginIndex != std::numeric_limits<unsigned>::max();
}
public:
TemplateArgumentListBuilder(ASTContext &Context) : Context(Context),
PackBeginIndex(std::numeric_limits<unsigned>::max()) { }
TemplateArgumentListBuilder(const TemplateParameterList *Parameters,
unsigned NumTemplateArgs)
: StructuredArgs(0), MaxStructuredArgs(Parameters->size()),
NumStructuredArgs(0), FlatArgs(0),
MaxFlatArgs(std::max(MaxStructuredArgs, NumTemplateArgs)), NumFlatArgs(0),
AddingToPack(false), PackBeginIndex(0) { }
size_t structuredSize() const {
assert(!isAddingFromParameterPack() &&
"Size is not valid when adding from a parameter pack");
return StructuredArgs.size();
}
size_t flatSize() const { return FlatArgs.size(); }
void Append(const TemplateArgument& Arg);
void BeginPack();
void EndPack();
void push_back(const TemplateArgument& Arg);
void ReleaseArgs();
/// BeginParameterPack - Start adding arguments from a parameter pack.
void BeginParameterPack();
/// EndParameterPack - Finish adding arguments from a parameter pack.
void EndParameterPack();
const TemplateArgument *getFlatArgumentList() const {
return FlatArgs.data();
unsigned flatSize() const {
return NumFlatArgs;
}
TemplateArgument *getFlatArgumentList() {
return FlatArgs.data();
const TemplateArgument *getFlatArguments() const {
return FlatArgs;
}
unsigned structuredSize() const {
// If we don't have any structured args, just reuse the flat size.
if (!StructuredArgs)
return flatSize();
return NumStructuredArgs;
}
const TemplateArgument *getStructuredArguments() const {
// If we don't have any structured args, just reuse the flat args.
if (!StructuredArgs)
return getFlatArguments();
return StructuredArgs;
}
};
@ -676,22 +679,25 @@ class TemplateArgumentList {
///
/// The integer value will be non-zero to indicate that this
/// template argument list does not own the pointer.
llvm::PointerIntPair<TemplateArgument *, 1> Arguments;
llvm::PointerIntPair<const TemplateArgument *, 1> FlatArguments;
/// \brief The number of template arguments in this template
/// argument list.
unsigned NumArguments;
unsigned NumFlatArguments;
llvm::PointerIntPair<const TemplateArgument *, 1> StructuredArguments;
unsigned NumStructuredArguments;
public:
TemplateArgumentList(ASTContext &Context,
TemplateArgumentListBuilder &Builder,
bool CopyArgs, bool FlattenArgs);
bool TakeArgs);
~TemplateArgumentList();
/// \brief Retrieve the template argument at a given index.
const TemplateArgument &get(unsigned Idx) const {
assert(Idx < NumArguments && "Invalid template argument index");
assert(Idx < NumFlatArguments && "Invalid template argument index");
return getFlatArgumentList()[Idx];
}
@ -700,15 +706,15 @@ public:
/// \brief Retrieve the number of template arguments in this
/// template argument list.
unsigned size() const { return NumArguments; }
unsigned size() const { return NumFlatArguments; }
/// \brief Retrieve the number of template arguments in the
/// flattened template argument list.
unsigned flat_size() const { return NumArguments; }
unsigned flat_size() const { return NumFlatArguments; }
/// \brief Retrieve the flattened template argument list.
const TemplateArgument *getFlatArgumentList() const {
return Arguments.getPointer();
return FlatArguments.getPointer();
}
};

View File

@ -239,79 +239,103 @@ TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) {
}
/// \brief Construct a template argument pack.
TemplateArgument::TemplateArgument(SourceLocation Loc, TemplateArgument *args,
unsigned NumArgs, bool CopyArgs)
: Kind(Pack) {
Args.NumArgs = NumArgs;
Args.CopyArgs = CopyArgs;
if (!Args.CopyArgs) {
Args.Args = args;
return;
}
Args.Args = new TemplateArgument[NumArgs];
for (unsigned I = 0; I != NumArgs; ++I)
Args.Args[I] = args[I];
void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs,
bool CopyArgs) {
assert(isNull() && "Must call setArgumentPack on a null argument");
Kind = Pack;
Args.NumArgs = NumArgs;
Args.CopyArgs = CopyArgs;
if (!Args.CopyArgs) {
Args.Args = args;
return;
}
Args.Args = new TemplateArgument[NumArgs];
for (unsigned I = 0; I != Args.NumArgs; ++I)
Args.Args[I] = args[I];
}
//===----------------------------------------------------------------------===//
// TemplateArgumentListBuilder Implementation
//===----------------------------------------------------------------------===//
void TemplateArgumentListBuilder::push_back(const TemplateArgument& Arg) {
void TemplateArgumentListBuilder::Append(const TemplateArgument& Arg) {
switch (Arg.getKind()) {
default: break;
case TemplateArgument::Type:
assert(Arg.getAsType()->isCanonical() && "Type must be canonical!");
break;
default: break;
case TemplateArgument::Type:
assert(Arg.getAsType()->isCanonical() && "Type must be canonical!");
break;
}
FlatArgs.push_back(Arg);
assert(NumFlatArgs < MaxFlatArgs && "Argument list builder is full!");
assert(!StructuredArgs &&
"Can't append arguments when an argument pack has been added!");
if (!isAddingFromParameterPack())
StructuredArgs.push_back(Arg);
if (!FlatArgs)
FlatArgs = new TemplateArgument[MaxFlatArgs];
FlatArgs[NumFlatArgs++] = Arg;
}
void TemplateArgumentListBuilder::BeginParameterPack() {
assert(!isAddingFromParameterPack() && "Already adding to parameter pack!");
PackBeginIndex = FlatArgs.size();
void TemplateArgumentListBuilder::BeginPack() {
assert(!AddingToPack && "Already adding to pack!");
assert(!StructuredArgs && "Argument list already contains a pack!");
AddingToPack = true;
PackBeginIndex = NumFlatArgs;
}
void TemplateArgumentListBuilder::EndParameterPack() {
assert(isAddingFromParameterPack() && "Not adding to parameter pack!");
void TemplateArgumentListBuilder::EndPack() {
assert(AddingToPack && "Not adding to pack!");
assert(!StructuredArgs && "Argument list already contains a pack!");
AddingToPack = false;
unsigned NumArgs = FlatArgs.size() - PackBeginIndex;
TemplateArgument *Args = NumArgs ? &FlatArgs[PackBeginIndex] : 0;
StructuredArgs = new TemplateArgument[MaxStructuredArgs];
StructuredArgs.push_back(TemplateArgument(SourceLocation(), Args, NumArgs,
/*CopyArgs=*/false));
// First copy the flat entries over to the list (if any)
for (unsigned I = 0; I != PackBeginIndex; ++I) {
NumStructuredArgs++;
StructuredArgs[I] = FlatArgs[I];
}
PackBeginIndex = std::numeric_limits<unsigned>::max();
}
// Next, set the pack.
TemplateArgument *PackArgs = 0;
unsigned NumPackArgs = NumFlatArgs - PackBeginIndex;
if (NumPackArgs)
PackArgs = &FlatArgs[PackBeginIndex];
StructuredArgs[NumStructuredArgs++].setArgumentPack(PackArgs, NumPackArgs,
/*CopyArgs=*/false);
}
void TemplateArgumentListBuilder::ReleaseArgs() {
FlatArgs = 0;
NumFlatArgs = 0;
MaxFlatArgs = 0;
StructuredArgs = 0;
NumStructuredArgs = 0;
MaxStructuredArgs = 0;
}
//===----------------------------------------------------------------------===//
// TemplateArgumentList Implementation
//===----------------------------------------------------------------------===//
TemplateArgumentList::TemplateArgumentList(ASTContext &Context,
TemplateArgumentListBuilder &Builder,
bool CopyArgs, bool FlattenArgs)
: NumArguments(Builder.flatSize()) {
if (!CopyArgs) {
Arguments.setPointer(Builder.getFlatArgumentList());
Arguments.setInt(1);
return;
}
bool TakeArgs)
: FlatArguments(Builder.getFlatArguments(), TakeArgs),
NumFlatArguments(Builder.flatSize()),
StructuredArguments(Builder.getStructuredArguments(), TakeArgs),
NumStructuredArguments(Builder.structuredSize()) {
unsigned Size = sizeof(TemplateArgument) * Builder.flatSize();
unsigned Align = llvm::AlignOf<TemplateArgument>::Alignment;
void *Mem = Context.Allocate(Size, Align);
Arguments.setPointer((TemplateArgument *)Mem);
Arguments.setInt(0);
TemplateArgument *Args = (TemplateArgument *)Mem;
for (unsigned I = 0; I != NumArguments; ++I)
new (Args + I) TemplateArgument(Builder.getFlatArgumentList()[I]);
if (!TakeArgs)
return;
if (Builder.getStructuredArguments() == Builder.getFlatArguments())
StructuredArguments.setInt(0);
Builder.ReleaseArgs();
}
TemplateArgumentList::~TemplateArgumentList() {
@ -333,7 +357,7 @@ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
// class template specializations?
SpecializedTemplate->getIdentifier()),
SpecializedTemplate(SpecializedTemplate),
TemplateArgs(Context, Builder, /*CopyArgs=*/true, /*FlattenArgs=*/true),
TemplateArgs(Context, Builder, /*TakeArgs=*/true),
SpecializationKind(TSK_Undeclared) {
}

View File

@ -847,13 +847,14 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// Check that the template argument list is well-formed for this
// template.
TemplateArgumentListBuilder ConvertedTemplateArgs(Context);
TemplateArgumentListBuilder Converted(Template->getTemplateParameters(),
NumTemplateArgs);
if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc,
TemplateArgs, NumTemplateArgs, RAngleLoc,
ConvertedTemplateArgs))
Converted))
return QualType();
assert((ConvertedTemplateArgs.structuredSize() ==
assert((Converted.structuredSize() ==
Template->getTemplateParameters()->size()) &&
"Converted template argument list is too short!");
@ -871,16 +872,16 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// template<typename T, typename U = T> struct A;
TemplateName CanonName = Context.getCanonicalTemplateName(Name);
CanonType = Context.getTemplateSpecializationType(CanonName,
ConvertedTemplateArgs.getFlatArgumentList(),
ConvertedTemplateArgs.flatSize());
Converted.getFlatArguments(),
Converted.flatSize());
} else if (ClassTemplateDecl *ClassTemplate
= dyn_cast<ClassTemplateDecl>(Template)) {
// Find the class template specialization declaration that
// corresponds to these arguments.
llvm::FoldingSetNodeID ID;
ClassTemplateSpecializationDecl::Profile(ID,
ConvertedTemplateArgs.getFlatArgumentList(),
ConvertedTemplateArgs.flatSize());
Converted.getFlatArguments(),
Converted.flatSize());
void *InsertPos = 0;
ClassTemplateSpecializationDecl *Decl
= ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
@ -892,7 +893,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
ClassTemplate->getDeclContext(),
TemplateLoc,
ClassTemplate,
ConvertedTemplateArgs, 0);
Converted, 0);
ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
Decl->setLexicalDeclContext(CurContext);
}
@ -1003,7 +1004,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
return true;
// Add the converted template type argument.
Converted.push_back(
Converted.Append(
TemplateArgument(Arg.getLocation(),
Context.getCanonicalType(Arg.getAsType())));
return false;
@ -1061,9 +1062,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// parameter.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
if (TTP->isParameterPack()) {
// We have an empty parameter pack.
Converted.BeginParameterPack();
Converted.EndParameterPack();
// We have an empty argument pack.
Converted.BeginPack();
Converted.EndPack();
break;
}
@ -1076,13 +1077,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// on the previously-computed template arguments.
if (ArgType->isDependentType()) {
InstantiatingTemplate Inst(*this, TemplateLoc,
Template, Converted.getFlatArgumentList(),
Template, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
TemplateArgumentList TemplateArgs(Context, Converted,
/*CopyArgs=*/false,
/*FlattenArgs=*/false);
/*TakeArgs=*/false);
ArgType = InstantiateType(ArgType, TemplateArgs,
TTP->getDefaultArgumentLoc(),
TTP->getDeclName());
@ -1098,13 +1098,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
break;
InstantiatingTemplate Inst(*this, TemplateLoc,
Template, Converted.getFlatArgumentList(),
Template, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
TemplateArgumentList TemplateArgs(Context, Converted,
/*CopyArgs=*/false,
/*FlattenArgs=*/false);
/*TakeArgs=*/false);
Sema::OwningExprResult E = InstantiateExpr(NTTP->getDefaultArgument(),
TemplateArgs);
@ -1130,14 +1129,14 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
if (TTP->isParameterPack()) {
Converted.BeginParameterPack();
Converted.BeginPack();
// Check all the remaining arguments (if any).
for (; ArgIdx < NumArgs; ++ArgIdx) {
if (CheckTemplateTypeArgument(TTP, TemplateArgs[ArgIdx], Converted))
Invalid = true;
}
Converted.EndParameterPack();
Converted.EndPack();
} else {
if (CheckTemplateTypeArgument(TTP, Arg, Converted))
Invalid = true;
@ -1152,13 +1151,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (NTTPType->isDependentType()) {
// Instantiate the type of the non-type template parameter.
InstantiatingTemplate Inst(*this, TemplateLoc,
Template, Converted.getFlatArgumentList(),
Template, Converted.getFlatArguments(),
Converted.flatSize(),
SourceRange(TemplateLoc, RAngleLoc));
TemplateArgumentList TemplateArgs(Context, Converted,
/*CopyArgs=*/false,
/*FlattenArgs=*/false);
/*TakeArgs=*/false);
NTTPType = InstantiateType(NTTPType, TemplateArgs,
NTTP->getLocation(),
NTTP->getDeclName());
@ -1167,7 +1165,6 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (!NTTPType.isNull())
NTTPType = CheckNonTypeTemplateParameterType(NTTPType,
NTTP->getLocation());
if (NTTPType.isNull()) {
Invalid = true;
break;
@ -1185,7 +1182,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (CheckTemplateArgument(NTTP, NTTPType, E, Result))
Invalid = true;
else
Converted.push_back(Result);
Converted.Append(Result);
break;
}
@ -1193,7 +1190,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
case TemplateArgument::Integral:
// We've already checked this template argument, so just copy
// it to the list of converted arguments.
Converted.push_back(Arg);
Converted.Append(Arg);
break;
case TemplateArgument::Type:
@ -1240,7 +1237,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// Add the converted template argument.
Decl *D
= Context.getCanonicalDecl(cast<DeclRefExpr>(ArgExpr)->getDecl());
Converted.push_back(TemplateArgument(Arg.getLocation(), D));
Converted.Append(TemplateArgument(Arg.getLocation(), D));
continue;
}
}
@ -1257,7 +1254,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
case TemplateArgument::Declaration:
// We've already checked this template argument, so just copy
// it to the list of converted arguments.
Converted.push_back(Arg);
Converted.Append(Arg);
break;
case TemplateArgument::Integral:
@ -2102,7 +2099,7 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
// accommodate variadic templates.
MirrorsPrimaryTemplate = true;
const TemplateArgument *ArgList = TemplateArgs.getFlatArgumentList();
const TemplateArgument *ArgList = TemplateArgs.getFlatArguments();
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
// Determine whether the template argument list of the partial
@ -2298,13 +2295,14 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// Check that the template argument list is well-formed for this
// template.
TemplateArgumentListBuilder ConvertedTemplateArgs(Context);
TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(),
TemplateArgs.size());
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
TemplateArgs.data(), TemplateArgs.size(),
RAngleLoc, ConvertedTemplateArgs))
RAngleLoc, Converted))
return true;
assert((ConvertedTemplateArgs.structuredSize() ==
assert((Converted.structuredSize() ==
ClassTemplate->getTemplateParameters()->size()) &&
"Converted template argument list is too short!");
@ -2315,8 +2313,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
bool MirrorsPrimaryTemplate;
if (CheckClassTemplatePartialSpecializationArgs(
ClassTemplate->getTemplateParameters(),
ConvertedTemplateArgs,
MirrorsPrimaryTemplate))
Converted, MirrorsPrimaryTemplate))
return true;
if (MirrorsPrimaryTemplate) {
@ -2338,13 +2335,13 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// FIXME: Template parameter list matters, too
ClassTemplatePartialSpecializationDecl::Profile(ID,
ConvertedTemplateArgs.getFlatArgumentList(),
ConvertedTemplateArgs.flatSize());
Converted.getFlatArguments(),
Converted.flatSize());
}
else
ClassTemplateSpecializationDecl::Profile(ID,
ConvertedTemplateArgs.getFlatArgumentList(),
ConvertedTemplateArgs.flatSize());
Converted.getFlatArguments(),
Converted.flatSize());
void *InsertPos = 0;
ClassTemplateSpecializationDecl *PrevDecl = 0;
@ -2387,7 +2384,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
TemplateNameLoc,
TemplateParams,
ClassTemplate,
ConvertedTemplateArgs,
Converted,
PrevPartial);
if (PrevPartial) {
@ -2437,7 +2434,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
ClassTemplate,
ConvertedTemplateArgs,
Converted,
PrevDecl);
if (PrevDecl) {
@ -2559,13 +2556,14 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
// Check that the template argument list is well-formed for this
// template.
TemplateArgumentListBuilder ConvertedTemplateArgs(Context);
TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(),
TemplateArgs.size());
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
TemplateArgs.data(), TemplateArgs.size(),
RAngleLoc, ConvertedTemplateArgs))
RAngleLoc, Converted))
return true;
assert((ConvertedTemplateArgs.structuredSize() ==
assert((Converted.structuredSize() ==
ClassTemplate->getTemplateParameters()->size()) &&
"Converted template argument list is too short!");
@ -2573,8 +2571,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
// corresponds to these arguments.
llvm::FoldingSetNodeID ID;
ClassTemplateSpecializationDecl::Profile(ID,
ConvertedTemplateArgs.getFlatArgumentList(),
ConvertedTemplateArgs.flatSize());
Converted.getFlatArguments(),
Converted.flatSize());
void *InsertPos = 0;
ClassTemplateSpecializationDecl *PrevDecl
= ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
@ -2617,7 +2615,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
ClassTemplate,
ConvertedTemplateArgs, 0);
Converted, 0);
Specialization->setLexicalDeclContext(CurContext);
CurContext->addDecl(Context, Specialization);
return DeclPtrTy::make(Specialization);
@ -2643,7 +2641,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
ClassTemplate->getDeclContext(),
TemplateNameLoc,
ClassTemplate,
ConvertedTemplateArgs, 0);
Converted, 0);
ClassTemplate->getSpecializations().InsertNode(Specialization,
InsertPos);

View File

@ -654,7 +654,8 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
TemplateArgumentListBuilder Builder(Context);
TemplateArgumentListBuilder Builder(Partial->getTemplateParameters(),
Deduced.size());
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
if (Deduced[I].isNull()) {
Decl *Param
@ -669,13 +670,12 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
return TDK_Incomplete;
}
Builder.push_back(Deduced[I]);
Builder.Append(Deduced[I]);
}
// Form the template argument list from the deduced template arguments.
TemplateArgumentList *DeducedArgumentList
= new (Context) TemplateArgumentList(Context, Builder, /*CopyArgs=*/true,
/*FlattenArgs=*/true);
= new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
Info.reset(DeducedArgumentList);
// Substitute the deduced template arguments into the template