[cfe-commits] r122418 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaTemplateDeduction.cpp test/CXX/temp/temp.decls/temp.variadic/count.cpp

Douglas Gregor dgregor at apple.com
Wed Dec 22 10:17:10 PST 2010


Author: dgregor
Date: Wed Dec 22 12:17:10 2010
New Revision: 122418

URL: http://llvm.org/viewvc/llvm-project?rev=122418&view=rev
Log:
Implicitly expand argument packs when performing template argument
deduction. Unify all of the looping over template arguments for
deduction purposes into a single place, where argument pack expansion
occurs; this is also the hook for deducing from pack expansions, which
itself is not yet implemented.

For now, at least we can handle a basic "count" metafunction written
with variadics. See the new test for the formulation that works.

Added:
    cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/count.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=122418&r1=122417&r2=122418&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Dec 22 12:17:10 2010
@@ -1861,12 +1861,15 @@
   "pack expansion contains parameter packs %0 and %1 that have different "
   "lengths (%2 vs. %3)">;
 
+// Unsupported variadic templates features
 def err_pack_expansion_unsupported : Error<
   "clang does not yet support %select{non-type|template}0 pack expansions">;
 def err_pack_expansion_instantiation_unsupported : Error<
   "clang cannot yet instantiate pack expansions">;
 def err_pack_expansion_mismatch_unsupported : Error<
   "clang cannot yet instantiate pack expansions with mismatched pack levels">;
+def err_pack_expansion_deduction : Error<
+  "clang cannot yet perform template argument deduction for a pack expansion">;
 
 def err_unexpected_typedef : Error<
   "unexpected type name %0: expected expression">;

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=122418&r1=122417&r2=122418&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Dec 22 12:17:10 2010
@@ -12,6 +12,7 @@
 
 #include "clang/Sema/Sema.h"
 #include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/SemaDiagnostic.h" // FIXME: temporary!
 #include "clang/Sema/Template.h"
 #include "clang/Sema/TemplateDeduction.h"
 #include "clang/AST/ASTContext.h"
@@ -82,6 +83,14 @@
                         TemplateDeductionInfo &Info,
                     llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced);
 
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(Sema &S,
+                        TemplateParameterList *TemplateParams,
+                        const TemplateArgument *Params, unsigned NumParams,
+                        const TemplateArgument *Args, unsigned NumArgs,
+                        TemplateDeductionInfo &Info,
+                      llvm::SmallVectorImpl<DeducedTemplateArgument> &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.
@@ -301,16 +310,13 @@
 
     // Perform template argument deduction on each template
     // argument.
+    // FIXME: This "min" function isn't going to work in general. We should
+    // probably pass down a flag that allows too few/too many arguments.
     unsigned NumArgs = std::min(SpecArg->getNumArgs(), Param->getNumArgs());
-    for (unsigned I = 0; I != NumArgs; ++I)
-      if (Sema::TemplateDeductionResult Result
-            = DeduceTemplateArguments(S, TemplateParams,
-                                      Param->getArg(I),
-                                      SpecArg->getArg(I),
-                                      Info, Deduced))
-        return Result;
-
-    return Sema::TDK_Success;
+    return DeduceTemplateArguments(S, TemplateParams, 
+                                   Param->getArgs(), NumArgs, 
+                                   SpecArg->getArgs(), NumArgs,
+                                   Info, Deduced);
   }
 
   // If the argument type is a class template specialization, we
@@ -334,20 +340,12 @@
                                   Info, Deduced))
     return Result;
 
-  unsigned NumArgs = Param->getNumArgs();
-  const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs();
-  if (NumArgs != ArgArgs.size())
-    return Sema::TDK_NonDeducedMismatch;
-
-  for (unsigned I = 0; I != NumArgs; ++I)
-    if (Sema::TemplateDeductionResult Result
-          = DeduceTemplateArguments(S, TemplateParams,
-                                    Param->getArg(I),
-                                    ArgArgs.get(I),
-                                    Info, Deduced))
-      return Result;
-
-  return Sema::TDK_Success;
+  // Perform template argument deduction for the template arguments.
+  return DeduceTemplateArguments(S, TemplateParams, 
+                                 Param->getArgs(), Param->getNumArgs(),
+                                 SpecArg->getTemplateArgs().data(),
+                                 SpecArg->getTemplateArgs().size(),
+                                 Info, Deduced);
 }
 
 /// \brief Determines whether the given type is an opaque type that
@@ -664,6 +662,7 @@
 
       for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) {
         // Check argument types.
+        // FIXME: Variadic templates.
         if (Sema::TemplateDeductionResult Result
               = DeduceTemplateArguments(S, TemplateParams,
                                         FunctionProtoParam->getArgType(I),
@@ -917,32 +916,94 @@
     return Sema::TDK_Success;
   }
   case TemplateArgument::Pack:
-    // FIXME: Variadic templates
-    assert(0 && "FIXME: Implement!");
-    break;
+    llvm_unreachable("Argument packs should be expanded by the caller!");
   }
 
   return Sema::TDK_Success;
 }
 
+/// \brief Determine whether there is a template argument to be used for
+/// deduction.
+///
+/// This routine "expands" argument packs in-place, overriding its input
+/// parameters so that \c Args[ArgIdx] will be the available template argument.
+///
+/// \returns true if there is another template argument (which will be at
+/// \c Args[ArgIdx]), false otherwise.
+static bool hasTemplateArgumentForDeduction(const TemplateArgument *&Args, 
+                                            unsigned &ArgIdx,
+                                            unsigned &NumArgs) {
+  if (ArgIdx == NumArgs)
+    return false;
+  
+  const TemplateArgument &Arg = Args[ArgIdx];
+  if (Arg.getKind() != TemplateArgument::Pack)
+    return true;
+
+  assert(ArgIdx == NumArgs - 1 && "Pack not at the end of argument list?");
+  Args = Arg.pack_begin();
+  NumArgs = Arg.pack_size();
+  ArgIdx = 0;
+  return ArgIdx < NumArgs;
+}
+
 static Sema::TemplateDeductionResult
 DeduceTemplateArguments(Sema &S,
                         TemplateParameterList *TemplateParams,
-                        const TemplateArgumentList &ParamList,
-                        const TemplateArgumentList &ArgList,
+                        const TemplateArgument *Params, unsigned NumParams,
+                        const TemplateArgument *Args, unsigned NumArgs,
                         TemplateDeductionInfo &Info,
                     llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
-  assert(ParamList.size() == ArgList.size());
-  for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
-    if (Sema::TemplateDeductionResult Result
+  unsigned ArgIdx = 0, ParamIdx = 0;
+  for (; hasTemplateArgumentForDeduction(Params, ParamIdx, NumParams); 
+       ++ParamIdx) {
+    if (!Params[ParamIdx].isPackExpansion()) {
+      // The simple case: deduce template arguments by matching P and A.
+      
+      // Check whether we have enough arguments.
+      if (!hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs))
+        return Sema::TDK_TooFewArguments;
+      
+      // Perform deduction for this P/A pair.
+      if (Sema::TemplateDeductionResult Result
           = DeduceTemplateArguments(S, TemplateParams,
-                                    ParamList[I], ArgList[I],
+                                    Params[ParamIdx], Args[ArgIdx],
                                     Info, Deduced))
-      return Result;
+        return Result;  
+      
+      // Move to the next argument.
+      ++ArgIdx;
+      continue;
+    }
+    
+    // FIXME: Variadic templates. 
+    // The parameter is a pack expansion, so we'll
+    // need to repeatedly unify arguments against the parameter, capturing
+    // the bindings for each expanded parameter pack.
+    S.Diag(Info.getLocation(), diag::err_pack_expansion_deduction);
+    return Sema::TDK_TooManyArguments;
   }
+  
+  // If there is an argument remaining, then we had too many arguments.
+  if (hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs))
+    return Sema::TDK_TooManyArguments;
+  
   return Sema::TDK_Success;
 }
 
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(Sema &S,
+                        TemplateParameterList *TemplateParams,
+                        const TemplateArgumentList &ParamList,
+                        const TemplateArgumentList &ArgList,
+                        TemplateDeductionInfo &Info,
+                    llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+  return DeduceTemplateArguments(S, TemplateParams, 
+                                 ParamList.data(), ParamList.size(),
+                                 ArgList.data(), ArgList.size(),
+                                 Info, Deduced);
+}
+
 /// \brief Determine whether two template arguments are the same.
 static bool isSameTemplateArg(ASTContext &Context,
                               const TemplateArgument &X,
@@ -1087,6 +1148,7 @@
       // When the argument is an expression, check the expression result
       // against the actual template parameter to get down to the canonical
       // template argument.
+      // FIXME: Variadic templates.
       Expr *InstExpr = InstArg.getAsExpr();
       if (NonTypeTemplateParmDecl *NTTP
             = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
@@ -1301,6 +1363,8 @@
   //
   // Take all of the explicitly-specified arguments and put them into the
   // set of deduced template arguments.
+  //
+  // FIXME: Variadic templates?
   Deduced.reserve(TemplateParams->size());
   for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I)
     Deduced.push_back(ExplicitArgumentList->get(I));
@@ -1394,6 +1458,7 @@
   //   explicitly specified, template argument deduction fails.
   llvm::SmallVector<TemplateArgument, 4> Builder;
   for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
+    // FIXME: Variadic templates. Unwrap argument packs?
     NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I);
     if (!Deduced[I].isNull()) {
       if (I < NumExplicitlySpecified) {

Added: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/count.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/count.cpp?rev=122418&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/count.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/count.cpp Wed Dec 22 12:17:10 2010
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename Head, typename ...Tail>
+struct count {
+  static const unsigned value = 1 + count<Tail...>::value;
+};
+
+template<typename T>
+struct count<T> {
+  static const unsigned value = 1;
+};
+
+int check1[count<int>::value == 1? 1 : -1];
+int check2[count<float, double>::value == 2? 1 : -1];
+int check3[count<char, signed char, unsigned char>::value == 3? 1 : -1];
+
+

Propchange: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/count.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/count.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/count.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list