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/Sema/Sema.h b/lib/Sema/Sema.h
index 9d71cf3..8c8cae2 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1940,11 +1940,11 @@
                            ClassTemplateSpecializationDecl *ClassTemplateSpec,
                            bool ExplicitInstantiation);
 
-  CXXScopeSpec InstantiateScopeSpecifier(const NestedNameSpecifier *Components,
-                                         unsigned NumComponents,
-                                         SourceRange Range,
-                                         const TemplateArgument *TemplateArgs,
-                                         unsigned NumTemplateArgs);
+  NestedNameSpecifier *
+  InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
+                                 SourceRange Range,
+                                 const TemplateArgument *TemplateArgs,
+                                 unsigned NumTemplateArgs);
 
   // Simple function for cloning expressions.
   template<typename T> 
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 9e11961..ca864a2 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -24,24 +24,41 @@
   if (!SS.isSet() || SS.isInvalid())
     return 0;
 
-  NestedNameSpecifier NNS
-    = NestedNameSpecifier::getFromOpaquePtr(SS.getCurrentScopeRep());
-  return NNS.computeDeclContext(Context);
+  NestedNameSpecifier *NNS 
+    = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+  if (NNS->isDependent())
+    return 0;
+
+  switch (NNS->getKind()) {
+  case NestedNameSpecifier::Identifier:
+    assert(false && "Dependent nested-name-specifier has no DeclContext");
+    break;
+
+  case NestedNameSpecifier::Namespace:
+    return NNS->getAsNamespace();
+
+  case NestedNameSpecifier::TypeSpec:
+  case NestedNameSpecifier::TypeSpecWithTemplate: {
+    const TagType *Tag = NNS->getAsType()->getAsTagType();
+    assert(Tag && "Non-tag type in nested-name-specifier");
+    return Tag->getDecl();
+  } break;
+
+  case NestedNameSpecifier::Global:
+    return Context.getTranslationUnitDecl();
+  }
+
+  // Required to silence a GCC warning.
+  return 0;
 }
 
 bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
   if (!SS.isSet() || SS.isInvalid())
     return false;
 
-  NestedNameSpecifier NNS
-    = NestedNameSpecifier::getFromOpaquePtr(SS.getCurrentScopeRep());
-
-  if (Type *T = NNS.getAsType())
-    return T->isDependentType();
-
-  // FIXME: What about the injected-class-name of a class template? It
-  // is dependent, but we represent it as a declaration.
-  return false;
+  NestedNameSpecifier *NNS 
+    = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+  return NNS->isDependent();
 }
 
 /// \brief Require that the context specified by SS be complete.
@@ -79,7 +96,7 @@
 /// global scope ('::').
 Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
                                                      SourceLocation CCLoc) {
-  return NestedNameSpecifier(Context.getTranslationUnitDecl()).getAsOpaquePtr();
+  return NestedNameSpecifier::GlobalSpecifier(Context);
 }
 
 /// ActOnCXXNestedNameSpecifier - Called during parsing of a
@@ -93,19 +110,37 @@
                                                     SourceLocation IdLoc,
                                                     SourceLocation CCLoc,
                                                     IdentifierInfo &II) {
+  NestedNameSpecifier *Prefix 
+    = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+
+  // If the prefix is already dependent, there is no name lookup to
+  // perform. Just build the resulting nested-name-specifier.
+  if (Prefix && Prefix->isDependent())
+    return NestedNameSpecifier::Create(Context, Prefix, &II);
+
   NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName);
 
   if (SD) {
-    if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
-      if (TD->getUnderlyingType()->isRecordType())
-        return NestedNameSpecifier(Context.getTypeDeclType(TD).getTypePtr())
-                .getAsOpaquePtr();
-    } else if (isa<NamespaceDecl>(SD) || isa<RecordDecl>(SD)) {
-      return NestedNameSpecifier(cast<DeclContext>(SD)).getAsOpaquePtr();
-    }
+    if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD))
+      return NestedNameSpecifier::Create(Context, Prefix, Namespace);
 
-    // FIXME: Template parameters and dependent types.
-    // FIXME: C++0x scoped enums
+    if (TypeDecl *Type = dyn_cast<TypeDecl>(SD)) {
+      // Determine whether we have a class (or, in C++0x, an enum) or
+      // a typedef thereof. If so, build the nested-name-specifier.
+      QualType T;
+      if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+        if (TD->getUnderlyingType()->isRecordType() ||
+            (getLangOptions().CPlusPlus0x && 
+             TD->getUnderlyingType()->isEnumeralType()))
+          T = Context.getTypeDeclType(TD);
+      } else if (isa<RecordDecl>(Type) || 
+                 (getLangOptions().CPlusPlus0x && isa<EnumDecl>(Type)))
+        T = Context.getTypeDeclType(Type);
+
+      if (!T.isNull())
+        return NestedNameSpecifier::Create(Context, Prefix, false, 
+                                           T.getTypePtr());
+    }
 
     // Fall through to produce an error: we found something that isn't
     // a class or a namespace.
@@ -137,8 +172,10 @@
                                                     TypeTy *Ty,
                                                     SourceRange TypeRange,
                                                     SourceLocation CCLoc) {
-  return NestedNameSpecifier(QualType::getFromOpaquePtr(Ty).getTypePtr())
-           .getAsOpaquePtr();
+  NestedNameSpecifier *Prefix 
+    = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+  return NestedNameSpecifier::Create(Context, Prefix, /*FIXME:*/false,
+                                QualType::getFromOpaquePtr(Ty).getTypePtr());
 }
 
 /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
@@ -152,6 +189,7 @@
   assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");
   PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity());
   CurContext = computeDeclContext(SS);
+  assert(CurContext && "No context?");
   S->setEntity(CurContext);
 }
 
@@ -170,4 +208,5 @@
   while (!S->getEntity() && S->getParent())
     S = S->getParent();
   CurContext = static_cast<DeclContext*>(S->getEntity());
+  assert(CurContext && "No context?");
 }
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index cb44cfc..bb306e4 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1159,9 +1159,13 @@
 /// Method declaration as if we had just parsed the qualified method
 /// name. However, it should not bring the parameters into scope;
 /// that will be performed by ActOnDelayedCXXMethodParameter.
-void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method) {
+void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *MethodD) {
   CXXScopeSpec SS;
-  SS.setScopeRep(((FunctionDecl*)Method)->getDeclContext());
+  FunctionDecl *Method = (FunctionDecl*)MethodD;
+  QualType ClassTy 
+    = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
+  SS.setScopeRep(
+    NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
   ActOnCXXEnterDeclaratorScope(S, SS);
 }
 
@@ -1192,7 +1196,10 @@
 void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclTy *MethodD) {
   FunctionDecl *Method = (FunctionDecl*)MethodD;
   CXXScopeSpec SS;
-  SS.setScopeRep(Method->getDeclContext());
+  QualType ClassTy 
+    = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
+  SS.setScopeRep(
+    NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr()));
   ActOnCXXExitDeclaratorScope(S, SS);
 
   // Now that we have our default arguments, check the constructor
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index c46bde0..288b617 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -440,13 +440,9 @@
                        bool TypeDependent, bool ValueDependent,
                        const CXXScopeSpec *SS) {
   if (SS && !SS->isEmpty()) {
-    llvm::SmallVector<NestedNameSpecifier, 16> Specs;
-    for (CXXScopeSpec::iterator Spec = SS->begin(), SpecEnd = SS->end();
-         Spec != SpecEnd; ++Spec)
-      Specs.push_back(NestedNameSpecifier::getFromOpaquePtr(*Spec));
-    return QualifiedDeclRefExpr::Create(Context, D, Ty, Loc, TypeDependent, 
-                                        ValueDependent, SS->getRange(),
-                                        &Specs[0], Specs.size());
+    return new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent, 
+                                              ValueDependent, SS->getRange(),
+                  static_cast<NestedNameSpecifier *>(SS->getCurrentScopeRep()));
   } else
     return new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent);
 }
@@ -619,13 +615,9 @@
   //     -- a nested-name-specifier that contains a class-name that
   //        names a dependent type.
   if (SS && isDependentScopeSpecifier(*SS)) {
-    llvm::SmallVector<NestedNameSpecifier, 16> Specs;
-    for (CXXScopeSpec::iterator Spec = SS->begin(), SpecEnd = SS->end();
-         Spec != SpecEnd; ++Spec)
-      Specs.push_back(NestedNameSpecifier::getFromOpaquePtr(*Spec));
-    return Owned(UnresolvedDeclRefExpr::Create(Context, Name, Loc,
-                                               SS->getRange(), &Specs[0],
-                                               Specs.size()));
+    return Owned(new (Context) UnresolvedDeclRefExpr(Name, Context.DependentTy,
+                                                     Loc, SS->getRange(), 
+                static_cast<NestedNameSpecifier *>(SS->getCurrentScopeRep())));
   }
 
   LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName,
@@ -2302,12 +2294,11 @@
       Expr *NewFn = 0;
       if (QualifiedDeclRefExpr *QDRExpr
             = dyn_cast_or_null<QualifiedDeclRefExpr>(DRExpr))
-        NewFn = QualifiedDeclRefExpr::Create(Context, FDecl, FDecl->getType(),
-                                             QDRExpr->getLocation(),
-                                             false, false,
-                                             QDRExpr->getQualifierRange(),
-                                             QDRExpr->begin(), 
-                                             QDRExpr->size());
+        NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(),
+                                                   QDRExpr->getLocation(),
+                                                   false, false,
+                                                 QDRExpr->getQualifierRange(),
+                                                   QDRExpr->getQualifier());
       else
         NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(),
                                           Fn->getSourceRange().getBegin());
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index f6e36bf..52f87b9 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -768,33 +768,52 @@
                           ClassTemplateSpec->getNumTemplateArgs());
 }
 
-/// \brief Instantiate a sequence of nested-name-specifiers into a
-/// scope specifier.
-CXXScopeSpec 
-Sema::InstantiateScopeSpecifier(const NestedNameSpecifier *Components,
-                                unsigned NumComponents,
-                                SourceRange Range,
-                                const TemplateArgument *TemplateArgs,
-                                unsigned NumTemplateArgs) {
-  CXXScopeSpec SS;
-  for (unsigned Comp = 0; Comp < NumComponents; ++Comp) {
-    if (Type *T = Components[Comp].getAsType()) {
-      QualType NewT = InstantiateType(QualType(T, 0), TemplateArgs, 
-                                      NumTemplateArgs, Range.getBegin(),
-                                      DeclarationName());
-      if (NewT.isNull())
-        return SS;
-      NestedNameSpecifier NNS(NewT.getTypePtr());
-      SS.addScopeRep(NNS.getAsOpaquePtr());
-    } else {
-      DeclContext *DC = Components[Comp].getAsDeclContext();
-      // FIXME: injected-class-name might be dependent, and therefore
-      // would need instantiation.
-      NestedNameSpecifier NNS(DC);
-      SS.addScopeRep(NNS.getAsOpaquePtr());
-    }
+/// \brief Instantiate a nested-name-specifier.
+NestedNameSpecifier *
+Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS,
+                                     SourceRange Range,
+                                     const TemplateArgument *TemplateArgs,
+                                     unsigned NumTemplateArgs) {
+  // Instantiate the prefix of this nested name specifier.
+  NestedNameSpecifier *Prefix = NNS->getPrefix();
+  if (Prefix) {
+    Prefix = InstantiateNestedNameSpecifier(Prefix, Range, TemplateArgs,
+                                            NumTemplateArgs);
+    if (!Prefix)
+      return 0;
   }
 
-  SS.setRange(Range);
-  return SS;
+  switch (NNS->getKind()) {
+  case NestedNameSpecifier::Identifier:
+    // FIXME: Implement this lookup!
+    assert(false && "Cannot instantiate this nested-name-specifier");
+    break;
+
+  case NestedNameSpecifier::Namespace:
+  case NestedNameSpecifier::Global:
+    return NNS;
+    
+  case NestedNameSpecifier::TypeSpecWithTemplate:
+  case NestedNameSpecifier::TypeSpec: {
+    QualType T = QualType(NNS->getAsType(), 0);
+    if (!T->isDependentType())
+      return NNS;
+
+    T = InstantiateType(T, TemplateArgs, NumTemplateArgs, Range.getBegin(),
+                        DeclarationName());
+    if (T.isNull())
+      return 0;
+
+    // Note that T.getTypePtr(), below, strips cv-qualifiers. This is
+    // perfectly reasonable, since cv-qualified types in
+    // nested-name-specifiers don't matter.
+    // FIXME: we need to perform more checking on this type.
+    return NestedNameSpecifier::Create(Context, Prefix, 
+                 NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
+                                       T.getTypePtr());
+  }
+  }
+
+  // Required to silence GCC warning.
+  return 0;
 }
diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp
index 780afd4..5476ad3 100644
--- a/lib/Sema/SemaTemplateInstantiateExpr.cpp
+++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp
@@ -321,13 +321,17 @@
 
 Sema::OwningExprResult 
 TemplateExprInstantiator::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *E) {
-  CXXScopeSpec SS = SemaRef.InstantiateScopeSpecifier(E->begin(), E->size(),
-                                                      E->getQualifierRange(),
-                                                      TemplateArgs,
-                                                      NumTemplateArgs);
-  if (SS.isInvalid() || SS.isEmpty())
+  NestedNameSpecifier *NNS 
+    = SemaRef.InstantiateNestedNameSpecifier(E->getQualifier(), 
+                                             E->getQualifierRange(),
+                                             TemplateArgs, NumTemplateArgs);
+  if (!NNS)
     return SemaRef.ExprError();
 
+  CXXScopeSpec SS;
+  SS.setRange(E->getQualifierRange());
+  SS.setScopeRep(NNS);
+
   // FIXME: We're passing in a NULL scope, because
   // ActOnDeclarationNameExpr doesn't actually use the scope when we
   // give it a non-empty scope specifier. Investigate whether it would
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 4b25657..0780ad8 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1101,9 +1101,7 @@
   if (!SS.isSet() || SS.isInvalid() || T.isNull())
     return T;
   
-  llvm::SmallVector<NestedNameSpecifier, 4> Specs;
-  for (CXXScopeSpec::iterator Spec = SS.begin(), SpecEnd = SS.end();
-       Spec != SpecEnd; ++Spec)
-    Specs.push_back(NestedNameSpecifier::getFromOpaquePtr(*Spec));
-  return Context.getQualifiedNameType(&Specs[0], Specs.size(), T);
+  NestedNameSpecifier *NNS
+    = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+  return Context.getQualifiedNameType(NNS, T);
 }