[cfe-commits] r73136 - in /cfe/trunk: lib/Sema/SemaTemplateDeduction.cpp test/SemaTemplate/example-typelist.cpp

Douglas Gregor dgregor at apple.com
Tue Jun 9 09:35:59 PDT 2009


Author: dgregor
Date: Tue Jun  9 11:35:58 2009
New Revision: 73136

URL: http://llvm.org/viewvc/llvm-project?rev=73136&view=rev
Log:
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.

Added:
    cfe/trunk/test/SemaTemplate/example-typelist.cpp   (with props)
Modified:
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=73136&r1=73135&r2=73136&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Tue Jun  9 11:35:58 2009
@@ -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 @@
   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 @@
       
       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;
   }

Added: cfe/trunk/test/SemaTemplate/example-typelist.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/example-typelist.cpp?rev=73136&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/example-typelist.cpp (added)
+++ cfe/trunk/test/SemaTemplate/example-typelist.cpp Tue Jun  9 11:35:58 2009
@@ -0,0 +1,28 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct nil { };
+
+template<typename Head, typename Tail = nil>
+struct cons { 
+  typedef Head head;
+  typedef Tail tail;
+};
+
+// metaprogram that computes the length of a list
+template<typename T> struct length;
+
+template<typename Head, typename Tail>
+struct length<cons<Head, Tail> > {
+  static const unsigned value = length<Tail>::value + 1;
+};
+
+template<>
+struct length<nil> {
+  static const unsigned value = 0;
+};
+
+typedef cons<unsigned char, 
+             cons<unsigned short, 
+                  cons<unsigned int,
+                       cons<unsigned long> > > > unsigned_inttypes;
+int length0[length<unsigned_inttypes>::value == 4? 1 : -1];

Propchange: cfe/trunk/test/SemaTemplate/example-typelist.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaTemplate/example-typelist.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaTemplate/example-typelist.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list