For template argument deduction from class template partial

specializations, separate out the deduction part from the checking and
substitution of the deduced arguments.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102600 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2010-04-29 06:21:43 +00:00
Родитель fc39dc4c78
Коммит 31dce8f606
1 изменённых файлов: 122 добавлений и 100 удалений

Просмотреть файл

@ -961,6 +961,115 @@ static TemplateParameter makeTemplateParameter(Decl *D) {
return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
}
/// Complete template argument deduction for a class template partial
/// specialization.
static Sema::TemplateDeductionResult
FinishTemplateArgumentDeduction(Sema &S,
ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs,
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
Sema::TemplateDeductionInfo &Info) {
// Trap errors.
Sema::SFINAETrap Trap(S);
Sema::ContextRAII SavedContext(S, Partial);
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
TemplateArgumentListBuilder Builder(Partial->getTemplateParameters(),
Deduced.size());
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
if (Deduced[I].isNull()) {
Decl *Param
= const_cast<NamedDecl *>(
Partial->getTemplateParameters()->getParam(I));
Info.Param = makeTemplateParameter(Param);
return Sema::TDK_Incomplete;
}
Builder.Append(Deduced[I]);
}
// Form the template argument list from the deduced template arguments.
TemplateArgumentList *DeducedArgumentList
= new (S.Context) TemplateArgumentList(S.Context, Builder,
/*TakeArgs=*/true);
Info.reset(DeducedArgumentList);
// Substitute the deduced template arguments into the template
// arguments of the class template partial specialization, and
// verify that the instantiated template arguments are both valid
// and are equivalent to the template arguments originally provided
// to the class template.
// FIXME: Do we have to correct the types of deduced non-type template
// arguments (in particular, integral non-type template arguments?).
Sema::LocalInstantiationScope InstScope(S);
ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate();
const TemplateArgumentLoc *PartialTemplateArgs
= Partial->getTemplateArgsAsWritten();
unsigned N = Partial->getNumTemplateArgsAsWritten();
// Note that we don't provide the langle and rangle locations.
TemplateArgumentListInfo InstArgs;
for (unsigned I = 0; I != N; ++I) {
Decl *Param = const_cast<NamedDecl *>(
ClassTemplate->getTemplateParameters()->getParam(I));
TemplateArgumentLoc InstArg;
if (S.Subst(PartialTemplateArgs[I], InstArg,
MultiLevelTemplateArgumentList(*DeducedArgumentList))) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = PartialTemplateArgs[I].getArgument();
return Sema::TDK_SubstitutionFailure;
}
InstArgs.addArgument(InstArg);
}
TemplateArgumentListBuilder ConvertedInstArgs(
ClassTemplate->getTemplateParameters(), N);
if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(),
InstArgs, false, ConvertedInstArgs)) {
// FIXME: fail with more useful information?
return Sema::TDK_SubstitutionFailure;
}
for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) {
TemplateArgument InstArg = ConvertedInstArgs.getFlatArguments()[I];
Decl *Param = const_cast<NamedDecl *>(
ClassTemplate->getTemplateParameters()->getParam(I));
if (InstArg.getKind() == TemplateArgument::Expression) {
// When the argument is an expression, check the expression result
// against the actual template parameter to get down to the canonical
// template argument.
Expr *InstExpr = InstArg.getAsExpr();
if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
if (S.CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = Partial->getTemplateArgs()[I];
return Sema::TDK_SubstitutionFailure;
}
}
}
if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = TemplateArgs[I];
Info.SecondArg = InstArg;
return Sema::TDK_NonDeducedMismatch;
}
}
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
return Sema::TDK_Success;
}
/// \brief Perform template argument deduction to determine whether
/// the given template arguments match the given class template
/// partial specialization per C++ [temp.class.spec.match].
@ -988,101 +1097,11 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
if (Inst)
return TDK_InstantiationDepth;
ContextRAII SavedContext(*this, Partial);
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
TemplateArgumentListBuilder Builder(Partial->getTemplateParameters(),
Deduced.size());
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
if (Deduced[I].isNull()) {
Decl *Param
= const_cast<NamedDecl *>(
Partial->getTemplateParameters()->getParam(I));
Info.Param = makeTemplateParameter(Param);
return TDK_Incomplete;
}
Builder.Append(Deduced[I]);
}
// Form the template argument list from the deduced template arguments.
TemplateArgumentList *DeducedArgumentList
= new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
Info.reset(DeducedArgumentList);
// Substitute the deduced template arguments into the template
// arguments of the class template partial specialization, and
// verify that the instantiated template arguments are both valid
// and are equivalent to the template arguments originally provided
// to the class template.
// FIXME: Do we have to correct the types of deduced non-type template
// arguments (in particular, integral non-type template arguments?).
Sema::LocalInstantiationScope InstScope(*this);
ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate();
const TemplateArgumentLoc *PartialTemplateArgs
= Partial->getTemplateArgsAsWritten();
unsigned N = Partial->getNumTemplateArgsAsWritten();
// Note that we don't provide the langle and rangle locations.
TemplateArgumentListInfo InstArgs;
for (unsigned I = 0; I != N; ++I) {
Decl *Param = const_cast<NamedDecl *>(
ClassTemplate->getTemplateParameters()->getParam(I));
TemplateArgumentLoc InstArg;
if (Subst(PartialTemplateArgs[I], InstArg,
MultiLevelTemplateArgumentList(*DeducedArgumentList))) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = PartialTemplateArgs[I].getArgument();
return TDK_SubstitutionFailure;
}
InstArgs.addArgument(InstArg);
}
TemplateArgumentListBuilder ConvertedInstArgs(
ClassTemplate->getTemplateParameters(), N);
if (CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(),
InstArgs, false, ConvertedInstArgs)) {
// FIXME: fail with more useful information?
return TDK_SubstitutionFailure;
}
for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) {
TemplateArgument InstArg = ConvertedInstArgs.getFlatArguments()[I];
Decl *Param = const_cast<NamedDecl *>(
ClassTemplate->getTemplateParameters()->getParam(I));
if (InstArg.getKind() == TemplateArgument::Expression) {
// When the argument is an expression, check the expression result
// against the actual template parameter to get down to the canonical
// template argument.
Expr *InstExpr = InstArg.getAsExpr();
if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
if (CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = Partial->getTemplateArgs()[I];
return TDK_SubstitutionFailure;
}
}
}
if (!isSameTemplateArg(Context, TemplateArgs[I], InstArg)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = TemplateArgs[I];
Info.SecondArg = InstArg;
return TDK_NonDeducedMismatch;
}
}
if (Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
return TDK_Success;
return Sema::TDK_SubstitutionFailure;
return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs,
Deduced, Info);
}
/// \brief Determine whether the given type T is a simple-template-id type.
@ -2341,12 +2360,15 @@ Sema::getMoreSpecializedPartialSpecialization(
// whose type is a class template specialization with the template
// arguments of the second partial specialization.
//
// Rather than synthesize function templates, we merely perform the
// equivalent partial ordering by performing deduction directly on the
// template arguments of the class template partial specializations. This
// computation is slightly simpler than the general problem of function
// template partial ordering, because class template partial specializations
// are more constrained. We know that every template parameter is deduc
// Rather than synthesize function templates, we merely perform the
// equivalent partial ordering by performing deduction directly on
// the template arguments of the class template partial
// specializations. This computation is slightly simpler than the
// general problem of function template partial ordering, because
// class template partial specializations are more constrained. We
// know that every template parameter is deducible from the class
// template partial specialization's template arguments, for
// example.
llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
Sema::TemplateDeductionInfo Info(Context, Loc);