Introduce a new type, PackExpansionType, to capture types that are
pack expansions, e.g. given

  template<typename... Types> struct tuple;

  template<typename... Types>
  struct tuple_of_refs {
    typedef tuple<Types&...> types;
  };

the type of the "types" typedef is a PackExpansionType whose pattern
is Types&. 

This commit introduces support for creating pack expansions for
template type arguments, as above, but not for any other kind of pack
expansion, nor for any form of instantiation.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122223 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 5d2bfb2..aee1612 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -106,6 +106,7 @@
   llvm::FoldingSet<DependentNameType> DependentNameTypes;
   llvm::ContextualFoldingSet<DependentTemplateSpecializationType, ASTContext&>
     DependentTemplateSpecializationTypes;
+  llvm::FoldingSet<PackExpansionType> PackExpansionTypes;
   llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes;
   llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
 
@@ -697,6 +698,8 @@
                                                   unsigned NumArgs,
                                                   const TemplateArgument *Args);
 
+  QualType getPackExpansionType(QualType Pattern);
+
   QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl);
 
   QualType getObjCObjectType(QualType Base,
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 2fd540a..263b006 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -738,6 +738,10 @@
     TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs()));
   })
 
+DEF_TRAVERSE_TYPE(PackExpansionType, {
+    TRY_TO(TraverseType(T->getPattern()));
+  })
+
 DEF_TRAVERSE_TYPE(ObjCInterfaceType, { })
 
 DEF_TRAVERSE_TYPE(ObjCObjectType, {
@@ -943,6 +947,10 @@
     }
   })
 
+DEF_TRAVERSE_TYPELOC(PackExpansionType, {
+    TRY_TO(TraverseTypeLoc(TL.getPatternLoc()));
+  })
+
 DEF_TRAVERSE_TYPELOC(ObjCInterfaceType, { })
 
 DEF_TRAVERSE_TYPELOC(ObjCObjectType, {
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 4c3a295..f489848 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -92,7 +92,6 @@
   class TemplateArgument;
   class TemplateArgumentLoc;
   class TemplateArgumentListInfo;
-  class Type;
   class ElaboratedType;
   struct PrintingPolicy;
 
@@ -3191,6 +3190,65 @@
   }  
 };
 
+/// \brief Represents a pack expansion of types.
+///
+/// Pack expansions are part of C++0x variadic templates. A pack
+/// expansion contains a pattern, which itself contains one or more
+/// "unexpanded" parameter packs. When instantiated, a pack expansion
+/// produces a series of types, each instantiated from the pattern of
+/// the expansion, where the Ith instantiation of the pattern uses the
+/// Ith arguments bound to each of the unexpanded parameter packs. The
+/// pack expansion is considered to "expand" these unexpanded
+/// parameter packs.
+///
+/// \code
+/// template<typename ...Types> struct tuple;
+///
+/// template<typename ...Types> 
+/// struct tuple_of_references {
+///   typedef tuple<Types&...> type;
+/// };
+/// \endcode
+///
+/// Here, the pack expansion \c Types&... is represented via a
+/// PackExpansionType whose pattern is Types&.
+class PackExpansionType : public Type, public llvm::FoldingSetNode {
+  /// \brief The pattern of the pack expansion.
+  QualType Pattern;
+
+  PackExpansionType(QualType Pattern, QualType Canon)
+    : Type(PackExpansion, Canon, /*Dependent=*/true,
+           /*VariableModified=*/Pattern->isVariablyModifiedType(),
+           /*ContainsUnexpandedParameterPack=*/false),
+      Pattern(Pattern) { }
+
+  friend class ASTContext;  // ASTContext creates these
+
+public:
+  /// \brief Retrieve the pattern of this pack expansion, which is the
+  /// type that will be repeatedly instantiated when instantiating the
+  /// pack expansion itself.
+  QualType getPattern() const { return Pattern; }
+
+  bool isSugared() const { return false; }
+  QualType desugar() const { return QualType(this, 0); }
+
+  void Profile(llvm::FoldingSetNodeID &ID) {
+    Profile(ID, getPattern());
+  }
+
+  static void Profile(llvm::FoldingSetNodeID &ID, QualType Pattern) {
+    ID.AddPointer(Pattern.getAsOpaquePtr());
+  }
+
+  static bool classof(const Type *T) {
+    return T->getTypeClass() == PackExpansion;
+  }
+  static bool classof(const PackExpansionType *T) {
+    return true;
+  }  
+};
+
 /// ObjCObjectType - Represents a class type in Objective C.
 /// Every Objective C type is a combination of a base type and a
 /// list of protocols.
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 5b695d0..aecc0c4 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -1446,6 +1446,40 @@
   }
 };
 
+
+struct PackExpansionTypeLocInfo {
+  SourceLocation EllipsisLoc;
+};
+
+class PackExpansionTypeLoc
+  : public ConcreteTypeLoc<UnqualTypeLoc, PackExpansionTypeLoc, 
+                           PackExpansionType, PackExpansionTypeLocInfo> {
+public:
+  SourceLocation getEllipsisLoc() const {
+    return this->getLocalData()->EllipsisLoc;
+  }
+
+  void setEllipsisLoc(SourceLocation Loc) {
+    this->getLocalData()->EllipsisLoc = Loc;
+  }
+
+  SourceRange getLocalSourceRange() const {
+    return SourceRange(getEllipsisLoc(), getEllipsisLoc());
+  }
+
+  void initializeLocal(SourceLocation Loc) {
+    setEllipsisLoc(Loc);
+  }
+
+  TypeLoc getPatternLoc() const {
+    return getInnerTypeLoc();
+  }
+
+  QualType getInnerType() const {
+    return this->getTypePtr()->getPattern();
+  }
+};
+
 }
 
 #endif
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index 5355af1..4e25b94 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -94,6 +94,7 @@
 DEPENDENT_TYPE(InjectedClassName, Type)
 DEPENDENT_TYPE(DependentName, Type)
 DEPENDENT_TYPE(DependentTemplateSpecialization, Type)
+DEPENDENT_TYPE(PackExpansion, Type)
 TYPE(ObjCObject, Type)
 TYPE(ObjCInterface, ObjCObjectType)
 TYPE(ObjCObjectPointer, Type)
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index b616cd9..8dfc391 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1853,6 +1853,13 @@
   "non-type template parameter type|exception type}0 "
   "contains unexpanded parameter packs %1, %2, ...">;
 
+def err_pack_expansion_without_parameter_packs : Error<
+  "pack expansion does not contain any unexpanded parameter packs">;
+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_unexpected_typedef : Error<
   "unexpected type name %0: expected expression">;
 def err_unexpected_namespace : Error<
diff --git a/include/clang/Sema/ParsedTemplate.h b/include/clang/Sema/ParsedTemplate.h
index 9d814c7..6a60ab1 100644
--- a/include/clang/Sema/ParsedTemplate.h
+++ b/include/clang/Sema/ParsedTemplate.h
@@ -32,7 +32,9 @@
       Template
     };
 
-    /// \brief Build an empty template argument. This template argument 
+    /// \brief Build an empty template argument. 
+    ///
+    /// This template argument is invalid.
     ParsedTemplateArgument() : Kind(Type), Arg(0) { }
     
     /// \brief Create a template type argument or non-type template argument.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index ed0d747..d47cf98 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -3236,6 +3236,25 @@
                                        TemplateName Template,
                                        UnexpandedParameterPackContext UPPC);
 
+  /// \brief Invoked when parsing a template argument followed by an
+  /// ellipsis, which creates a pack expansion.
+  ///
+  /// \param Arg The template argument preceding the ellipsis, which
+  /// may already be invalid.
+  ///
+  /// \param EllipsisLoc The location of the ellipsis.
+  ParsedTemplateArgument ActOnPackExpansion(const ParsedTemplateArgument &Arg,
+                                            SourceLocation EllipsisLoc);
+
+  /// \brief Invoked when parsing a type follows by an ellipsis, which
+  /// creates a pack expansion.
+  ///
+  /// \param Type The type preceding the ellipsis, which will become
+  /// the pattern of the pack expansion.
+  ///
+  /// \param EllipsisLoc The location of the ellipsis.
+  TypeResult ActOnPackExpansion(ParsedType Type, SourceLocation EllipsisLoc);
+
   /// \brief Describes the result of template argument deduction.
   ///
   /// The TemplateDeductionResult enumeration describes the result of
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index d32cc27..8665fb6 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -551,7 +551,9 @@
       /// \brief A DependentSizedArrayType record.
       TYPE_DEPENDENT_SIZED_ARRAY    = 33,
       /// \brief A ParenType record.
-      TYPE_PAREN                    = 34
+      TYPE_PAREN                    = 34,
+      /// \brief A PackExpansionType record.
+      TYPE_PACK_EXPANSION           = 35
     };
 
     /// \brief The type IDs for special types constructed by semantic
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index e9d8c0f..9403841 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2216,6 +2216,32 @@
   return QualType(T, 0);
 }
 
+QualType ASTContext::getPackExpansionType(QualType Pattern) {
+  llvm::FoldingSetNodeID ID;
+  PackExpansionType::Profile(ID, Pattern);
+
+  assert(Pattern->containsUnexpandedParameterPack() &&
+         "Pack expansions must expand one or more parameter packs");
+  void *InsertPos = 0;
+  PackExpansionType *T
+    = PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos);
+  if (T)
+    return QualType(T, 0);
+
+  QualType Canon;
+  if (!Pattern.isCanonical()) {
+    Canon = getPackExpansionType(getCanonicalType(Pattern));
+
+    // Find the insert position again.
+    PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos);
+  }
+
+  T = new (*this) PackExpansionType(Pattern, Canon);
+  Types.push_back(T);
+  PackExpansionTypes.InsertNode(T, InsertPos);
+  return QualType(T, 0);  
+}
+
 /// CmpProtocolNames - Comparison predicate for sorting protocols
 /// alphabetically.
 static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index cc485c4..7ff217e 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -707,7 +707,14 @@
     }
     break;
   }
-  
+
+  case Type::PackExpansion:
+    if (!IsStructurallyEquivalent(Context,
+                                  cast<PackExpansionType>(T1)->getPattern(),
+                                  cast<PackExpansionType>(T2)->getPattern()))
+      return false;
+    break;
+
   case Type::ObjCInterface: {
     const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1);
     const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2);
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 15c3fb2..e12d7e0 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -36,7 +36,7 @@
     void printTag(TagDecl *T, std::string &S);
 #define ABSTRACT_TYPE(CLASS, PARENT)
 #define TYPE(CLASS, PARENT) \
-  void print##CLASS(const CLASS##Type *T, std::string &S);
+    void print##CLASS(const CLASS##Type *T, std::string &S);
 #include "clang/AST/TypeNodes.def"
   };
 }
@@ -668,6 +668,12 @@
     S = MyString + ' ' + S;
 }
 
+void TypePrinter::printPackExpansion(const PackExpansionType *T, 
+                                     std::string &S) {
+  print(T->getPattern(), S);
+  S += "...";
+}
+
 void TypePrinter::printObjCInterface(const ObjCInterfaceType *T, 
                                      std::string &S) { 
   if (!S.empty())    // Prefix the basic type, e.g. 'typedefname X'.
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 026f6ba..4659831 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -1474,6 +1474,12 @@
   mangleType(T->getElementType());
 }
 
+void CXXNameMangler::mangleType(const PackExpansionType *T) {
+  // FIXME: We may need to push this mangling into the callers
+  Out << "sp";
+  mangleType(T->getPattern());
+}
+
 void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
   mangleSourceName(T->getDecl()->getIdentifier());
 }
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index dd2f1cb..aa9046f 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1140,6 +1140,10 @@
          "Don't know how to mangle DependentTemplateSpecializationTypes yet!");
 }
 
+void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T) {
+  assert(false && "Don't know how to mangle PackExpansionTypes yet!");
+}
+
 void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T) {
   assert(false && "Don't know how to mangle TypeOfTypes yet!");
 }
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 333d72a..d38d059 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -1045,6 +1045,11 @@
 Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
   while (true) {
     ParsedTemplateArgument Arg = ParseTemplateArgument();
+    if (Tok.is(tok::ellipsis)) {
+      SourceLocation EllipsisLoc  = ConsumeToken();
+      Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc);
+    }
+
     if (Arg.isInvalid()) {
       SkipUntil(tok::comma, tok::greater, true, true);
       return true;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 5819362..36bb76f 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2386,6 +2386,7 @@
 
     // If we have a template parameter pack, check every remaining template
     // argument against that template parameter pack.
+    // FIXME: Variadic templates are unimplemented
     if ((*Param)->isTemplateParameterPack()) {
       Diag(TemplateLoc, diag::err_variadic_templates_unsupported);
       return true;
@@ -2640,6 +2641,11 @@
   return VisitNestedNameSpecifier(T->getQualifier());
 }
 
+bool UnnamedLocalNoLinkageFinder::VisitPackExpansionType(
+                                                   const PackExpansionType* T) {
+  return Visit(T->getPattern());
+}
+
 bool UnnamedLocalNoLinkageFinder::VisitObjCObjectType(const ObjCObjectType *) {
   return false;
 }
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index da04b62..d4e99e8 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -2815,6 +2815,12 @@
                                  OnlyDeduced, Depth, Used);
     break;
 
+  case Type::PackExpansion:
+    MarkUsedTemplateParameters(SemaRef, 
+                               cast<PackExpansionType>(T)->getPattern(),
+                               OnlyDeduced, Depth, Used);
+    break;
+
   // None of these types have any template parameters in them.
   case Type::Builtin:
   case Type::VariableArray:
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index f190b3c..321f383 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -10,6 +10,7 @@
 //===----------------------------------------------------------------------===/
 
 #include "clang/Sema/Sema.h"
+#include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/SemaInternal.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/RecursiveASTVisitor.h"
@@ -254,3 +255,62 @@
   return true;
 }
 
+ParsedTemplateArgument 
+Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg,
+                         SourceLocation EllipsisLoc) {
+  if (Arg.isInvalid())
+    return Arg;
+
+  switch (Arg.getKind()) {
+  case ParsedTemplateArgument::Type: {
+    TypeResult Result = ActOnPackExpansion(Arg.getAsType(), EllipsisLoc);
+    if (Result.isInvalid())
+      return ParsedTemplateArgument();
+
+    return ParsedTemplateArgument(Arg.getKind(), Result.get().getAsOpaquePtr(), 
+                                  Arg.getLocation());
+  }
+
+  case ParsedTemplateArgument::NonType:
+    Diag(EllipsisLoc, diag::err_pack_expansion_unsupported)
+      << 0;
+    return ParsedTemplateArgument();
+
+  case ParsedTemplateArgument::Template:
+    Diag(EllipsisLoc, diag::err_pack_expansion_unsupported)
+      << 1;
+    return ParsedTemplateArgument();
+  }
+  llvm_unreachable("Unhandled template argument kind?");
+  return ParsedTemplateArgument();
+}
+
+TypeResult Sema::ActOnPackExpansion(ParsedType Type, 
+                                    SourceLocation EllipsisLoc) {
+  TypeSourceInfo *TSInfo;
+  GetTypeFromParser(Type, &TSInfo);
+  if (!TSInfo)
+    return true;
+
+  // 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()) {
+    Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
+      << TSInfo->getTypeLoc().getSourceRange();
+    return true;
+  }
+
+  // Create the pack expansion type and source-location information.
+  QualType Result = Context.getPackExpansionType(TSInfo->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);
+}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index f4a4ae2..a90ea39 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -3506,6 +3506,15 @@
 }
 
 template<typename Derived>
+QualType TreeTransform<Derived>::TransformPackExpansionType(TypeLocBuilder &TLB,
+                                                      PackExpansionTypeLoc TL) {
+  // FIXME: Implement!
+  getSema().Diag(TL.getEllipsisLoc(), 
+                 diag::err_pack_expansion_instantiation_unsupported);
+  return QualType();
+}
+
+template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB,
                                                    ObjCInterfaceTypeLoc TL) {
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 724ebdf..72360e7 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -2930,6 +2930,18 @@
     return Context->getParenType(InnerType);
   }
 
+  case TYPE_PACK_EXPANSION: {
+    if (Record.size() != 1) {
+      Error("incorrect encoding of pack expansion type");
+      return QualType();
+    }
+    QualType Pattern = GetType(Record[0]);
+    if (Pattern.isNull())
+      return QualType();
+
+    return Context->getPackExpansionType(Pattern);
+  }
+
   case TYPE_ELABORATED: {
     unsigned Idx = 0;
     ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
@@ -3229,6 +3241,9 @@
                                           TL.getTypePtr()->getArg(I).getKind(),
                                           Record, Idx));
 }
+void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
+  TL.setEllipsisLoc(ReadSourceLocation(Record, Idx));
+}
 void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
   TL.setNameLoc(ReadSourceLocation(Record, Idx));
 }
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 26a54b1..345cc8e 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -298,6 +298,11 @@
   Code = TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION;
 }
 
+void ASTTypeWriter::VisitPackExpansionType(const PackExpansionType *T) {
+  Writer.AddTypeRef(T->getPattern(), Record);
+  Code = TYPE_PACK_EXPANSION;
+}
+
 void ASTTypeWriter::VisitParenType(const ParenType *T) {
   Writer.AddTypeRef(T->getInnerType(), Record);
   Code = TYPE_PAREN;
@@ -499,6 +504,9 @@
     Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(I).getArgument().getKind(),
                                       TL.getArgLoc(I).getLocInfo(), Record);
 }
+void TypeLocWriter::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
+  Writer.AddSourceLocation(TL.getEllipsisLoc(), Record);
+}
 void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
   Writer.AddSourceLocation(TL.getNameLoc(), Record);
 }
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
index 259a862..8fef90f 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
@@ -1,11 +1,23 @@
 // RUN: %clang_cc1 -std=c++0x -fblocks -fsyntax-only -verify %s
 
+template<typename T, typename U> struct pair;
+
+// A parameter pack whose name appears within the pattern of a pack
+// expansion is expanded by that pack expansion. An appearance of the
+// name of a parameter pack is only expanded by the innermost
+// enclosing pack expansion. The pattern of a pack expansion shall
+// name one or more parameter packs that are not expanded by a nested
+// pack expansion.
+template<typename... Types>
+struct Expansion {
+  typedef pair<Types..., int> expand_with_pacs; // okay
+  typedef pair<Types, int...> expand_no_packs;  // expected-error{{pack expansion does not contain any unexpanded parameter packs}}
+  typedef pair<pair<Types..., int>..., int> expand_with_expanded_nested; // expected-error{{pack expansion does not contain any unexpanded parameter packs}}
+};
 
 // An appearance of a name of a parameter pack that is not expanded is
 // ill-formed.
 
-template<typename T, typename U> struct pair;
-
 // Test for unexpanded parameter packs in each of the type nodes.
 template<typename T, int N, typename ... Types>
 struct TestPPName 
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index c8dbf3b..ca6efe8 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -338,6 +338,7 @@
   // FIXME: Implement visitors here when the unimplemented TypeLocs get
   // implemented
   bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL);
+  bool VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL);
   bool VisitTypeOfTypeLoc(TypeOfTypeLoc TL);
 
   // Data-recursive visitor functions.
@@ -1435,6 +1436,10 @@
   return false;
 }
 
+bool CursorVisitor::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
+  return Visit(TL.getPatternLoc());
+}
+
 bool CursorVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) {
   if (D->isDefinition()) {
     for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),