Merged Elaborated and QualifiedName types.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103517 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 71ef09a..81b56ad 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -626,10 +626,6 @@
     return getTypeInfo(cast<SubstTemplateTypeParmType>(T)->
                        getReplacementType().getTypePtr());
 
-  case Type::Elaborated:
-    return getTypeInfo(cast<ElaboratedType>(T)->getUnderlyingType()
-                         .getTypePtr());
-
   case Type::Typedef: {
     const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl();
     if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) {
@@ -652,8 +648,8 @@
     return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType()
                         .getTypePtr());
 
-  case Type::QualifiedName:
-    return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr());
+  case Type::Elaborated:
+    return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr());
 
   case Type::TemplateSpecialization:
     assert(getCanonicalType(T) != T &&
@@ -1890,29 +1886,28 @@
 }
 
 QualType
-ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS,
-                                 QualType NamedType) {
+ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword,
+                              NestedNameSpecifier *NNS,
+                              QualType NamedType) {
   llvm::FoldingSetNodeID ID;
-  QualifiedNameType::Profile(ID, NNS, NamedType);
+  ElaboratedType::Profile(ID, Keyword, NNS, NamedType);
 
   void *InsertPos = 0;
-  QualifiedNameType *T
-    = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos);
+  ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
   if (T)
     return QualType(T, 0);
 
   QualType Canon = NamedType;
   if (!Canon.isCanonical()) {
     Canon = getCanonicalType(NamedType);
-    QualifiedNameType *CheckT
-      = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos);
-    assert(!CheckT && "Qualified name canonical type broken");
+    ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
+    assert(!CheckT && "Elaborated canonical type broken");
     (void)CheckT;
   }
 
-  T = new (*this) QualifiedNameType(NNS, NamedType, Canon);
+  T = new (*this) ElaboratedType(Keyword, NNS, NamedType, Canon);
   Types.push_back(T);
-  QualifiedNameTypes.InsertNode(T, InsertPos);
+  ElaboratedTypes.InsertNode(T, InsertPos);
   return QualType(T, 0);
 }
 
@@ -1989,30 +1984,6 @@
   return QualType(T, 0);
 }
 
-QualType
-ASTContext::getElaboratedType(QualType UnderlyingType,
-                              ElaboratedType::TagKind Tag) {
-  llvm::FoldingSetNodeID ID;
-  ElaboratedType::Profile(ID, UnderlyingType, Tag);
-
-  void *InsertPos = 0;
-  ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
-  if (T)
-    return QualType(T, 0);
-
-  QualType Canon = UnderlyingType;
-  if (!Canon.isCanonical()) {
-    Canon = getCanonicalType(Canon);
-    ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
-    assert(!CheckT && "Elaborated canonical type is broken"); (void)CheckT;
-  }
-
-  T = new (*this) ElaboratedType(UnderlyingType, Tag, Canon);
-  Types.push_back(T);
-  ElaboratedTypes.InsertNode(T, InsertPos);
-  return QualType(T, 0);
-}
-
 /// CmpProtocolNames - Comparison predicate for sorting protocols
 /// alphabetically.
 static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
@@ -2813,7 +2784,7 @@
 QualType ASTContext::getCFConstantStringType() {
   if (!CFConstantStringTypeDecl) {
     CFConstantStringTypeDecl =
-      CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+      CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
                        &Idents.get("NSConstantString"));
     CFConstantStringTypeDecl->startDefinition();
 
@@ -2855,7 +2826,7 @@
 QualType ASTContext::getNSConstantStringType() {
   if (!NSConstantStringTypeDecl) {
     NSConstantStringTypeDecl =
-    CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+    CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
                      &Idents.get("__builtin_NSString"));
     NSConstantStringTypeDecl->startDefinition();
     
@@ -2894,7 +2865,7 @@
 QualType ASTContext::getObjCFastEnumerationStateType() {
   if (!ObjCFastEnumerationStateTypeDecl) {
     ObjCFastEnumerationStateTypeDecl =
-      CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+      CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
                        &Idents.get("__objcFastEnumerationState"));
     ObjCFastEnumerationStateTypeDecl->startDefinition();
 
@@ -2929,7 +2900,7 @@
 
   RecordDecl *T;
   // FIXME: Needs the FlagAppleBlock bit.
-  T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+  T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
                        &Idents.get("__block_descriptor"));
   T->startDefinition();
   
@@ -2974,7 +2945,7 @@
 
   RecordDecl *T;
   // FIXME: Needs the FlagAppleBlock bit.
-  T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+  T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
                        &Idents.get("__block_descriptor_withcopydispose"));
   T->startDefinition();
   
@@ -3046,7 +3017,7 @@
   llvm::raw_svector_ostream(Name) << "__Block_byref_" <<
                                   ++UniqueBlockByRefTypeID << '_' << DeclName;
   RecordDecl *T;
-  T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+  T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
                        &Idents.get(Name.str()));
   T->startDefinition();
   QualType Int32Ty = IntTy;
@@ -3097,7 +3068,7 @@
   llvm::raw_svector_ostream(Name) << "__block_literal_"
                                   << ++UniqueBlockParmTypeID;
   RecordDecl *T;
-  T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+  T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
                        &Idents.get(Name.str()));
   T->startDefinition();
   QualType FieldTypes[] = {
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index e4cd2a9..23aae39 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -50,12 +50,6 @@
       QT = cast<ElaboratedType>(Ty)->desugar();
       continue;
     }
-    
-    // ...or a qualified name type...
-    if (isa<QualifiedNameType>(Ty)) {
-      QT = cast<QualifiedNameType>(Ty)->desugar();
-      continue;
-    }
 
     // ...or a substituted template type parameter.
     if (isa<SubstTemplateTypeParmType>(Ty)) {
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 083c1bf..aae02a4 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -68,11 +68,10 @@
     // FIXME: DependentDecltypeType
     QualType VisitRecordType(RecordType *T);
     QualType VisitEnumType(EnumType *T);
-    QualType VisitElaboratedType(ElaboratedType *T);
     // FIXME: TemplateTypeParmType
     // FIXME: SubstTemplateTypeParmType
     // FIXME: TemplateSpecializationType
-    QualType VisitQualifiedNameType(QualifiedNameType *T);
+    QualType VisitElaboratedType(ElaboratedType *T);
     // FIXME: DependentNameType
     QualType VisitObjCInterfaceType(ObjCInterfaceType *T);
     QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T);
@@ -532,19 +531,7 @@
                                   cast<TagType>(T2)->getDecl()))
       return false;
     break;
-      
-  case Type::Elaborated: {
-    const ElaboratedType *Elab1 = cast<ElaboratedType>(T1);
-    const ElaboratedType *Elab2 = cast<ElaboratedType>(T2);
-    if (Elab1->getTagKind() != Elab2->getTagKind())
-      return false;
-    if (!IsStructurallyEquivalent(Context, 
-                                  Elab1->getUnderlyingType(),
-                                  Elab2->getUnderlyingType()))
-      return false;
-    break;
-  }
-   
+
   case Type::TemplateTypeParm: {
     const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1);
     const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2);
@@ -594,16 +581,19 @@
     break;
   }
       
-  case Type::QualifiedName: {
-    const QualifiedNameType *Qual1 = cast<QualifiedNameType>(T1);
-    const QualifiedNameType *Qual2 = cast<QualifiedNameType>(T2);
+  case Type::Elaborated: {
+    const ElaboratedType *Elab1 = cast<ElaboratedType>(T1);
+    const ElaboratedType *Elab2 = cast<ElaboratedType>(T2);
+    // CHECKME: what if a keyword is ETK_None or ETK_typename ?
+    if (Elab1->getKeyword() != Elab2->getKeyword())
+      return false;
     if (!IsStructurallyEquivalent(Context, 
-                                  Qual1->getQualifier(), 
-                                  Qual2->getQualifier()))
+                                  Elab1->getQualifier(), 
+                                  Elab2->getQualifier()))
       return false;
     if (!IsStructurallyEquivalent(Context,
-                                  Qual1->getNamedType(),
-                                  Qual2->getNamedType()))
+                                  Elab1->getNamedType(),
+                                  Elab2->getNamedType()))
       return false;
     break;
   }
@@ -1293,24 +1283,20 @@
 }
 
 QualType ASTNodeImporter::VisitElaboratedType(ElaboratedType *T) {
-  QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType());
-  if (ToUnderlyingType.isNull())
-    return QualType();
-
-  return Importer.getToContext().getElaboratedType(ToUnderlyingType,
-                                                   T->getTagKind());
-}
-
-QualType ASTNodeImporter::VisitQualifiedNameType(QualifiedNameType *T) {
-  NestedNameSpecifier *ToQualifier = Importer.Import(T->getQualifier());
-  if (!ToQualifier)
-    return QualType();
+  NestedNameSpecifier *ToQualifier = 0;
+  // Note: the qualifier in an ElaboratedType is optional.
+  if (T->getQualifier()) {
+    ToQualifier = Importer.Import(T->getQualifier());
+    if (!ToQualifier)
+      return QualType();
+  }
 
   QualType ToNamedType = Importer.Import(T->getNamedType());
   if (ToNamedType.isNull())
     return QualType();
 
-  return Importer.getToContext().getQualifiedNameType(ToQualifier, ToNamedType);
+  return Importer.getToContext().getElaboratedType(T->getKeyword(),
+                                                   ToQualifier, ToNamedType);
 }
 
 QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) {
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 25f5fb7..28332bd 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -23,7 +23,7 @@
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/IdentifierTable.h"
-#include "clang/Parse/DeclSpec.h"
+#include "clang/Basic/Specifiers.h"
 #include "llvm/Support/ErrorHandling.h"
 
 using namespace clang;
@@ -1520,16 +1520,6 @@
   return 0;
 }
 
-TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) {
-  switch (TypeSpec) {
-  default: llvm_unreachable("unexpected type specifier");
-  case DeclSpec::TST_struct: return TK_struct;
-  case DeclSpec::TST_class: return TK_class;
-  case DeclSpec::TST_union: return TK_union;
-  case DeclSpec::TST_enum: return TK_enum;
-  }
-}
-
 void TagDecl::setQualifierInfo(NestedNameSpecifier *Qualifier,
                                SourceRange QualifierRange) {
   if (Qualifier) {
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index a279eda..8d9be13 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -137,7 +137,7 @@
 
     data().VBases[I] =
       CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
-                       VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
+                       VBaseClassDecl->getTagKind() == TTK_Class,
                        VBases[I]->getAccessSpecifier(), VBaseType);
   }
 }
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 45518e9..d6594cd 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -145,14 +145,14 @@
     InnerPolicy.SuppressScope = true;
 
     // Nested-name-specifiers are intended to contain minimally-qualified
-    // types. An actual QualifiedNameType will not occur, since we'll store
+    // types. An actual ElaboratedType will not occur, since we'll store
     // just the type that is referred to in the nested-name-specifier (e.g.,
     // a TypedefType, TagType, etc.). However, when we are dealing with
     // dependent template-id types (e.g., Outer<T>::template Inner<U>),
     // the type requires its own nested-name-specifier for uniqueness, so we
     // suppress that nested-name-specifier during printing.
-    assert(!isa<QualifiedNameType>(T) &&
-           "Qualified name type in nested-name-specifier");
+    assert(!isa<ElaboratedType>(T) &&
+           "Elaborated type in nested-name-specifier");
     if (const TemplateSpecializationType *SpecType
           = dyn_cast<TemplateSpecializationType>(T)) {
       // Print the template name without its corresponding
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 73f0e91..843785e 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -18,6 +18,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/PrettyPrinter.h"
+#include "clang/Basic/Specifiers.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
@@ -764,36 +765,105 @@
   case TemplateTypeParm:
   case SubstTemplateTypeParm:
   case TemplateSpecialization:
-  case QualifiedName:
+  case Elaborated:
   case DependentName:
   case ObjCInterface:
   case ObjCObjectPointer:
-  case Elaborated:
     return true;
   default:
     return false;
   }
 }
 
-bool Type::isElaboratedTypeSpecifier() const {
-  if (getTypeClass() == Elaborated)
-    return true;
-  
-  if (const DependentNameType *Dependent = dyn_cast<DependentNameType>(this)) {
-    switch (Dependent->getKeyword()) {
-    case ETK_None:
-    case ETK_Typename:
-      return false;
-        
-    case ETK_Class:
-    case ETK_Struct:
-    case ETK_Union:
-    case ETK_Enum:
-      return true;
-    }
+TypeWithKeyword::~TypeWithKeyword() {
+}
+
+ElaboratedTypeKeyword
+TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) {
+  switch (TypeSpec) {
+  default: return ETK_None;
+  case TST_typename: return ETK_Typename;
+  case TST_class: return ETK_Class;
+  case TST_struct: return ETK_Struct;
+  case TST_union: return ETK_Union;
+  case TST_enum: return ETK_Enum;
   }
-  
-  return false;
+}
+
+TagTypeKind
+TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) {
+  switch(TypeSpec) {
+  case TST_class: return TTK_Class;
+  case TST_struct: return TTK_Struct;
+  case TST_union: return TTK_Union;
+  case TST_enum: return TTK_Enum;
+  default: llvm_unreachable("Type specifier is not a tag type kind.");
+  }
+}
+
+ElaboratedTypeKeyword
+TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) {
+  switch (Kind) {
+  case TTK_Class: return ETK_Class;
+  case TTK_Struct: return ETK_Struct;
+  case TTK_Union: return ETK_Union;
+  case TTK_Enum: return ETK_Enum;
+  }
+  llvm_unreachable("Unknown tag type kind.");
+}
+
+TagTypeKind
+TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) {
+  switch (Keyword) {
+  case ETK_Class: return TTK_Class;
+  case ETK_Struct: return TTK_Struct;
+  case ETK_Union: return TTK_Union;
+  case ETK_Enum: return TTK_Enum;
+  case ETK_None: // Fall through.
+  case ETK_Typename:
+    llvm_unreachable("Elaborated type keyword is not a tag type kind.");
+  }
+  llvm_unreachable("Unknown elaborated type keyword.");
+}
+
+bool
+TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) {
+  switch (Keyword) {
+  case ETK_None:
+  case ETK_Typename:
+    return false;
+  case ETK_Class:
+  case ETK_Struct:
+  case ETK_Union:
+  case ETK_Enum:
+    return true;
+  }
+  llvm_unreachable("Unknown elaborated type keyword.");
+}
+
+const char*
+TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) {
+  switch (Keyword) {
+  default: llvm_unreachable("Unknown elaborated type keyword.");
+  case ETK_None: return "";
+  case ETK_Typename: return "typename";
+  case ETK_Class:  return "class";
+  case ETK_Struct: return "struct";
+  case ETK_Union:  return "union";
+  case ETK_Enum:   return "enum";
+  }
+}
+
+bool Type::isElaboratedTypeSpecifier() const {
+  ElaboratedTypeKeyword Keyword;
+  if (const ElaboratedType *Elab = dyn_cast<ElaboratedType>(this))
+    Keyword = Elab->getKeyword();
+  else if (const DependentNameType *DepName = dyn_cast<DependentNameType>(this))
+    Keyword = DepName->getKeyword();
+  else
+    return false;
+
+  return TypeWithKeyword::KeywordIsTagTypeKind(Keyword);
 }
 
 const char *Type::getTypeClassName() const {
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 915d7af..0478d4e 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -497,16 +497,6 @@
   PrintTag(T->getDecl(), S);
 }
 
-void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) { 
-  Print(T->getUnderlyingType(), S);
-
-  // We don't actually make these in C, but the language options
-  // sometimes lie to us -- for example, if someone calls
-  // QualType::getAsString().  Just suppress the redundant tag if so.
-  if (Policy.LangOpts.CPlusPlus)
-    S = std::string(T->getNameForTagKind(T->getTagKind())) + ' ' + S;  
-}
-
 void TypePrinter::PrintTemplateTypeParm(const TemplateTypeParmType *T, 
                                         std::string &S) { 
   if (!S.empty())    // Prefix the basic type, e.g. 'parmname X'.
@@ -549,13 +539,17 @@
   PrintTemplateSpecialization(T->getInjectedTST(), S);
 }
 
-void TypePrinter::PrintQualifiedName(const QualifiedNameType *T, 
-                                     std::string &S) { 
+void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) {
   std::string MyString;
   
   {
     llvm::raw_string_ostream OS(MyString);
-    T->getQualifier()->print(OS, Policy);
+    OS << TypeWithKeyword::getKeywordName(T->getKeyword());
+    if (T->getKeyword() != ETK_None)
+      OS << " ";
+    NestedNameSpecifier* Qualifier = T->getQualifier();
+    if (Qualifier)
+      Qualifier->print(OS, Policy);
   }
   
   std::string TypeStr;
@@ -575,14 +569,9 @@
   
   {
     llvm::raw_string_ostream OS(MyString);
-    switch (T->getKeyword()) {
-    case ETK_None: break;
-    case ETK_Typename: OS << "typename "; break;
-    case ETK_Class: OS << "class "; break;
-    case ETK_Struct: OS << "struct "; break;
-    case ETK_Union: OS << "union "; break;
-    case ETK_Enum: OS << "enum "; break;
-    }
+    OS << TypeWithKeyword::getKeywordName(T->getKeyword());
+    if (T->getKeyword() != ETK_None)
+      OS << " ";
     
     T->getQualifier()->print(OS, Policy);
     
diff --git a/lib/Checker/LLVMConventionsChecker.cpp b/lib/Checker/LLVMConventionsChecker.cpp
index 14f0fc1..39ded43 100644
--- a/lib/Checker/LLVMConventionsChecker.cpp
+++ b/lib/Checker/LLVMConventionsChecker.cpp
@@ -47,7 +47,7 @@
 }
 
 static bool IsStdString(QualType T) {
-  if (const QualifiedNameType *QT = T->getAs<QualifiedNameType>())
+  if (const ElaboratedType *QT = T->getAs<ElaboratedType>())
     T = QT->getNamedType();
 
   const TypedefType *TT = T->getAs<TypedefType>();
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index cb6efe8..43f47a0 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -1154,15 +1154,12 @@
     case Type::Decltype:
       T = cast<DecltypeType>(T)->getUnderlyingType();
       break;
-    case Type::QualifiedName:
-      T = cast<QualifiedNameType>(T)->getNamedType();
+    case Type::Elaborated:
+      T = cast<ElaboratedType>(T)->getNamedType();
       break;
     case Type::SubstTemplateTypeParm:
       T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
       break;
-    case Type::Elaborated:
-      T = cast<ElaboratedType>(T)->getUnderlyingType();
-      break;
     }
     
     assert(T != LastT && "Type unwrapping failed to unwrap!");
@@ -1253,7 +1250,6 @@
 
   case Type::TemplateSpecialization:
   case Type::Elaborated:
-  case Type::QualifiedName:
   case Type::SubstTemplateTypeParm:
   case Type::TypeOfExpr:
   case Type::TypeOf:
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 77eabbf..5140bb6 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -3669,7 +3669,7 @@
   //   id self;
   //   Class cls;
   // }
-  RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct,
+  RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
                                       Ctx.getTranslationUnitDecl(),
                                       SourceLocation(),
                                       &Ctx.Idents.get("_objc_super"));
@@ -4131,7 +4131,7 @@
   // };
 
   // First the clang type for struct _message_ref_t
-  RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct,
+  RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
                                       Ctx.getTranslationUnitDecl(),
                                       SourceLocation(),
                                       &Ctx.Idents.get("_message_ref_t"));
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 6e4e28e..c329f7b 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -2165,8 +2165,10 @@
       return QualType();
     }
     unsigned Tag = Record[1];
-    return Context->getElaboratedType(GetType(Record[0]),
-                                      (ElaboratedType::TagKind) Tag);
+    // FIXME: Deserialize the qualifier (C++ only)
+    return Context->getElaboratedType((ElaboratedTypeKeyword) Tag,
+                                      /* NNS */ 0,
+                                      GetType(Record[0]));
   }
 
   case pch::TYPE_OBJC_INTERFACE: {
@@ -2334,9 +2336,6 @@
 void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) {
   TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
 }
-void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
-  TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
-}
 void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
   TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
 }
@@ -2354,7 +2353,7 @@
         Reader.GetTemplateArgumentLocInfo(TL.getTypePtr()->getArg(i).getKind(),
                                           Record, Idx));
 }
-void TypeLocReader::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) {
+void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
   TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
 }
 void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index c4f9622..3f91d0c 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -865,7 +865,7 @@
     D = EnumDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(), 0);
     break;
   case pch::DECL_RECORD:
-    D = RecordDecl::Create(*Context, TagDecl::TK_struct, 0, SourceLocation(),
+    D = RecordDecl::Create(*Context, TTK_Struct, 0, SourceLocation(),
                            0, SourceLocation(), 0);
     break;
   case pch::DECL_ENUM_CONSTANT:
@@ -913,7 +913,7 @@
                                             DeclarationName());
     break;
   case pch::DECL_CXX_RECORD:
-    D = CXXRecordDecl::Create(*Context, TagDecl::TK_struct, 0,
+    D = CXXRecordDecl::Create(*Context, TTK_Struct, 0,
                               SourceLocation(), 0, SourceLocation(), 0);
     break;
   case pch::DECL_CXX_METHOD:
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index dc1fb23..b323dcf 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -213,12 +213,6 @@
   Code = pch::TYPE_ENUM;
 }
 
-void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
-  Writer.AddTypeRef(T->getUnderlyingType(), Record);
-  Record.push_back(T->getTagKind());
-  Code = pch::TYPE_ELABORATED;
-}
-
 void
 PCHTypeWriter::VisitSubstTemplateTypeParmType(
                                         const SubstTemplateTypeParmType *T) {
@@ -234,9 +228,12 @@
   assert(false && "Cannot serialize template specialization types");
 }
 
-void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) {
-  // FIXME: Serialize this type (C++ only)
-  assert(false && "Cannot serialize qualified name types");
+void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
+  Writer.AddTypeRef(T->getNamedType(), Record);
+  Record.push_back(T->getKeyword());
+  // FIXME: Serialize the qualifier (C++ only)
+  assert(T->getQualifier() == 0 && "Cannot serialize qualified name types");
+  Code = pch::TYPE_ELABORATED;
 }
 
 void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
@@ -383,9 +380,6 @@
 void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) {
   Writer.AddSourceLocation(TL.getNameLoc(), Record);
 }
-void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
-  Writer.AddSourceLocation(TL.getNameLoc(), Record);
-}
 void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
   Writer.AddSourceLocation(TL.getNameLoc(), Record);
 }
@@ -401,7 +395,7 @@
   for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
     Writer.AddTemplateArgumentLoc(TL.getArgLoc(i), Record);
 }
-void TypeLocWriter::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) {
+void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
   Writer.AddSourceLocation(TL.getNameLoc(), Record);
 }
 void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index 1169832..3c415c7 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -1349,7 +1349,7 @@
       std::string RecName = clsDeclared->getIdentifier()->getName();
       RecName += "_IMPL";
       IdentifierInfo *II = &Context->Idents.get(RecName);
-      RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+      RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
                                           SourceLocation(), II);
       assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
       QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
@@ -1394,7 +1394,7 @@
       std::string RecName = clsDeclared->getIdentifier()->getName();
       RecName += "_IMPL";
       IdentifierInfo *II = &Context->Idents.get(RecName);
-      RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+      RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
                                           SourceLocation(), II);
       assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
       QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
@@ -2426,7 +2426,7 @@
 void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
   IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper");
   llvm::SmallVector<QualType, 16> ArgTys;
-  RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+  RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
                                       SourceLocation(),
                                       &Context->Idents.get("objc_super"));
   QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
@@ -2475,7 +2475,7 @@
   IdentifierInfo *msgSendIdent =
     &Context->Idents.get("objc_msgSendSuper_stret");
   llvm::SmallVector<QualType, 16> ArgTys;
-  RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+  RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
                                       SourceLocation(),
                                       &Context->Idents.get("objc_super"));
   QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
@@ -2625,7 +2625,7 @@
 // struct objc_super { struct objc_object *receiver; struct objc_class *super; };
 QualType RewriteObjC::getSuperStructType() {
   if (!SuperStructDecl) {
-    SuperStructDecl = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+    SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
                                          SourceLocation(),
                                          &Context->Idents.get("objc_super"));
     QualType FieldTypes[2];
@@ -2651,7 +2651,7 @@
 
 QualType RewriteObjC::getConstantStringStructType() {
   if (!ConstantStringDecl) {
-    ConstantStringDecl = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+    ConstantStringDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
                                             SourceLocation(),
                          &Context->Idents.get("__NSConstantStringImpl"));
     QualType FieldTypes[4];
@@ -4573,7 +4573,7 @@
   const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
   // FTP will be null for closures that don't take arguments.
 
-  RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+  RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
                                       SourceLocation(),
                                       &Context->Idents.get("__block_impl"));
   QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD));
@@ -5245,7 +5245,7 @@
       RewriteByRefString(RecName, Name, ND);
       IdentifierInfo *II = &Context->Idents.get(RecName.c_str() 
                                                 + sizeof("struct"));
-      RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+      RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
                                           SourceLocation(), II);
       assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl");
       QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index a432978..0c713e7 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -40,11 +40,11 @@
 
 static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
   if (C.getLangOptions().CPlusPlus)
-    return CXXRecordDecl::Create(C, TagDecl::TK_struct,
+    return CXXRecordDecl::Create(C, TTK_Struct,
                                  C.getTranslationUnitDecl(),
                                  SourceLocation(), &C.Idents.get(Name));
 
-  return RecordDecl::Create(C, TagDecl::TK_struct,
+  return RecordDecl::Create(C, TTK_Struct,
                             C.getTranslationUnitDecl(),
                             SourceLocation(), &C.Idents.get(Name));
 }
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 3bea485..fa8976f 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -768,7 +768,8 @@
   bool RequireCompleteType(SourceLocation Loc, QualType T,
                            unsigned DiagID);
 
-  QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T);
+  QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
+                             const CXXScopeSpec &SS, QualType T);
 
   QualType BuildTypeofExprType(Expr *E);
   QualType BuildDecltypeType(Expr *E);
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index c075d16..77bf919 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -672,8 +672,8 @@
     ND = ClassTemplate->getTemplatedDecl();
   
   if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
-    return RD->getTagKind() == TagDecl::TK_class ||
-    RD->getTagKind() == TagDecl::TK_struct;
+    return RD->getTagKind() == TTK_Class ||
+    RD->getTagKind() == TTK_Struct;
   
   return false;
 }
@@ -685,7 +685,7 @@
     ND = ClassTemplate->getTemplatedDecl();
   
   if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
-    return RD->getTagKind() == TagDecl::TK_union;
+    return RD->getTagKind() == TTK_Union;
   
   return false;
 }
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 40ba8ff..b4f5d13 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -191,7 +191,7 @@
       T = Context.getTypeDeclType(TD);
     
     if (SS)
-      T = getQualifiedNameType(*SS, T);
+      T = getElaboratedType(ETK_None, *SS, T);
     
   } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
     T = Context.getObjCInterfaceType(IDecl);
@@ -223,10 +223,11 @@
   if (R.getResultKind() == LookupResult::Found)
     if (const TagDecl *TD = R.getAsSingle<TagDecl>()) {
       switch (TD->getTagKind()) {
-      case TagDecl::TK_struct: return DeclSpec::TST_struct;
-      case TagDecl::TK_union:  return DeclSpec::TST_union;
-      case TagDecl::TK_class:  return DeclSpec::TST_class;
-      case TagDecl::TK_enum:   return DeclSpec::TST_enum;
+      default:         return DeclSpec::TST_unspecified;
+      case TTK_Struct: return DeclSpec::TST_struct;
+      case TTK_Union:  return DeclSpec::TST_union;
+      case TTK_Class:  return DeclSpec::TST_class;
+      case TTK_Enum:   return DeclSpec::TST_enum;
       }
     }
 
@@ -4845,38 +4846,38 @@
 ///
 /// \returns true if the new tag kind is acceptable, false otherwise.
 bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
-                                        TagDecl::TagKind NewTag,
+                                        TagTypeKind NewTag,
                                         SourceLocation NewTagLoc,
                                         const IdentifierInfo &Name) {
   // C++ [dcl.type.elab]p3:
   //   The class-key or enum keyword present in the
   //   elaborated-type-specifier shall agree in kind with the
-  //   declaration to which the name in theelaborated-type-specifier
+  //   declaration to which the name in the elaborated-type-specifier
   //   refers. This rule also applies to the form of
   //   elaborated-type-specifier that declares a class-name or
   //   friend class since it can be construed as referring to the
   //   definition of the class. Thus, in any
   //   elaborated-type-specifier, the enum keyword shall be used to
-  //   refer to an enumeration (7.2), the union class-keyshall be
+  //   refer to an enumeration (7.2), the union class-key shall be
   //   used to refer to a union (clause 9), and either the class or
   //   struct class-key shall be used to refer to a class (clause 9)
   //   declared using the class or struct class-key.
-  TagDecl::TagKind OldTag = Previous->getTagKind();
+  TagTypeKind OldTag = Previous->getTagKind();
   if (OldTag == NewTag)
     return true;
 
-  if ((OldTag == TagDecl::TK_struct || OldTag == TagDecl::TK_class) &&
-      (NewTag == TagDecl::TK_struct || NewTag == TagDecl::TK_class)) {
+  if ((OldTag == TTK_Struct || OldTag == TTK_Class) &&
+      (NewTag == TTK_Struct || NewTag == TTK_Class)) {
     // Warn about the struct/class tag mismatch.
     bool isTemplate = false;
     if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous))
       isTemplate = Record->getDescribedClassTemplate();
 
     Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
-      << (NewTag == TagDecl::TK_class)
+      << (NewTag == TTK_Class)
       << isTemplate << &Name
       << FixItHint::CreateReplacement(SourceRange(NewTagLoc),
-                              OldTag == TagDecl::TK_class? "class" : "struct");
+                              OldTag == TTK_Class? "class" : "struct");
     Diag(Previous->getLocation(), diag::note_previous_use);
     return true;
   }
@@ -4898,7 +4899,7 @@
          "Nameless record must be a definition!");
 
   OwnedDecl = false;
-  TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
+  TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
 
   // FIXME: Check explicit specializations more carefully.
   bool isExplicitSpecialization = false;
@@ -4922,7 +4923,7 @@
       } else {
         // The "template<>" header is extraneous.
         Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
-          << ElaboratedType::getNameForTagKind(Kind) << Name;
+          << TypeWithKeyword::getTagTypeKindName(Kind) << Name;
         isExplicitSpecialization = true;
       }
     }
@@ -5141,8 +5142,8 @@
         // struct or something similar.
         if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
           bool SafeToContinue
-            = (PrevTagDecl->getTagKind() != TagDecl::TK_enum &&
-               Kind != TagDecl::TK_enum);
+            = (PrevTagDecl->getTagKind() != TTK_Enum &&
+               Kind != TTK_Enum);
           if (SafeToContinue)
             Diag(KWLoc, diag::err_use_with_wrong_tag)
               << Name
@@ -5296,7 +5297,7 @@
   // PrevDecl.
   TagDecl *New;
 
-  if (Kind == TagDecl::TK_enum) {
+  if (Kind == TTK_Enum) {
     // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
     // enum X { A, B, C } D;    D should chain to X.
     New = EnumDecl::Create(Context, SearchDC, Loc, Name, KWLoc,
@@ -5331,7 +5332,7 @@
     New->setQualifierInfo(NNS, SS.getRange());
   }
 
-  if (Kind != TagDecl::TK_enum) {
+  if (Kind != TTK_Enum) {
     // Handle #pragma pack: if the #pragma pack stack has non-default
     // alignment, make up a packed attribute for this decl. These
     // attributes are checked when the ASTContext lays out the
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 90aa9c1..af922d2 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -150,7 +150,7 @@
     return false;
 
   const RecordDecl *RD = RT->getDecl();
-  if (RD->getTagKind() != TagDecl::TK_struct)
+  if (RD->getTagKind() != TTK_Struct)
     return false;
 
   return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index e32a308..72a57c3 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -461,7 +461,7 @@
 
   if (BaseType->isDependentType())
     return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
-                                Class->getTagKind() == RecordDecl::TK_class,
+                                Class->getTagKind() == TTK_Class,
                                 Access, BaseType);
 
   // Base specifiers must be record types.
@@ -505,7 +505,7 @@
   
   // Create the base specifier.
   return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
-                              Class->getTagKind() == RecordDecl::TK_class,
+                              Class->getTagKind() == TTK_Class,
                               Access, BaseType);
 }
 
@@ -1191,7 +1191,7 @@
           static_cast<NestedNameSpecifier*>(SS.getScopeRep());
 
         // FIXME: preserve source range information
-        BaseType = Context.getQualifiedNameType(Qualifier, BaseType);
+        BaseType = Context.getElaboratedType(ETK_None, Qualifier, BaseType);
       }
     }
   }
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 67ad45d..8b17f84 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1173,7 +1173,7 @@
   if (!StdBadAlloc) {
     // The "std::bad_alloc" class has not yet been declared, so build it
     // implicitly.
-    StdBadAlloc = CXXRecordDecl::Create(Context, TagDecl::TK_class, 
+    StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, 
                                         StdNamespace, 
                                         SourceLocation(), 
                                       &PP.getIdentifierTable().get("bad_alloc"), 
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index b2f416c..fea7e61 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -2742,8 +2742,8 @@
       //    without a user-provided constructor, then the object is
       //    zero-initialized and, if T’s implicitly-declared default
       //    constructor is non-trivial, that constructor is called.
-      if ((ClassDecl->getTagKind() == TagDecl::TK_class ||
-           ClassDecl->getTagKind() == TagDecl::TK_struct) &&
+      if ((ClassDecl->getTagKind() == TTK_Class ||
+           ClassDecl->getTagKind() == TTK_Struct) &&
           !ClassDecl->hasTrivialConstructor()) {
         Sequence.AddZeroInitializationStep(Entity.getType());
         return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence);        
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index d660d6a..0f3f86d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -739,8 +739,8 @@
   if (CheckTemplateDeclScope(S, TemplateParams))
     return true;
 
-  TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
-  assert(Kind != TagDecl::TK_enum && "can't build template of enumerated type");
+  TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
+  assert(Kind != TTK_Enum && "can't build template of enumerated type");
 
   // There is no such thing as an unnamed class template.
   if (!Name) {
@@ -1568,7 +1568,7 @@
   QualType Type = GetTypeFromParser(TypeResult.get(), &DI);
 
   // Verify the tag specifier.
-  TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec);
+  TagTypeKind TagKind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
 
   if (const RecordType *RT = Type->getAs<RecordType>()) {
     RecordDecl *D = RT->getDecl();
@@ -1584,7 +1584,9 @@
     }
   }
 
-  QualType ElabType = Context.getElaboratedType(Type, TagKind);
+  ElaboratedTypeKeyword Keyword
+    = TypeWithKeyword::getKeywordForTagTypeKind(TagKind);
+  QualType ElabType = Context.getElaboratedType(Keyword, /*NNS=*/0, Type);
 
   return ElabType.getAsOpaquePtr();
 }
@@ -3664,13 +3666,8 @@
 
   // Check that the specialization uses the same tag kind as the
   // original template.
-  TagDecl::TagKind Kind;
-  switch (TagSpec) {
-  default: assert(0 && "Unknown tag type!");
-  case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
-  case DeclSpec::TST_union:  Kind = TagDecl::TK_union; break;
-  case DeclSpec::TST_class:  Kind = TagDecl::TK_class; break;
-  }
+  TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
+  assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!");
   if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
                                     Kind, KWLoc,
                                     *ClassTemplate->getIdentifier())) {
@@ -4621,13 +4618,9 @@
 
   // Check that the specialization uses the same tag kind as the
   // original template.
-  TagDecl::TagKind Kind;
-  switch (TagSpec) {
-  default: assert(0 && "Unknown tag type!");
-  case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
-  case DeclSpec::TST_union:  Kind = TagDecl::TK_union; break;
-  case DeclSpec::TST_class:  Kind = TagDecl::TK_class; break;
-  }
+  TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
+  assert(Kind != TTK_Enum &&
+         "Invalid enum tag in class template explicit instantiation!");
   if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
                                     Kind, KWLoc,
                                     *ClassTemplate->getIdentifier())) {
@@ -5173,23 +5166,16 @@
   if (!NNS)
     return true;
 
-  ElaboratedTypeKeyword Keyword = ETK_None;
-  switch (TagDecl::getTagKindForTypeSpec(TagSpec)) {
-  case TagDecl::TK_struct: Keyword = ETK_Struct; break;
-  case TagDecl::TK_class: Keyword = ETK_Class; break;
-  case TagDecl::TK_union: Keyword = ETK_Union; break;
-  case TagDecl::TK_enum: Keyword = ETK_Enum; break;
-  }
-  assert(Keyword != ETK_None && "Invalid tag kind!");
+  TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
 
   if (TUK == TUK_Declaration || TUK == TUK_Definition) {
     Diag(NameLoc, diag::err_dependent_tag_decl)
-      << (TUK == TUK_Definition) << TagDecl::getTagKindForTypeSpec(TagSpec)
-      << SS.getRange();
+      << (TUK == TUK_Definition) << Kind << SS.getRange();
     return true;
   }
-  
-  return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr();
+
+  ElaboratedTypeKeyword Kwd = TypeWithKeyword::getKeywordForTagTypeKind(Kind);
+  return Context.getDependentNameType(Kwd, NNS, Name).getAsOpaquePtr();
 }
 
 static void FillTypeLoc(DependentNameTypeLoc TL,
@@ -5199,7 +5185,7 @@
   TL.setNameLoc(TypenameLoc);
 }
 
-static void FillTypeLoc(QualifiedNameTypeLoc TL,
+static void FillTypeLoc(ElaboratedTypeLoc TL,
                         SourceLocation TypenameLoc,
                         SourceRange QualifierRange) {
   // FIXME: typename, qualifier range
@@ -5225,7 +5211,7 @@
     // FIXME: fill inner type loc
     FillTypeLoc(TL, TypenameLoc, SS.getRange());
   } else {
-    QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc());
+    ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
     // FIXME: fill inner type loc
     FillTypeLoc(TL, TypenameLoc, SS.getRange());
   }
@@ -5245,14 +5231,11 @@
 
   if (computeDeclContext(SS, false)) {
     // If we can compute a declaration context, then the "typename"
-    // keyword was superfluous. Just build a QualifiedNameType to keep
+    // keyword was superfluous. Just build an ElaboratedType to keep
     // track of the nested-name-specifier.
-
-    // FIXME: Note that the QualifiedNameType had the "typename" keyword!
-    
-    T = Context.getQualifiedNameType(NNS, T);
+    T = Context.getElaboratedType(ETK_Typename, NNS, T);
     TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
-    QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc());
+    ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
     // FIXME: fill inner type loc
     FillTypeLoc(TL, TypenameLoc, SS.getRange());
     return CreateLocInfoType(T, TSI).getAsOpaquePtr();
@@ -5309,10 +5292,10 @@
 
   case LookupResult::Found:
     if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
-      // We found a type. Build a QualifiedNameType, since the
-      // typename-specifier was just sugar. FIXME: Tell
-      // QualifiedNameType that it has a "typename" prefix.
-      return Context.getQualifiedNameType(NNS, Context.getTypeDeclType(Type));
+      // We found a type. Build an ElaboratedType, since the
+      // typename-specifier was just sugar.
+      return Context.getElaboratedType(ETK_Typename, NNS,
+                                       Context.getTypeDeclType(Type));
     }
 
     DiagID = diag::err_typename_nested_not_type;
@@ -5391,9 +5374,10 @@
 
     /// \brief Transforms a typename type by determining whether the type now
     /// refers to a member of the current instantiation, and then
-    /// type-checking and building a QualifiedNameType (when possible).
-    QualType TransformDependentNameType(TypeLocBuilder &TLB, DependentNameTypeLoc TL, 
-                                   QualType ObjectType);
+    /// type-checking and building an ElaboratedType (when possible).
+    QualType TransformDependentNameType(TypeLocBuilder &TLB,
+                                        DependentNameTypeLoc TL,
+                                        QualType ObjectType);
   };
 }
 
@@ -5422,7 +5406,7 @@
     Result = QualType(T, 0);
 
   // Rebuild the typename type, which will probably turn into a
-  // QualifiedNameType.
+  // ElaboratedType.
   else if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
     QualType NewTemplateId
       = TransformType(QualType(TemplateId, 0));
@@ -5471,7 +5455,7 @@
 /// Here, the type "typename X<T>::pointer" will be created as a DependentNameType,
 /// since we do not know that we can look into X<T> when we parsed the type.
 /// This function will rebuild the type, performing the lookup of "pointer"
-/// in X<T> and returning a QualifiedNameType whose canonical type is the same
+/// in X<T> and returning an ElaboratedType whose canonical type is the same
 /// as the canonical type of T*, allowing the return types of the out-of-line
 /// definition and the declaration to match.
 TypeSourceInfo *Sema::RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 7dab4bd..06b9539 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -601,7 +601,8 @@
       
     /// \brief Check for tag mismatches when instantiating an
     /// elaborated type.
-    QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag);
+    QualType RebuildElaboratedType(ElaboratedTypeKeyword Keyword,
+                                   NestedNameSpecifier *NNS, QualType T);
 
     Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E);
     Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E);
@@ -719,8 +720,9 @@
 }
 
 QualType
-TemplateInstantiator::RebuildElaboratedType(QualType T,
-                                            ElaboratedType::TagKind Tag) {
+TemplateInstantiator::RebuildElaboratedType(ElaboratedTypeKeyword Keyword,
+                                            NestedNameSpecifier *NNS,
+                                            QualType T) {
   if (const TagType *TT = T->getAs<TagType>()) {
     TagDecl* TD = TT->getDecl();
 
@@ -732,16 +734,20 @@
 
     // TODO: should we even warn on struct/class mismatches for this?  Seems
     // like it's likely to produce a lot of spurious errors.
-    if (!SemaRef.isAcceptableTagRedeclaration(TD, Tag, TagLocation, *Id)) {
-      SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag)
-        << Id
-        << FixItHint::CreateReplacement(SourceRange(TagLocation),
-                                        TD->getKindName());
-      SemaRef.Diag(TD->getLocation(), diag::note_previous_use);
+    if (Keyword != ETK_None && Keyword != ETK_Typename) {
+      TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
+      if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, TagLocation, *Id)) {
+        SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag)
+          << Id
+          << FixItHint::CreateReplacement(SourceRange(TagLocation),
+                                          TD->getKindName());
+        SemaRef.Diag(TD->getLocation(), diag::note_previous_use);
+      }
     }
   }
 
-  return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(T, Tag);
+  return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(Keyword,
+                                                                    NNS, T);
 }
 
 Sema::OwningExprResult 
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index d1a74be..d926b9b 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -283,12 +283,11 @@
 
     // In C++, make an ElaboratedType.
     if (TheSema.getLangOptions().CPlusPlus) {
-      TagDecl::TagKind Tag
-        = TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType());
-      Result = TheSema.getQualifiedNameType(DS.getTypeSpecScope(), Result);
-      Result = Context.getElaboratedType(Result, Tag);
+      ElaboratedTypeKeyword Keyword
+        = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType());
+      Result = TheSema.getElaboratedType(Keyword, DS.getTypeSpecScope(),
+                                         Result);
     }
-
     if (D->isInvalidDecl())
       TheDeclarator.setInvalidType(true);
     break;
@@ -995,10 +994,10 @@
       break;
     case Declarator::MemberContext:
       switch (cast<TagDecl>(CurContext)->getTagKind()) {
-      case TagDecl::TK_enum: assert(0 && "unhandled tag kind"); break;
-      case TagDecl::TK_struct: Error = 1; /* Struct member */ break;
-      case TagDecl::TK_union:  Error = 2; /* Union member */ break;
-      case TagDecl::TK_class:  Error = 3; /* Class member */ break;
+      case TTK_Enum: assert(0 && "unhandled tag kind"); break;
+      case TTK_Struct: Error = 1; /* Struct member */ break;
+      case TTK_Union:  Error = 2; /* Union member */ break;
+      case TTK_Class:  Error = 3; /* Class member */ break;
       }
       break;
     case Declarator::CXXCatchContext:
@@ -1301,7 +1300,7 @@
         case NestedNameSpecifier::TypeSpecWithTemplate:
           ClsType = QualType(NNS->getAsType(), 0);
           if (NNSPrefix)
-            ClsType = Context.getQualifiedNameType(NNSPrefix, ClsType);
+            ClsType = Context.getElaboratedType(ETK_None, NNSPrefix, ClsType);
           break;
         }
       } else {
@@ -2082,15 +2081,21 @@
                              std::make_pair(SourceLocation(), PDiag(0)));
 }
 
-/// \brief Retrieve a version of the type 'T' that is qualified by the
-/// nested-name-specifier contained in SS.
-QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) {
-  if (!SS.isSet() || SS.isInvalid() || T.isNull())
+/// \brief Retrieve a version of the type 'T' that is elaborated by Keyword
+/// and qualified by the nested-name-specifier contained in SS.
+QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,
+                                 const CXXScopeSpec &SS, QualType T) {
+  if (T.isNull())
     return T;
-
-  NestedNameSpecifier *NNS
-    = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
-  return Context.getQualifiedNameType(NNS, T);
+  NestedNameSpecifier *NNS;
+  if (SS.isSet() && !SS.isInvalid())
+    NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+  else {
+    if (Keyword == ETK_None)
+      return T;
+    NNS = 0;
+  }
+  return Context.getElaboratedType(Keyword, NNS, T);
 }
 
 QualType Sema::BuildTypeofExprType(Expr *E) {
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 77d720b..4923480 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -492,11 +492,6 @@
     return SemaRef.Context.getTypeDeclType(Enum);
   }
 
-  /// \brief Build a new elaborated type.
-  QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag) {
-    return SemaRef.Context.getElaboratedType(T, Tag);
-  }
-
   /// \brief Build a new typeof(expr) type.
   ///
   /// By default, performs semantic analysis when building the typeof type.
@@ -525,11 +520,12 @@
 
   /// \brief Build a new qualified name type.
   ///
-  /// By default, builds a new QualifiedNameType type from the
-  /// nested-name-specifier and the named type. Subclasses may override
-  /// this routine to provide different behavior.
-  QualType RebuildQualifiedNameType(NestedNameSpecifier *NNS, QualType Named) {
-    return SemaRef.Context.getQualifiedNameType(NNS, Named);
+  /// By default, builds a new ElaboratedType type from the keyword,
+  /// the nested-name-specifier and the named type.
+  /// Subclasses may override this routine to provide different behavior.
+  QualType RebuildElaboratedType(ElaboratedTypeKeyword Keyword,
+                                 NestedNameSpecifier *NNS, QualType Named) {
+    return SemaRef.Context.getElaboratedType(Keyword, NNS, Named);
   }
 
   /// \brief Build a new typename type that refers to a template-id.
@@ -548,9 +544,8 @@
         return SemaRef.Context.getDependentNameType(Keyword, NNS,
                                           cast<TemplateSpecializationType>(T));
     }
-    
-    // FIXME: Handle elaborated-type-specifiers separately.
-    return SemaRef.Context.getQualifiedNameType(NNS, T);
+
+    return SemaRef.Context.getElaboratedType(Keyword, NNS, T);
   }
 
   /// \brief Build a new typename type that refers to an identifier.
@@ -571,19 +566,11 @@
         return SemaRef.Context.getDependentNameType(Keyword, NNS, Id);
     }
 
-    TagDecl::TagKind Kind = TagDecl::TK_enum;
-    switch (Keyword) {
-      case ETK_None:
-        // Fall through.
-      case ETK_Typename:
-        return SemaRef.CheckTypenameType(Keyword, NNS, *Id, SR);
-        
-      case ETK_Class: Kind = TagDecl::TK_class; break;
-      case ETK_Struct: Kind = TagDecl::TK_struct; break;
-      case ETK_Union: Kind = TagDecl::TK_union; break;
-      case ETK_Enum: Kind = TagDecl::TK_enum; break;
-    }
-    
+    if (Keyword == ETK_None || Keyword == ETK_Typename)
+      return SemaRef.CheckTypenameType(Keyword, NNS, *Id, SR);
+
+    TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
+
     // We had a dependent elaborated-type-specifier that as been transformed
     // into a non-dependent elaborated-type-specifier. Find the tag we're
     // referring to.
@@ -619,7 +606,7 @@
         << Kind << Id << DC;
       return QualType();
     }
-    
+
     // FIXME: Terrible location information
     if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, SR.getEnd(), *Id)) {
       SemaRef.Diag(SR.getBegin(), diag::err_use_with_wrong_tag) << Id;
@@ -629,8 +616,7 @@
 
     // Build the elaborated-type-specifier type.
     QualType T = SemaRef.Context.getTypeDeclType(Tag);
-    T = SemaRef.Context.getQualifiedNameType(NNS, T);
-    return SemaRef.Context.getElaboratedType(T, Kind);
+    return SemaRef.Context.getElaboratedType(Keyword, NNS, T);
   }
 
   /// \brief Build a new nested-name-specifier given the prefix and an
@@ -3146,31 +3132,6 @@
   return Result;
 }
 
-template <typename Derived>
-QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
-                                                         ElaboratedTypeLoc TL,
-                                                       QualType ObjectType) {
-  ElaboratedType *T = TL.getTypePtr();
-
-  // FIXME: this should be a nested type.
-  QualType Underlying = getDerived().TransformType(T->getUnderlyingType());
-  if (Underlying.isNull())
-    return QualType();
-
-  QualType Result = TL.getType();
-  if (getDerived().AlwaysRebuild() ||
-      Underlying != T->getUnderlyingType()) {
-    Result = getDerived().RebuildElaboratedType(Underlying, T->getTagKind());
-    if (Result.isNull())
-      return QualType();
-  }
-
-  ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
-  NewTL.setNameLoc(TL.getNameLoc());
-
-  return Result;
-}
-
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformInjectedClassNameType(
                                          TypeLocBuilder &TLB,
@@ -3275,16 +3236,20 @@
 
 template<typename Derived>
 QualType
-TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB,
-                                                   QualifiedNameTypeLoc TL,
-                                                   QualType ObjectType) {
-  QualifiedNameType *T = TL.getTypePtr();
-  NestedNameSpecifier *NNS
-    = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
-                                                SourceRange(),
-                                                ObjectType);
-  if (!NNS)
-    return QualType();
+TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
+                                                ElaboratedTypeLoc TL,
+                                                QualType ObjectType) {
+  ElaboratedType *T = TL.getTypePtr();
+
+  NestedNameSpecifier *NNS = 0;
+  // NOTE: the qualifier in an ElaboratedType is optional.
+  if (T->getQualifier() != 0) {
+    NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
+                                                    SourceRange(),
+                                                    ObjectType);
+    if (!NNS)
+      return QualType();
+  }
 
   QualType Named = getDerived().TransformType(T->getNamedType());
   if (Named.isNull())
@@ -3294,12 +3259,12 @@
   if (getDerived().AlwaysRebuild() ||
       NNS != T->getQualifier() ||
       Named != T->getNamedType()) {
-    Result = getDerived().RebuildQualifiedNameType(NNS, Named);
+    Result = getDerived().RebuildElaboratedType(T->getKeyword(), NNS, Named);
     if (Result.isNull())
       return QualType();
   }
 
-  QualifiedNameTypeLoc NewTL = TLB.push<QualifiedNameTypeLoc>(Result);
+  ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
   NewTL.setNameLoc(TL.getNameLoc());
 
   return Result;