From b6217665c6a987f2d6c8665fd70365d7719ac4df Mon Sep 17 00:00:00 2001 From: John McCall Date: Mon, 15 Mar 2010 10:12:16 +0000 Subject: [PATCH] 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 --- include/clang/AST/Decl.h | 94 ++++++++++++++++++++---- lib/AST/ASTImporter.cpp | 25 +++++++ lib/AST/Decl.cpp | 75 +++++++++++++++++-- lib/AST/DeclCXX.cpp | 3 +- lib/Frontend/PCHReaderDecl.cpp | 6 +- lib/Frontend/PCHWriterDecl.cpp | 4 +- lib/Sema/SemaDecl.cpp | 18 +++++ lib/Sema/SemaDeclAttr.cpp | 8 ++ lib/Sema/SemaTemplate.cpp | 10 +++ lib/Sema/SemaTemplateInstantiateDecl.cpp | 64 ++++++++++++++++ 10 files changed, 281 insertions(+), 26 deletions(-) diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index e9a991ecfe..e23811d8f9 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -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 DeclInfo; + + bool hasExtInfo() const { return DeclInfo.is(); } + ExtInfo *getExtInfo() { return DeclInfo.get(); } + const ExtInfo *getExtInfo() const { return DeclInfo.get(); } 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()->TInfo + : DeclInfo.get(); + } + void setTypeSourceInfo(TypeSourceInfo *TI) { + if (hasExtInfo()) + DeclInfo.get()->TInfo = TI; + else + DeclInfo = TI; + } + + NestedNameSpecifier *getQualifier() const { + return hasExtInfo() ? DeclInfo.get()->NNS : 0; + } + SourceRange getQualifierRange() const { + return hasExtInfo() ? DeclInfo.get()->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 TypedefDeclOrQualifier; + + bool hasExtInfo() const { return TypedefDeclOrQualifier.is(); } + ExtInfo *getExtInfo() { return TypedefDeclOrQualifier.get(); } + const ExtInfo *getExtInfo() const { + return TypedefDeclOrQualifier.get(); + } + 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(); + } + void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefDeclOrQualifier = TDD; } + + NestedNameSpecifier *getQualifier() const { + return hasExtInfo() ? TypedefDeclOrQualifier.get()->NNS : 0; + } + SourceRange getQualifierRange() const { + return hasExtInfo() + ? TypedefDeclOrQualifier.get()->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 650bb53236..3b4995958b 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -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); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 23f5fba437..f568d1cdd4 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -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(); + // 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, diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 6deadcce54..37f7479b36 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -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() { diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 70aa0dd3c9..f847becb15 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -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(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(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) { diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index d40658c3f9..7917280295 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -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) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 7179f4bc6b..dab7d883a1 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(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(PrevDecl)); } + // Maybe add qualifier info. + if (SS.isNotEmpty()) { + NestedNameSpecifier *NNS + = static_cast(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 242d66fa52..d369b773e8 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -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(NewD); + NewFD->setQualifierInfo(FD->getQualifier(), FD->getQualifierRange()); + } } else if (VarDecl *VD = dyn_cast(ND)) { NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), VD->getLocation(), II, VD->getType(), VD->getTypeSourceInfo(), VD->getStorageClass()); + if (VD->getQualifier()) { + VarDecl *NewVD = cast(NewD); + NewVD->setQualifierInfo(VD->getQualifier(), VD->getQualifierRange()); + } } return NewD; } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 79298acc22..434d5563e1 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -697,6 +697,12 @@ Sema::ActOnTemplateParameterList(unsigned Depth, RAngleLoc); } +static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) { + if (SS.isSet()) + T->setQualifierInfo(static_cast(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 diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index e8bcb8be89..dbe041c4aa 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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); -- 2.40.0