Implement support for C++0x alias templates.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130953 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index f86835a..9dcddfa 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -32,6 +32,7 @@
   </ul>
 <li><a href="#checking_upcoming_features">Checks for Upcoming Standard Language Features</a></li>
   <ul>
+  <li><a href="#cxx_alias_templates">C++0x alias templates</a></li>
   <li><a href="#cxx_attributes">C++0x attributes</a></li>
   <li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
   <li><a href="#cxx_default_function_template_args">C++0x default template arguments in function templates</a></li>
@@ -378,6 +379,11 @@
 <p>Use <tt>__has_feature(cxx_decltype)</tt> to determine if support for the
 <tt>decltype()</tt> specifier is enabled.</p>
 
+<h3 id="cxx_alias_templates">C++0x alias templates</h3>
+
+<p>Use <tt>__has_feature(cxx_alias_templates)</tt> to determine if support for
+C++0x's alias declarations and alias templates is enabled.</p>
+
 <h3 id="cxx_attributes">C++0x attributes</h3>
 
 <p>Use <tt>__has_feature(cxx_attributes)</tt> to determine if support for
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index ddbe344..dc50d61 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -30,6 +30,7 @@
 class TemplateTypeParmDecl;
 class NonTypeTemplateParmDecl;
 class TemplateTemplateParmDecl;
+class TypeAliasTemplateDecl;
 
 /// \brief Stores a template parameter of any kind.
 typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*,
@@ -230,6 +231,7 @@
   static bool classof(const FunctionTemplateDecl *D) { return true; }
   static bool classof(const ClassTemplateDecl *D) { return true; }
   static bool classof(const TemplateTemplateParmDecl *D) { return true; }
+  static bool classof(const TypeAliasTemplateDecl *D) { return true; }
   static bool classofKind(Kind K) {
     return K >= firstTemplate && K <= lastTemplate;
   }
@@ -672,6 +674,7 @@
   static bool classof(const RedeclarableTemplateDecl *D) { return true; }
   static bool classof(const FunctionTemplateDecl *D) { return true; }
   static bool classof(const ClassTemplateDecl *D) { return true; }
+  static bool classof(const TypeAliasTemplateDecl *D) { return true; }
   static bool classofKind(Kind K) {
     return K >= firstRedeclarableTemplate && K <= lastRedeclarableTemplate;
   }
@@ -2014,6 +2017,78 @@
   friend class ASTDeclReader;
 };
 
+/// Declaration of an alias template.  For example:
+///
+/// template <typename T> using V = std::map<T*, int, MyCompare<T>>;
+class TypeAliasTemplateDecl : public RedeclarableTemplateDecl,
+                            public RedeclarableTemplate<TypeAliasTemplateDecl> {
+  static void DeallocateCommon(void *Ptr);
+
+protected:
+  typedef RedeclarableTemplate<TypeAliasTemplateDecl> redeclarable_base;
+
+  typedef CommonBase Common;
+
+  TypeAliasTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
+                        TemplateParameterList *Params, NamedDecl *Decl)
+    : RedeclarableTemplateDecl(TypeAliasTemplate, DC, L, Name, Params, Decl) { }
+
+  CommonBase *newCommon(ASTContext &C);
+
+  Common *getCommonPtr() {
+    return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
+  }
+
+public:
+  /// Get the underlying function declaration of the template.
+  TypeAliasDecl *getTemplatedDecl() const {
+    return static_cast<TypeAliasDecl*>(TemplatedDecl);
+  }
+
+
+  TypeAliasTemplateDecl *getCanonicalDecl() {
+    return redeclarable_base::getCanonicalDecl();
+  }
+  const TypeAliasTemplateDecl *getCanonicalDecl() const {
+    return redeclarable_base::getCanonicalDecl();
+  }
+
+  /// \brief Retrieve the previous declaration of this function template, or
+  /// NULL if no such declaration exists.
+  TypeAliasTemplateDecl *getPreviousDeclaration() {
+    return redeclarable_base::getPreviousDeclaration();
+  }
+
+  /// \brief Retrieve the previous declaration of this function template, or
+  /// NULL if no such declaration exists.
+  const TypeAliasTemplateDecl *getPreviousDeclaration() const {
+    return redeclarable_base::getPreviousDeclaration();
+  }
+
+  TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() {
+    return redeclarable_base::getInstantiatedFromMemberTemplate();
+  }
+
+                               
+  /// \brief Create a function template node.
+  static TypeAliasTemplateDecl *Create(ASTContext &C, DeclContext *DC,
+                                       SourceLocation L,
+                                       DeclarationName Name,
+                                       TemplateParameterList *Params,
+                                       NamedDecl *Decl);
+
+  /// \brief Create an empty alias template node.
+  static TypeAliasTemplateDecl *Create(ASTContext &C, EmptyShell);
+
+  // Implement isa/cast/dyncast support
+  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+  static bool classof(const TypeAliasTemplateDecl *D) { return true; }
+  static bool classofKind(Kind K) { return K == TypeAliasTemplate; }
+
+  friend class ASTDeclReader;
+  friend class ASTDeclWriter;
+};
+
 /// Implementation of inline functions that require the template declarations
 inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
   : Function(FTD) { }
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 930d193..33171bd 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1368,6 +1368,11 @@
     // source.
   })
 
+DEF_TRAVERSE_DECL(TypeAliasTemplateDecl, {
+    TRY_TO(TraverseDecl(D->getTemplatedDecl()));
+    TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+  })
+
 DEF_TRAVERSE_DECL(UnresolvedUsingTypenameDecl, {
     // A dependent using declaration which was marked with 'typename'.
     //   template<class T> class A : public B<T> { using typename B<T>::foo; };
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 975a66f..c1c60c0 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -3201,6 +3201,10 @@
 /// Other template specialization types, for which the template name
 /// is dependent, may be canonical types. These types are always
 /// dependent.
+///
+/// An instance of this type is followed by an array of TemplateArgument*s,
+/// then, if the template specialization type is for a type alias template,
+/// a QualType representing the non-canonical aliased type.
 class TemplateSpecializationType
   : public Type, public llvm::FoldingSetNode {
   /// \brief The name of the template being specialized.
@@ -3212,7 +3216,8 @@
 
   TemplateSpecializationType(TemplateName T,
                              const TemplateArgument *Args,
-                             unsigned NumArgs, QualType Canon);
+                             unsigned NumArgs, QualType Canon,
+                             QualType Aliased);
 
   friend class ASTContext;  // ASTContext creates these
 
@@ -3247,6 +3252,16 @@
     return isa<InjectedClassNameType>(getCanonicalTypeInternal());
   }
 
+  /// True if this template specialization type is for a type alias
+  /// template.
+  bool isTypeAlias() const;
+  /// Get the aliased type, if this is a specialization of a type alias
+  /// template.
+  QualType getAliasedType() const {
+    assert(isTypeAlias() && "not a type alias template specialization");
+    return *reinterpret_cast<const QualType*>(end());
+  }
+
   typedef const TemplateArgument * iterator;
 
   iterator begin() const { return getArgs(); }
@@ -3268,12 +3283,14 @@
   const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h
 
   bool isSugared() const {
-    return !isDependentType() || isCurrentInstantiation();
+    return !isDependentType() || isCurrentInstantiation() || isTypeAlias();
   }
   QualType desugar() const { return getCanonicalTypeInternal(); }
 
   void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) {
     Profile(ID, Template, getArgs(), NumArgs, Ctx);
+    if (isTypeAlias())
+      getAliasedType().Profile(ID);
   }
 
   static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index 9e69492..ddd0827 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -50,6 +50,7 @@
     def RedeclarableTemplate : DDecl<Template, 1>;
       def FunctionTemplate : DDecl<RedeclarableTemplate>;
       def ClassTemplate : DDecl<RedeclarableTemplate>;
+      def TypeAliasTemplate : DDecl<RedeclarableTemplate>;
     def TemplateTemplateParm : DDecl<Template>;
   def Using : DDecl<Named>;
   def UsingShadow : DDecl<Named>;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index e2ffe10..3a8a708 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -443,6 +443,8 @@
   "alias declarations accepted as a C++0x extension">, InGroup<CXX0x>;
 def err_alias_declaration_not_identifier : Error<
   "name defined in alias declaration must be an identifier">;
+def err_alias_declaration_specialization : Error<
+  "%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">;
     
 // C++0x override control
 def ext_override_control_keyword : Extension<
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 26dfc88..8b73f90 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -544,6 +544,8 @@
   "%0 can not be defined in the result type of a function">;
 def err_type_defined_in_param_type : Error<
   "%0 can not be defined in a parameter type">;
+def err_type_defined_in_alias_template : Error<
+  "%0 can not be defined in a type alias template">;
 
 def note_pure_virtual_function : Note<
   "unimplemented pure virtual method %0 in %1">;
@@ -1674,7 +1676,7 @@
 def err_template_arg_nontype_ambig : Error<
   "template argument for non-type template parameter is treated as type %0">;
 def err_template_arg_must_be_template : Error<
-  "template argument for template template parameter must be a class template">;
+  "template argument for template template parameter must be a class template%select{| or type alias template}0">;
 def ext_template_arg_local_type : ExtWarn<
   "template argument uses local type %0">, InGroup<LocalTypeTemplateArgs>;
 def ext_template_arg_unnamed_type : ExtWarn<
@@ -1820,6 +1822,8 @@
 def err_template_param_list_matches_nontemplate : Error<
   "template parameter list matching the non-templated nested type %0 should "
   "be empty ('template<>')">;
+def err_alias_template_extra_headers : Error<
+  "extraneous template parameter list in alias template declaration">;
 def err_template_spec_extra_headers : Error<
   "extraneous template parameter list in template specialization or "
   "out-of-line template definition">;
@@ -1897,6 +1901,8 @@
   "in instantiation of function template specialization %q0 requested here">;
 def note_template_static_data_member_def_here : Note<
   "in instantiation of static data member %q0 requested here">;
+def note_template_type_alias_instantiation_here : Note<
+  "in instantiation of template type alias %0 requested here">;
   
 def note_default_arg_instantiation_here : Note<
   "in instantiation of default argument for '%0' required here">;
@@ -2034,7 +2040,7 @@
 def err_template_id_not_a_type : Error<
   "template name refers to non-type template '%0'">;
 def note_template_declared_here : Note<
-  "%select{function template|class template|template template parameter}0 "
+  "%select{function template|class template|type alias template|template template parameter}0 "
   "%1 declared here">;
 
 // C++0x Variadic Templates
@@ -2172,9 +2178,9 @@
 def err_redefinition_different_kind : Error<
   "redefinition of %0 as different kind of symbol">;
 def err_redefinition_different_typedef : Error<
-  "%select{typedef|type alias}0 redefinition with different types (%1 vs %2)">;
+  "%select{typedef|type alias|type alias template}0 redefinition with different types (%1 vs %2)">;
 def err_tag_reference_non_tag : Error<
-  "elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template}0">;
+  "elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template|a type alias template}0">;
 def err_tag_reference_conflict : Error<
   "implicit declaration introduced by elaborated type conflicts with "
   "%select{a declaration|a typedef|a type alias|a template}0 of the same name">;
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 708c9b2..8179b63 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -1332,7 +1332,8 @@
     CXXCatchContext,     // C++ catch exception-declaration
     BlockLiteralContext,  // Block literal declarator.
     TemplateTypeArgContext, // Template type argument.
-    AliasDeclContext     // C++0x alias-declaration.
+    AliasDeclContext,    // C++0x alias-declaration.
+    AliasTemplateContext // C++0x alias-declaration template.
   };
 
 private:
@@ -1474,6 +1475,7 @@
 
     case TypeNameContext:
     case AliasDeclContext:
+    case AliasTemplateContext:
     case PrototypeContext:
     case ObjCPrototypeContext:
     case TemplateParamContext:
@@ -1503,6 +1505,7 @@
 
     case TypeNameContext:
     case AliasDeclContext:
+    case AliasTemplateContext:
     case ObjCPrototypeContext:
     case BlockLiteralContext:
     case TemplateTypeArgContext:
@@ -1531,6 +1534,7 @@
     case CXXCatchContext:
     case TypeNameContext:
     case AliasDeclContext:
+    case AliasTemplateContext:
     case BlockLiteralContext:
     case TemplateTypeArgContext:
       return false;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index fee483b..4f8a615 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -944,6 +944,7 @@
   void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
   void CheckShadow(Scope *S, VarDecl *D);
   void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange);
+  void CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *D);
   NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                                     QualType R, TypeSourceInfo *TInfo,
                                     LookupResult &Previous, bool &Redeclaration);
@@ -1652,6 +1653,10 @@
                                    AssociatedNamespaceSet &AssociatedNamespaces,
                                    AssociatedClassSet &AssociatedClasses);
 
+  void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S,
+                            bool ConsiderLinkage,
+                            bool ExplicitInstantiationOrSpecialization);
+
   bool DiagnoseAmbiguousLookup(LookupResult &Result);
   //@}
 
@@ -2468,6 +2473,7 @@
                               SourceLocation TypenameLoc);
   Decl *ActOnAliasDeclaration(Scope *CurScope,
                               AccessSpecifier AS,
+                              MultiTemplateParamsArg TemplateParams,
                               SourceLocation UsingLoc,
                               UnqualifiedId &Name,
                               TypeResult Type);
@@ -3412,7 +3418,8 @@
     TPC_FunctionTemplate,
     TPC_ClassTemplateMember,
     TPC_FriendFunctionTemplate,
-    TPC_FriendFunctionTemplateDefinition
+    TPC_FriendFunctionTemplateDefinition,
+    TPC_TypeAliasTemplate
   };
 
   bool CheckTemplateParameterList(TemplateParameterList *NewParams,
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index 4d97f9b..a257772 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -335,9 +335,9 @@
     Decl *VisitLabelDecl(LabelDecl *D);
     Decl *VisitNamespaceDecl(NamespaceDecl *D);
     Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
-    Decl *VisitTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias);
     Decl *VisitTypedefDecl(TypedefDecl *D);
     Decl *VisitTypeAliasDecl(TypeAliasDecl *D);
+    Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
     Decl *VisitVarDecl(VarDecl *D);
     Decl *VisitAccessSpecDecl(AccessSpecDecl *D);
     Decl *VisitFieldDecl(FieldDecl *D);
@@ -415,6 +415,7 @@
     bool SubstQualifier(const TagDecl *OldDecl,
                         TagDecl *NewDecl);
       
+    Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias);
     ClassTemplatePartialSpecializationDecl *
     InstantiateClassTemplatePartialSpecialization(
                                               ClassTemplateDecl *ClassTemplate,
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 7b9e98d..0b99756 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -761,6 +761,8 @@
       DECL_NON_TYPE_TEMPLATE_PARM,
       /// \brief A TemplateTemplateParmDecl record.
       DECL_TEMPLATE_TEMPLATE_PARM,
+      /// \brief A TypeAliasTemplateDecl record.
+      DECL_TYPE_ALIAS_TEMPLATE,
       /// \brief A StaticAssertDecl record.
       DECL_STATIC_ASSERT,
       /// \brief A record containing CXXBaseSpecifiers.
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index d6535e9..a5ff664 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -969,13 +969,18 @@
     return getTypeInfo(
                   cast<AttributedType>(T)->getEquivalentType().getTypePtr());
 
-  case Type::TemplateSpecialization:
+  case Type::TemplateSpecialization: {
     assert(getCanonicalType(T) != T &&
            "Cannot request the size of a dependent type");
-    // FIXME: this is likely to be wrong once we support template
-    // aliases, since a template alias could refer to a typedef that
-    // has an __aligned__ attribute on it.
-    return getTypeInfo(getCanonicalType(T));
+    const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T);
+    // A type alias template specialization may refer to a typedef with the
+    // aligned attribute on it.
+    if (TST->isTypeAlias())
+      return getTypeInfo(TST->getAliasedType().getTypePtr());
+    else
+      return getTypeInfo(getCanonicalType(T));
+  }
+
   }
 
   assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2");
@@ -2247,10 +2252,10 @@
 ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
                                               SourceLocation NameLoc,
                                         const TemplateArgumentListInfo &Args,
-                                              QualType CanonType) const {
+                                              QualType Underlying) const {
   assert(!Name.getAsDependentTemplateName() && 
          "No dependent template names here!");
-  QualType TST = getTemplateSpecializationType(Name, Args, CanonType);
+  QualType TST = getTemplateSpecializationType(Name, Args, Underlying);
 
   TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
   TemplateSpecializationTypeLoc TL
@@ -2266,7 +2271,7 @@
 QualType
 ASTContext::getTemplateSpecializationType(TemplateName Template,
                                           const TemplateArgumentListInfo &Args,
-                                          QualType Canon) const {
+                                          QualType Underlying) const {
   assert(!Template.getAsDependentTemplateName() && 
          "No dependent template names here!");
   
@@ -2278,35 +2283,46 @@
     ArgVec.push_back(Args[i].getArgument());
 
   return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs,
-                                       Canon);
+                                       Underlying);
 }
 
 QualType
 ASTContext::getTemplateSpecializationType(TemplateName Template,
                                           const TemplateArgument *Args,
                                           unsigned NumArgs,
-                                          QualType Canon) const {
+                                          QualType Underlying) const {
   assert(!Template.getAsDependentTemplateName() && 
          "No dependent template names here!");
   // Look through qualified template names.
   if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
     Template = TemplateName(QTN->getTemplateDecl());
   
-  if (!Canon.isNull())
-    Canon = getCanonicalType(Canon);
-  else
-    Canon = getCanonicalTemplateSpecializationType(Template, Args, NumArgs);
+  bool isTypeAlias = 
+    Template.getAsTemplateDecl() &&
+    isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
+
+  QualType CanonType;
+  if (!Underlying.isNull())
+    CanonType = getCanonicalType(Underlying);
+  else {
+    assert(!isTypeAlias &&
+           "Underlying type for template alias must be computed by caller");
+    CanonType = getCanonicalTemplateSpecializationType(Template, Args,
+                                                       NumArgs);
+  }
 
   // Allocate the (non-canonical) template specialization type, but don't
   // try to unique it: these types typically have location information that
   // we don't unique and don't want to lose.
-  void *Mem = Allocate((sizeof(TemplateSpecializationType) +
-                        sizeof(TemplateArgument) * NumArgs),
+  void *Mem = Allocate(sizeof(TemplateSpecializationType) +
+                       sizeof(TemplateArgument) * NumArgs +
+                       (isTypeAlias ? sizeof(QualType) : 0),
                        TypeAlignment);
   TemplateSpecializationType *Spec
     = new (Mem) TemplateSpecializationType(Template,
                                            Args, NumArgs,
-                                           Canon);
+                                           CanonType,
+                                         isTypeAlias ? Underlying : QualType());
 
   Types.push_back(Spec);
   return QualType(Spec, 0);
@@ -2318,6 +2334,10 @@
                                                    unsigned NumArgs) const {
   assert(!Template.getAsDependentTemplateName() && 
          "No dependent template names here!");
+  assert((!Template.getAsTemplateDecl() ||
+          !isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) &&
+         "Underlying type for template alias must be computed by caller");
+
   // Look through qualified template names.
   if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
     Template = TemplateName(QTN->getTemplateDecl());
@@ -2346,7 +2366,7 @@
                          TypeAlignment);
     Spec = new (Mem) TemplateSpecializationType(CanonTemplate,
                                                 CanonArgs.data(), NumArgs,
-                                                QualType());
+                                                QualType(), QualType());
     Types.push_back(Spec);
     TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
   }
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 897b4a4..16d2f85 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -56,9 +56,11 @@
       continue;
     }
 
-    // Don't desugar template specializations. 
-    if (isa<TemplateSpecializationType>(Ty))
-      break;
+    // Don't desugar template specializations, unless it's an alias template.
+    if (const TemplateSpecializationType *TST
+          = dyn_cast<TemplateSpecializationType>(Ty))
+      if (!TST->isTypeAlias())
+        break;
 
     // Don't desugar magic Objective-C types.
     if (QualType(Ty,0) == Context.getObjCIdType() ||
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 6d517c5..8f3388e 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -439,6 +439,7 @@
 
     case Typedef:
     case TypeAlias:
+    case TypeAliasTemplate:
     case UnresolvedUsingTypename:
     case TemplateTypeParm:
       return IDNS_Ordinary | IDNS_Type;
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 6272340..bc375d0 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -735,3 +735,34 @@
                                                EmptyShell Empty) {
   return new (Context) FriendTemplateDecl(Empty);
 }
+
+//===----------------------------------------------------------------------===//
+// TypeAliasTemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C,
+                                                     DeclContext *DC,
+                                                     SourceLocation L,
+                                                     DeclarationName Name,
+                                                  TemplateParameterList *Params,
+                                                     NamedDecl *Decl) {
+  AdoptTemplateParameterList(Params, DC);
+  return new (C) TypeAliasTemplateDecl(DC, L, Name, Params, Decl);
+}
+
+TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C,
+                                                     EmptyShell) {
+  return new (C) TypeAliasTemplateDecl(0, SourceLocation(), DeclarationName(),
+                                       0, 0);
+}
+
+void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) {
+  static_cast<Common *>(Ptr)->~Common();
+}
+RedeclarableTemplateDecl::CommonBase *
+TypeAliasTemplateDecl::newCommon(ASTContext &C) {
+  Common *CommonPtr = new (C) Common;
+  C.AddDeallocation(DeallocateCommon, CommonPtr);
+  return CommonPtr;
+}
+
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 7d593bc..8bb39ba 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -619,7 +619,8 @@
   // TemplateDecl
   void visitTemplateDeclChildren(TemplateDecl *D) {
     visitTemplateParameters(D->getTemplateParameters());
-    dispatch(D->getTemplatedDecl());
+    if (D->getTemplatedDecl())
+      dispatch(D->getTemplatedDecl());
   }
 
   // FunctionTemplateDecl
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index ed22235..b0086d9 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1559,13 +1559,13 @@
 
 TemplateSpecializationType::
 TemplateSpecializationType(TemplateName T,
-                           const TemplateArgument *Args,
-                           unsigned NumArgs, QualType Canon)
+                           const TemplateArgument *Args, unsigned NumArgs,
+                           QualType Canon, QualType AliasedType)
   : Type(TemplateSpecialization,
          Canon.isNull()? QualType(this, 0) : Canon,
-         T.isDependent(), false, T.containsUnexpandedParameterPack()),
-    Template(T), NumArgs(NumArgs) 
-{
+         Canon.isNull()? T.isDependent() : Canon->isDependentType(),
+         false, T.containsUnexpandedParameterPack()),
+    Template(T), NumArgs(NumArgs) {
   assert(!T.getAsDependentTemplateName() && 
          "Use DependentTemplateSpecializationType for dependent template-name");
   assert((!Canon.isNull() ||
@@ -1576,7 +1576,12 @@
     = reinterpret_cast<TemplateArgument *>(this + 1);
   for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
     // Update dependent and variably-modified bits.
-    if (Args[Arg].isDependent())
+    // If the canonical type exists and is non-dependent, the template
+    // specialization type can be non-dependent even if one of the type
+    // arguments is. Given:
+    //   template<typename T> using U = int;
+    // U<T> is always non-dependent, irrespective of the type T.
+    if (Canon.isNull() && Args[Arg].isDependent())
       setDependent();
     if (Args[Arg].getKind() == TemplateArgument::Type &&
         Args[Arg].getAsType()->isVariablyModifiedType())
@@ -1586,6 +1591,15 @@
 
     new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
   }
+
+  // Store the aliased type if this is a type alias template specialization.
+  bool IsTypeAlias = !AliasedType.isNull();
+  assert(IsTypeAlias == isTypeAlias() &&
+         "allocated wrong size for type alias");
+  if (IsTypeAlias) {
+    TemplateArgument *Begin = reinterpret_cast<TemplateArgument *>(this + 1);
+    *reinterpret_cast<QualType*>(Begin + getNumArgs()) = AliasedType;
+  }
 }
 
 void
@@ -1599,6 +1613,11 @@
     Args[Idx].Profile(ID, Context);
 }
 
+bool TemplateSpecializationType::isTypeAlias() const {
+  TemplateDecl *D = Template.getAsTemplateDecl();
+  return D && isa<TypeAliasTemplateDecl>(D);
+}
+
 QualType
 QualifierCollector::apply(const ASTContext &Context, QualType QT) const {
   if (!hasNonFastQualifiers())
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index c027375..0e1054a 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -51,6 +51,7 @@
   case Decl::ImplicitParam:
   case Decl::ClassTemplate:
   case Decl::FunctionTemplate:
+  case Decl::TypeAliasTemplate:
   case Decl::TemplateTemplateParm:
   case Decl::ObjCMethod:
   case Decl::ObjCCategory:
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 4ce12ec..4bf1e3a 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -2060,6 +2060,7 @@
   case Decl::UsingDirective:
   case Decl::ClassTemplate:
   case Decl::FunctionTemplate:
+  case Decl::TypeAliasTemplate:
   case Decl::NamespaceAlias:
     break;
   case Decl::CXXConstructor:
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index d6e0d3a..3b4f042 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -557,6 +557,7 @@
            .Case("ownership_returns", true)
            .Case("ownership_takes", true)
            // C++0x features
+           .Case("cxx_alias_templates", LangOpts.CPlusPlus0x)
            .Case("cxx_attributes", LangOpts.CPlusPlus0x)
            .Case("cxx_auto_type", LangOpts.CPlusPlus0x)
            .Case("cxx_decltype", LangOpts.CPlusPlus0x)
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 41b773e..ae6b3ff 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -387,13 +387,34 @@
   bool IsAliasDecl = Tok.is(tok::equal);
   TypeResult TypeAlias;
   if (IsAliasDecl) {
-    // TODO: Do we want to support attributes somewhere in an alias declaration?
-    // Can't follow GCC since it doesn't support them yet!
+    // TODO: Attribute support. C++0x attributes may appear before the equals.
+    // Where can GNU attributes appear?
     ConsumeToken();
 
     if (!getLang().CPlusPlus0x)
       Diag(Tok.getLocation(), diag::ext_alias_declaration);
 
+    // Type alias templates cannot be specialized.
+    int SpecKind = -1;
+    if (Name.getKind() == UnqualifiedId::IK_TemplateId)
+      SpecKind = 0;
+    if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization)
+      SpecKind = 1;
+    if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
+      SpecKind = 2;
+    if (SpecKind != -1) {
+      SourceRange Range;
+      if (SpecKind == 0)
+        Range = SourceRange(Name.TemplateId->LAngleLoc,
+                            Name.TemplateId->RAngleLoc);
+      else
+        Range = TemplateInfo.getSourceRange();
+      Diag(Range.getBegin(), diag::err_alias_declaration_specialization)
+        << SpecKind << Range;
+      SkipUntil(tok::semi);
+      return 0;
+    }
+
     // Name must be an identifier.
     if (Name.getKind() != UnqualifiedId::IK_Identifier) {
       Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier);
@@ -408,7 +429,9 @@
       Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
         << FixItHint::CreateRemoval(SS.getRange());
 
-    TypeAlias = ParseTypeName(0, Declarator::AliasDeclContext);
+    TypeAlias = ParseTypeName(0, TemplateInfo.Kind ?
+                              Declarator::AliasTemplateContext :
+                              Declarator::AliasDeclContext);
   } else
     // Parse (optional) attributes (most likely GNU strong-using extension).
     MaybeParseGNUAttributes(attrs);
@@ -421,9 +444,9 @@
                    tok::semi);
 
   // Diagnose an attempt to declare a templated using-declaration.
-  // TODO: in C++0x, alias-declarations can be templates:
+  // In C++0x, alias-declarations can be templates:
   //   template <...> using id = type;
-  if (TemplateInfo.Kind) {
+  if (TemplateInfo.Kind && !IsAliasDecl) {
     SourceRange R = TemplateInfo.getSourceRange();
     Diag(UsingLoc, diag::err_templated_using_declaration)
       << R << FixItHint::CreateRemoval(R);
@@ -434,9 +457,14 @@
     return 0;
   }
 
-  if (IsAliasDecl)
-    return Actions.ActOnAliasDeclaration(getCurScope(), AS, UsingLoc, Name,
-                                         TypeAlias);
+  if (IsAliasDecl) {
+    TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
+    MultiTemplateParamsArg TemplateParamsArg(Actions,
+      TemplateParams ? TemplateParams->data() : 0,
+      TemplateParams ? TemplateParams->size() : 0);
+    return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
+                                         UsingLoc, Name, TypeAlias);
+  }
 
   return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS,
                                        Name, attrs.getList(),
@@ -1515,8 +1543,6 @@
   MaybeParseMicrosoftAttributes(attrs);
 
   if (Tok.is(tok::kw_using)) {
-    // FIXME: Check for template aliases
-
     ProhibitAttributes(attrs);
 
     // Eat 'using'.
@@ -1527,7 +1553,7 @@
       SkipUntil(tok::semi, true, true);
     } else {
       SourceLocation DeclEnd;
-      // Otherwise, it must be using-declaration.
+      // Otherwise, it must be a using-declaration or an alias-declaration.
       ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo,
                             UsingLoc, DeclEnd, AS);
     }
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 12e38da..aa89d75 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -905,10 +905,10 @@
 
   // C++0x [temp.arg.template]p1:
   //   A template-argument for a template template-parameter shall be the name
-  //   of a class template or a template alias, expressed as id-expression.
+  //   of a class template or an alias template, expressed as id-expression.
   //   
-  // We parse an id-expression that refers to a class template or template
-  // alias. The grammar we parse is:
+  // We parse an id-expression that refers to a class template or alias
+  // template. The grammar we parse is:
   //
   //   nested-name-specifier[opt] template[opt] identifier ...[opt]
   //
@@ -969,7 +969,7 @@
                                                 MemberOfUnknownSpecialization);
       if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) {
         // We have an id-expression that refers to a class template or
-        // (C++0x) template alias. 
+        // (C++0x) alias template. 
         Result = ParsedTemplateArgument(SS, Template, Name.StartLocation);
       }
     }
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 411d424..63983c3 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -445,8 +445,8 @@
       continue;
 
     // If the template names don't match, it can't be a dependent
-    // match.  This isn't true in C++0x because of template aliases.
-    if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName())
+    // match.
+    if (CTD->getDeclName() != Friend->getDeclName())
       continue;
 
     // If the class's context can't instantiate to the friend's
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 5ee256a..ff38900 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -94,9 +94,13 @@
     if (EnteringContext) {
       const Type *NNSType = NNS->getAsType();
       if (!NNSType) {
-        // do nothing, fall out
-      } else if (const TemplateSpecializationType *SpecType
-                   = NNSType->getAs<TemplateSpecializationType>()) {
+        return 0;
+      }
+
+      // Look through type alias templates, per C++0x [temp.dep.type]p1.
+      NNSType = Context.getCanonicalType(NNSType);
+      if (const TemplateSpecializationType *SpecType
+            = NNSType->getAs<TemplateSpecializationType>()) {
         // We are entering the context of the nested name specifier, so try to
         // match the nested name specifier to either a primary class template
         // or a class template partial specialization.
@@ -382,7 +386,7 @@
     isDependent = ObjectType->isDependentType();
   } else if (SS.isSet()) {
     // This nested-name-specifier occurs after another nested-name-specifier,
-    // so long into the context associated with the prior nested-name-specifier.
+    // so look into the context associated with the prior nested-name-specifier.
     LookupCtx = computeDeclContext(SS, EnteringContext);
     isDependent = isDependentScopeSpecifier(SS);
     Found.setContextRange(SS.getRange());
@@ -712,8 +716,13 @@
   if (T.isNull())
     return true;
 
-  // FIXME: Template aliases will need to check the resulting type to make
-  // sure that it's either dependent or a tag type.
+  // Alias template specializations can produce types which are not valid
+  // nested name specifiers.
+  if (!T->isDependentType() && !T->getAs<TagType>()) {
+    Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T;
+    NoteAllFoundTemplates(Template.get());
+    return true;
+  }
 
   // Provide source-location information for the template specialization 
   // type.
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 6231fbd..7845247 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -891,19 +891,19 @@
 
 /// Filters out lookup results that don't fall within the given scope
 /// as determined by isDeclInScope.
-static void FilterLookupForScope(Sema &SemaRef, LookupResult &R,
-                                 DeclContext *Ctx, Scope *S,
-                                 bool ConsiderLinkage,
-                                 bool ExplicitInstantiationOrSpecialization) {
+void Sema::FilterLookupForScope(LookupResult &R,
+                                DeclContext *Ctx, Scope *S,
+                                bool ConsiderLinkage,
+                                bool ExplicitInstantiationOrSpecialization) {
   LookupResult::Filter F = R.makeFilter();
   while (F.hasNext()) {
     NamedDecl *D = F.next();
 
-    if (SemaRef.isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization))
+    if (isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization))
       continue;
 
     if (ConsiderLinkage &&
-        isOutOfScopePreviousDeclaration(D, Ctx, SemaRef.Context))
+        isOutOfScopePreviousDeclaration(D, Ctx, Context))
       continue;
     
     F.erase();
@@ -3304,15 +3304,13 @@
   // Handle attributes prior to checking for duplicates in MergeVarDecl
   ProcessDeclAttributes(S, NewTD, D);
 
+  CheckTypedefForVariablyModifiedType(S, NewTD);
+
   return ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration);
 }
 
-/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which
-/// declares a typedef-name, either using the 'typedef' type specifier or via
-/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'.
-NamedDecl*
-Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
-                           LookupResult &Previous, bool &Redeclaration) {
+void
+Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) {
   // C99 6.7.7p2: If a typedef name specifies a variably modified type
   // then it shall have block scope.
   // Note that variably modified types must be fixed before merging the decl so
@@ -3343,10 +3341,18 @@
       }
     }
   }
+}
 
+
+/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which
+/// declares a typedef-name, either using the 'typedef' type specifier or via
+/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'.
+NamedDecl*
+Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
+                           LookupResult &Previous, bool &Redeclaration) {
   // Merge the decl with the existing one if appropriate. If the decl is
   // in an outer scope, it isn't the same thing.
-  FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false,
+  FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/ false,
                        /*ExplicitInstantiationOrSpecialization=*/false);
   if (!Previous.empty()) {
     Redeclaration = true;
@@ -3625,7 +3631,7 @@
   // Don't consider existing declarations that are in a different
   // scope and are out-of-semantic-context declarations (if the new
   // declaration has linkage).
-  FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage(),
+  FilterLookupForScope(Previous, DC, S, NewVD->hasLinkage(),
                        isExplicitSpecialization);
   
   if (!getLangOptions().CPlusPlus)
@@ -4072,7 +4078,7 @@
     // Set the lexical context.
     NewFD->setLexicalDeclContext(CurContext);
     // Filter out previous declarations that don't match the scope.
-    FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
+    FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
                          /*ExplicitInstantiationOrSpecialization=*/false);
   } else {
     isFriend = D.getDeclSpec().isFriendSpecified();
@@ -4350,7 +4356,7 @@
     }
 
     // Filter out previous declarations that don't match the scope.
-    FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
+    FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
                          isExplicitSpecialization || 
                          isFunctionTemplateSpecialization);
 
@@ -4417,6 +4423,9 @@
         bool IsTypeAlias = false;
         if (const TypedefType *TT = Param->getType()->getAs<TypedefType>())
           IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl());
+        else if (const TemplateSpecializationType *TST =
+                   Param->getType()->getAs<TemplateSpecializationType>())
+          IsTypeAlias = TST->isTypeAlias();
         Diag(Param->getLocation(), diag::err_param_typedef_of_void)
           << IsTypeAlias;
       }
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 2ef15b6..6dad784 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -3467,6 +3467,11 @@
   if (const TypedefType *TT = DeclaratorType->getAs<TypedefType>())
     Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
       << DeclaratorType << isa<TypeAliasDecl>(TT->getDecl());
+  else if (const TemplateSpecializationType *TST =
+             DeclaratorType->getAs<TemplateSpecializationType>())
+    if (TST->isTypeAlias())
+      Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
+        << DeclaratorType << 1;
 
   // C++ [class.dtor]p2:
   //   A destructor is used to destroy objects of its class type. A
@@ -4701,9 +4706,13 @@
 
 Decl *Sema::ActOnAliasDeclaration(Scope *S,
                                   AccessSpecifier AS,
+                                  MultiTemplateParamsArg TemplateParamLists,
                                   SourceLocation UsingLoc,
                                   UnqualifiedId &Name,
                                   TypeResult Type) {
+  // Skip up to the relevant declaration scope.
+  while (S->getFlags() & Scope::TemplateParamScope)
+    S = S->getParent();
   assert((S->getFlags() & Scope::DeclScope) &&
          "got alias-declaration outside of declaration scope");
 
@@ -4719,8 +4728,11 @@
     return 0;
 
   if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo,
-                                      UPPC_DeclarationType))
+                                      UPPC_DeclarationType)) {
     Invalid = true;
+    TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy, 
+                                             TInfo->getTypeLoc().getBeginLoc());
+  }
 
   LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
   LookupName(Previous, S);
@@ -4745,13 +4757,93 @@
   if (Invalid)
     NewTD->setInvalidDecl();
 
+  CheckTypedefForVariablyModifiedType(S, NewTD);
+  Invalid |= NewTD->isInvalidDecl();
+
   bool Redeclaration = false;
-  ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration);
+
+  NamedDecl *NewND;
+  if (TemplateParamLists.size()) {
+    TypeAliasTemplateDecl *OldDecl = 0;
+    TemplateParameterList *OldTemplateParams = 0;
+
+    if (TemplateParamLists.size() != 1) {
+      Diag(UsingLoc, diag::err_alias_template_extra_headers)
+        << SourceRange(TemplateParamLists.get()[1]->getTemplateLoc(),
+         TemplateParamLists.get()[TemplateParamLists.size()-1]->getRAngleLoc());
+    }
+    TemplateParameterList *TemplateParams = TemplateParamLists.get()[0];
+
+    // Only consider previous declarations in the same scope.
+    FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false,
+                         /*ExplicitInstantiationOrSpecialization*/false);
+    if (!Previous.empty()) {
+      Redeclaration = true;
+
+      OldDecl = Previous.getAsSingle<TypeAliasTemplateDecl>();
+      if (!OldDecl && !Invalid) {
+        Diag(UsingLoc, diag::err_redefinition_different_kind)
+          << Name.Identifier;
+
+        NamedDecl *OldD = Previous.getRepresentativeDecl();
+        if (OldD->getLocation().isValid())
+          Diag(OldD->getLocation(), diag::note_previous_definition);
+
+        Invalid = true;
+      }
+
+      if (!Invalid && OldDecl && !OldDecl->isInvalidDecl()) {
+        if (TemplateParameterListsAreEqual(TemplateParams,
+                                           OldDecl->getTemplateParameters(),
+                                           /*Complain=*/true,
+                                           TPL_TemplateMatch))
+          OldTemplateParams = OldDecl->getTemplateParameters();
+        else
+          Invalid = true;
+
+        TypeAliasDecl *OldTD = OldDecl->getTemplatedDecl();
+        if (!Invalid &&
+            !Context.hasSameType(OldTD->getUnderlyingType(),
+                                 NewTD->getUnderlyingType())) {
+          // FIXME: The C++0x standard does not clearly say this is ill-formed,
+          // but we can't reasonably accept it.
+          Diag(NewTD->getLocation(), diag::err_redefinition_different_typedef)
+            << 2 << NewTD->getUnderlyingType() << OldTD->getUnderlyingType();
+          if (OldTD->getLocation().isValid())
+            Diag(OldTD->getLocation(), diag::note_previous_definition);
+          Invalid = true;
+        }
+      }
+    }
+
+    // Merge any previous default template arguments into our parameters,
+    // and check the parameter list.
+    if (CheckTemplateParameterList(TemplateParams, OldTemplateParams,
+                                   TPC_TypeAliasTemplate))
+      return 0;
+
+    TypeAliasTemplateDecl *NewDecl =
+      TypeAliasTemplateDecl::Create(Context, CurContext, UsingLoc,
+                                    Name.Identifier, TemplateParams,
+                                    NewTD);
+
+    NewDecl->setAccess(AS);
+
+    if (Invalid)
+      NewDecl->setInvalidDecl();
+    else if (OldDecl)
+      NewDecl->setPreviousDeclaration(OldDecl);
+
+    NewND = NewDecl;
+  } else {
+    ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration);
+    NewND = NewTD;
+  }
 
   if (!Redeclaration)
-    PushOnScopeChains(NewTD, S);
+    PushOnScopeChains(NewND, S);
 
-  return NewTD;
+  return NewND;
 }
 
 Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 7a4e54d..0943165 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -92,11 +92,9 @@
       //   ambiguity in certain cases (for example, if it is found in more than
       //   one base class). If all of the injected-class-names that are found
       //   refer to specializations of the same class template, and if the name
-      //   is followed by a template-argument-list, the reference refers to the
-      //   class template itself and not a specialization thereof, and is not
+      //   is used as a template-name, the reference refers to the class
+      //   template itself and not a specialization thereof, and is not
       //   ambiguous.
-      //
-      // FIXME: Will we eventually have to do the same for alias templates?
       if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl))
         if (!ClassTemplates.insert(ClassTmpl)) {
           filter.erase();
@@ -199,7 +197,8 @@
       // We'll do this lookup again later.
       R.suppressDiagnostics();
     } else {
-      assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD));
+      assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) ||
+             isa<TypeAliasTemplateDecl>(TD));
       TemplateKind = TNK_Type_template;
     }
   }
@@ -1062,6 +1061,7 @@
                                             SourceRange DefArgRange) {
   switch (TPC) {
   case Sema::TPC_ClassTemplate:
+  case Sema::TPC_TypeAliasTemplate:
     return false;
 
   case Sema::TPC_FunctionTemplate:
@@ -1187,9 +1187,10 @@
     bool MissingDefaultArg = false;
 
     // C++0x [temp.param]p11:
-    //   If a template parameter of a primary class template is a template
-    //   parameter pack, it shall be the last template parameter.
-    if (SawParameterPack && TPC == TPC_ClassTemplate) {
+    //   If a template parameter of a primary class template or alias template
+    //   is a template parameter pack, it shall be the last template parameter.
+    if (SawParameterPack &&
+        (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) {
       Diag(ParameterPackLoc,
            diag::err_template_param_pack_must_be_last_template_parameter);
       Invalid = true;
@@ -1655,7 +1656,8 @@
     Diag(Template->getLocation(), diag::note_template_declared_here)
       << (isa<FunctionTemplateDecl>(Template)? 0
           : isa<ClassTemplateDecl>(Template)? 1
-          : 2)
+          : isa<TypeAliasTemplateDecl>(Template)? 2
+          : 3)
       << Template->getDeclName();
     return;
   }
@@ -1675,13 +1677,24 @@
 QualType Sema::CheckTemplateIdType(TemplateName Name,
                                    SourceLocation TemplateLoc,
                                    TemplateArgumentListInfo &TemplateArgs) {
+  DependentTemplateName *DTN = Name.getAsDependentTemplateName();
+  if (DTN && DTN->isIdentifier())
+    // When building a template-id where the template-name is dependent,
+    // assume the template is a type template. Either our assumption is
+    // correct, or the code is ill-formed and will be diagnosed when the
+    // dependent name is substituted.
+    return Context.getDependentTemplateSpecializationType(ETK_None,
+                                                          DTN->getQualifier(),
+                                                          DTN->getIdentifier(),
+                                                          TemplateArgs);
+
   TemplateDecl *Template = Name.getAsTemplateDecl();
   if (!Template || isa<FunctionTemplateDecl>(Template)) {
     // We might have a substituted template template parameter pack. If so,
     // build a template specialization type for it.
     if (Name.getAsSubstTemplateTemplateParmPack())
       return Context.getTemplateSpecializationType(Name, TemplateArgs);
-    
+
     Diag(TemplateLoc, diag::err_template_id_not_a_type)
       << Name;
     NoteAllFoundTemplates(Name);
@@ -1700,9 +1713,29 @@
 
   QualType CanonType;
 
-  if (Name.isDependent() ||
-      TemplateSpecializationType::anyDependentTemplateArguments(
-                                                      TemplateArgs)) {
+  if (TypeAliasTemplateDecl *AliasTemplate
+        = dyn_cast<TypeAliasTemplateDecl>(Template)) {
+    // Find the canonical type for this type alias template specialization.
+    TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
+    if (Pattern->isInvalidDecl())
+      return QualType();
+
+    TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
+                                      Converted.data(), Converted.size());
+
+    // Only substitute for the innermost template argument list.
+    MultiLevelTemplateArgumentList TemplateArgLists;
+    TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+
+    InstantiatingTemplate Inst(*this, TemplateLoc, Template);
+    CanonType = SubstType(Pattern->getUnderlyingType(),
+                          TemplateArgLists, AliasTemplate->getLocation(),
+                          AliasTemplate->getDeclName());
+    if (CanonType.isNull())
+      return QualType();
+  } else if (Name.isDependent() ||
+             TemplateSpecializationType::anyDependentTemplateArguments(
+               TemplateArgs)) {
     // This class template specialization is a dependent
     // type. Therefore, its canonical type is another class template
     // specialization type that contains all of the converted
@@ -1894,6 +1927,16 @@
       SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
     return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
   }
+
+  if (TypeAliasTemplateDecl *TAT =
+        dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) {
+    // C++0x [dcl.type.elab]p2:
+    //   If the identifier resolves to a typedef-name or the simple-template-id
+    //   resolves to an alias template specialization, the
+    //   elaborated-type-specifier is ill-formed.
+    Diag(TemplateLoc, diag::err_tag_reference_non_tag) << 4;
+    Diag(TAT->getLocation(), diag::note_declared_at);
+  }
   
   QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs);
   if (Result.isNull())
@@ -2485,7 +2528,7 @@
       }
 
       // We have a template argument that actually does refer to a class
-      // template, template alias, or template template parameter, and
+      // template, alias template, or template template parameter, and
       // therefore cannot be a non-type template argument.
       Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr)
         << Arg.getSourceRange();
@@ -2562,7 +2605,8 @@
   case TemplateArgument::Type:
     // We have a template template parameter but the template
     // argument does not refer to a template.
-    Diag(Arg.getLocation(), diag::err_template_arg_must_be_template);
+    Diag(Arg.getLocation(), diag::err_template_arg_must_be_template)
+      << getLangOptions().CPlusPlus0x;
     return true;
 
   case TemplateArgument::Declaration:
@@ -3722,9 +3766,10 @@
     return false;
   }
 
-  // C++ [temp.arg.template]p1:
+  // C++0x [temp.arg.template]p1:
   //   A template-argument for a template template-parameter shall be
-  //   the name of a class template, expressed as id-expression. Only
+  //   the name of a class template or an alias template, expressed as an
+  //   id-expression. When the template-argument names a class template, only
   //   primary class templates are considered when matching the
   //   template template argument with the corresponding parameter;
   //   partial specializations are not considered even if their
@@ -3734,7 +3779,8 @@
   // will happen when we are dealing with, e.g., class template
   // partial specializations.
   if (!isa<ClassTemplateDecl>(Template) &&
-      !isa<TemplateTemplateParmDecl>(Template)) {
+      !isa<TemplateTemplateParmDecl>(Template) &&
+      !isa<TypeAliasTemplateDecl>(Template)) {
     assert(isa<FunctionTemplateDecl>(Template) &&
            "Only function templates are possible here");
     Diag(Arg.getLocation(), diag::err_template_arg_not_class_template);
@@ -4051,7 +4097,7 @@
   // C++0x [temp.arg.template]p3:
   //   A template-argument matches a template template-parameter (call it P)
   //   when each of the template parameters in the template-parameter-list of
-  //   the template-argument's corresponding class template or template alias
+  //   the template-argument's corresponding class template or alias template
   //   (call it A) matches the corresponding template parameter in the
   //   template-parameter-list of P. [...]
   TemplateParameterList::iterator NewParm = New->begin();
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 92ba095..3e1e735 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -446,10 +446,15 @@
         Diags.Report(Active->PointOfInstantiation, DiagID)
           << Function
           << Active->InstantiationRange;
-      } else {
+      } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
         Diags.Report(Active->PointOfInstantiation,
                      diag::note_template_static_data_member_def_here)
-          << cast<VarDecl>(D)
+          << VD
+          << Active->InstantiationRange;
+      } else {
+        Diags.Report(Active->PointOfInstantiation,
+                     diag::note_template_type_alias_instantiation_here)
+          << cast<TypeAliasTemplateDecl>(D)
           << Active->InstantiationRange;
       }
       break;
@@ -968,8 +973,7 @@
       }
       
       TemplateName Template = Arg.getAsTemplate();
-      assert(!Template.isNull() && Template.getAsTemplateDecl() &&
-             "Wrong kind of template template argument");
+      assert(!Template.isNull() && "Null template template argument");
       
       // We don't ever want to substitute for a qualified template name, since
       // the qualifier is handled separately. So, look through the qualified
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 6fa208f..2c0c7ae 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -128,8 +128,8 @@
   return Inst;
 }
 
-Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D,
-                                                     bool IsTypeAlias) {
+Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
+                                                           bool IsTypeAlias) {
   bool Invalid = false;
   TypeSourceInfo *DI = D->getTypeSourceInfo();
   if (DI->getType()->isDependentType() ||
@@ -178,17 +178,62 @@
   SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
 
   Typedef->setAccess(D->getAccess());
-  Owner->addDecl(Typedef);
 
   return Typedef;
 }
 
 Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
-  return VisitTypedefNameDecl(D, /*IsTypeAlias=*/false);
+  Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/false);
+  Owner->addDecl(Typedef);
+  return Typedef;
 }
 
 Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) {
-  return VisitTypedefNameDecl(D, /*IsTypeAlias=*/true);
+  Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/true);
+  Owner->addDecl(Typedef);
+  return Typedef;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+  // Create a local instantiation scope for this type alias template, which
+  // will contain the instantiations of the template parameters.
+  LocalInstantiationScope Scope(SemaRef);
+
+  TemplateParameterList *TempParams = D->getTemplateParameters();
+  TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+  if (!InstParams)
+    return 0;
+
+  TypeAliasDecl *Pattern = D->getTemplatedDecl();
+
+  TypeAliasTemplateDecl *PrevAliasTemplate = 0;
+  if (Pattern->getPreviousDeclaration()) {
+    DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
+    if (Found.first != Found.second) {
+      PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(*Found.first);
+    }
+  }
+
+  TypeAliasDecl *AliasInst = cast_or_null<TypeAliasDecl>(
+    InstantiateTypedefNameDecl(Pattern, /*IsTypeAlias=*/true));
+  if (!AliasInst)
+    return 0;
+
+  TypeAliasTemplateDecl *Inst
+    = TypeAliasTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+                                    D->getDeclName(), InstParams, AliasInst);
+  if (PrevAliasTemplate)
+    Inst->setPreviousDeclaration(PrevAliasTemplate);
+
+  Inst->setAccess(D->getAccess());
+
+  if (!PrevAliasTemplate)
+    Inst->setInstantiatedFromMemberTemplate(D);
+  
+  Owner->addDecl(Inst);
+
+  return Inst;
 }
 
 /// \brief Instantiate an initializer, breaking it into separate
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 00ac1d6..06548a4 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1601,6 +1601,7 @@
       Error = 7; // Template type argument
       break;
     case Declarator::AliasDeclContext:
+    case Declarator::AliasTemplateContext:
       Error = 9; // Type alias
       break;
     case Declarator::TypeNameContext:
@@ -1659,7 +1660,8 @@
   // Does this declaration declare a typedef-name?
   bool IsTypedefName =
     D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef ||
-    D.getContext() == Declarator::AliasDeclContext;
+    D.getContext() == Declarator::AliasDeclContext ||
+    D.getContext() == Declarator::AliasTemplateContext;
 
   // Walk the DeclTypeInfo, building the recursive type as we go.
   // DeclTypeInfos are ordered from the identifier out, which is
@@ -1839,7 +1841,8 @@
       // anyway.
       if (IsTypedefName && FTI.getExceptionSpecType())
         Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef)
-          << (D.getContext() == Declarator::AliasDeclContext);
+          << (D.getContext() == Declarator::AliasDeclContext ||
+              D.getContext() == Declarator::AliasTemplateContext);
 
       if (!FTI.NumArgs && !FTI.isVariadic && !getLangOptions().CPlusPlus) {
         // Simple void foo(), where the incoming T is the result type.
@@ -2204,6 +2207,7 @@
     case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here?
     case Declarator::TypeNameContext:
     case Declarator::AliasDeclContext:
+    case Declarator::AliasTemplateContext:
     case Declarator::MemberContext:
     case Declarator::BlockContext:
     case Declarator::ForContext:
@@ -2640,13 +2644,17 @@
     CheckExtraCXXDefaultArguments(D);
 
     // C++0x [dcl.type]p3:
-    //   A type-specifier-seq shall not define a class or enumeration
-    //   unless it appears in the type-id of an alias-declaration
-    //   (7.1.3).
-    if (OwnedTag && OwnedTag->isDefinition() &&
-        D.getContext() != Declarator::AliasDeclContext)
-      Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier)
-        << Context.getTypeDeclType(OwnedTag);
+    //   A type-specifier-seq shall not define a class or enumeration unless
+    //   it appears in the type-id of an alias-declaration (7.1.3) that is not
+    //   the declaration of a template-declaration.
+    if (OwnedTag && OwnedTag->isDefinition()) {
+      if (D.getContext() == Declarator::AliasTemplateContext)
+        Diag(OwnedTag->getLocation(), diag::err_type_defined_in_alias_template)
+          << Context.getTypeDeclType(OwnedTag);
+      else if (D.getContext() != Declarator::AliasDeclContext)
+        Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier)
+          << Context.getTypeDeclType(OwnedTag);
+    }
   }
 
   return CreateParsedType(T, TInfo);
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 4bb1841..da60fcc 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -21,6 +21,7 @@
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
@@ -855,7 +856,7 @@
         case LookupResult::Found:
         case LookupResult::FoundOverloaded:
         case LookupResult::FoundUnresolvedValue: {
-	  NamedDecl *SomeDecl = Result.getRepresentativeDecl();
+          NamedDecl *SomeDecl = Result.getRepresentativeDecl();
           unsigned Kind = 0;
           if (isa<TypedefDecl>(SomeDecl)) Kind = 1;
           else if (isa<TypeAliasDecl>(SomeDecl)) Kind = 2;
@@ -863,7 +864,7 @@
           SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << Kind;
           SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at);
           break;
-	}
+        }
         default:
           // FIXME: Would be nice to highlight just the source range.
           SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope)
@@ -4389,6 +4390,23 @@
                                                    NewTemplateArgs);
 
   if (!Result.isNull()) {
+    // Specializations of template template parameters are represented as
+    // TemplateSpecializationTypes, and substitution of type alias templates
+    // within a dependent context can transform them into
+    // DependentTemplateSpecializationTypes.
+    if (isa<DependentTemplateSpecializationType>(Result)) {
+      DependentTemplateSpecializationTypeLoc NewTL
+        = TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
+      NewTL.setKeywordLoc(TL.getTemplateNameLoc());
+      NewTL.setQualifierLoc(NestedNameSpecifierLoc());
+      NewTL.setNameLoc(TL.getTemplateNameLoc());
+      NewTL.setLAngleLoc(TL.getLAngleLoc());
+      NewTL.setRAngleLoc(TL.getRAngleLoc());
+      for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i)
+        NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo());
+      return Result;
+    }
+
     TemplateSpecializationTypeLoc NewTL
       = TLB.push<TemplateSpecializationTypeLoc>(Result);
     NewTL.setTemplateNameLoc(TL.getTemplateNameLoc());
@@ -4478,6 +4496,21 @@
   if (NamedT.isNull())
     return QualType();
 
+  // C++0x [dcl.type.elab]p2:
+  //   If the identifier resolves to a typedef-name or the simple-template-id
+  //   resolves to an alias template specialization, the
+  //   elaborated-type-specifier is ill-formed.
+  if (const TemplateSpecializationType *TST =
+        NamedT->getAs<TemplateSpecializationType>()) {
+    TemplateName Template = TST->getTemplateName();
+    if (TypeAliasTemplateDecl *TAT =
+        dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) {
+      SemaRef.Diag(TL.getNamedTypeLoc().getBeginLoc(),
+                   diag::err_tag_reference_non_tag) << 4;
+      SemaRef.Diag(TAT->getLocation(), diag::note_declared_at);
+    }
+  }
+
   QualType Result = TL.getType();
   if (getDerived().AlwaysRebuild() ||
       QualifierLoc != TL.getQualifierLoc() ||
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 45a771a..bad18ff 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -3366,14 +3366,14 @@
     TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx);
     llvm::SmallVector<TemplateArgument, 8> Args;
     ReadTemplateArgumentList(Args, *Loc.F, Record, Idx);
-    QualType Canon = GetType(Record[Idx++]);
+    QualType Underlying = GetType(Record[Idx++]);
     QualType T;
-    if (Canon.isNull())
+    if (Underlying.isNull())
       T = Context->getCanonicalTemplateSpecializationType(Name, Args.data(),
                                                           Args.size());
     else
       T = Context->getTemplateSpecializationType(Name, Args.data(),
-                                                 Args.size(), Canon);
+                                                 Args.size(), Underlying);
     const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
     return T;
   }
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 3a825de..2b82f90 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -125,6 +125,7 @@
     void VisitClassTemplateDecl(ClassTemplateDecl *D);
     void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
     void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+    void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
     void VisitUsingDecl(UsingDecl *D);
     void VisitUsingShadowDecl(UsingShadowDecl *D);
     void VisitLinkageSpecDecl(LinkageSpecDecl *D);
@@ -1266,6 +1267,10 @@
   D->ParameterPack = Record[Idx++];
 }
 
+void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+  VisitRedeclarableTemplateDecl(D);
+}
+
 void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
   VisitDecl(D);
   D->AssertExpr = Reader.ReadExpr(F);
@@ -1572,6 +1577,9 @@
     D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0,
                                          false, 0, 0);
     break;
+  case DECL_TYPE_ALIAS_TEMPLATE:
+    D = TypeAliasTemplateDecl::Create(*Context, Decl::EmptyShell());
+    break;
   case DECL_STATIC_ASSERT:
     D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0,
                                  SourceLocation());
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index be41501..1c62bfd 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -277,7 +277,8 @@
   for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end();
          ArgI != ArgE; ++ArgI)
     Writer.AddTemplateArgument(*ArgI, Record);
-  Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType()
+  Writer.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() :
+                    T->isCanonicalUnqualified() ? QualType()
                                                 : T->getCanonicalTypeInternal(),
                     Record);
   Code = TYPE_TEMPLATE_SPECIALIZATION;
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 1ca00a3..dbcbadb 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -86,6 +86,7 @@
     void VisitClassTemplateDecl(ClassTemplateDecl *D);
     void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
     void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+    void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
     void VisitUsingDecl(UsingDecl *D);
     void VisitUsingShadowDecl(UsingShadowDecl *D);
     void VisitLinkageSpecDecl(LinkageSpecDecl *D);
@@ -1081,6 +1082,11 @@
   Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
 }
 
+void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+  VisitRedeclarableTemplateDecl(D);
+  Code = serialization::DECL_TYPE_ALIAS_TEMPLATE;
+}
+
 void ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) {
   VisitDecl(D);
   Writer.AddStmt(D->getAssertExpr());
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp
new file mode 100644
index 0000000..5fc0fe0
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+struct A { };
+template<typename T> using X = A; // expected-note {{declared here}}
+struct X<int>* p2; // expected-error {{elaborated type refers to a type alias template}}
+
+
+template<typename T> using Id = T; // expected-note {{declared here}}
+template<template<typename> class F>
+struct Y {
+  struct F<int> i; // expected-error {{elaborated type refers to a type alias template}}
+};
+template struct Y<Id>; // expected-note {{requested here}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
index 10184a0..8b278bf 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
@@ -1,10 +1,9 @@
 // RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
 
-// FIXME: when clang supports alias-declarations.
-#if 0
 using X = struct { // ok
 };
-#endif
+template<typename T> using Y = struct { // expected-error {{can not be defined in a type alias template}}
+};
 
 class K {
   virtual ~K();
diff --git a/test/CXX/temp/temp.decls/p3.cpp b/test/CXX/temp/temp.decls/p3.cpp
new file mode 100644
index 0000000..21c82e6
--- /dev/null
+++ b/test/CXX/temp/temp.decls/p3.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename T> using A = int;
+template<typename T> using A<T*> = char; // expected-error {{partial specialization of alias templates is not permitted}}
+template<> using A<char> = char; // expected-error {{explicit specialization of alias templates is not permitted}}
+template using A<char> = char; // expected-error {{explicit instantiation of alias templates is not permitted}}
+// Best guess as to what the user was trying to do: missing template<>.
+using A<char> = char; // expected-error {{partial specialization of alias templates is not permitted}}
diff --git a/test/CXX/temp/temp.decls/temp.alias/p1.cpp b/test/CXX/temp/temp.decls/temp.alias/p1.cpp
new file mode 100644
index 0000000..80079b3
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.alias/p1.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename T> using U = T;
+
+// The name of the alias template is a template-name.
+U<char> x;
+void f(U<int>);
+typedef U<U<U<U<int>>>> I;
diff --git a/test/CXX/temp/temp.decls/temp.alias/p2.cpp b/test/CXX/temp/temp.decls/temp.alias/p2.cpp
new file mode 100644
index 0000000..e145727
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.alias/p2.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename T> using U = T;
+
+using I = U<U<U<U<int>>>>;
+using I = int;
+
+template<typename A, typename B> using Fst = A;
+template<typename A, typename B> using Snd = B;
+
+using I = Fst<Snd<char,int>,double>;
+
+namespace StdExample {
+  // Prerequisites for example.
+  template<class T, class A> struct vector { /* ... */ };
+
+
+  template<class T> struct Alloc {};
+  template<class T> using Vec = vector<T, Alloc<T>>;
+  Vec<int> v;
+
+  template<class T>
+    void process(Vec<T>& v) // expected-note {{previous definition is here}}
+    { /* ... */ }
+
+  template<class T>
+    void process(vector<T, Alloc<T>>& w) // expected-error {{redefinition of 'process'}}
+    { /* ... */ }
+
+  template<template<class> class TT>
+    void f(TT<int>); // expected-note {{candidate template ignored}}
+
+  template<template<class,class> class TT>
+    void g(TT<int, Alloc<int>>);
+
+  int h() {
+    f(v); // expected-error {{no matching function for call to 'f'}}
+    g(v); // OK: TT = vector
+  }
+
+
+  // v's type is same as vector<int, Alloc<int>>.
+  using VTest = vector<int, Alloc<int>>;
+  using VTest = decltype(v);
+}
diff --git a/test/CXX/temp/temp.decls/temp.alias/p3.cpp b/test/CXX/temp/temp.decls/temp.alias/p3.cpp
new file mode 100644
index 0000000..2e9e55c
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.alias/p3.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// The example given in the standard (this is rejected for other reasons anyway).
+template<class T> struct A;
+template<class T> using B = typename A<T>::U; // expected-error {{no type named 'U' in 'A<T>'}}
+template<class T> struct A {
+  typedef B<T> U; // expected-note {{in instantiation of template type alias 'B' requested here}}
+};
+B<short> b;
+
+template<typename T> using U = int;
+// FIXME: This is illegal, but probably only because CWG1044 missed this paragraph.
+template<typename T> using U = U<T>;
diff --git a/test/CXX/temp/temp.param/p10-0x.cpp b/test/CXX/temp/temp.param/p10-0x.cpp
new file mode 100644
index 0000000..bc7e616
--- /dev/null
+++ b/test/CXX/temp/temp.param/p10-0x.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s 
+
+template<typename> struct Y1;
+template<typename, int> struct Y2;
+
+template<class T1, class T2 = int> using B2 = T1;
+template<class T1 = int, class T2> using B2 = T1;
+
+template<template<class> class F, template<class> class G = Y1> using B2t = F<G<int>>;
+template<template<class> class F = Y2, template<class> class G> using B2t = F<G<int>>;
+
+template<int N, int M = 5> using B2n = Y2<int, N + M>;
+template<int N = 5, int M> using B2n = Y2<int, N + M>;
diff --git a/test/CXX/temp/temp.param/p11-0x.cpp b/test/CXX/temp/temp.param/p11-0x.cpp
index 0bf4341..10a4438 100644
--- a/test/CXX/temp/temp.param/p11-0x.cpp
+++ b/test/CXX/temp/temp.param/p11-0x.cpp
@@ -1,29 +1,48 @@
 // RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
 
-// If a template-parameter of a class template has a default
-// template-argument, each subsequent template-parameter shall either
-// have a default template-argument supplied or be a template
-// parameter pack.
+// If a template-parameter of a class template or alias template has a default
+// template-argument, each subsequent template-parameter shall either have a
+// default template-argument supplied or be a template parameter pack.
 template<typename> struct vector;
 
+template<typename T = int, typename> struct X3t; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
+template<typename T = int, typename> using A3t = int; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
+template<int V = 0, int> struct X3nt; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
+template<int V = 0, int> using A3nt = int; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
+template<template<class> class M = vector, template<class> class> struct X3tt; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
+template<template<class> class M = vector, template<class> class> using A3tt = int; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
+
 template<typename T = int, typename ...Types> struct X2t;
+template<typename T = int, typename ...Types> using A2t = X2t<T, Types...>;
 template<int V = 0, int ...Values> struct X2nt;
+template<int V = 0, int ...Values> using A2nt = X2nt<V, Values...>;
 template<template<class> class M = vector, template<class> class... Metas>
   struct X2tt;
+template<template<class> class M = vector, template<class> class... Metas>
+  using A2tt = X2tt<M, Metas...>;
 
-// If a template-parameter of a primary class template is a template
-// parameter pack, it shall be the last template-parameter .
+// If a template-parameter of a primary class template or alias template is a
+// template parameter pack, it shall be the last template-parameter.
 template<typename ...Types, // expected-error{{template parameter pack must be the last template parameter}}
          int After>
 struct X0t;
+template<typename ...Types, // expected-error{{template parameter pack must be the last template parameter}}
+         int After>
+using A0t = int;
 
 template<int ...Values, // expected-error{{template parameter pack must be the last template parameter}}
          int After>
 struct X0nt;
+template<int ...Values, // expected-error{{template parameter pack must be the last template parameter}}
+         int After>
+using A0nt = int;
 
 template<template<typename> class ...Templates, // expected-error{{template parameter pack must be the last template parameter}}
          int After>
 struct X0tt;
+template<template<typename> class ...Templates, // expected-error{{template parameter pack must be the last template parameter}}
+         int After>
+using A0tt = int;
 
 // [ Note: These are not requirements for function templates or class
 // template partial specializations because template arguments can be
diff --git a/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp b/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
new file mode 100644
index 0000000..1d1d350
--- /dev/null
+++ b/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s 
+
+// Examples from CWG1056.
+namespace Example1 {
+  template<class T> struct A;
+  template<class T> using B = A<T>;
+
+  template<class T> struct A {
+    struct C {};
+    B<T>::C bc; // ok, B<T> is the current instantiation.
+  };
+
+  template<class T> struct A<A<T>> {
+    struct C {};
+    B<B<T>>::C bc; // ok, B<B<T>> is the current instantiation.
+  };
+
+  template<class T> struct A<A<A<T>>> {
+    struct C {};
+    B<B<T>>::C bc; // expected-error {{missing 'typename'}}
+  };
+}
+
+namespace Example2 {
+  template<class T> struct A {
+    void g();
+  };
+  template<class T> using B = A<T>;
+  template<class T> void B<T>::g() {} // ok.
+}
diff --git a/test/CXX/temp/temp.type/p1-0x.cpp b/test/CXX/temp/temp.type/p1-0x.cpp
new file mode 100644
index 0000000..c22af22
--- /dev/null
+++ b/test/CXX/temp/temp.type/p1-0x.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+namespace Old {
+  template<template<class> class TT> struct X { };
+  template<class> struct Y { };
+  template<class T> using Z = Y<T>;
+  X<Y> y;
+  X<Z> z;
+
+  using SameType = decltype(y); // expected-note {{here}}
+  using SameType = decltype(z); // expected-error {{different types}}
+}
+
+namespace New {
+  template<class T> struct X { };
+  template<class> struct Y { };
+  template<class T> using Z = Y<T>;
+  X<Y<int>> y;
+  X<Z<int>> z;
+
+  using SameType = decltype(y);
+  using SameType = decltype(z); // ok
+}
diff --git a/test/CodeGenCXX/mangle-alias-template.cpp b/test/CodeGenCXX/mangle-alias-template.cpp
new file mode 100644
index 0000000..2020a0a
--- /dev/null
+++ b/test/CodeGenCXX/mangle-alias-template.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+
+template<typename T> struct alloc {};
+template<typename T> using Alloc = alloc<T>;
+template<typename T, typename A = Alloc<T>> struct vector {};
+
+template<typename T> using Vec = vector<T>;
+
+template<typename T> void f(Vec<T> v);
+template<typename T> void g(T);
+
+template<template<typename> class F> void h(F<int>);
+
+// CHECK: define void @_Z1zv(
+void z() {
+  vector<int> VI;
+  f(VI);
+  // CHECK: call void @_Z1fIiEv6vectorIT_5allocIS1_EE(
+
+  Vec<double> VD;
+  g(VD);
+  // CHECK: call void @_Z1gI6vectorId5allocIdEEEvT_(
+
+  h<Vec>(VI);
+  // CHECK: call void @_Z1hI3VecEvT_IiE(
+
+  Alloc<int> AC;
+  h(AC);
+  // CHECK: call void @_Z1hI5allocEvT_IiE(
+
+  h<Alloc>(AC);
+  // CHECK: call void @_Z1hI5AllocEvT_IiE(
+
+  Vec<char> VC;
+  g<Vec<char>>(VC);
+  // CHECK: call void @_Z1gI6vectorIc5allocIcEEEvT_(
+
+  Vec<Vec<int>> VVI;
+  g(VVI);
+  // CHECK: call void @_Z1gI6vectorIS0_Ii5allocIiEES1_IS3_EEEvT_(
+}
diff --git a/test/CodeGenCXX/mangle-unnameable-conversions.cpp b/test/CodeGenCXX/mangle-unnameable-conversions.cpp
new file mode 100644
index 0000000..2132eff
--- /dev/null
+++ b/test/CodeGenCXX/mangle-unnameable-conversions.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+
+template<typename T> using id = T;
+struct S {
+  template<typename T, int N>
+    operator id<T[N]>&();
+  template<typename T, typename U>
+    operator id<T (U::*)()>() const;
+};
+
+void f() {
+  int (&a)[42] = S(); // CHECK: @_ZN1ScvRAT0__T_IiLi42EEEv(
+  char (S::*fp)() = S(); // CHECK: @_ZNK1ScvMT0_FT_vEIcS_EEv(
+};
diff --git a/test/Lexer/has_feature_cxx0x.cpp b/test/Lexer/has_feature_cxx0x.cpp
index 57949e3..57354f8 100644
--- a/test/Lexer/has_feature_cxx0x.cpp
+++ b/test/Lexer/has_feature_cxx0x.cpp
@@ -155,3 +155,12 @@
 
 // CHECK-0X: has_override_control
 // CHECK-NO-0X: no_override_control
+
+#if __has_feature(cxx_alias_templates)
+int has_alias_templates();
+#else
+int no_alias_templates();
+#endif
+
+// CHECK-0X: has_alias_templates
+// CHECK-NO-0X: no_alias_templates
diff --git a/test/PCH/cxx-alias-decl.cpp b/test/PCH/cxx-alias-decl.cpp
new file mode 100644
index 0000000..e30311c
--- /dev/null
+++ b/test/PCH/cxx-alias-decl.cpp
@@ -0,0 +1,20 @@
+// Test this without pch.
+// RUN: %clang_cc1 -x c++ -std=c++0x -include %S/cxx-alias-decl.h -fsyntax-only -emit-llvm -o - %s
+
+// Test with pch.
+// RUN: %clang_cc1 -x c++ -std=c++0x -emit-pch -o %t %S/cxx-alias-decl.h
+// RUN: %clang_cc1 -x c++ -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s 
+
+template struct T<S>;
+C<A>::A<char> a;
+
+using T1 = decltype(a);
+using T1 = D<int, char>;
+
+using T2 = B<A>;
+using T2 = S;
+
+using A = int;
+template<typename U> using B = S;
+template<typename U> using C = T<U>;
+template<typename U, typename V> using D = typename T<U>::template A<V>;
diff --git a/test/PCH/cxx-alias-decl.h b/test/PCH/cxx-alias-decl.h
new file mode 100644
index 0000000..26bc716
--- /dev/null
+++ b/test/PCH/cxx-alias-decl.h
@@ -0,0 +1,11 @@
+// Header for PCH test cxx-alias-decl.cpp
+
+struct S {};
+template<typename U> struct T {
+  template<typename V> using A = T<V>;
+};
+
+using A = int;
+template<typename U> using B = S;
+template<typename U> using C = T<U>;
+template<typename U, typename V> using D = typename T<U>::template A<V>;
diff --git a/test/SemaCXX/alias-template.cpp b/test/SemaCXX/alias-template.cpp
new file mode 100644
index 0000000..f29a932
--- /dev/null
+++ b/test/SemaCXX/alias-template.cpp
@@ -0,0 +1,147 @@
+// RUN: %clang_cc1 -verify -std=c++0x %s
+
+namespace RedeclAliasTypedef {
+  template<typename U> using T = int;
+  template<typename U> using T = int;
+  template<typename U> using T = T<U>;
+}
+
+namespace IllegalTypeIds {
+  template<typename U> using A = void(int n = 0); // expected-error {{default arguments can only be specified for parameters in a function declaration}}
+  template<typename U> using B = inline void(int n); // expected-error {{type name does not allow function specifier}}
+  template<typename U> using C = virtual void(int n); // expected-error {{type name does not allow function specifier}}
+  template<typename U> using D = explicit void(int n); // expected-error {{type name does not allow function specifier}}
+  template<typename U> using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
+  // FIXME: this is illegal; we incorrectly accept it for typedefs too.
+  template<typename U> using F = void(*)(int n) &&; // expected-err
+  template<typename U> using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
+
+  template<typename U> using H = void(int n); // ok
+  template<typename U> using I = void(int n) &&; // ok
+}
+
+namespace IllegalSyntax {
+  template<typename Z> using ::T = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
+  template<typename Z> using operator int = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
+  template<typename Z> using typename U = void; // expected-error {{name defined in alias declaration must be an identifier}}
+  template<typename Z> using typename ::V = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
+  template<typename Z> using typename ::operator bool = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
+}
+
+namespace VariableLengthArrays {
+  template<typename Z> using T = int[42]; // ok
+
+  int n = 32;
+  template<typename Z> using T = int[n]; // expected-error {{variable length array declaration not allowed at file scope}}
+
+  const int m = 42;
+  template<typename Z> using U = int[m]; // expected-note {{previous definition}}
+  template<typename Z> using U = int[42]; // ok
+  template<typename Z> using U = int; // expected-error {{type alias template redefinition with different types ('int' vs 'int [42]')}}
+}
+
+namespace RedeclFunc {
+  int f(int, char**);
+  template<typename Z> using T = int;
+  T<char> f(int, char **); // ok
+}
+
+namespace LookupFilter {
+  namespace N { template<typename U> using S = int; }
+  using namespace N;
+  template<typename U> using S = S<U>*; // ok
+}
+
+namespace InFunctions {
+  template<typename...T> struct S0 {
+    template<typename Z> using U = T*; // expected-error {{declaration type contains unexpanded parameter pack 'T'}}
+    U<char> u;
+  };
+
+  template<typename Z> using T1 = int;
+  template<typename Z> using T2 = int[-1]; // expected-error {{array size is negative}}
+  template<typename...T> struct S3 { // expected-note {{template parameter is declared here}}
+    template<typename Z> using T = int; // expected-error {{declaration of 'T' shadows template parameter}}
+  };
+  template<typename Z> using Z = Z;
+}
+
+namespace ClassNameRedecl {
+  class C0 {
+    // FIXME: this diagnostic is pretty poor
+    template<typename U> using C0 = int; // expected-error {{name defined in alias declaration must be an identifier}}
+  };
+  class C1 {
+    // FIXME: this diagnostic is pretty poor
+    template<typename U> using C1 = C1; // expected-error {{name defined in alias declaration must be an identifier}}
+  };
+  class C2 {
+    template<typename U> using C0 = C1; // ok
+  };
+  template<typename...T> class C3 {
+    template<typename U> using f = T; // expected-error {{declaration type contains unexpanded parameter pack 'T'}}
+  };
+  template<typename T> class C4 { // expected-note {{template parameter is declared here}}
+    template<typename U> using T = int; // expected-error {{declaration of 'T' shadows template parameter}}
+  };
+  class C5 {
+    class c; // expected-note {{previous definition}}
+    template<typename U> using c = int; // expected-error {{redefinition of 'c' as different kind of symbol}}
+    class d; // expected-note {{previous definition}}
+    template<typename U> using d = d; // expected-error {{redefinition of 'd' as different kind of symbol}}
+  };
+  class C6 {
+    class c { template<typename U> using C6 = int; }; // ok
+  };
+}
+
+class CtorDtorName {
+  template<typename T> using X = CtorDtorName;
+  X<int>(); // expected-error {{expected member name}}
+  ~X<int>(); // expected-error {{destructor cannot be declared using a type alias}}
+};
+
+namespace TagName {
+  template<typename Z> using S = struct { int n; }; // expected-error {{can not be defined}}
+  template<typename Z> using T = class { int n; }; // expected-error {{can not be defined}}
+  template<typename Z> using U = enum { a, b, c }; // expected-error {{can not be defined}}
+  template<typename Z> using V = struct V { int n; }; // expected-error {{redefinition of 'V' as different kind of symbol}} \
+                                                         expected-error {{'TagName::V' can not be defined in a type alias template}} \
+                                                         expected-note {{previous definition is here}}
+}
+
+namespace StdExample {
+  template<typename T, typename U> struct pair;
+
+  template<typename T> using handler_t = void (*)(T);
+  extern handler_t<int> ignore;
+  extern void (*ignore)(int);
+  // FIXME: we recover as if cell is an undeclared variable. the diagnostics are terrible!
+  template<typename T> using cell = pair<T*, cell<T>*>; // expected-error {{use of undeclared identifier 'cell'}} \
+                                                           expected-error {{'T' does not refer to a value}} \
+                                                           expected-note {{declared here}} \
+                                                           expected-error {{expected ';' after alias declaration}}
+}
+
+namespace Access {
+  class C0 {
+    template<typename Z> using U = int; // expected-note {{declared private here}}
+  };
+  C0::U<int> v; // expected-error {{'U' is a private member}}
+  class C1 {
+  public:
+    template<typename Z> using U = int;
+  };
+  C1::U<int> w; // ok
+}
+
+namespace VoidArg {
+  template<typename Z> using V = void;
+  V<int> f(int); // ok
+  V<char> g(V<double>); // expected-error {{empty parameter list defined with a type alias of 'void' not allowed}}
+}
+
+namespace Curried {
+  template<typename T, typename U> struct S;
+  template<typename T> template<typename U> using SS = S<T, U>; // expected-error {{extraneous template parameter list in alias template declaration}}
+}
diff --git a/test/SemaCXX/attr-cxx0x.cpp b/test/SemaCXX/attr-cxx0x.cpp
index 40fe0e0..725f018 100644
--- a/test/SemaCXX/attr-cxx0x.cpp
+++ b/test/SemaCXX/attr-cxx0x.cpp
@@ -9,8 +9,13 @@
   int member [[align(8)]];
 };
 
+typedef char align_typedef [[align(8)]];
+template<typename T> using align_alias_template = align_typedef;
+
 static_assert(alignof(align_big) == alignof(int), "k's alignment is wrong");
 static_assert(alignof(align_small) == 1, "j's alignment is wrong");
 static_assert(alignof(align_multiple) == 8, "l's alignment is wrong");
 static_assert(alignof(align_member) == 8, "quuux's alignment is wrong");
 static_assert(sizeof(align_member) == 8, "quuux's size is wrong");
+static_assert(alignof(align_typedef) == 8, "typedef's alignment is wrong");
+static_assert(alignof(align_alias_template<int>) == 8, "alias template's alignment is wrong");
diff --git a/test/SemaCXX/dependent-types.cpp b/test/SemaCXX/dependent-types.cpp
index d9b5323..053e79b 100644
--- a/test/SemaCXX/dependent-types.cpp
+++ b/test/SemaCXX/dependent-types.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify -std=c++0x %s
+
+template<typename T> using U = int &;
 
 template<typename T, int Size> void f() {
   T x1;
@@ -7,4 +9,5 @@
   T x4[]; // expected-error{{needs an explicit size or an initializer}}
   T x5[Size];
   int x6[Size];
+  U<T> x7; // expected-error{{declaration of reference variable 'x7' requires an initializer}}
 }
diff --git a/test/SemaCXX/redeclared-alias-template.cpp b/test/SemaCXX/redeclared-alias-template.cpp
new file mode 100644
index 0000000..b368fcf
--- /dev/null
+++ b/test/SemaCXX/redeclared-alias-template.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+template<typename T> using A = int; // expected-note 2{{previous}}
+template<typename T> using A = char; // expected-error {{type alias template redefinition with different types ('char' vs 'int')}}
+template<typename T1, typename T2> using A = T1; // expected-error {{too many template parameters in template redeclaration}}
+
+template<typename T1, typename T2> using B = T1; // expected-note {{previous}}
+template<typename T2, typename T1> using B = T1; // expected-error {{type alias template redefinition with different types}}
+
+
+template<typename> struct S;
+template<template<typename> class F> using FInt = F<int>;
+template<typename X> using SXRInt = FInt<S<X>::template R>;
+template<typename X> using SXRInt = typename S<X>::template R<int>; // ok, redeclaration.
+
+template<template<typename> class> struct TT;
+
+namespace FilterLookup {
+  TT<A> f(); // expected-note {{previous declaration is here}}
+
+  template<typename> using A = int;
+  TT<A> f(); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+}
diff --git a/test/SemaTemplate/alias-church-numerals.cpp b/test/SemaTemplate/alias-church-numerals.cpp
new file mode 100644
index 0000000..751cac7
--- /dev/null
+++ b/test/SemaTemplate/alias-church-numerals.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<template<template<typename> class, typename> class T, template<typename> class V> struct PartialApply {
+  template<typename W> using R = T<V, W>;
+};
+
+template<typename T> using Id = T;
+template<template<typename> class, typename X> using Zero = X;
+template<template<template<typename> class, typename> class N, template<typename> class F, typename X> using Succ = F<N<F,X>>;
+
+template<template<typename> class F, typename X> using One = Succ<Zero, F, X>;
+template<template<typename> class F, typename X> using Two = Succ<One, F, X>;
+
+template<template<template<typename> class, typename> class A,
+         template<template<typename> class, typename> class B,
+         template<typename> class F,
+         typename X> using Add = A<F, B<F, X>>;
+
+template<template<template<typename> class, typename> class A,
+         template<template<typename> class, typename> class B,
+         template<typename> class F,
+         typename X> using Mul = A<PartialApply<B,F>::template R, X>;
+
+template<template<typename> class F, typename X> using Four = Add<Two, Two, F, X>;
+template<template<typename> class F, typename X> using Sixteen = Mul<Four, Four, F, X>;
+template<template<typename> class F, typename X> using TwoHundredAndFiftySix = Mul<Sixteen, Sixteen, F, X>;
+
+template<typename T, T N> struct Const { static const T value = N; };
+template<typename A> struct IncrementHelper;
+template<typename T, T N> struct IncrementHelper<Const<T, N>> { using Result = Const<T, N+1>; };
+template<typename A> using Increment = typename IncrementHelper<A>::Result;
+
+using Arr = int[TwoHundredAndFiftySix<Increment, Const<int, 0>>::value];
+using Arr = int[256];
diff --git a/test/SemaTemplate/alias-nested-nontag.cpp b/test/SemaTemplate/alias-nested-nontag.cpp
new file mode 100644
index 0000000..1bb5ce3
--- /dev/null
+++ b/test/SemaTemplate/alias-nested-nontag.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+template<typename T> using Id = T; // expected-note {{type alias template 'Id' declared here}}
+struct U { static Id<int> V; };
+Id<int> ::U::V; // expected-error {{type 'Id<int>' (aka 'int') cannot be used prior to '::' because it has no members}} \
+                   expected-error {{C++ requires a type specifier}}
diff --git a/test/SemaTemplate/alias-template-template-param.cpp b/test/SemaTemplate/alias-template-template-param.cpp
new file mode 100644
index 0000000..a847b06
--- /dev/null
+++ b/test/SemaTemplate/alias-template-template-param.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+template<template<typename> class D> using C = D<int>;
+
+// Substitution of the alias template transforms the TemplateSpecializationType
+// 'D<int>' into the DependentTemplateSpecializationType 'T::template U<int>'.
+template<typename T> void f(C<T::template U>);
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 9bd83a5..7234da3 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -3915,6 +3915,7 @@
   case Decl::Namespace:
   case Decl::Typedef:
   case Decl::TypeAlias:
+  case Decl::TypeAliasTemplate:
   case Decl::TemplateTypeParm:
   case Decl::EnumConstant:
   case Decl::Field:
diff --git a/www/cxx_status.html b/www/cxx_status.html
index f0361d3..ad9a7d0 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -460,14 +460,13 @@
 </tr>
 <tr>
   <td>template aliases</td>
-  <td class="basic"></td>
-  <td class="basic"></td>
-  <td class="basic"></td>
-  <td></td>
+  <td class="complete" align="center">&#x2713;</td>
+  <td class="complete" align="center">&#x2713;</td>
+  <td class="complete" align="center">&#x2713;</td>
+  <td class="complete" align="center">&#x2713;</td>
   <td>7.1.3, 14.6.7</td>
   <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1489.pdf">N1489</a>
       <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf">N2258</a>
-      Only non-template type aliases implemented
   </td>
 </tr>
 <tr>