Revamp our representation of C++ nested-name-specifiers. We now have a
uniqued representation that should both save some memory and make it
far easier to properly build canonical types for types involving
dependent nested-name-specifiers, e.g., "typename T::Nested::type".

This approach will greatly simplify the representation of
CXXScopeSpec. That'll be next.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67799 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index c656d96..84976a0 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -33,9 +33,9 @@
                        TargetInfo &t,
                        IdentifierTable &idents, SelectorTable &sels,
                        bool FreeMem, unsigned size_reserve) : 
-  CFConstantStringTypeDecl(0), ObjCFastEnumerationStateTypeDecl(0),
-  SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t), 
-  Idents(idents), Selectors(sels)
+  GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), 
+  ObjCFastEnumerationStateTypeDecl(0), SourceMgr(SM), LangOpts(LOpts), 
+  FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels)
 {  
   if (size_reserve > 0) Types.reserve(size_reserve);    
   InitBuiltinTypes();
@@ -77,7 +77,18 @@
     }
   }
 
+  // Destroy nested-name-specifiers.
+  for (llvm::FoldingSet<NestedNameSpecifier>::iterator 
+         NNS = NestedNameSpecifiers.begin(),
+         NNSEnd = NestedNameSpecifiers.end(); 
+       NNS != NNSEnd; ++NNS)
+    NNS->Destroy(*this);
+
+  if (GlobalNestedNameSpecifier)
+    GlobalNestedNameSpecifier->Destroy(*this);
+
   TUDecl->Destroy(*this);
+
 }
 
 void ASTContext::PrintStats() const {
@@ -1376,11 +1387,10 @@
 }
 
 QualType 
-ASTContext::getQualifiedNameType(const NestedNameSpecifier *Components,
-                                 unsigned NumComponents,
+ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS,
                                  QualType NamedType) {
   llvm::FoldingSetNodeID ID;
-  QualifiedNameType::Profile(ID, Components, NumComponents, NamedType);
+  QualifiedNameType::Profile(ID, NNS, NamedType);
 
   void *InsertPos = 0;
   QualifiedNameType *T 
@@ -1388,11 +1398,8 @@
   if (T)
     return QualType(T, 0);
 
-  void *Mem = Allocate((sizeof(QualifiedNameType) +
-                        sizeof(NestedNameSpecifier) * NumComponents), 
-                       8);
-  T = new (Mem) QualifiedNameType(Components, NumComponents, NamedType,
-                                  getCanonicalType(NamedType));
+  T = new (*this) QualifiedNameType(NNS, NamedType, 
+                                    getCanonicalType(NamedType));
   Types.push_back(T);
   QualifiedNameTypes.InsertNode(T, InsertPos);
   return QualType(T, 0);
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 5a9de19..c2fcc5f 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -24,54 +24,6 @@
   C.Deallocate(this);
 }
 
-QualifiedDeclRefExpr::QualifiedDeclRefExpr(NamedDecl *d, QualType t, 
-                                           SourceLocation l, bool TD, 
-                                           bool VD, SourceRange R,
-                                       const NestedNameSpecifier *Components,
-                                           unsigned NumComponents)
-  : DeclRefExpr(QualifiedDeclRefExprClass, d, t, l, TD, VD), 
-    QualifierRange(R), NumComponents(NumComponents) {
-  NestedNameSpecifier *Data 
-    = reinterpret_cast<NestedNameSpecifier *>(this + 1);
-  for (unsigned I = 0; I < NumComponents; ++I)
-    Data[I] = Components[I];
-}
-
-QualifiedDeclRefExpr *
-QualifiedDeclRefExpr::Create(ASTContext &Context, NamedDecl *d, QualType t, 
-                             SourceLocation l, bool TD, 
-                             bool VD, SourceRange R,
-                             const NestedNameSpecifier *Components,
-                             unsigned NumComponents) {
-  void *Mem = Context.Allocate((sizeof(QualifiedDeclRefExpr) +
-                                sizeof(NestedNameSpecifier) * NumComponents));
-  return new (Mem) QualifiedDeclRefExpr(d, t, l, TD, VD, R, Components, 
-                                        NumComponents);
-}
-
-UnresolvedDeclRefExpr::UnresolvedDeclRefExpr(DeclarationName N, QualType T,
-                                             SourceLocation L, SourceRange R,
-                                       const NestedNameSpecifier *Components,
-                                             unsigned NumComponents)
-  : Expr(UnresolvedDeclRefExprClass, T, true, true), 
-    Name(N), Loc(L), QualifierRange(R), NumComponents(NumComponents) {
-  NestedNameSpecifier *Data 
-    = reinterpret_cast<NestedNameSpecifier *>(this + 1);
-  for (unsigned I = 0; I < NumComponents; ++I)
-    Data[I] = Components[I];
-}
-
-UnresolvedDeclRefExpr *
-UnresolvedDeclRefExpr::Create(ASTContext &Context, DeclarationName N,
-                              SourceLocation L, SourceRange R,
-                              const NestedNameSpecifier *Components,
-                              unsigned NumComponents) {
-  void *Mem = Context.Allocate((sizeof(UnresolvedDeclRefExpr) +
-                                sizeof(NestedNameSpecifier) * NumComponents));
-  return new (Mem) UnresolvedDeclRefExpr(N, Context.DependentTy, L, R, 
-                                         Components, NumComponents);
-}
-
 //===----------------------------------------------------------------------===//
 //  Child Iterators for iterating over subexpressions/substatements
 //===----------------------------------------------------------------------===//
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index ea4b506..62e972e 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -16,46 +16,137 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/Type.h"
 #include "llvm/Support/raw_ostream.h"
+#include <cassert>
 
 using namespace clang;
 
-DeclContext *
-NestedNameSpecifier::computeDeclContext(ASTContext &Context) const {
-  // The simple case: we're storing a DeclContext
-  if ((Data & 0x01) == 0)
-    return reinterpret_cast<DeclContext *>(Data);
+NestedNameSpecifier *
+NestedNameSpecifier::FindOrInsert(ASTContext &Context, 
+                                  const NestedNameSpecifier &Mockup) {
+  llvm::FoldingSetNodeID ID;
+  Mockup.Profile(ID);
 
-  Type *T = getAsType();
-  if (!T)
-    return 0;
+  void *InsertPos = 0;
+  NestedNameSpecifier *NNS 
+    = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos);
+  if (!NNS) {
+    NNS = new (Context) NestedNameSpecifier(Mockup);
+    Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos);
+  }
 
-  // Retrieve the DeclContext associated with this type.
-  const TagType *TagT = T->getAsTagType();
-  assert(TagT && "No DeclContext from a non-tag type");
-  return TagT->getDecl();
+  return NNS;
 }
 
-void NestedNameSpecifier::Print(llvm::raw_ostream &OS, 
-                                const NestedNameSpecifier *First,
-                                const NestedNameSpecifier *Last) {
-  for (; First != Last; ++First) {
-    if (Type *T = First->getAsType()) {
-      std::string TypeStr;
+NestedNameSpecifier *
+NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, 
+                            IdentifierInfo *II) {
+  assert(II && "Identifier cannot be NULL");
+  assert(Prefix && Prefix->isDependent() && "Prefix must be dependent");
 
-      // If this is a qualified name type, suppress the qualification:
-      // it's part of our nested-name-specifier sequence anyway.
-      if (const QualifiedNameType *QualT = dyn_cast<QualifiedNameType>(T))
-        T = QualT->getNamedType().getTypePtr();
+  NestedNameSpecifier Mockup;
+  Mockup.Prefix = Prefix;
+  Mockup.Specifier.setPointer(II);
+  Mockup.Specifier.setInt(Identifier);
+  return FindOrInsert(Context, Mockup);
+}
 
-      if (const TagType *TagT = dyn_cast<TagType>(T))
-        TagT->getAsStringInternal(TypeStr, true);
-      else
-        T->getAsStringInternal(TypeStr);
-      OS << TypeStr;
-    } else if (NamedDecl *NamedDC 
-                 = dyn_cast_or_null<NamedDecl>(First->getAsDeclContext()))
-      OS << NamedDC->getNameAsString();
+NestedNameSpecifier *
+NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, 
+                            NamespaceDecl *NS) {
+  assert(NS && "Namespace cannot be NULL");
+  assert((!Prefix || 
+          (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
+         "Broken nested name specifier");
+  NestedNameSpecifier Mockup;
+  Mockup.Prefix = Prefix;
+  Mockup.Specifier.setPointer(NS);
+  Mockup.Specifier.setInt(Namespace);
+  return FindOrInsert(Context, Mockup);
+}
+
+NestedNameSpecifier *
+NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
+                            bool Template, Type *T) {
+  assert(T && "Type cannot be NULL");
+  NestedNameSpecifier Mockup;
+  Mockup.Prefix = Prefix;
+  Mockup.Specifier.setPointer(T);
+  Mockup.Specifier.setInt(Template? TypeSpecWithTemplate : TypeSpec);
+  return FindOrInsert(Context, Mockup);
+}
   
-    OS <<  "::";
+NestedNameSpecifier *NestedNameSpecifier::GlobalSpecifier(ASTContext &Context) {
+  if (!Context.GlobalNestedNameSpecifier)
+    Context.GlobalNestedNameSpecifier = new (Context) NestedNameSpecifier();
+  return Context.GlobalNestedNameSpecifier;
+}
+
+/// \brief Whether this nested name specifier refers to a dependent
+/// type or not.
+bool NestedNameSpecifier::isDependent() const {
+  switch (getKind()) {
+  case Identifier:
+    // Identifier specifiers always represent dependent types
+    return true;
+
+  case Namespace:
+  case Global:
+    return false;
+
+  case TypeSpec:
+  case TypeSpecWithTemplate:
+    return getAsType()->isDependentType();
   }
+
+  // Necessary to suppress a GCC warning.
+  return false;
+}
+
+/// \brief Print this nested name specifier to the given output
+/// stream.
+void NestedNameSpecifier::Print(llvm::raw_ostream &OS) const {
+  if (Prefix)
+    Prefix->Print(OS);
+
+  switch (getKind()) {
+  case Identifier:
+    OS << getAsIdentifier()->getName();
+    break;
+
+  case Namespace:
+    OS << getAsNamespace()->getIdentifier()->getName();
+    break;
+
+  case Global:
+    break;
+
+  case TypeSpecWithTemplate:
+    OS << "template ";
+    // Fall through to print the type.
+
+  case TypeSpec: {
+    std::string TypeStr;
+    Type *T = getAsType();
+
+    // If this is a qualified name type, suppress the qualification:
+    // it's part of our nested-name-specifier sequence anyway.  FIXME:
+    // We should be able to assert that this doesn't happen.
+    if (const QualifiedNameType *QualT = dyn_cast<QualifiedNameType>(T))
+      T = QualT->getNamedType().getTypePtr();
+    
+    if (const TagType *TagT = dyn_cast<TagType>(T))
+      TagT->getAsStringInternal(TypeStr, true);
+    else
+      T->getAsStringInternal(TypeStr);
+    OS << TypeStr;
+    break;
+  }
+  }
+
+  OS << "::";
+}
+
+void NestedNameSpecifier::Destroy(ASTContext &Context) {
+  this->~NestedNameSpecifier();
+  Context.Deallocate((void *)this);
 }
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 60300ba..bd5e224 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -533,12 +533,12 @@
 void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) {  
   NamedDecl *D = Node->getDecl();
 
-  NestedNameSpecifier::Print(OS, Node->begin(), Node->end());
+  Node->getQualifier()->Print(OS);
   OS << D->getNameAsString();
 }
 
 void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) {  
-  NestedNameSpecifier::Print(OS, Node->begin(), Node->end());
+  Node->getQualifier()->Print(OS);
   OS << Node->getDeclName().getAsString();
 }
 
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 19a3f14..103c0a9 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1047,28 +1047,6 @@
     Args[Idx].Profile(ID);
 }
 
-QualifiedNameType::QualifiedNameType(const NestedNameSpecifier *Components,
-                                     unsigned NumComponents, 
-                                     QualType NamedType,
-                                     QualType CanonType)
-  : Type(QualifiedName, CanonType, NamedType->isDependentType()),
-    NumComponents(NumComponents), NamedType(NamedType) {
-  NestedNameSpecifier *InitComponents 
-    = reinterpret_cast<NestedNameSpecifier *>(this + 1);
-  for (unsigned I = 0; I < NumComponents; ++I)
-    new (InitComponents + I) NestedNameSpecifier(Components[I]);
-}
-
-void QualifiedNameType::Profile(llvm::FoldingSetNodeID &ID, 
-                                const NestedNameSpecifier *Components,
-                                unsigned NumComponents, 
-                                QualType NamedType) {
-  ID.AddInteger(NumComponents);
-  for (unsigned I = 0; I < NumComponents; ++I)
-    ID.AddPointer(Components[I].getAsOpaquePtr());
-  NamedType.Profile(ID);
-}
-
 //===----------------------------------------------------------------------===//
 // Type Printing
 //===----------------------------------------------------------------------===//
@@ -1440,7 +1418,7 @@
 
   {
     llvm::raw_string_ostream OS(MyString);
-    NestedNameSpecifier::Print(OS, begin(), end());
+    NNS->Print(OS);
   }
   
   std::string TypeStr;
diff --git a/lib/AST/TypeSerialization.cpp b/lib/AST/TypeSerialization.cpp
index 6f93a18..4490847 100644
--- a/lib/AST/TypeSerialization.cpp
+++ b/lib/AST/TypeSerialization.cpp
@@ -421,9 +421,7 @@
 // QualifiedNameType
 //===----------------------------------------------------------------------===//
 void QualifiedNameType::EmitImpl(llvm::Serializer& S) const {
-  S.EmitInt(NumComponents);
   // FIXME: Serialize the actual components
-  S.Emit(NamedType);
 }
 
 Type*