[cfe-commits] r123163 - in /cfe/trunk: include/clang/AST/ include/clang/Sema/ lib/Sema/ test/CXX/temp/temp.decls/temp.variadic/ test/CXX/temp/temp.fct.spec/temp.arg.explicit/

Douglas Gregor dgregor at apple.com
Sun Jan 9 23:32:04 PST 2011


Author: dgregor
Date: Mon Jan 10 01:32:04 2011
New Revision: 123163

URL: http://llvm.org/viewvc/llvm-project?rev=123163&view=rev
Log:
Work-in-progress implementation of C++0x [temp.arg.explicit]p9, which
allows an argument pack determines via explicit specification of
function template arguments to be extended by further, deduced
arguments. For example:

template<class ... Types> void f(Types ... values);
void g() { 
  f<int*, float*>(0, 0, 0);   // Types is deduced to the sequence int*, float*, int
}

There are a number of FIXMEs in here that indicate places where we
need to implement + test retained expansions, plus a number of other
places in deduction where we need to correctly cope with the
explicitly-specified arguments when deducing an argument
pack. Furthermore, it appears that the RecursiveASTVisitor needs to be
auditied; it's missing some traversals (especially w.r.t. template
arguments) that cause it not to find unexpanded parameter packs when
it should.

The good news, however, is that the tr1::tuple implementation now
works fully, and the tr1::bind example (both from N2080) is actually
working now. 

Added:
    cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp   (with props)
Modified:
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/include/clang/AST/TemplateBase.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Sema/Template.h
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=123163&r1=123162&r2=123163&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Mon Jan 10 01:32:04 2011
@@ -1801,7 +1801,7 @@
 DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
 DEF_TRAVERSE_STMT(ExprWithCleanups, { })
 DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
-DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, { })
+  DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, { }) // FIXME: Incomplete!
 DEF_TRAVERSE_STMT(CXXThisExpr, { })
 DEF_TRAVERSE_STMT(CXXThrowExpr, { })
 DEF_TRAVERSE_STMT(DesignatedInitExpr, { })
@@ -1820,8 +1820,18 @@
 DEF_TRAVERSE_STMT(PredefinedExpr, { })
 DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
 DEF_TRAVERSE_STMT(StmtExpr, { })
-DEF_TRAVERSE_STMT(UnresolvedLookupExpr, { })
-DEF_TRAVERSE_STMT(UnresolvedMemberExpr, { })
+DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
+  TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
+  TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(), 
+                                            S->getNumTemplateArgs()));
+})
+  
+DEF_TRAVERSE_STMT(UnresolvedMemberExpr, {
+  TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
+  TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(), 
+                                            S->getNumTemplateArgs()));
+})
+
 DEF_TRAVERSE_STMT(CXXOperatorCallExpr, { })
 DEF_TRAVERSE_STMT(OpaqueValueExpr, { })
 

Modified: cfe/trunk/include/clang/AST/TemplateBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TemplateBase.h?rev=123163&r1=123162&r2=123163&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/TemplateBase.h (original)
+++ cfe/trunk/include/clang/AST/TemplateBase.h Mon Jan 10 01:32:04 2011
@@ -77,7 +77,7 @@
       void *Type;
     } Integer;
     struct {
-      TemplateArgument *Args;
+      const TemplateArgument *Args;
       unsigned NumArgs;
     } Args;
   };
@@ -136,7 +136,7 @@
   ///
   /// We assume that storage for the template arguments provided
   /// outlives the TemplateArgument itself.
-  TemplateArgument(TemplateArgument *Args, unsigned NumArgs) : Kind(Pack) {
+  TemplateArgument(const TemplateArgument *Args, unsigned NumArgs) : Kind(Pack){
     this->Args.Args = Args;
     this->Args.NumArgs = NumArgs;
   }

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=123163&r1=123162&r2=123163&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Jan 10 01:32:04 2011
@@ -3361,6 +3361,11 @@
   /// expand the corresponding pack expansions into separate arguments. When
   /// set, \c NumExpansions must also be set.
   ///
+  /// \param RetainExpansion Whether the caller should add an unexpanded
+  /// pack expansion after all of the expanded arguments. This is used
+  /// when extending explicitly-specified template argument packs per
+  /// C++0x [temp.arg.explicit]p9.
+  ///
   /// \param NumExpansions The number of separate arguments that will be in
   /// the expanded form of the corresponding pack expansion. Must be set when
   /// \c ShouldExpand is \c true.
@@ -3375,6 +3380,7 @@
                                        unsigned NumUnexpanded,
                              const MultiLevelTemplateArgumentList &TemplateArgs,
                                        bool &ShouldExpand,
+                                       bool &RetainExpansion,
                                        unsigned &NumExpansions);
 
   /// \brief Determine whether the given declarator contains any unexpanded

Modified: cfe/trunk/include/clang/Sema/Template.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Template.h?rev=123163&r1=123162&r2=123163&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Template.h (original)
+++ cfe/trunk/include/clang/Sema/Template.h Mon Jan 10 01:32:04 2011
@@ -81,6 +81,16 @@
       return !(*this)(Depth, Index).isNull();
     }
     
+    /// \brief Clear out a specific template argument.
+    void setArgument(unsigned Depth, unsigned Index,
+                     TemplateArgument Arg) {
+      assert(Depth < TemplateArgumentLists.size());
+      assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].second);
+      const_cast<TemplateArgument&>(
+                TemplateArgumentLists[getNumLevels() - Depth - 1].first[Index])
+        = Arg;
+    }
+    
     /// \brief Add a new outermost level to the multi-level template argument 
     /// list.
     void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) {
@@ -141,7 +151,7 @@
       : TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) { }
 
     /// \brief Construct an integral non-type template argument that
-    /// has been deduced, possible from an array bound.
+    /// has been deduced, possibly from an array bound.
     DeducedTemplateArgument(const llvm::APSInt &Value,
                             QualType ValueType,
                             bool DeducedFromArrayBound)
@@ -214,6 +224,19 @@
     /// lookup will search our outer scope.
     bool CombineWithOuterScope;
     
+    /// \brief If non-NULL, the template parameter pack that has been
+    /// partially substituted per C++0x [temp.arg.explicit]p9.
+    NamedDecl *PartiallySubstitutedPack;
+    
+    /// \brief If \c PartiallySubstitutedPack is non-null, the set of
+    /// explicitly-specified template arguments in that pack.
+    const TemplateArgument *ArgsInPartiallySubstitutedPack;    
+    
+    /// \brief If \c PartiallySubstitutedPack, the number of 
+    /// explicitly-specified template arguments in 
+    /// ArgsInPartiallySubstitutedPack.
+    unsigned NumArgsInPartiallySubstitutedPack;
+
     // This class is non-copyable
     LocalInstantiationScope(const LocalInstantiationScope &);
     LocalInstantiationScope &operator=(const LocalInstantiationScope &);
@@ -221,7 +244,8 @@
   public:
     LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
       : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
-        Exited(false), CombineWithOuterScope(CombineWithOuterScope)
+        Exited(false), CombineWithOuterScope(CombineWithOuterScope),
+        PartiallySubstitutedPack(0)
     {
       SemaRef.CurrentInstantiationScope = this;
     }
@@ -271,6 +295,29 @@
     void InstantiatedLocal(const Decl *D, Decl *Inst);
     void InstantiatedLocalPackArg(const Decl *D, Decl *Inst);
     void MakeInstantiatedLocalArgPack(const Decl *D);
+    
+    /// \brief Note that the given parameter pack has been partially substituted
+    /// via explicit specification of template arguments 
+    /// (C++0x [temp.arg.explicit]p9).
+    ///
+    /// \param Pack The parameter pack, which will always be a template
+    /// parameter pack.
+    ///
+    /// \param ExplicitArgs The explicitly-specified template arguments provided
+    /// for this parameter pack.
+    ///
+    /// \param NumExplicitArgs The number of explicitly-specified template
+    /// arguments provided for this parameter pack.
+    void SetPartiallySubstitutedPack(NamedDecl *Pack, 
+                                     const TemplateArgument *ExplicitArgs,
+                                     unsigned NumExplicitArgs);
+    
+    /// \brief Retrieve the partially-substitued template parameter pack.
+    ///
+    /// If there is no partially-substituted parameter pack, returns NULL.
+    NamedDecl *getPartiallySubstitutedPack(
+                                      const TemplateArgument **ExplicitArgs = 0,
+                                           unsigned *NumExplicitArgs = 0) const;
   };
 
   class TemplateDeclInstantiator

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=123163&r1=123162&r2=123163&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Jan 10 01:32:04 2011
@@ -2550,10 +2550,13 @@
   
   // Form argument packs for each of the parameter packs remaining.
   while (Param != ParamEnd) {
+    // If we're checking a partial list of template arguments, don't fill
+    // in arguments for non-template parameter packs.
+    
     if ((*Param)->isTemplateParameterPack()) {     
-      // The parameter pack takes the contents of the current argument pack,
-      // which we built up earlier.
-      if (ArgumentPack.empty()) {
+      if (PartialTemplateArgs && ArgumentPack.empty()) {
+        Converted.push_back(TemplateArgument());
+      } else if (ArgumentPack.empty()) {
         Converted.push_back(TemplateArgument(0, 0));
       } else {
         TemplateArgument *PackedArgs
@@ -3600,7 +3603,7 @@
 Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
                                                   SourceLocation Loc) {
   assert(Arg.getKind() == TemplateArgument::Integral &&
-         "Operation is only value for integral template arguments");
+         "Operation is only valid for integral template arguments");
   QualType T = Arg.getIntegralType();
   if (T->isCharType() || T->isWideCharType())
     return Owned(new (Context) CharacterLiteral(

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=123163&r1=123162&r2=123163&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Mon Jan 10 01:32:04 2011
@@ -478,14 +478,9 @@
   }
 }
 
-/// \brief Retrieve the depth and index of an unexpanded parameter pack.
+/// \brief Retrieve the depth and index of a template parameter.
 static std::pair<unsigned, unsigned> 
-getDepthAndIndex(UnexpandedParameterPack UPP) {
-  if (const TemplateTypeParmType *TTP
-                          = UPP.first.dyn_cast<const TemplateTypeParmType *>())
-    return std::make_pair(TTP->getDepth(), TTP->getIndex());
-  
-  NamedDecl *ND = UPP.first.get<NamedDecl *>();
+getDepthAndIndex(NamedDecl *ND) {
   if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
     return std::make_pair(TTP->getDepth(), TTP->getIndex());
   
@@ -496,6 +491,16 @@
   return std::make_pair(TTP->getDepth(), TTP->getIndex());
 }
 
+/// \brief Retrieve the depth and index of an unexpanded parameter pack.
+static std::pair<unsigned, unsigned> 
+getDepthAndIndex(UnexpandedParameterPack UPP) {
+  if (const TemplateTypeParmType *TTP
+                          = UPP.first.dyn_cast<const TemplateTypeParmType *>())
+    return std::make_pair(TTP->getDepth(), TTP->getIndex());
+  
+  return getDepthAndIndex(UPP.first.get<NamedDecl *>());
+}
+
 /// \brief Helper function to build a TemplateParameter when we don't
 /// know its type statically.
 static TemplateParameter makeTemplateParameter(Decl *D) {
@@ -602,6 +607,12 @@
     }
     assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?");
 
+    // Keep track of the deduced template arguments for each parameter pack
+    // expanded by this pack expansion (the outer index) and for each 
+    // template argument (the inner SmallVectors).
+    llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2>
+      NewlyDeducedPacks(PackIndices.size());
+
     // Save the deduced template arguments for each parameter pack expanded
     // by this pack expansion, then clear out the deduction.
     llvm::SmallVector<DeducedTemplateArgument, 2> 
@@ -609,13 +620,21 @@
     for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
       SavedPacks[I] = Deduced[PackIndices[I]];
       Deduced[PackIndices[I]] = DeducedTemplateArgument();
+      
+      // If the template arugment pack was explicitly specified, add that to
+      // the set of deduced arguments.
+      const TemplateArgument *ExplicitArgs;
+      unsigned NumExplicitArgs;
+      if (NamedDecl *PartiallySubstitutedPack 
+            = S.CurrentInstantiationScope->getPartiallySubstitutedPack(
+                                                           &ExplicitArgs,
+                                                           &NumExplicitArgs)) {
+        if (getDepthAndIndex(PartiallySubstitutedPack).second == PackIndices[I])
+          NewlyDeducedPacks[I].append(ExplicitArgs, 
+                                      ExplicitArgs + NumExplicitArgs);
+      }
     }
     
-    // Keep track of the deduced template arguments for each parameter pack
-    // expanded by this pack expansion (the outer index) and for each 
-    // template argument (the inner SmallVectors).
-    llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2>
-      NewlyDeducedPacks(PackIndices.size());
     bool HasAnyArguments = false;
     for (; ArgIdx < NumArgs; ++ArgIdx) {
       HasAnyArguments = true;
@@ -1879,13 +1898,30 @@
   TemplateArgumentList *ExplicitArgumentList
     = TemplateArgumentList::CreateCopy(Context, Builder.data(), Builder.size());
   Info.reset(ExplicitArgumentList);
-
+  
   // Template argument deduction and the final substitution should be
   // done in the context of the templated declaration.  Explicit
   // argument substitution, on the other hand, needs to happen in the
   // calling context.
   ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl());
 
+  // If we deduced template arguments for a template parameter pack, 
+  // note that the template argument pack is partially substituted and record
+  // the explicit template arguments. They'll be used as part of deduction
+  // for this template parameter pack.
+  bool HasPartiallySubstitutedPack = false;
+  for (unsigned I = 0, N = Builder.size(); I != N; ++I) {
+    const TemplateArgument &Arg = Builder[I];
+    if (Arg.getKind() == TemplateArgument::Pack) {
+      HasPartiallySubstitutedPack = true;
+      CurrentInstantiationScope->SetPartiallySubstitutedPack(
+                                                 TemplateParams->getParam(I), 
+                                                             Arg.pack_begin(),
+                                                             Arg.pack_size());
+      break;
+    }
+  }
+
   // Instantiate the types of each of the function parameters given the
   // explicitly-specified template arguments.
   if (SubstParmTypes(Function->getLocation(), 
@@ -1927,11 +1963,18 @@
   //   template arguments can be deduced, they may all be omitted; in this
   //   case, the empty template argument list <> itself may also be omitted.
   //
-  // Take all of the explicitly-specified arguments and put them into the
-  // set of deduced template arguments.
+  // Take all of the explicitly-specified arguments and put them into
+  // the set of deduced template arguments. Explicitly-specified
+  // parameter packs, however, will be set to NULL since the deduction
+  // mechanisms handle explicitly-specified argument packs directly.
   Deduced.reserve(TemplateParams->size());
-  for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I)
-    Deduced.push_back(ExplicitArgumentList->get(I));
+  for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) {
+    const TemplateArgument &Arg = ExplicitArgumentList->get(I);
+    if (Arg.getKind() == TemplateArgument::Pack)
+      Deduced.push_back(DeducedTemplateArgument());
+    else
+      Deduced.push_back(Arg);
+  }
 
   return TDK_Success;
 }
@@ -2025,7 +2068,18 @@
     //    be deduced to an empty sequence of template arguments.
     // FIXME: Where did the word "trailing" come from?
     if (Param->isTemplateParameterPack()) {
-      Builder.push_back(TemplateArgument(0, 0));
+      // We may have had explicitly-specified template arguments for this
+      // template parameter pack. If so, our empty deduction extends the
+      // explicitly-specified set (C++0x [temp.arg.explicit]p9).
+      const TemplateArgument *ExplicitArgs;
+      unsigned NumExplicitArgs;
+      if (CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs,
+                                                             &NumExplicitArgs)
+          == Param)
+        Builder.push_back(TemplateArgument(ExplicitArgs, NumExplicitArgs));
+      else   
+        Builder.push_back(TemplateArgument(0, 0));
+      
       continue;
     }
 
@@ -2446,20 +2500,36 @@
     }
     assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?");
     
+    // Keep track of the deduced template arguments for each parameter pack
+    // expanded by this pack expansion (the outer index) and for each 
+    // template argument (the inner SmallVectors).
+    llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2>
+      NewlyDeducedPacks(PackIndices.size());
+    
     // Save the deduced template arguments for each parameter pack expanded
     // by this pack expansion, then clear out the deduction.
     llvm::SmallVector<DeducedTemplateArgument, 2> 
-    SavedPacks(PackIndices.size());
+      SavedPacks(PackIndices.size());
     for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
+      // Save the previously-deduced argument pack, then clear it out so that we
+      // can deduce a new argument pack.
       SavedPacks[I] = Deduced[PackIndices[I]];
-      Deduced[PackIndices[I]] = DeducedTemplateArgument();
+      Deduced[PackIndices[I]] = TemplateArgument();      
+      
+      // If the template arugment pack was explicitly specified, add that to
+      // the set of deduced arguments.
+      const TemplateArgument *ExplicitArgs;
+      unsigned NumExplicitArgs;
+      if (NamedDecl *PartiallySubstitutedPack 
+            = CurrentInstantiationScope->getPartiallySubstitutedPack(
+                                                                &ExplicitArgs,
+                                                            &NumExplicitArgs)) {
+        if (getDepthAndIndex(PartiallySubstitutedPack).second == PackIndices[I])
+          NewlyDeducedPacks[I].append(ExplicitArgs, 
+                                      ExplicitArgs + NumExplicitArgs);
+      }
     }
     
-    // Keep track of the deduced template arguments for each parameter pack
-    // expanded by this pack expansion (the outer index) and for each 
-    // template argument (the inner SmallVectors).
-    llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2>
-    NewlyDeducedPacks(PackIndices.size());
     bool HasAnyArguments = false;
     for (; ArgIdx < NumArgs; ++ArgIdx) {
       HasAnyArguments = true;

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=123163&r1=123162&r2=123163&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Jan 10 01:32:04 2011
@@ -564,6 +564,19 @@
   return 0;
 }
 
+/// \brief Retrieve the depth and index of a parameter pack.
+static std::pair<unsigned, unsigned> 
+getDepthAndIndex(NamedDecl *ND) {
+  if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
+    return std::make_pair(TTP->getDepth(), TTP->getIndex());
+  
+  if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
+    return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
+  
+  TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
+  return std::make_pair(TTP->getDepth(), TTP->getIndex());
+}
+
 //===----------------------------------------------------------------------===/
 // Template Instantiation for Types
 //===----------------------------------------------------------------------===/
@@ -608,12 +621,14 @@
                                  const UnexpandedParameterPack *Unexpanded,
                                  unsigned NumUnexpanded,
                                  bool &ShouldExpand,
+                                 bool &RetainExpansion,
                                  unsigned &NumExpansions) {
       return getSema().CheckParameterPacksForExpansion(EllipsisLoc, 
                                                        PatternRange, Unexpanded,
                                                        NumUnexpanded, 
                                                        TemplateArgs, 
                                                        ShouldExpand,
+                                                       RetainExpansion,
                                                        NumExpansions);
     }
 
@@ -621,6 +636,37 @@
       SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Pack);
     }
     
+    TemplateArgument ForgetPartiallySubstitutedPack() {
+      TemplateArgument Result;
+      if (NamedDecl *PartialPack
+            = SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()){
+        MultiLevelTemplateArgumentList &TemplateArgs
+          = const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+        unsigned Depth, Index;
+        llvm::tie(Depth, Index) = getDepthAndIndex(PartialPack);
+        if (TemplateArgs.hasTemplateArgument(Depth, Index)) {
+          Result = TemplateArgs(Depth, Index);
+          TemplateArgs.setArgument(Depth, Index, TemplateArgument());
+        }
+      }
+      
+      return Result;
+    }
+    
+    void RememberPartiallySubstitutedPack(TemplateArgument Arg) {
+      if (Arg.isNull())
+        return;
+      
+      if (NamedDecl *PartialPack
+            = SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()){
+        MultiLevelTemplateArgumentList &TemplateArgs
+        = const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+        unsigned Depth, Index;
+        llvm::tie(Depth, Index) = getDepthAndIndex(PartialPack);
+        TemplateArgs.setArgument(Depth, Index, Arg);
+      }
+    }
+
     /// \brief Transform the given declaration by instantiating a reference to
     /// this declaration.
     Decl *TransformDecl(SourceLocation Loc, Decl *D);
@@ -713,6 +759,7 @@
           return 0;
         }
         
+        assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
         Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
       }
 
@@ -761,6 +808,7 @@
           return 0;
         }
         
+        assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
         Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
       }
 
@@ -877,6 +925,7 @@
       return ExprError();
     }
     
+    assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
     Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
   }
 
@@ -981,6 +1030,7 @@
         return QualType();
       }
       
+      assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
       Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
     }
     
@@ -1272,11 +1322,13 @@
       collectUnexpandedParameterPacks(Base->getTypeSourceInfo()->getTypeLoc(),
                                       Unexpanded);
       bool ShouldExpand = false;
+      bool RetainExpansion = false;
       unsigned NumExpansions = 0;
       if (CheckParameterPacksForExpansion(Base->getEllipsisLoc(), 
                                           Base->getSourceRange(),
                                           Unexpanded.data(), Unexpanded.size(),
                                           TemplateArgs, ShouldExpand, 
+                                          RetainExpansion,
                                           NumExpansions)) {
         Invalid = true;
         continue;
@@ -1959,9 +2011,13 @@
 
 void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) {
   llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
-  assert((Stored.isNull() || 
-          (Stored.get<Decl *>() == Inst)) && "Already instantiated this local");
-  Stored = Inst;
+  if (Stored.isNull())
+    Stored = Inst;
+  else if (Stored.is<Decl *>()) {
+    assert(Stored.get<Decl *>() == Inst && "Already instantiated this local");
+    Stored = Inst;
+  } else
+    LocalDecls[D].get<DeclArgumentPack *>()->push_back(Inst);
 }
 
 void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, 
@@ -1978,3 +2034,41 @@
   ArgumentPacks.push_back(Pack);
 }
 
+void LocalInstantiationScope::SetPartiallySubstitutedPack(NamedDecl *Pack, 
+                                          const TemplateArgument *ExplicitArgs,
+                                                    unsigned NumExplicitArgs) {
+  assert((!PartiallySubstitutedPack || PartiallySubstitutedPack == Pack) &&
+         "Already have a partially-substituted pack");
+  assert((!PartiallySubstitutedPack 
+          || NumArgsInPartiallySubstitutedPack == NumExplicitArgs) &&
+         "Wrong number of arguments in partially-substituted pack");
+  PartiallySubstitutedPack = Pack;
+  ArgsInPartiallySubstitutedPack = ExplicitArgs;
+  NumArgsInPartiallySubstitutedPack = NumExplicitArgs;
+}
+
+NamedDecl *LocalInstantiationScope::getPartiallySubstitutedPack(
+                                         const TemplateArgument **ExplicitArgs,
+                                              unsigned *NumExplicitArgs) const {
+  if (ExplicitArgs)
+    *ExplicitArgs = 0;
+  if (NumExplicitArgs)
+    *NumExplicitArgs = 0;
+  
+  for (const LocalInstantiationScope *Current = this; Current; 
+       Current = Current->Outer) {
+    if (Current->PartiallySubstitutedPack) {
+      if (ExplicitArgs)
+        *ExplicitArgs = Current->ArgsInPartiallySubstitutedPack;
+      if (NumExplicitArgs)
+        *NumExplicitArgs = Current->NumArgsInPartiallySubstitutedPack;
+      
+      return Current->PartiallySubstitutedPack;
+    }
+
+    if (!Current->CombineWithOuterScope)
+      break;
+  }
+  
+  return 0;
+}

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=123163&r1=123162&r2=123163&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Jan 10 01:32:04 2011
@@ -1973,13 +1973,16 @@
                "Pack expansion without parameter packs?");
         
         bool Expand = false;
+        bool RetainExpansion = false;
         unsigned NumExpansions = 0;
         if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(), 
                                                     SourceRange(),
                                                     Unexpanded.data(), 
                                                     Unexpanded.size(),
                                                     TemplateArgs,
-                                                    Expand, NumExpansions))
+                                                    Expand, 
+                                                    RetainExpansion,
+                                                    NumExpansions))
           break;
                       
         if (!Expand) {
@@ -2377,12 +2380,14 @@
       llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
       collectUnexpandedParameterPacks(BaseTL, Unexpanded);
       bool ShouldExpand = false;
+      bool RetainExpansion = false;
       unsigned NumExpansions = 0;
       if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(), 
                                           BaseTL.getSourceRange(),
                                           Unexpanded.data(), 
                                           Unexpanded.size(),
                                           TemplateArgs, ShouldExpand, 
+                                          RetainExpansion,
                                           NumExpansions)) {
         AnyErrors = true;
         New->setInvalidDecl();

Modified: cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp?rev=123163&r1=123162&r2=123163&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp Mon Jan 10 01:32:04 2011
@@ -419,14 +419,29 @@
                                                EllipsisLoc));
 }
 
+/// \brief Retrieve the depth and index of a parameter pack.
+static std::pair<unsigned, unsigned> 
+getDepthAndIndex(NamedDecl *ND) {
+  if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
+    return std::make_pair(TTP->getDepth(), TTP->getIndex());
+  
+  if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
+    return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
+  
+  TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
+  return std::make_pair(TTP->getDepth(), TTP->getIndex());
+}
+
 bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
                                            SourceRange PatternRange,
                                      const UnexpandedParameterPack *Unexpanded,
                                            unsigned NumUnexpanded,
                              const MultiLevelTemplateArgumentList &TemplateArgs,
                                            bool &ShouldExpand,
+                                           bool &RetainExpansion,
                                            unsigned &NumExpansions) {                                        
   ShouldExpand = true;
+  RetainExpansion = false;
   std::pair<IdentifierInfo *, SourceLocation> FirstPack;
   bool HaveFirstPack = false;
   
@@ -444,21 +459,11 @@
       Name = TTP->getName();
     } else {
       NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>();
-      if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) {
-        Depth = TTP->getDepth();
-        Index = TTP->getIndex();
-      } else if (NonTypeTemplateParmDecl *NTTP
-                 = dyn_cast<NonTypeTemplateParmDecl>(ND)) {        
-        Depth = NTTP->getDepth();
-        Index = NTTP->getIndex();
-      } else if (TemplateTemplateParmDecl *TTP
-                                    = dyn_cast<TemplateTemplateParmDecl>(ND)) {
-        Depth = TTP->getDepth();
-        Index = TTP->getIndex();
-      } else {
-        assert(cast<ParmVarDecl>(ND)->isParameterPack());
+      if (isa<ParmVarDecl>(ND))
         IsFunctionParameterPack = true;
-      }
+      else
+        llvm::tie(Depth, Index) = getDepthAndIndex(ND);        
+      
       Name = ND->getIdentifier();
     }
     
@@ -495,6 +500,18 @@
       NewPackSize = TemplateArgs(Depth, Index).pack_size();
     }
     
+    // C++0x [temp.arg.explicit]p9:
+    //   Template argument deduction can extend the sequence of template 
+    //   arguments corresponding to a template parameter pack, even when the
+    //   sequence contains explicitly specified template arguments.
+    if (NamedDecl *PartialPack 
+                  = CurrentInstantiationScope->getPartiallySubstitutedPack()) {
+      unsigned PartialDepth, PartialIndex;
+      llvm::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack);
+      if (PartialDepth == Depth && PartialIndex == Index)
+        RetainExpansion = true;
+    }
+
     if (!HaveFirstPack) {
       // The is the first pack we've seen for which we have an argument. 
       // Record it.

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=123163&r1=123162&r2=123163&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Mon Jan 10 01:32:04 2011
@@ -89,6 +89,23 @@
 /// (\c getBaseLocation(), \c getBaseEntity()).
 template<typename Derived>
 class TreeTransform {
+  /// \brief Private RAII object that helps us forget and then re-remember
+  /// the template argument corresponding to a partially-substituted parameter
+  /// pack.
+  class ForgetPartiallySubstitutedPackRAII {
+    Derived &Self;
+    TemplateArgument Old;
+    
+  public:
+    ForgetPartiallySubstitutedPackRAII(Derived &Self) : Self(Self) {
+      Old = Self.ForgetPartiallySubstitutedPack();
+    }
+    
+    ~ForgetPartiallySubstitutedPackRAII() {
+      Self.RememberPartiallySubstitutedPack(Old);
+    }
+  };
+  
 protected:
   Sema &SemaRef;
   
@@ -204,6 +221,11 @@
   /// expand the corresponding pack expansions into separate arguments. When
   /// set, \c NumExpansions must also be set.
   ///
+  /// \param RetainExpansion Whether the caller should add an unexpanded
+  /// pack expansion after all of the expanded arguments. This is used
+  /// when extending explicitly-specified template argument packs per
+  /// C++0x [temp.arg.explicit]p9.
+  ///
   /// \param NumExpansions The number of separate arguments that will be in
   /// the expanded form of the corresponding pack expansion. Must be set when
   /// \c ShouldExpand is \c true.
@@ -217,11 +239,28 @@
                                const UnexpandedParameterPack *Unexpanded,
                                unsigned NumUnexpanded,
                                bool &ShouldExpand,
+                               bool &RetainExpansion,
                                unsigned &NumExpansions) {
     ShouldExpand = false;
     return false;
   }
   
+  /// \brief "Forget" about the partially-substituted pack template argument,
+  /// when performing an instantiation that must preserve the parameter pack
+  /// use.
+  ///
+  /// This routine is meant to be overridden by the template instantiator.
+  TemplateArgument ForgetPartiallySubstitutedPack() {
+    return TemplateArgument();
+  }
+  
+  /// \brief "Remember" the partially-substituted pack template argument
+  /// after performing an instantiation that must preserve the parameter pack
+  /// use.
+  ///
+  /// This routine is meant to be overridden by the template instantiator.
+  void RememberPartiallySubstitutedPack(TemplateArgument Arg) { }
+  
   /// \brief Note to the derived class when a function parameter pack is
   /// being expanded.
   void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { }
@@ -2250,12 +2289,14 @@
       // Determine whether the set of unexpanded parameter packs can and should
       // be expanded.
       bool Expand = true;
+      bool RetainExpansion = false;
       unsigned NumExpansions = 0;
       if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(),
                                                Pattern->getSourceRange(),
                                                Unexpanded.data(),
                                                Unexpanded.size(),
-                                               Expand, NumExpansions))
+                                               Expand, RetainExpansion,
+                                               NumExpansions))
         return true;
         
       if (!Expand) {
@@ -2770,12 +2811,15 @@
       // Determine whether the set of unexpanded parameter packs can and should
       // be expanded.
       bool Expand = true;
+      bool RetainExpansion = false;
       unsigned NumExpansions = 0;
       if (getDerived().TryExpandParameterPacks(Ellipsis,
                                                Pattern.getSourceRange(),
                                                Unexpanded.data(),
                                                Unexpanded.size(),
-                                               Expand, NumExpansions))
+                                               Expand, 
+                                               RetainExpansion,
+                                               NumExpansions))
         return true;
       
       if (!Expand) {
@@ -2806,6 +2850,8 @@
         Outputs.addArgument(Out);
       }
       
+      // FIXME: Variadic templates retain expansion!
+      
       continue;
     }
     
@@ -3415,12 +3461,15 @@
         
         // Determine whether we should expand the parameter packs.
         bool ShouldExpand = false;
+        bool RetainExpansion = false;
         unsigned NumExpansions = 0;
         if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
                                                  Pattern.getSourceRange(),
                                                  Unexpanded.data(), 
                                                  Unexpanded.size(),
-                                                 ShouldExpand, NumExpansions)) {
+                                                 ShouldExpand, 
+                                                 RetainExpansion,
+                                                 NumExpansions)) {
           return true;
         }
         
@@ -3439,7 +3488,21 @@
             if (PVars)
               PVars->push_back(NewParm);
           }
-          
+
+          // If we're supposed to retain a pack expansion, do so by temporarily
+          // forgetting the partially-substituted parameter pack.
+          if (RetainExpansion) {
+            ForgetPartiallySubstitutedPackRAII Forget(getDerived());
+            ParmVarDecl *NewParm 
+              = getDerived().TransformFunctionTypeParam(OldParm);
+            if (!NewParm)
+              return true;
+            
+            OutParamTypes.push_back(NewParm->getType());
+            if (PVars)
+              PVars->push_back(NewParm);
+          }
+
           // We're done with the pack expansion.
           continue;
         }
@@ -3472,11 +3535,14 @@
       
       // Determine whether we should expand the parameter packs.
       bool ShouldExpand = false;
+      bool RetainExpansion = false;
       unsigned NumExpansions = 0;
       if (getDerived().TryExpandParameterPacks(Loc, SourceRange(),
                                                Unexpanded.data(), 
                                                Unexpanded.size(),
-                                               ShouldExpand, NumExpansions)) {
+                                               ShouldExpand, 
+                                               RetainExpansion,
+                                               NumExpansions)) {
         return true;
       }
       
@@ -3498,6 +3564,8 @@
         continue;
       }
       
+      // FIXME: Variadic templates retain pack expansion!
+
       // We'll substitute the parameter now without expanding the pack 
       // expansion.
       OldType = Expansion->getPattern();
@@ -6674,13 +6742,15 @@
   // so 
   UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc());
   bool ShouldExpand = false;
+  bool RetainExpansion = false;
   unsigned NumExpansions = 0;
   if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(), 
                                            &Unexpanded, 1, 
-                                           ShouldExpand, NumExpansions))
+                                           ShouldExpand, RetainExpansion,
+                                           NumExpansions))
     return ExprError();
   
-  if (!ShouldExpand)
+  if (!ShouldExpand || RetainExpansion)
     return SemaRef.Owned(E);
   
   // We now know the length of the parameter pack, so build a new expression

Added: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp?rev=123163&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp Mon Jan 10 01:32:04 2011
@@ -0,0 +1,352 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// Example bind implementation from the variadic templates proposal,
+// ISO C++ committee document number N2080.
+
+// Helper type traits
+template<typename T>
+struct add_reference {
+  typedef T &type;
+};
+
+template<typename T>
+struct add_reference<T&> {
+  typedef T &type;
+};
+
+template<typename T>
+struct add_const_reference {
+  typedef T const &type;
+};
+
+template<typename T>
+struct add_const_reference<T&> {
+  typedef T &type;
+};
+
+template<typename T, typename U>
+struct is_same {
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+  static const bool value = true;
+};
+
+template<typename T> 
+class reference_wrapper { 
+  T *ptr;
+
+public:
+  reference_wrapper(T& t) : ptr(&t) { }
+  operator T&() const { return *ptr; }
+};
+
+template<typename T> reference_wrapper<T> ref(T& t) { 
+  return reference_wrapper<T>(t); 
+}
+template<typename T> reference_wrapper<const T> cref(const T& t) {
+  return reference_wrapper<const T>(t); 
+}
+
+template<typename... Values> class tuple;
+
+// Basis case: zero-length tuple
+template<> class tuple<> { };
+
+template<typename Head, typename... Tail> 
+class tuple<Head, Tail...> : private tuple<Tail...> { 
+  typedef tuple<Tail...> inherited;
+
+public: 
+  tuple() { }
+  // implicit copy-constructor is okay
+
+  // Construct tuple from separate arguments. 
+  tuple(typename add_const_reference<Head>::type v,
+        typename add_const_reference<Tail>::type... vtail) 
+    : m_head(v), inherited(vtail...) { }
+
+  // Construct tuple from another tuple. 
+  template<typename... VValues> tuple(const tuple<VValues...>& other)
+    : m_head(other.head()), inherited(other.tail()) { }
+
+  template<typename... VValues> tuple& 
+  operator=(const tuple<VValues...>& other) {
+    m_head = other.head(); 
+    tail() = other.tail(); 
+    return *this;
+  }
+
+  typename add_reference<Head>::type head() { return m_head; } 
+  typename add_reference<const Head>::type head() const { return m_head; }
+  inherited& tail() { return *this; } 
+  const inherited& tail() const { return *this; }
+
+protected: 
+  Head m_head;
+};
+
+// Creation functions
+template<typename T> 
+struct make_tuple_result {
+  typedef T type;
+};
+
+template<typename T> 
+struct make_tuple_result<reference_wrapper<T> > {
+  typedef T& type;
+};
+
+template<typename... Values> 
+tuple<typename make_tuple_result<Values>::type...> 
+make_tuple(const Values&... values) {
+  return tuple<typename make_tuple_result<Values>::type...>(values...);
+}
+
+template<typename... Values> 
+tuple<Values&...> tie(Values&... values) {
+  return tuple<Values&...>(values...);
+}
+
+// Helper classes
+template<typename Tuple> struct tuple_size;
+
+template<typename... Values> struct tuple_size<tuple<Values...> > {
+  static const int value = sizeof...(Values);
+};
+
+template<int I, typename Tuple> struct tuple_element;
+
+template<int I, typename Head, typename... Tail> 
+struct tuple_element<I, tuple<Head, Tail...> > {
+  typedef typename tuple_element<I-1, tuple<Tail...> >::type type;
+};
+
+template<typename Head, typename... Tail> 
+struct tuple_element<0, tuple<Head, Tail...> > {
+  typedef Head type;
+};
+
+// Element access
+template<int I, typename Tuple> class get_impl;
+template<int I, typename Head, typename... Values> 
+class get_impl<I, tuple<Head, Values...> > {
+  typedef typename tuple_element<I-1, tuple<Values...> >::type Element;
+  typedef typename add_reference<Element>::type RJ; 
+  typedef typename add_const_reference<Element>::type PJ;
+  typedef get_impl<I-1, tuple<Values...> > Next;
+public: 
+  static RJ get(tuple<Head, Values...>& t) { return Next::get(t.tail()); }
+  static PJ get(const tuple<Head, Values...>& t) { return Next::get(t.tail()); }
+};
+
+template<typename Head, typename... Values> 
+class get_impl<0, tuple<Head, Values...> > {
+  typedef typename add_reference<Head>::type RJ; 
+  typedef typename add_const_reference<Head>::type PJ;
+public: 
+  static RJ get(tuple<Head, Values...>& t) { return t.head(); } 
+  static PJ get(const tuple<Head, Values...>& t) { return t.head(); }
+};
+
+template<int I, typename... Values> typename add_reference<
+typename tuple_element<I, tuple<Values...> >::type >::type
+get(tuple<Values...>& t) { 
+  return get_impl<I, tuple<Values...> >::get(t);
+}
+
+template<int I, typename... Values> typename add_const_reference<
+typename tuple_element<I, tuple<Values...> >::type >::type
+get(const tuple<Values...>& t) { 
+  return get_impl<I, tuple<Values...> >::get(t);
+}
+
+// Relational operators
+inline bool operator==(const tuple<>&, const tuple<>&) { return true; }
+
+template<typename T, typename... TTail, typename U, typename... UTail> 
+bool operator==(const tuple<T, TTail...>& t, const tuple<U, UTail...>& u) {
+  return t.head() == u.head() && t.tail() == u.tail();
+}
+
+template<typename... TValues, typename... UValues> 
+bool operator!=(const tuple<TValues...>& t, const tuple<UValues...>& u) {
+  return !(t == u); 
+}
+
+inline bool operator<(const tuple<>&, const tuple<>&) { return false; }
+
+template<typename T, typename... TTail, typename U, typename... UTail> 
+bool operator<(const tuple<T, TTail...>& t, const tuple<U, UTail...>& u) {
+  return (t.head() < u.head() || (!(t.head() < u.head()) && t.tail() < u.tail()));
+}
+
+template<typename... TValues, typename... UValues> 
+bool operator>(const tuple<TValues...>& t, const tuple<UValues...>& u) {
+  return u < t;
+}
+
+template<typename... TValues, typename... UValues>
+bool operator<=(const tuple<TValues...>& t, const tuple<UValues...>& u) {
+  return !(u < t);
+}
+
+template<typename... TValues, typename... UValues>
+bool operator>=(const tuple<TValues...>& t, const tuple<UValues...>& u) {
+  return !(t < u);
+}
+
+// make_indices helper
+template<int...> struct int_tuple {};
+// make_indexes impl is a helper for make_indexes 
+template<int I, typename IntTuple, typename... Types> struct make_indexes_impl;
+
+template<int I, int... Indexes, typename T, typename... Types>
+struct make_indexes_impl<I, int_tuple<Indexes...>, T, Types...> {
+  typedef typename make_indexes_impl<I+1, int_tuple<Indexes..., I>, Types...>::type type;
+};
+
+template<int I, int... Indexes> 
+struct make_indexes_impl<I, int_tuple<Indexes...> > {
+  typedef int_tuple<Indexes...> type; 
+};
+
+template<typename... Types>
+struct make_indexes : make_indexes_impl<0, int_tuple<>, Types...> { 
+}; 
+
+// Bind
+template<typename T> struct is_bind_expression {
+  static const bool value = false;
+};
+
+template<typename T> struct is_placeholder {
+  static const int value = 0;
+};
+
+
+template<typename F, typename... BoundArgs> class bound_functor {
+  typedef typename make_indexes<BoundArgs...>::type indexes; 
+public:
+  typedef typename F::result_type result_type; 
+  explicit bound_functor(const F& f, const BoundArgs&... bound_args)
+    : f(f), bound_args(bound_args...) { } template<typename... Args>
+  typename F::result_type operator()(Args&... args);
+private: F f;
+  tuple<BoundArgs...> bound_args;
+};
+
+template<typename F, typename... BoundArgs> 
+inline bound_functor<F, BoundArgs...> bind(const F& f, const BoundArgs&... bound_args) {
+  return bound_functor<F, BoundArgs...>(f, bound_args...);
+}
+
+template<typename F, typename ...BoundArgs>
+struct is_bind_expression<bound_functor<F, BoundArgs...> > {
+  static const bool value = true;
+};
+
+// enable_if helper
+template<bool Cond, typename T = void>
+struct enable_if;
+
+template<typename T>
+struct enable_if<true, T> {
+  typedef T type;
+};
+
+template<typename T>
+struct enable_if<false, T> { };
+
+// safe_tuple_element helper
+template<int I, typename Tuple, typename = void>
+struct safe_tuple_element { };
+
+template<int I, typename... Values> 
+struct safe_tuple_element<I, tuple<Values...>,
+                          typename enable_if<(I >= 0 && I < tuple_size<tuple<Values...> >::value)>::type> { 
+   typedef typename tuple_element<I, tuple<Values...> >::type type;
+};
+
+// mu
+template<typename Bound, typename... Args> 
+inline typename safe_tuple_element<is_placeholder<Bound>::value -1,
+                                   tuple<Args...> >::type 
+mu(Bound& bound_arg, const tuple<Args&...>& args) {
+  return get<is_placeholder<Bound>::value-1>(args);
+}
+
+template<typename T, typename... Args> 
+inline T& mu(reference_wrapper<T>& bound_arg, const tuple<Args&...>&) {
+  return bound_arg.get();
+}
+
+template<typename F, int... Indexes, typename... Args> 
+inline typename F::result_type 
+unwrap_and_forward(F& f, int_tuple<Indexes...>, const tuple<Args&...>& args) {
+  return f(get<Indexes>(args)...);
+}
+
+template<typename Bound, typename... Args> 
+inline typename enable_if<is_bind_expression<Bound>::value,
+                          typename Bound::result_type>::type 
+mu(Bound& bound_arg, const tuple<Args&...>& args) {
+  typedef typename make_indexes<Args...>::type Indexes; 
+  return unwrap_and_forward(bound_arg, Indexes(), args);
+}
+
+template<typename T>
+struct is_reference_wrapper {
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_reference_wrapper<reference_wrapper<T>> {
+  static const bool value = true;
+};
+
+template<typename Bound, typename... Args> 
+inline typename enable_if<(!is_bind_expression<Bound>::value 
+                           && !is_placeholder<Bound>::value 
+                           && !is_reference_wrapper<Bound>::value), 
+                           Bound&>::type
+mu(Bound& bound_arg, const tuple<Args&...>&) {
+  return bound_arg;
+}
+
+template<typename F, typename... BoundArgs, int... Indexes, typename... Args> 
+typename F::result_type apply_functor(F& f, tuple<BoundArgs...>& bound_args, 
+                                      int_tuple<Indexes...>, 
+                                      const tuple<Args&...>& args) {
+  return f(mu(get<Indexes>(bound_args), args)...);
+}
+
+template<typename F, typename... BoundArgs> 
+template<typename... Args> 
+typename F::result_type bound_functor<F, BoundArgs...>::operator()(Args&... args) {
+  return apply_functor(f, bound_args, indexes(), tie(args...));
+}
+
+template<int N> struct placeholder { };
+template<int N>
+struct is_placeholder<placeholder<N>> {
+  static const int value = N;
+};
+
+template<typename T>
+struct plus {
+  typedef T result_type;
+
+  T operator()(T x, T y) { return x + y; }
+};
+
+placeholder<1> _1;
+
+// Test bind
+void test_bind() {
+  int x = 17;
+  int y = 25;
+  bind(plus<int>(), x, _1)(y);
+}

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

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

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

Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp?rev=123163&r1=123162&r2=123163&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp Mon Jan 10 01:32:04 2011
@@ -206,9 +206,6 @@
   return get_impl<I, tuple<Values...> >::get(t);
 }
 
-#if 0
-// FIXME: Not yet functional, because we aren't currently able to
-// extend a partially-explicitly-specified parameter pack.
 void test_element_access(tuple<int*, float*, double*&> t3) {
   int i;
   float f;
@@ -217,7 +214,6 @@
   get<1>(t3) = &f;
   get<2>(t3) = &d;
 }
-#endif
 
 // Relational operators
 inline bool operator==(const tuple<>&, const tuple<>&) { return true; }

Modified: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp?rev=123163&r1=123162&r2=123163&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp Mon Jan 10 01:32:04 2011
@@ -35,13 +35,11 @@
 // Template argument deduction can extend the sequence of template
 // arguments corresponding to a template parameter pack, even when the
 // sequence contains explicitly specified template arguments.
-// FIXME: Actually test what this paragraph specifies.
-#if 0
-void test_explicit_spec_extension() {
+void test_explicit_spec_extension(double *dp) {
   int *ip1 = first_arg<int *>(0, 0);
   int *ip2 = first_arg<int *, float*>(0, 0, 0, 0);
   float *fp1 = first_arg<float *, double*, int*>(0, 0, 0);  
-  int i1 = second_arg<float *>(0, 0, 0);  
+  int *i1 = second_arg<float *>(0, (int*)0, 0);  
+  double *dp1 = first_arg<>(dp);
 }
-#endif
 





More information about the cfe-commits mailing list