diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index fc1d4232d6d78b07dc217bb287d08ffa07b87375..4096dc1731f480ff8e5520df0da58f137612aade 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -197,6 +197,9 @@ public:
   /// parameter pack.
   bool containsUnexpandedParameterPack() const;
 
+  /// \brief Determine whether this template argument is a pack expansion.
+  bool isPackExpansion() const;
+  
   /// \brief Retrieve the template argument as a type.
   QualType getAsType() const {
     if (Kind != Type)
@@ -409,6 +412,13 @@ public:
     assert(Argument.getKind() == TemplateArgument::Template);
     return LocInfo.getTemplateNameLoc();
   }  
+  
+  /// \brief When the template argument is a pack expansion, returns 
+  /// the pattern of the pack expansion.
+  ///
+  /// \param Ellipsis Will be set to the location of the ellipsis.
+  TemplateArgumentLoc getPackExpansionPattern(SourceLocation &Ellipsis,
+                                              ASTContext &Context) const;
 };
 
 /// A convenient class for passing around template argument
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 32bf184f6edf269d9e1bc7bb170b83cfb6836898..a6f4cc81303d3605cb1f9eb0bdc0f55dd2d8a0c2 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1855,10 +1855,16 @@ def err_unexpanded_parameter_pack_3_or_more : Error<
 
 def err_pack_expansion_without_parameter_packs : Error<
   "pack expansion does not contain any unexpanded parameter packs">;
+def err_pack_expansion_length_conflict : Error<
+  "pack expansion contains parameter packs %0 and %1 that have different "
+  "lengths (%2 vs. %3)">;
+
 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_unexpected_typedef : Error<
   "unexpected type name %0: expected expression">;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index d47cf9862ade489139d82f3a3014dc59db277004..77ecde89e117285ce8928b24a03642b909f42afb 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -185,6 +185,11 @@ public:
   static bool classof(const LocInfoType *) { return true; }
 };
 
+// FIXME: No way to easily map from TemplateTypeParmTypes to
+// TemplateTypeParmDecls, so we have this horrible PointerUnion.
+typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>,
+                  SourceLocation> UnexpandedParameterPack;
+
 /// Sema - This implements semantic analysis and AST building for C.
 class Sema {
   Sema(const Sema&);           // DO NOT IMPLEMENT
@@ -3236,6 +3241,14 @@ public:
                                        TemplateName Template,
                                        UnexpandedParameterPackContext UPPC);
 
+  /// \brief Collect the set of unexpanded parameter packs within the given
+  /// template argument.  
+  ///
+  /// \param Arg The template argument that will be traversed to find
+  /// unexpanded parameter packs.
+  void collectUnexpandedParameterPacks(TemplateArgumentLoc Arg,
+                    llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
+                                       
   /// \brief Invoked when parsing a template argument followed by an
   /// ellipsis, which creates a pack expansion.
   ///
@@ -3255,6 +3268,11 @@ public:
   /// \param EllipsisLoc The location of the ellipsis.
   TypeResult ActOnPackExpansion(ParsedType Type, SourceLocation EllipsisLoc);
 
+  /// \brief Construct a pack expansion type from the pattern of the pack
+  /// expansion.
+  TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern,
+                                     SourceLocation EllipsisLoc);
+  
   /// \brief Describes the result of template argument deduction.
   ///
   /// The TemplateDeductionResult enumeration describes the result of
@@ -3517,6 +3535,35 @@ public:
   /// to implement it anywhere else.
   ActiveTemplateInstantiation LastTemplateInstantiationErrorContext;
 
+  /// \brief The current index into pack expansion arguments that will be
+  /// used for substitution of parameter packs.
+  ///
+  /// The pack expansion index will be -1 to indicate that parameter packs 
+  /// should be instantiated as themselves. Otherwise, the index specifies
+  /// which argument within the parameter pack will be used for substitution.
+  int ArgumentPackSubstitutionIndex;
+  
+  /// \brief RAII object used to change the argument pack substitution index
+  /// within a \c Sema object.
+  ///
+  /// See \c ArgumentPackSubstitutionIndex for more information.
+  class ArgumentPackSubstitutionIndexRAII {
+    Sema &Self;
+    int OldSubstitutionIndex;
+    
+  public:
+    ArgumentPackSubstitutionIndexRAII(Sema &Self, int NewSubstitutionIndex)
+      : Self(Self), OldSubstitutionIndex(Self.ArgumentPackSubstitutionIndex) {
+      Self.ArgumentPackSubstitutionIndex = NewSubstitutionIndex;
+    }
+    
+    ~ArgumentPackSubstitutionIndexRAII() {
+      Self.ArgumentPackSubstitutionIndex = OldSubstitutionIndex;
+    }
+  };
+  
+  friend class ArgumentPackSubstitutionRAII;
+  
   /// \brief The stack of calls expression undergoing template instantiation.
   ///
   /// The top of this stack is used by a fixit instantiating unresolved
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index 38d4b9fd254131411d7dc5897a7710c78d9632aa..484d58dd0b102de8c9f5f5a1792b2478d9331222 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -242,8 +242,10 @@ namespace clang {
   };
 
   class TemplateDeclInstantiator
-    : public DeclVisitor<TemplateDeclInstantiator, Decl *> {
+    : public DeclVisitor<TemplateDeclInstantiator, Decl *> 
+  {
     Sema &SemaRef;
+    Sema::ArgumentPackSubstitutionIndexRAII SubstIndex;
     DeclContext *Owner;
     const MultiLevelTemplateArgumentList &TemplateArgs;
 
@@ -257,7 +259,8 @@ namespace clang {
   public:
     TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
                              const MultiLevelTemplateArgumentList &TemplateArgs)
-      : SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs) { }
+      : SemaRef(SemaRef), SubstIndex(SemaRef, -1), Owner(Owner), 
+        TemplateArgs(TemplateArgs) { }
 
     // FIXME: Once we get closer to completion, replace these manually-written
     // declarations with automatically-generated ones from
@@ -347,7 +350,7 @@ namespace clang {
     InstantiateClassTemplatePartialSpecialization(
                                               ClassTemplateDecl *ClassTemplate,
                            ClassTemplatePartialSpecializationDecl *PartialSpec);
-  };
+  };  
 }
 
 #endif // LLVM_CLANG_SEMA_TEMPLATE_H
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index ee404852262cbb71d610457519226740dd30431f..fd1146c084dda0e854d94d6462226a264624e7aa 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -63,6 +63,29 @@ bool TemplateArgument::isDependent() const {
   return false;
 }
 
+bool TemplateArgument::isPackExpansion() const {
+  switch (getKind()) {
+  case Null:
+  case Declaration:
+  case Integral:
+  case Pack:    
+    return false;
+      
+  case Type:
+    return llvm::isa<PackExpansionType>(getAsType());
+      
+  case Template:
+    // FIXME: Template template pack expansions.
+    break;
+    
+  case Expression:
+    // FIXME: Expansion pack expansions.
+    break;  
+  }
+  
+  return false;
+}
+
 bool TemplateArgument::containsUnexpandedParameterPack() const {
   switch (getKind()) {
   case Null:
@@ -265,6 +288,47 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
   return SourceRange();
 }
 
+TemplateArgumentLoc 
+TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
+                                             ASTContext &Context) const {
+  assert(Argument.isPackExpansion());
+  
+  switch (Argument.getKind()) {
+  case TemplateArgument::Type: {
+    PackExpansionTypeLoc Expansion
+      = cast<PackExpansionTypeLoc>(getTypeSourceInfo()->getTypeLoc());
+    Ellipsis = Expansion.getEllipsisLoc();
+    
+    TypeLoc Pattern = Expansion.getPatternLoc();
+    
+    // FIXME: This is horrible. We know where the source location data is for
+    // the pattern, and we have the pattern's type, but we are forced to copy
+    // them into an ASTContext because TypeSourceInfo bundles them together
+    // and TemplateArgumentLoc traffics in TypeSourceInfo pointers.
+    TypeSourceInfo *PatternTSInfo
+      = Context.CreateTypeSourceInfo(Pattern.getType(),
+                                     Pattern.getFullDataSize());
+    memcpy(PatternTSInfo->getTypeLoc().getOpaqueData(), 
+           Pattern.getOpaqueData(), Pattern.getFullDataSize());
+    return TemplateArgumentLoc(TemplateArgument(Pattern.getType()),
+                               PatternTSInfo);
+  }
+      
+  case TemplateArgument::Expression:
+  case TemplateArgument::Template:
+    // FIXME: Variadic templates.
+      llvm_unreachable("Expression and template pack expansions unsupported");
+    
+  case TemplateArgument::Declaration:
+  case TemplateArgument::Integral:
+  case TemplateArgument::Pack:
+  case TemplateArgument::Null:
+    return TemplateArgumentLoc();
+  }
+  
+  return TemplateArgumentLoc();
+}
+
 const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
                                            const TemplateArgument &Arg) {
   switch (Arg.getKind()) {
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index fcc5370ed9e500508b1ccef53df56bee087e8b39..ca69d69959cac791ffba0e2e81e43276ffe8f79a 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -140,7 +140,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
     GlobalNewDeleteDeclared(false), 
     CompleteTranslationUnit(CompleteTranslationUnit),
     NumSFINAEErrors(0), SuppressAccessChecking(false),
-    NonInstantiationEntries(0), CurrentInstantiationScope(0), TyposCorrected(0),
+    NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
+    CurrentInstantiationScope(0), TyposCorrected(0),
     AnalysisWarnings(*this)
 {
   TUScope = 0;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 4651759398303090b090c280963fbfe0077e1799..923e7cc30f3c9bd2b5cb9ae62e8ce28b3f3e0225 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2295,8 +2295,6 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
                                 MultiLevelTemplateArgumentList(TemplateArgs)));
     if (!TempParm)
       return true;
-    
-    // FIXME: TempParam is leaked.
   }
     
   switch (Arg.getArgument().getKind()) {
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index fe9750108bf3097addc15f2b22e2ec7375c4c914..4c1b3807f71831c95d0335ae732d2ed04f805af3 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -589,7 +589,14 @@ namespace {
       this->Loc = Loc;
       this->Entity = Entity;
     }
-      
+
+    bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
+                                 SourceRange PatternRange,
+                                 const UnexpandedParameterPack *Unexpanded,
+                                 unsigned NumUnexpanded,
+                                 bool &ShouldExpand,
+                                 unsigned &NumExpansions);
+
     /// \brief Transform the given declaration by instantiating a reference to
     /// this declaration.
     Decl *TransformDecl(SourceLocation Loc, Decl *D);
@@ -656,6 +663,79 @@ bool TemplateInstantiator::AlreadyTransformed(QualType T) {
   return true;
 }
 
+bool TemplateInstantiator::TryExpandParameterPacks(SourceLocation EllipsisLoc,
+                                                   SourceRange PatternRange,
+                                     const UnexpandedParameterPack *Unexpanded,
+                                                   unsigned NumUnexpanded,
+                                                   bool &ShouldExpand,
+                                                   unsigned &NumExpansions) {
+  ShouldExpand = true;
+  std::pair<IdentifierInfo *, SourceLocation> FirstPack;
+  bool HaveFirstPack = false;
+  
+  for (unsigned I = 0; I != NumUnexpanded; ++I) {
+    // Compute the depth and index for this parameter pack.
+    unsigned Depth;
+    unsigned Index;
+    IdentifierInfo *Name;
+    
+    if (const TemplateTypeParmType *TTP
+              = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) {
+      Depth = TTP->getDepth();
+      Index = TTP->getIndex();
+      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 {
+        TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
+        Depth = TTP->getDepth();
+        Index = TTP->getIndex();
+      }
+      // FIXME: Variadic templates function parameter packs?
+      Name = ND->getIdentifier();
+    }
+    
+    // If we don't have a template argument at this depth/index, then we 
+    // cannot expand the pack expansion. Make a note of this, but we still 
+    // want to check that any parameter packs we *do* have arguments for.
+    if (!TemplateArgs.hasTemplateArgument(Depth, Index)) {
+      ShouldExpand = false;
+      continue;
+    }
+
+    // Determine the size of the argument pack.
+    unsigned NewPackSize = TemplateArgs(Depth, Index).pack_size();
+    if (!HaveFirstPack) {
+      // The is the first pack we've seen for which we have an argument. 
+      // Record it.
+      NumExpansions = NewPackSize;
+      FirstPack.first = Name;
+      FirstPack.second = Unexpanded[I].second;
+      HaveFirstPack = true;
+      continue;
+    }
+    
+    if (NewPackSize != NumExpansions) {
+      // C++0x [temp.variadic]p5:
+      //   All of the parameter packs expanded by a pack expansion shall have 
+      //   the same number of arguments specified.
+      getSema().Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict)
+        << FirstPack.first << Name << NumExpansions << NewPackSize
+        << SourceRange(FirstPack.second) << SourceRange(Unexpanded[I].second);
+      return true;
+    }
+  }
+  
+  return false;
+}
+
 Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
   if (!D)
     return 0;
@@ -670,6 +750,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
                                             TTP->getPosition()))
         return D;
 
+      // FIXME: Variadic templates index substitution.
       TemplateName Template
         = TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsTemplate();
       assert(!Template.isNull() && Template.getAsTemplateDecl() &&
@@ -702,6 +783,7 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
     const TemplateTypeParmType *TTP 
       = cast<TemplateTypeParmType>(getSema().Context.getTypeDeclType(TTPD));
     if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
+      // FIXME: Variadic templates index substitution.
       QualType T = TemplateArgs(TTP->getDepth(), TTP->getIndex()).getAsType();
       if (T.isNull())
         return cast_or_null<NamedDecl>(TransformDecl(Loc, D));
@@ -844,6 +926,7 @@ ExprResult
 TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
   NamedDecl *D = E->getDecl();
   if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+    // FIXME: Variadic templates index substitution.
     if (NTTP->getDepth() < TemplateArgs.getNumLevels())
       return TransformTemplateParmRefExpr(E, NTTP);
     
@@ -895,12 +978,26 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
       return TL.getType();
     }
 
-    assert(TemplateArgs(T->getDepth(), T->getIndex()).getKind()
-             == TemplateArgument::Type &&
+    TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex());
+    
+    if (T->isParameterPack()) {
+      assert(Arg.getKind() == TemplateArgument::Pack && 
+             "Missing argument pack");
+      
+      if (getSema().ArgumentPackSubstitutionIndex == -1) {
+        // FIXME: Variadic templates fun case.
+        getSema().Diag(TL.getSourceRange().getBegin(), 
+                       diag::err_pack_expansion_mismatch_unsupported);
+        return QualType();
+      }
+      
+      Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
+    }
+    
+    assert(Arg.getKind() == TemplateArgument::Type &&
            "Template argument kind mismatch");
 
-    QualType Replacement
-      = TemplateArgs(T->getDepth(), T->getIndex()).getAsType();
+    QualType Replacement = Arg.getAsType();
 
     // TODO: only do this uniquing once, at the start of instantiation.
     QualType Result
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 321f38397d5d5d55dd68cdec9246331f3cdf700c..e71c2334ca555f3827565bfbba699a37cc55369f 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -12,6 +12,7 @@
 #include "clang/Sema/Sema.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Template.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/TypeLoc.h"
@@ -22,11 +23,6 @@ using namespace clang;
 // Visitor that collects unexpanded parameter packs
 //----------------------------------------------------------------------------
 
-// FIXME: No way to easily map from TemplateTypeParmTypes to
-// TemplateTypeParmDecls, so we have this horrible PointerUnion.
-typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>,
-                  SourceLocation> UnexpandedParameterPack;
-
 namespace {
   /// \brief A class that collects unexpanded parameter packs.
   class CollectUnexpandedParameterPacksVisitor :
@@ -255,6 +251,12 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
   return true;
 }
 
+void Sema::collectUnexpandedParameterPacks(TemplateArgumentLoc Arg,
+                   llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
+  CollectUnexpandedParameterPacksVisitor(Unexpanded)
+    .TraverseTemplateArgumentLoc(Arg);
+}
+
 ParsedTemplateArgument 
 Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg,
                          SourceLocation EllipsisLoc) {
@@ -292,25 +294,34 @@ TypeResult Sema::ActOnPackExpansion(ParsedType Type,
   if (!TSInfo)
     return true;
 
+  TypeSourceInfo *TSResult = CheckPackExpansion(TSInfo, EllipsisLoc);
+  if (!TSResult)
+    return true;
+  
+  return CreateParsedType(TSResult->getType(), TSResult);
+}
+
+TypeSourceInfo *Sema::CheckPackExpansion(TypeSourceInfo *Pattern,
+                                         SourceLocation EllipsisLoc) {
   // C++0x [temp.variadic]p5:
   //   The pattern of a pack expansion shall name one or more
   //   parameter packs that are not expanded by a nested pack
   //   expansion.
-  if (!TSInfo->getType()->containsUnexpandedParameterPack()) {
+  if (!Pattern->getType()->containsUnexpandedParameterPack()) {
     Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
-      << TSInfo->getTypeLoc().getSourceRange();
-    return true;
+      << Pattern->getTypeLoc().getSourceRange();
+    return 0;
   }
-
+  
   // Create the pack expansion type and source-location information.
-  QualType Result = Context.getPackExpansionType(TSInfo->getType());
+  QualType Result = Context.getPackExpansionType(Pattern->getType());
   TypeSourceInfo *TSResult = Context.CreateTypeSourceInfo(Result);
   PackExpansionTypeLoc TL = cast<PackExpansionTypeLoc>(TSResult->getTypeLoc());
   TL.setEllipsisLoc(EllipsisLoc);
-
+  
   // Copy over the source-location information from the type.
   memcpy(TL.getNextTypeLoc().getOpaqueData(),
-         TSInfo->getTypeLoc().getOpaqueData(),
-         TSInfo->getTypeLoc().getFullDataSize());
-  return CreateParsedType(Result, TSResult);
+         Pattern->getTypeLoc().getOpaqueData(),
+         Pattern->getTypeLoc().getFullDataSize());
+  return TSResult;
 }
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 55388129f4ab0e245b2654773d98e75dc8b10f7d..fc0b749828f942ddbbde7b8bb221894b11d24682 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -15,6 +15,7 @@
 
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/SemaDiagnostic.h"
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/AST/Decl.h"
@@ -90,10 +91,11 @@ template<typename Derived>
 class TreeTransform {
 protected:
   Sema &SemaRef;
-
+  Sema::ArgumentPackSubstitutionIndexRAII SubstIndex;
+  
 public:
   /// \brief Initializes a new tree transformer.
-  TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { }
+  TreeTransform(Sema &SemaRef) : SemaRef(SemaRef), SubstIndex(SemaRef, -1) { }
 
   /// \brief Retrieves a reference to the derived class.
   Derived &getDerived() { return static_cast<Derived&>(*this); }
@@ -180,6 +182,47 @@ public:
     return E->isDefaultArgument();
   }
   
+  /// \brief Determine whether we should expand a pack expansion with the
+  /// given set of parameter packs into separate arguments by repeatedly
+  /// transforming the pattern.
+  ///
+  /// By default, the transformed never tries to expand pack expansions.
+  /// Subclasses can override this routine to provide different behavior.
+  ///
+  /// \param EllipsisLoc The location of the ellipsis that identifies the
+  /// pack expansion.
+  ///
+  /// \param PatternRange The source range that covers the entire pattern of
+  /// the pack expansion.
+  ///
+  /// \param Unexpanded The set of unexpanded parameter packs within the 
+  /// pattern.
+  ///
+  /// \param NumUnexpanded The number of unexpanded parameter packs in
+  /// \p Unexpanded.
+  ///
+  /// \param ShouldExpand Will be set to \c true if the transformer should
+  /// expand the corresponding pack expansions into separate arguments. When
+  /// set, \c NumExpansions must also be set.
+  ///
+  /// \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.
+  ///
+  /// \returns true if an error occurred (e.g., because the parameter packs 
+  /// are to be instantiated with arguments of different lengths), false 
+  /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions) 
+  /// must be set.
+  bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
+                               SourceRange PatternRange,
+                               const UnexpandedParameterPack *Unexpanded,
+                               unsigned NumUnexpanded,
+                               bool &ShouldExpand,
+                               unsigned &NumExpansions) {
+    ShouldExpand = false;
+    return false;
+  }
+  
   /// \brief Transforms the given type into another type.
   ///
   /// By default, this routine transforms a type by creating a
@@ -2018,6 +2061,36 @@ public:
     return move(Result);
   }
 
+  /// \brief Build a new template argument pack expansion.
+  ///
+  /// By default, performs semantic analysis to build a new pack expansion
+  /// for a template argument. Subclasses may override this routine to provide 
+  /// different behavior.
+  TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern,
+                                           SourceLocation EllipsisLoc) {
+    switch (Pattern.getArgument().getKind()) {
+    case TemplateArgument::Expression:
+    case TemplateArgument::Template:
+      llvm_unreachable("Unsupported pack expansion of expressions/templates");
+        
+    case TemplateArgument::Null:
+    case TemplateArgument::Integral:
+    case TemplateArgument::Declaration:
+    case TemplateArgument::Pack:
+      llvm_unreachable("Pack expansion pattern has no parameter packs");
+        
+    case TemplateArgument::Type:
+      if (TypeSourceInfo *Expansion 
+            = getSema().CheckPackExpansion(Pattern.getTypeSourceInfo(),
+                                           EllipsisLoc))
+        return TemplateArgumentLoc(TemplateArgument(Expansion->getType()),
+                                   Expansion);
+      break;
+    }
+    
+    return TemplateArgumentLoc();
+  }
+  
 private:
   QualType TransformTypeInObjectScope(QualType T,
                                       QualType ObjectType,
@@ -2457,7 +2530,86 @@ bool TreeTransform<Derived>::TransformTemplateArgumentsFromArgLoc(
                                             TemplateArgumentListInfo &Outputs) {
   for (unsigned I = 0, N = Inputs.getNumArgs(); I != N; ++I) {
     TemplateArgumentLoc Out;
-    if (getDerived().TransformTemplateArgument(Inputs.getArgLoc(I), Out))
+    TemplateArgumentLoc In = Inputs.getArgLoc(I);
+    
+    if (In.getArgument().getKind() == TemplateArgument::Pack) {
+      // Unpack argument packs, which we translate them into separate
+      // arguments.
+      // FIXME: It would be far better to make this a recursive call using
+      // some kind of argument-pack adaptor.
+      for (TemplateArgument::pack_iterator P = In.getArgument().pack_begin(), 
+                                        PEnd = In.getArgument().pack_end();
+           P != PEnd; ++P) {
+        TemplateArgumentLoc PLoc;
+        
+        // FIXME: We could do much better if we could guarantee that the
+        // TemplateArgumentLocInfo for the pack expansion would be usable for
+        // all of the template arguments in the argument pack.
+        getDerived().InventTemplateArgumentLoc(*P, PLoc);
+        if (getDerived().TransformTemplateArgument(PLoc, Out))
+          return true;
+        
+        Outputs.addArgument(Out);
+      }
+      
+      continue;
+    }
+    
+    if (In.getArgument().isPackExpansion()) {
+      // We have a pack expansion, for which we will be substituting into
+      // the pattern.
+      SourceLocation Ellipsis;
+      TemplateArgumentLoc Pattern
+        = In.getPackExpansionPattern(Ellipsis, getSema().Context);
+      
+      llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+      getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
+      assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+      
+      // Determine whether the set of unexpanded parameter packs can and should
+      // be expanded.
+      bool Expand = true;
+      unsigned NumExpansions = 0;
+      if (getDerived().TryExpandParameterPacks(Ellipsis,
+                                               Pattern.getSourceRange(),
+                                               Unexpanded.data(),
+                                               Unexpanded.size(),
+                                               Expand, NumExpansions))
+        return true;
+      
+      if (!Expand) {
+        // The transform has determined that we should perform a simple
+        // transformation on the pack expansion, producing another pack 
+        // expansion.
+        TemplateArgumentLoc OutPattern;
+        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+        if (getDerived().TransformTemplateArgument(Pattern, OutPattern))
+          return true;
+                
+        Out = getDerived().RebuildPackExpansion(OutPattern, Ellipsis);
+        if (Out.getArgument().isNull())
+          return true;
+        
+        Outputs.addArgument(Out);
+        continue;
+      }
+      
+      // The transform has determined that we should perform an elementwise
+      // expansion of the pattern. Do so.
+      for (unsigned I = 0; I != NumExpansions; ++I) {
+        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
+
+        if (getDerived().TransformTemplateArgument(Pattern, Out))
+          return true;
+        
+        Outputs.addArgument(Out);
+      }
+      
+      continue;
+    }
+    
+    // The simple case: 
+    if (getDerived().TransformTemplateArgument(In, Out))
       return true;
     
     Outputs.addArgument(Out);
@@ -3738,9 +3890,8 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
     
     // Convert the condition to a boolean value.
     if (S->getCond()) {
-      ExprResult CondE = getSema().ActOnBooleanCondition(0, 
-                                                               S->getIfLoc(), 
-                                                               Cond.get());
+      ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getIfLoc(), 
+                                                         Cond.get());
       if (CondE.isInvalid())
         return StmtError();
     
@@ -3834,9 +3985,8 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
 
     if (S->getCond()) {
       // Convert the condition to a boolean value.
-      ExprResult CondE = getSema().ActOnBooleanCondition(0, 
-                                                             S->getWhileLoc(), 
-                                                               Cond.get());
+      ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getWhileLoc(), 
+                                                         Cond.get());
       if (CondE.isInvalid())
         return StmtError();
       Cond = CondE;
@@ -3912,9 +4062,8 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
 
     if (S->getCond()) {
       // Convert the condition to a boolean value.
-      ExprResult CondE = getSema().ActOnBooleanCondition(0, 
-                                                               S->getForLoc(), 
-                                                               Cond.get());
+      ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getForLoc(), 
+                                                         Cond.get());
       if (CondE.isInvalid())
         return StmtError();
 
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..47883fe423c23ab2650d5af8046c8b1c433c87bf
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename... Types> struct Tuple;
+
+// FIXME: Many more bullets to go
+
+// In a template-argument-list (14.3); the pattern is a template-argument.
+template<typename ...Types>
+struct tuple_of_refs {
+  typedef Tuple<Types& ...> types;
+};
+
+Tuple<int&, float&> *t_int_ref_float_ref;
+tuple_of_refs<int&, float&>::types *t_int_ref_float_ref_2 =  t_int_ref_float_ref;
+  
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
index 8fef90fbc2bf0b523d14f350043b91a28455a753..94d874fc8d77606a039cdac3e0f43c8a93f961ff 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -std=c++0x -fblocks -fsyntax-only -verify %s
 
 template<typename T, typename U> struct pair;
+template<typename ...> struct tuple;
 
 // A parameter pack whose name appears within the pattern of a pack
 // expansion is expanded by that pack expansion. An appearance of the
@@ -15,6 +16,24 @@ struct Expansion {
   typedef pair<pair<Types..., int>..., int> expand_with_expanded_nested; // expected-error{{pack expansion does not contain any unexpanded parameter packs}}
 };
 
+// All of the parameter packs expanded by a pack expansion shall have
+// the same number of arguments specified.
+template<typename ...Types>
+struct ExpansionLengthMismatch {
+  template<typename ...OtherTypes>
+  struct Inner {
+    typedef tuple<pair<Types, OtherTypes>...> type; // expected-error{{pack expansion contains parameter packs 'Types' and 'OtherTypes' that have different lengths (3 vs. 2)}}
+  };
+};
+
+ExpansionLengthMismatch<int, long>::Inner<unsigned int, unsigned long>::type 
+  *il_pairs;
+tuple<pair<int, unsigned int>, pair<long, unsigned long> >*il_pairs_2 = il_pairs;
+
+ExpansionLengthMismatch<short, int, long>::Inner<unsigned int, unsigned long>::type // expected-note{{in instantiation of}}
+  *il_pairs_bad; 
+
+
 // An appearance of a name of a parameter pack that is not expanded is
 // ill-formed.