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
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index e7a12d6..0312092 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -961,6 +961,115 @@
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 @@
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 @@
// 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);