Remember declaration scope qualifiers in the AST.  Imposes no memory overhead
on unqualified declarations.

Patch by Enea Zaffanella!  Minimal adjustments:  allocate the ExtInfo nodes
with the ASTContext and delete them during Destroy().  I audited a bunch of
Destroy methods at the same time, to ensure that the correct teardown was
being done.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98540 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index e9a991e..e23811d 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -319,7 +319,19 @@
 /// \brief Represents a ValueDecl that came out of a declarator.
 /// Contains type source information through TypeSourceInfo.
 class DeclaratorDecl : public ValueDecl {
-  TypeSourceInfo *DeclInfo;
+  // A struct representing both a TInfo and a syntactic qualifier,
+  // to be used for the (uncommon) case of out-of-line declarations.
+  struct ExtInfo {
+    TypeSourceInfo *TInfo;
+    NestedNameSpecifier *NNS;
+    SourceRange NNSRange;
+  };
+
+  llvm::PointerUnion<TypeSourceInfo*, ExtInfo*> DeclInfo;
+
+  bool hasExtInfo() const { return DeclInfo.is<ExtInfo*>(); }
+  ExtInfo *getExtInfo() { return DeclInfo.get<ExtInfo*>(); }
+  const ExtInfo *getExtInfo() const { return DeclInfo.get<ExtInfo*>(); }
 
 protected:
   DeclaratorDecl(Kind DK, DeclContext *DC, SourceLocation L,
@@ -327,8 +339,29 @@
     : ValueDecl(DK, DC, L, N, T), DeclInfo(TInfo) {}
 
 public:
-  TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; }
-  void setTypeSourceInfo(TypeSourceInfo *TInfo) { DeclInfo = TInfo; }
+  virtual ~DeclaratorDecl();
+  virtual void Destroy(ASTContext &C);
+
+  TypeSourceInfo *getTypeSourceInfo() const {
+    return hasExtInfo()
+      ? DeclInfo.get<ExtInfo*>()->TInfo
+      : DeclInfo.get<TypeSourceInfo*>();
+  }
+  void setTypeSourceInfo(TypeSourceInfo *TI) {
+    if (hasExtInfo())
+      DeclInfo.get<ExtInfo*>()->TInfo = TI;
+    else
+      DeclInfo = TI;
+  }
+
+  NestedNameSpecifier *getQualifier() const {
+    return hasExtInfo() ? DeclInfo.get<ExtInfo*>()->NNS : 0;
+  }
+  SourceRange getQualifierRange() const {
+    return hasExtInfo() ? DeclInfo.get<ExtInfo*>()->NNSRange : SourceRange();
+  }
+  void setQualifierInfo(NestedNameSpecifier *Qualifier,
+                        SourceRange QualifierRange);
 
   SourceLocation getTypeSpecStartLoc() const;
 
@@ -1534,22 +1567,38 @@
 
   /// IsEmbeddedInDeclarator - True if this tag declaration is
   /// "embedded" (i.e., defined or declared for the very first time)
-  /// in the syntax of a declarator,
+  /// in the syntax of a declarator.
   bool IsEmbeddedInDeclarator : 1;
 
-  /// TypedefForAnonDecl - If a TagDecl is anonymous and part of a typedef,
-  /// this points to the TypedefDecl. Used for mangling.
-  TypedefDecl *TypedefForAnonDecl;
-
   SourceLocation TagKeywordLoc;
   SourceLocation RBraceLoc;
 
+  // A struct representing syntactic qualifier info,
+  // to be used for the (uncommon) case of out-of-line declarations.
+  struct ExtInfo {
+    NestedNameSpecifier *NNS;
+    SourceRange NNSRange;
+  };
+
+  /// TypedefDeclOrQualifier - If the (out-of-line) tag declaration name
+  /// is qualified, it points to the qualifier info (nns and range);
+  /// otherwise, if the tag declaration is anonymous and it is part of
+  /// a typedef, it points to the TypedefDecl (used for mangling);
+  /// otherwise, it is a null (TypedefDecl) pointer.
+  llvm::PointerUnion<TypedefDecl*, ExtInfo*> TypedefDeclOrQualifier;
+
+  bool hasExtInfo() const { return TypedefDeclOrQualifier.is<ExtInfo*>(); }
+  ExtInfo *getExtInfo() { return TypedefDeclOrQualifier.get<ExtInfo*>(); }
+  const ExtInfo *getExtInfo() const {
+    return TypedefDeclOrQualifier.get<ExtInfo*>();
+  }
+
 protected:
-  TagDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
-          IdentifierInfo *Id, TagDecl *PrevDecl,
-          SourceLocation TKL = SourceLocation())
-    : TypeDecl(DK, DC, L, Id), DeclContext(DK), TypedefForAnonDecl(0),
-      TagKeywordLoc(TKL) {
+  TagDecl(Kind DK, TagKind TK, DeclContext *DC,
+          SourceLocation L, IdentifierInfo *Id,
+          TagDecl *PrevDecl, SourceLocation TKL = SourceLocation())
+    : TypeDecl(DK, DC, L, Id), DeclContext(DK), TagKeywordLoc(TKL),
+      TypedefDeclOrQualifier((TypedefDecl*) 0) {
     assert((DK != Enum || TK == TK_enum) &&"EnumDecl not matched with TK_enum");
     TagDeclKind = TK;
     IsDefinition = false;
@@ -1561,6 +1610,8 @@
   virtual TagDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
 
 public:
+  void Destroy(ASTContext &C);
+
   typedef redeclarable_base::redecl_iterator redecl_iterator;
   redecl_iterator redecls_begin() const {
     return redeclarable_base::redecls_begin();
@@ -1640,8 +1691,21 @@
   bool isUnion()  const { return getTagKind() == TK_union; }
   bool isEnum()   const { return getTagKind() == TK_enum; }
 
-  TypedefDecl *getTypedefForAnonDecl() const { return TypedefForAnonDecl; }
-  void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefForAnonDecl = TDD; }
+  TypedefDecl *getTypedefForAnonDecl() const {
+    return hasExtInfo() ? 0 : TypedefDeclOrQualifier.get<TypedefDecl*>();
+  }
+  void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefDeclOrQualifier = TDD; }
+
+  NestedNameSpecifier *getQualifier() const {
+    return hasExtInfo() ? TypedefDeclOrQualifier.get<ExtInfo*>()->NNS : 0;
+  }
+  SourceRange getQualifierRange() const {
+    return hasExtInfo()
+      ? TypedefDeclOrQualifier.get<ExtInfo*>()->NNSRange
+      : SourceRange();
+  }
+  void setQualifierInfo(NestedNameSpecifier *Qualifier,
+                        SourceRange QualifierRange);
 
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 650bb53..3b49959 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -1592,6 +1592,12 @@
                                       Name.getAsIdentifierInfo(),
                                       Importer.Import(D->getTagKeywordLoc()),
                                       0);
+  // Import the qualifier, if any.
+  if (D->getQualifier()) {
+    NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
+    SourceRange NNSRange = Importer.Import(D->getQualifierRange());
+    D2->setQualifierInfo(NNS, NNSRange);
+  }
   D2->setAccess(D->getAccess());
   D2->setLexicalDeclContext(LexicalDC);
   Importer.Imported(D, D2);
@@ -1734,6 +1740,12 @@
                                     Name.getAsIdentifierInfo(), 
                                     Importer.Import(D->getTagKeywordLoc()));
     }
+    // Import the qualifier, if any.
+    if (D->getQualifier()) {
+      NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
+      SourceRange NNSRange = Importer.Import(D->getQualifierRange());
+      D2->setQualifierInfo(NNS, NNSRange);
+    }
     D2->setLexicalDeclContext(LexicalDC);
     LexicalDC->addDecl(D2);
   }
@@ -1900,6 +1912,13 @@
                                       D->isInlineSpecified(),
                                       D->hasWrittenPrototype());
   }
+
+  // Import the qualifier, if any.
+  if (D->getQualifier()) {
+    NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
+    SourceRange NNSRange = Importer.Import(D->getQualifierRange());
+    ToFunction->setQualifierInfo(NNS, NNSRange);
+  }
   ToFunction->setAccess(D->getAccess());
   ToFunction->setLexicalDeclContext(LexicalDC);
   Importer.Imported(D, ToFunction);
@@ -2110,6 +2129,12 @@
   VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc, 
                                    Name.getAsIdentifierInfo(), T, TInfo,
                                    D->getStorageClass());
+  // Import the qualifier, if any.
+  if (D->getQualifier()) {
+    NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
+    SourceRange NNSRange = Importer.Import(D->getQualifierRange());
+    ToVar->setQualifierInfo(NNS, NNSRange);
+  }
   ToVar->setAccess(D->getAccess());
   ToVar->setLexicalDeclContext(LexicalDC);
   Importer.Imported(D, ToVar);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 23f5fba..f568d1c 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -495,9 +495,16 @@
 // DeclaratorDecl Implementation
 //===----------------------------------------------------------------------===//
 
+DeclaratorDecl::~DeclaratorDecl() {}
+void DeclaratorDecl::Destroy(ASTContext &C) {
+  if (hasExtInfo())
+    C.Deallocate(getExtInfo());
+  ValueDecl::Destroy(C);
+}
+
 SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
   if (DeclInfo) {
-    TypeLoc TL = DeclInfo->getTypeLoc();
+    TypeLoc TL = getTypeSourceInfo()->getTypeLoc();
     while (true) {
       TypeLoc NextTL = TL.getNextTypeLoc();
       if (!NextTL)
@@ -508,6 +515,36 @@
   return SourceLocation();
 }
 
+void DeclaratorDecl::setQualifierInfo(NestedNameSpecifier *Qualifier,
+                                      SourceRange QualifierRange) {
+  if (Qualifier) {
+    // Make sure the extended decl info is allocated.
+    if (!hasExtInfo()) {
+      // Save (non-extended) type source info pointer.
+      TypeSourceInfo *savedTInfo = DeclInfo.get<TypeSourceInfo*>();
+      // Allocate external info struct.
+      DeclInfo = new (getASTContext()) ExtInfo;
+      // Restore savedTInfo into (extended) decl info.
+      getExtInfo()->TInfo = savedTInfo;
+    }
+    // Set qualifier info.
+    getExtInfo()->NNS = Qualifier;
+    getExtInfo()->NNSRange = QualifierRange;
+  }
+  else {
+    // Here Qualifier == 0, i.e., we are removing the qualifier (if any).
+    assert(QualifierRange.isInvalid());
+    if (hasExtInfo()) {
+      // Save type source info pointer.
+      TypeSourceInfo *savedTInfo = getExtInfo()->TInfo;
+      // Deallocate the extended decl info.
+      getASTContext().Deallocate(getExtInfo());
+      // Restore savedTInfo into (non-extended) decl info.
+      DeclInfo = savedTInfo;
+    }
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // VarDecl Implementation
 //===----------------------------------------------------------------------===//
@@ -542,7 +579,7 @@
     }
   }
   this->~VarDecl();
-  C.Deallocate((void *)this);
+  DeclaratorDecl::Destroy(C);
 }
 
 VarDecl::~VarDecl() {
@@ -818,7 +855,7 @@
   
   C.Deallocate(ParamInfo);
 
-  Decl::Destroy(C);
+  DeclaratorDecl::Destroy(C);
 }
 
 void FunctionDecl::getNameForDiagnostic(std::string &S,
@@ -1348,6 +1385,12 @@
 // TagDecl Implementation
 //===----------------------------------------------------------------------===//
 
+void TagDecl::Destroy(ASTContext &C) {
+  if (hasExtInfo())
+    C.Deallocate(getExtInfo());
+  TypeDecl::Destroy(C);
+}
+
 SourceRange TagDecl::getSourceRange() const {
   SourceLocation E = RBraceLoc.isValid() ? RBraceLoc : getLocation();
   return SourceRange(TagKeywordLoc, E);
@@ -1409,6 +1452,26 @@
   }
 }
 
+void TagDecl::setQualifierInfo(NestedNameSpecifier *Qualifier,
+                               SourceRange QualifierRange) {
+  if (Qualifier) {
+    // Make sure the extended qualifier info is allocated.
+    if (!hasExtInfo())
+      TypedefDeclOrQualifier = new (getASTContext()) ExtInfo;
+    // Set qualifier info.
+    getExtInfo()->NNS = Qualifier;
+    getExtInfo()->NNSRange = QualifierRange;
+  }
+  else {
+    // Here Qualifier == 0, i.e., we are removing the qualifier (if any).
+    assert(QualifierRange.isInvalid());
+    if (hasExtInfo()) {
+      getASTContext().Deallocate(getExtInfo());
+      TypedefDeclOrQualifier = (TypedefDecl*) 0;
+    }
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // EnumDecl Implementation
 //===----------------------------------------------------------------------===//
@@ -1422,7 +1485,7 @@
 }
 
 void EnumDecl::Destroy(ASTContext& C) {
-  Decl::Destroy(C);
+  TagDecl::Destroy(C);
 }
 
 void EnumDecl::completeDefinition(QualType NewType,
@@ -1529,7 +1592,7 @@
   // together. They are all top-level Decls.
 
   this->~NamespaceDecl();
-  C.Deallocate((void *)this);
+  Decl::Destroy(C);
 }
 
 
@@ -1563,7 +1626,7 @@
 
 void EnumConstantDecl::Destroy(ASTContext& C) {
   if (Init) Init->Destroy(C);
-  Decl::Destroy(C);
+  ValueDecl::Destroy(C);
 }
 
 TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 6deadcc..37f7479 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -943,8 +943,7 @@
 void StaticAssertDecl::Destroy(ASTContext& C) {
   AssertExpr->Destroy(C);
   Message->Destroy(C);
-  this->~StaticAssertDecl();
-  C.Deallocate((void *)this);
+  Decl::Destroy(C);
 }
 
 StaticAssertDecl::~StaticAssertDecl() {
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index 70aa0dd..f847bec 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -131,10 +131,11 @@
   TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
   TD->setDefinition(Record[Idx++]);
   TD->setEmbeddedInDeclarator(Record[Idx++]);
-  TD->setTypedefForAnonDecl(
-                    cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++])));
   TD->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
   TD->setTagKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+  // FIXME: maybe read optional qualifier and its range.
+  TD->setTypedefForAnonDecl(
+                    cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++])));
 }
 
 void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) {
@@ -168,6 +169,7 @@
   TypeSourceInfo *TInfo = Reader.GetTypeSourceInfo(Record, Idx);
   if (TInfo)
     DD->setTypeSourceInfo(TInfo);
+  // FIXME: read optional qualifier and its range.
 }
 
 void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index d40658c..7917280 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -127,9 +127,10 @@
   Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
   Record.push_back(D->isDefinition());
   Record.push_back(D->isEmbeddedInDeclarator());
-  Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record);
   Writer.AddSourceLocation(D->getRBraceLoc(), Record);
   Writer.AddSourceLocation(D->getTagKeywordLoc(), Record);
+  // FIXME: maybe write optional qualifier and its range.
+  Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record);
 }
 
 void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) {
@@ -165,6 +166,7 @@
 void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
   VisitValueDecl(D);
   Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+  // FIXME: write optional qualifier and its range.
 }
 
 void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 7179f4b..dab7d88 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2262,6 +2262,13 @@
   return true;
 }
 
+static void SetNestedNameSpecifier(DeclaratorDecl *DD, Declarator &D) {
+  CXXScopeSpec &SS = D.getCXXScopeSpec();
+  if (!SS.isSet()) return;
+  DD->setQualifierInfo(static_cast<NestedNameSpecifier*>(SS.getScopeRep()),
+                       SS.getRange());
+}
+
 NamedDecl*
 Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                               QualType R, TypeSourceInfo *TInfo,
@@ -2371,6 +2378,8 @@
   if (D.isInvalidType())
     NewVD->setInvalidDecl();
 
+  SetNestedNameSpecifier(NewVD, D);
+
   if (D.getDeclSpec().isThreadSpecified()) {
     if (NewVD->hasLocalStorage())
       Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global);
@@ -2799,6 +2808,8 @@
   if (D.isInvalidType())
     NewFD->setInvalidDecl();
 
+  SetNestedNameSpecifier(NewFD, D);
+
   // Set the lexical context. If the declarator has a C++
   // scope specifier, or is the object of a friend declaration, the
   // lexical context will be different from the semantic context.
@@ -4847,6 +4858,13 @@
                                cast_or_null<RecordDecl>(PrevDecl));
   }
 
+  // Maybe add qualifier info.
+  if (SS.isNotEmpty()) {
+    NestedNameSpecifier *NNS
+      = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+    New->setQualifierInfo(NNS, SS.getRange());
+  }
+
   if (Kind != TagDecl::TK_enum) {
     // Handle #pragma pack: if the #pragma pack stack has non-default
     // alignment, make up a packed attribute for this decl. These
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 242d66f..d369b77 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -1945,11 +1945,19 @@
     NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
                                 FD->getLocation(), DeclarationName(II),
                                 FD->getType(), FD->getTypeSourceInfo());
+    if (FD->getQualifier()) {
+      FunctionDecl *NewFD = cast<FunctionDecl>(NewD);
+      NewFD->setQualifierInfo(FD->getQualifier(), FD->getQualifierRange());
+    }
   } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) {
     NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
                            VD->getLocation(), II,
                            VD->getType(), VD->getTypeSourceInfo(),
                            VD->getStorageClass());
+    if (VD->getQualifier()) {
+      VarDecl *NewVD = cast<VarDecl>(NewD);
+      NewVD->setQualifierInfo(VD->getQualifier(), VD->getQualifierRange());
+    }
   }
   return NewD;
 }
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 79298ac..434d556 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -697,6 +697,12 @@
                                        RAngleLoc);
 }
 
+static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) {
+  if (SS.isSet())
+    T->setQualifierInfo(static_cast<NestedNameSpecifier*>(SS.getScopeRep()),
+                        SS.getRange());
+}
+
 Sema::DeclResult
 Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
                          SourceLocation KWLoc, const CXXScopeSpec &SS,
@@ -864,6 +870,7 @@
                           PrevClassTemplate?
                             PrevClassTemplate->getTemplatedDecl() : 0,
                           /*DelayTypeCreation=*/true);
+  SetNestedNameSpecifier(NewClass, SS);
 
   ClassTemplateDecl *NewTemplate
     = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
@@ -3491,6 +3498,7 @@
                                                        TemplateArgs,
                                                        CanonType,
                                                        PrevPartial);
+    SetNestedNameSpecifier(Partial, SS);
 
     if (PrevPartial) {
       ClassTemplate->getPartialSpecializations().RemoveNode(PrevPartial);
@@ -3547,6 +3555,7 @@
                                                 ClassTemplate,
                                                 Converted,
                                                 PrevDecl);
+    SetNestedNameSpecifier(Specialization, SS);
 
     if (PrevDecl) {
       ClassTemplate->getSpecializations().RemoveNode(PrevDecl);
@@ -4328,6 +4337,7 @@
                                                 TemplateNameLoc,
                                                 ClassTemplate,
                                                 Converted, PrevDecl);
+    SetNestedNameSpecifier(Specialization, SS);
 
     if (PrevDecl) {
       // Remove the previous declaration from the folding set, since we want
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e8bcb8b..dbe041c 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -97,6 +97,11 @@
 
     TemplateParameterList *
       SubstTemplateParams(TemplateParameterList *List);
+
+    bool SubstQualifier(const DeclaratorDecl *OldDecl,
+                        DeclaratorDecl *NewDecl);
+    bool SubstQualifier(const TagDecl *OldDecl,
+                        TagDecl *NewDecl);
       
     bool InstantiateClassTemplatePartialSpecialization(
                                               ClassTemplateDecl *ClassTemplate,
@@ -104,6 +109,38 @@
   };
 }
 
+bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
+                                              DeclaratorDecl *NewDecl) {
+  NestedNameSpecifier *OldQual = OldDecl->getQualifier();
+  if (!OldQual) return false;
+
+  SourceRange QualRange = OldDecl->getQualifierRange();
+
+  NestedNameSpecifier *NewQual
+    = SemaRef.SubstNestedNameSpecifier(OldQual, QualRange, TemplateArgs);
+  if (!NewQual)
+    return true;
+
+  NewDecl->setQualifierInfo(NewQual, QualRange);
+  return false;
+}
+
+bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
+                                              TagDecl *NewDecl) {
+  NestedNameSpecifier *OldQual = OldDecl->getQualifier();
+  if (!OldQual) return false;
+
+  SourceRange QualRange = OldDecl->getQualifierRange();
+
+  NestedNameSpecifier *NewQual
+    = SemaRef.SubstNestedNameSpecifier(OldQual, QualRange, TemplateArgs);
+  if (!NewQual)
+    return true;
+
+  NewDecl->setQualifierInfo(NewQual, QualRange);
+  return false;
+}
+
 // FIXME: Is this too simple?
 void TemplateDeclInstantiator::InstantiateAttrs(Decl *Tmpl, Decl *New) {
   for (const Attr *TmplAttr = Tmpl->getAttrs(); TmplAttr; 
@@ -287,6 +324,10 @@
   Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
   Var->setDeclaredInCondition(D->isDeclaredInCondition());
 
+  // Substitute the nested name specifier, if any.
+  if (SubstQualifier(D, Var))
+    return 0;
+
   // If we are instantiating a static data member defined
   // out-of-line, the instantiation will have the same lexical
   // context (which will be a namespace scope) as the template.
@@ -511,6 +552,7 @@
                                     /*PrevDecl=*/0);
   Enum->setInstantiationOfMemberEnum(D);
   Enum->setAccess(D->getAccess());
+  if (SubstQualifier(D, Enum)) return 0;
   Owner->addDecl(Enum);
   Enum->startDefinition();
 
@@ -611,6 +653,10 @@
                             Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL,
                             /*DelayTypeCreation=*/true);
 
+  // Substitute the nested name specifier, if any.
+  if (SubstQualifier(Pattern, RecordInst))
+    return 0;
+
   ClassTemplateDecl *Inst
     = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
                                 D->getIdentifier(), InstParams, RecordInst, 0);
@@ -745,6 +791,11 @@
     = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
                             D->getLocation(), D->getIdentifier(),
                             D->getTagKeywordLoc(), PrevDecl);
+
+  // Substitute the nested name specifier, if any.
+  if (SubstQualifier(D, Record))
+    return 0;
+
   Record->setImplicit(D->isImplicit());
   // FIXME: Check against AS_none is an ugly hack to work around the issue that
   // the tag decls introduced by friend class declarations don't have an access
@@ -818,6 +869,11 @@
                            D->getDeclName(), T, TInfo,
                            D->getStorageClass(),
                            D->isInlineSpecified(), D->hasWrittenPrototype());
+
+  // Substitute the nested name specifier, if any.
+  if (SubstQualifier(D, Function))
+    return 0;
+
   Function->setLexicalDeclContext(Owner);
 
   // Attach the parameters
@@ -979,6 +1035,10 @@
                                    D->isStatic(), D->isInlineSpecified());
   }
 
+  // Substitute the nested name specifier, if any.
+  if (SubstQualifier(D, Method))
+    return 0;
+
   if (TemplateParams) {
     // Our resulting instantiation is actually a function template, since we
     // are substituting only the outer template parameters. For example, given
@@ -1508,6 +1568,10 @@
                                                      InstTemplateArgs,
                                                      CanonType,
                                                      0);
+  // Substitute the nested name specifier, if any.
+  if (SubstQualifier(PartialSpec, InstPartialSpec))
+    return 0;
+
   InstPartialSpec->setInstantiatedFromMember(PartialSpec);
   InstPartialSpec->setTypeAsWritten(WrittenTy);