aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaTemplateDeduction.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-06-09 16:35:58 +0000
committerDouglas Gregor <dgregor@apple.com>2009-06-09 16:35:58 +0000
commitd708c72e3e5186662fb0045d2bd666bfd93a013d (patch)
tree5537553ebd7b8bbcdb01ea2d07f8b0d0dded1465 /lib/Sema/SemaTemplateDeduction.cpp
parent9c5fc1674925f25a2f01faa018df87ab8580e197 (diff)
Implement template argument deduction for class template
specialization types. As the example shows, we can now compute the length of a type-list using a template metaprogram and class template partial specialization. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73136 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplateDeduction.cpp')
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp102
1 files changed, 102 insertions, 0 deletions
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 1789ba7856..0ad79358cd 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -20,6 +20,11 @@
#include "llvm/Support/Compiler.h"
using namespace clang;
+static bool
+DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
+ const TemplateArgument &Arg,
+ llvm::SmallVectorImpl<TemplateArgument> &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.
@@ -100,6 +105,24 @@ static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
return true;
}
+static bool DeduceTemplateArguments(ASTContext &Context,
+ TemplateName Param,
+ TemplateName Arg,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ // FIXME: Implement template argument deduction for template
+ // template parameters.
+
+ TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
+ TemplateDecl *ArgDecl = Arg.getAsTemplateDecl();
+
+ if (!ParamDecl || !ArgDecl)
+ return false;
+
+ ParamDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ParamDecl));
+ ArgDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ArgDecl));
+ return ParamDecl == ArgDecl;
+}
+
static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
QualType Arg,
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
@@ -305,7 +328,86 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
return true;
}
+
+ // template-name<T> (wheretemplate-name refers to a class template)
+ // template-name<i>
+ // TT<T> (TODO)
+ // TT<i> (TODO)
+ // TT<> (TODO)
+ case Type::TemplateSpecialization: {
+ const TemplateSpecializationType *SpecParam
+ = cast<TemplateSpecializationType>(Param);
+
+ // Check whether the template argument is a dependent template-id.
+ // FIXME: This is untested code; it can be tested when we implement
+ // partial ordering of class template partial specializations.
+ if (const TemplateSpecializationType *SpecArg
+ = dyn_cast<TemplateSpecializationType>(Arg)) {
+ // Perform template argument deduction for the template name.
+ if (!DeduceTemplateArguments(Context,
+ SpecParam->getTemplateName(),
+ SpecArg->getTemplateName(),
+ Deduced))
+ return false;
+
+ unsigned NumArgs = SpecParam->getNumArgs();
+
+ // FIXME: When one of the template-names refers to a
+ // declaration with default template arguments, do we need to
+ // fill in those default template arguments here? Most likely,
+ // the answer is "yes", but I don't see any references. This
+ // issue may be resolved elsewhere, because we may want to
+ // instantiate default template arguments when
+ if (SpecArg->getNumArgs() != NumArgs)
+ return false;
+
+ // Perform template argument deduction on each template
+ // argument.
+ for (unsigned I = 0; I != NumArgs; ++I)
+ if (!DeduceTemplateArguments(Context,
+ SpecParam->getArg(I),
+ SpecArg->getArg(I),
+ Deduced))
+ return false;
+
+ return true;
+ }
+
+ // If the argument type is a class template specialization, we
+ // perform template argument deduction using its template
+ // arguments.
+ const RecordType *RecordArg = dyn_cast<RecordType>(Arg);
+ if (!RecordArg)
+ return false;
+
+ ClassTemplateSpecializationDecl *SpecArg
+ = dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl());
+ if (!SpecArg)
+ return false;
+
+ // Perform template argument deduction for the template name.
+ if (!DeduceTemplateArguments(Context,
+ SpecParam->getTemplateName(),
+ TemplateName(SpecArg->getSpecializedTemplate()),
+ Deduced))
+ return false;
+
+ // FIXME: Can the # of arguments in the parameter and the argument differ?
+ unsigned NumArgs = SpecParam->getNumArgs();
+ const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs();
+ if (NumArgs != ArgArgs.size())
+ return false;
+
+ for (unsigned I = 0; I != NumArgs; ++I)
+ if (!DeduceTemplateArguments(Context,
+ SpecParam->getArg(I),
+ ArgArgs.get(I),
+ Deduced))
+ return false;
+ return true;
+ }
+
default:
break;
}