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);