]> granicus.if.org Git - clang/commitdiff
Remember declaration scope qualifiers in the AST. Imposes no memory overhead
authorJohn McCall <rjmccall@apple.com>
Mon, 15 Mar 2010 10:12:16 +0000 (10:12 +0000)
committerJohn McCall <rjmccall@apple.com>
Mon, 15 Mar 2010 10:12:16 +0000 (10:12 +0000)
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

include/clang/AST/Decl.h
lib/AST/ASTImporter.cpp
lib/AST/Decl.cpp
lib/AST/DeclCXX.cpp
lib/Frontend/PCHReaderDecl.cpp
lib/Frontend/PCHWriterDecl.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp

index e9a991ecfed0f4c6305398fa6d9dd38c5842b255..e23811d8f9c0f93abbea3a92974fb09ba5c4c4c8 100644 (file)
@@ -319,7 +319,19 @@ public:
 /// \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 @@ protected:
     : 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 @@ private:
 
   /// 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 @@ protected:
   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 @@ public:
   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()); }
index 650bb53236ba7abd5ec7cb63281aacf17dd547fb..3b4995958b9ab4d03d53feb25eafa26c41be85ba 100644 (file)
@@ -1592,6 +1592,12 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
                                       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 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
                                     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 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
                                       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 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
   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);
index 23f5fba437a53f7d80cc5dd0e53cff0cf4b8388b..f568d1cdd45e4f8614e81a7ef35cea688dbead8a 100644 (file)
@@ -495,9 +495,16 @@ NamedDecl *NamedDecl::getUnderlyingDecl() {
 // 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 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
   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 @@ void VarDecl::Destroy(ASTContext& C) {
     }
   }
   this->~VarDecl();
-  C.Deallocate((void *)this);
+  DeclaratorDecl::Destroy(C);
 }
 
 VarDecl::~VarDecl() {
@@ -818,7 +855,7 @@ void FunctionDecl::Destroy(ASTContext& C) {
   
   C.Deallocate(ParamInfo);
 
-  Decl::Destroy(C);
+  DeclaratorDecl::Destroy(C);
 }
 
 void FunctionDecl::getNameForDiagnostic(std::string &S,
@@ -1348,6 +1385,12 @@ bool FieldDecl::isAnonymousStructOrUnion() const {
 // 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 @@ TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) {
   }
 }
 
+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 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
 }
 
 void EnumDecl::Destroy(ASTContext& C) {
-  Decl::Destroy(C);
+  TagDecl::Destroy(C);
 }
 
 void EnumDecl::completeDefinition(QualType NewType,
@@ -1529,7 +1592,7 @@ void NamespaceDecl::Destroy(ASTContext& C) {
   // together. They are all top-level Decls.
 
   this->~NamespaceDecl();
-  C.Deallocate((void *)this);
+  Decl::Destroy(C);
 }
 
 
@@ -1563,7 +1626,7 @@ EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
 
 void EnumConstantDecl::Destroy(ASTContext& C) {
   if (Init) Init->Destroy(C);
-  Decl::Destroy(C);
+  ValueDecl::Destroy(C);
 }
 
 TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
index 6deadcce547318d8b52c7901abec6a27f56ca9c6..37f7479b36cd53f2ed8fca5f71ec5b4b50218f26 100644 (file)
@@ -943,8 +943,7 @@ StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
 void StaticAssertDecl::Destroy(ASTContext& C) {
   AssertExpr->Destroy(C);
   Message->Destroy(C);
-  this->~StaticAssertDecl();
-  C.Deallocate((void *)this);
+  Decl::Destroy(C);
 }
 
 StaticAssertDecl::~StaticAssertDecl() {
index 70aa0dd3c9fda5eecde4756c7de0c6ed3ad52b17..f847becb15b878562082026c717026fd936061b5 100644 (file)
@@ -131,10 +131,11 @@ void PCHDeclReader::VisitTagDecl(TagDecl *TD) {
   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 @@ void PCHDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
   TypeSourceInfo *TInfo = Reader.GetTypeSourceInfo(Record, Idx);
   if (TInfo)
     DD->setTypeSourceInfo(TInfo);
+  // FIXME: read optional qualifier and its range.
 }
 
 void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
index d40658c3f9b6bb6d92a9f3ac4372c38e68f2e348..7917280295adfb64252e824bd36deda37771d5d6 100644 (file)
@@ -127,9 +127,10 @@ void PCHDeclWriter::VisitTagDecl(TagDecl *D) {
   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::VisitEnumConstantDecl(EnumConstantDecl *D) {
 void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
   VisitValueDecl(D);
   Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+  // FIXME: write optional qualifier and its range.
 }
 
 void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
index 7179f4bc6bb7742188618e7776e7c88017af90c6..dab7d883a1d6e57b9acd0a55811b13f81688f589 100644 (file)
@@ -2262,6 +2262,13 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
   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 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
   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 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
   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 @@ CreateNewDecl:
                                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
index 242d66fa521f8d53b6963952896ba0bc1dddc36a..d369b773e8dde562f8e3a9e448a608a12a77c0c5 100644 (file)
@@ -1945,11 +1945,19 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
     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;
 }
index 79298acc229cda1049ab17a7a45e6fa1e6f46035..434d5563e1b36b060e89175c266eed246a6a78be 100644 (file)
@@ -697,6 +697,12 @@ Sema::ActOnTemplateParameterList(unsigned Depth,
                                        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 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
                           PrevClassTemplate?
                             PrevClassTemplate->getTemplatedDecl() : 0,
                           /*DelayTypeCreation=*/true);
+  SetNestedNameSpecifier(NewClass, SS);
 
   ClassTemplateDecl *NewTemplate
     = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
@@ -3491,6 +3498,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
                                                        TemplateArgs,
                                                        CanonType,
                                                        PrevPartial);
+    SetNestedNameSpecifier(Partial, SS);
 
     if (PrevPartial) {
       ClassTemplate->getPartialSpecializations().RemoveNode(PrevPartial);
@@ -3547,6 +3555,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
                                                 ClassTemplate,
                                                 Converted,
                                                 PrevDecl);
+    SetNestedNameSpecifier(Specialization, SS);
 
     if (PrevDecl) {
       ClassTemplate->getSpecializations().RemoveNode(PrevDecl);
@@ -4328,6 +4337,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
                                                 TemplateNameLoc,
                                                 ClassTemplate,
                                                 Converted, PrevDecl);
+    SetNestedNameSpecifier(Specialization, SS);
 
     if (PrevDecl) {
       // Remove the previous declaration from the folding set, since we want
index e8bcb8be89b0142d7459fb565bace5b0f944bffe..dbe041c4aadeed9f91cccd867954d1efc2b5d379 100644 (file)
@@ -97,6 +97,11 @@ namespace {
 
     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 @@ namespace {
   };
 }
 
+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 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
   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 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
                                     /*PrevDecl=*/0);
   Enum->setInstantiationOfMemberEnum(D);
   Enum->setAccess(D->getAccess());
+  if (SubstQualifier(D, Enum)) return 0;
   Owner->addDecl(Enum);
   Enum->startDefinition();
 
@@ -611,6 +653,10 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
                             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 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
     = 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 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
                            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 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
                                    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 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
                                                      InstTemplateArgs,
                                                      CanonType,
                                                      0);
+  // Substitute the nested name specifier, if any.
+  if (SubstQualifier(PartialSpec, InstPartialSpec))
+    return 0;
+
   InstPartialSpec->setInstantiatedFromMember(PartialSpec);
   InstPartialSpec->setTypeAsWritten(WrittenTy);