]> granicus.if.org Git - clang/commitdiff
Implement the rest of C++0x [temp.deduct.type]p9, which specifies that
authorDouglas Gregor <dgregor@apple.com>
Thu, 23 Dec 2010 01:24:45 +0000 (01:24 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 23 Dec 2010 01:24:45 +0000 (01:24 +0000)
the presence of a pack expansion anywhere except at the end of a
template-argument-list causes the entire template-argument-list to be
a non-deduced context.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122461 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaTemplateDeduction.cpp
test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp
test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp [new file with mode: 0644]

index 79cbc5ab029c77150d8fd977736b0a5b375cead3..ad649c067c69968b75f3ed9034fd2912567e253e 100644 (file)
@@ -1059,6 +1059,33 @@ static TemplateParameter makeTemplateParameter(Decl *D) {
   return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
 }
 
+/// \brief Determine whether the given set of template arguments has a pack
+/// expansion that is not the last template argument.
+static bool hasPackExpansionBeforeEnd(const TemplateArgument *Args,
+                                      unsigned NumArgs) {
+  unsigned ArgIdx = 0;
+  while (ArgIdx < NumArgs) {
+    const TemplateArgument &Arg = Args[ArgIdx];
+    
+    // Unwrap argument packs.
+    if (Args[ArgIdx].getKind() == TemplateArgument::Pack) {
+      Args = Arg.pack_begin();
+      NumArgs = Arg.pack_size();
+      ArgIdx = 0;
+      continue;
+    }
+    
+    ++ArgIdx;
+    if (ArgIdx == NumArgs)
+      return false;
+    
+    if (Arg.isPackExpansion())
+      return true;
+  }
+  
+  return false;
+}
+
 static Sema::TemplateDeductionResult
 DeduceTemplateArguments(Sema &S,
                         TemplateParameterList *TemplateParams,
@@ -1071,9 +1098,9 @@ DeduceTemplateArguments(Sema &S,
   //   If the template argument list of P contains a pack expansion that is not 
   //   the last template argument, the entire template argument list is a 
   //   non-deduced context.
-  // FIXME: Implement this.
-
-
+  if (hasPackExpansionBeforeEnd(Params, NumParams))
+    return Sema::TDK_Success;
+  
   // C++0x [temp.deduct.type]p9:
   //   If P has a form that contains <T> or <i>, then each argument Pi of the 
   //   respective template argument list P is compared with the corresponding 
@@ -3052,6 +3079,15 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
       = cast<TemplateSpecializationType>(T);
     MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced,
                                Depth, Used);
+    
+    // C++0x [temp.deduct.type]p9:
+    //   If the template argument list of P contains a pack expansion that is not 
+    //   the last template argument, the entire template argument list is a 
+    //   non-deduced context.
+    if (OnlyDeduced && 
+        hasPackExpansionBeforeEnd(Spec->getArgs(), Spec->getNumArgs()))
+      break;
+
     for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
       MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth,
                                  Used);
@@ -3078,6 +3114,15 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
     if (!OnlyDeduced)
       MarkUsedTemplateParameters(SemaRef, Spec->getQualifier(),
                                  OnlyDeduced, Depth, Used);
+    
+    // C++0x [temp.deduct.type]p9:
+    //   If the template argument list of P contains a pack expansion that is not 
+    //   the last template argument, the entire template argument list is a 
+    //   non-deduced context.
+    if (OnlyDeduced && 
+        hasPackExpansionBeforeEnd(Spec->getArgs(), Spec->getNumArgs()))
+      break;
+
     for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
       MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth,
                                  Used);
@@ -3181,6 +3226,14 @@ void
 Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
                                  bool OnlyDeduced, unsigned Depth,
                                  llvm::SmallVectorImpl<bool> &Used) {
+  // C++0x [temp.deduct.type]p9:
+  //   If the template argument list of P contains a pack expansion that is not 
+  //   the last template argument, the entire template argument list is a 
+  //   non-deduced context.
+  if (OnlyDeduced && 
+      hasPackExpansionBeforeEnd(TemplateArgs.data(), TemplateArgs.size()))
+    return;
+
   for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
     ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, 
                                  Depth, Used);
@@ -3196,6 +3249,7 @@ Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
   Deduced.clear();
   Deduced.resize(TemplateParams->size());
   
+  // FIXME: Variadic templates.
   FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
   for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I)
     ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(),
index ad8a81c1dea27d2b52c4a8d885b4cc6cee2f5f37..198f11fe5298b768c84a7b65cfa26b9e329f4df9 100644 (file)
@@ -18,6 +18,6 @@ struct same_tuple<tuple<Types1...>, tuple<Types1...> > {
   static const bool value = true;
 };
 
-//int same_tuple_check1[same_tuple<tuple<int, float>, tuple<int, double>>::value? -1 : 1];
+int same_tuple_check1[same_tuple<tuple<int, float>, tuple<int, double>>::value? -1 : 1];
 int same_tuple_check2[same_tuple<tuple<float, double>, tuple<float, double>>::value? 1 : -1];
 
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
new file mode 100644 (file)
index 0000000..ebfcd38
--- /dev/null
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename ...Types> struct tuple;
+
+namespace PackExpansionNotAtEnd {
+  template<typename T, typename U>
+  struct tuple_same_with_int {
+    static const bool value = false;
+  };
+
+  template<typename ...Types>
+  struct tuple_same_with_int<tuple<Types...>, tuple<Types..., int>> {
+    static const bool value = true;
+  };
+
+  int tuple_same_with_int_1[tuple_same_with_int<tuple<int, float, double>,
+                                                tuple<int, float, double, int>
+                                                >::value? 1 : -1];
+
+  template<typename ... Types> struct UselessPartialSpec;
+
+           template<typename ... Types, // expected-note{{non-deducible template parameter 'Types'}}
+           typename Tail> // expected-note{{non-deducible template parameter 'Tail'}}
+  struct UselessPartialSpec<Types..., Tail>; // expected-warning{{class template partial specialization contains template parameters that can not be deduced; this partial specialization will never be used}}
+}