Teach NestedNameSpecifier to keep track of namespace aliases the same
way it keeps track of namespaces. Previously, we would map from the
namespace alias to its underlying namespace when building a
nested-name-specifier, losing source information in the process.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126358 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 0b3febd..9c24550 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2981,7 +2981,15 @@
case NestedNameSpecifier::Namespace:
// A namespace is canonical; build a nested-name-specifier with
// this namespace and no prefix.
- return NestedNameSpecifier::Create(*this, 0, NNS->getAsNamespace());
+ return NestedNameSpecifier::Create(*this, 0,
+ NNS->getAsNamespace()->getOriginalNamespace());
+
+ case NestedNameSpecifier::NamespaceAlias:
+ // A namespace is canonical; build a nested-name-specifier with
+ // this namespace and no prefix.
+ return NestedNameSpecifier::Create(*this, 0,
+ NNS->getAsNamespaceAlias()->getNamespace()
+ ->getOriginalNamespace());
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index e2dbb83..939ca7a 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -606,6 +606,9 @@
case NestedNameSpecifier::Namespace:
mangleName(Qualifier->getAsNamespace());
break;
+ case NestedNameSpecifier::NamespaceAlias:
+ mangleName(Qualifier->getAsNamespaceAlias()->getNamespace());
+ break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
const Type *QTy = Qualifier->getAsType();
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 650321d..1b477d8 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/Type.h"
#include "llvm/Support/raw_ostream.h"
@@ -46,7 +47,7 @@
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
- Mockup.Prefix.setInt(Identifier);
+ Mockup.Prefix.setInt(StoredIdentifier);
Mockup.Specifier = II;
return FindOrInsert(Context, Mockup);
}
@@ -60,19 +61,34 @@
"Broken nested name specifier");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
- Mockup.Prefix.setInt(Namespace);
+ Mockup.Prefix.setInt(StoredNamespaceOrAlias);
Mockup.Specifier = NS;
return FindOrInsert(Context, Mockup);
}
NestedNameSpecifier *
NestedNameSpecifier::Create(const ASTContext &Context,
+ NestedNameSpecifier *Prefix,
+ NamespaceAliasDecl *Alias) {
+ assert(Alias && "Namespace alias cannot be NULL");
+ assert((!Prefix ||
+ (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
+ "Broken nested name specifier");
+ NestedNameSpecifier Mockup;
+ Mockup.Prefix.setPointer(Prefix);
+ Mockup.Prefix.setInt(StoredNamespaceOrAlias);
+ Mockup.Specifier = Alias;
+ return FindOrInsert(Context, Mockup);
+}
+
+NestedNameSpecifier *
+NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
bool Template, const Type *T) {
assert(T && "Type cannot be NULL");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
- Mockup.Prefix.setInt(Template? TypeSpecWithTemplate : TypeSpec);
+ Mockup.Prefix.setInt(Template? StoredTypeSpecWithTemplate : StoredTypeSpec);
Mockup.Specifier = const_cast<Type*>(T);
return FindOrInsert(Context, Mockup);
}
@@ -82,7 +98,7 @@
assert(II && "Identifier cannot be NULL");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(0);
- Mockup.Prefix.setInt(Identifier);
+ Mockup.Prefix.setInt(StoredIdentifier);
Mockup.Specifier = II;
return FindOrInsert(Context, Mockup);
}
@@ -94,6 +110,47 @@
return Context.GlobalNestedNameSpecifier;
}
+NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const {
+ if (Specifier == 0)
+ return Global;
+
+ switch (Prefix.getInt()) {
+ case StoredIdentifier:
+ return Identifier;
+
+ case StoredNamespaceOrAlias:
+ return isa<NamespaceDecl>(static_cast<NamedDecl *>(Specifier))? Namespace
+ : NamespaceAlias;
+
+ case StoredTypeSpec:
+ return TypeSpec;
+
+ case StoredTypeSpecWithTemplate:
+ return TypeSpecWithTemplate;
+ }
+
+ return Global;
+}
+
+/// \brief Retrieve the namespace stored in this nested name
+/// specifier.
+NamespaceDecl *NestedNameSpecifier::getAsNamespace() const {
+ if (Prefix.getInt() == StoredNamespaceOrAlias)
+ return dyn_cast<NamespaceDecl>(static_cast<NamedDecl *>(Specifier));
+
+ return 0;
+}
+
+/// \brief Retrieve the namespace alias stored in this nested name
+/// specifier.
+NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const {
+ if (Prefix.getInt() == StoredNamespaceOrAlias)
+ return dyn_cast<NamespaceAliasDecl>(static_cast<NamedDecl *>(Specifier));
+
+ return 0;
+}
+
+
/// \brief Whether this nested name specifier refers to a dependent
/// type or not.
bool NestedNameSpecifier::isDependent() const {
@@ -103,6 +160,7 @@
return true;
case Namespace:
+ case NamespaceAlias:
case Global:
return false;
@@ -121,6 +179,7 @@
return getPrefix() && getPrefix()->containsUnexpandedParameterPack();
case Namespace:
+ case NamespaceAlias:
case Global:
return false;
@@ -147,7 +206,11 @@
break;
case Namespace:
- OS << getAsNamespace()->getIdentifier()->getName();
+ OS << getAsNamespace()->getName();
+ break;
+
+ case NamespaceAlias:
+ OS << getAsNamespaceAlias()->getName();
break;
case Global:
diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp
index b24ece5..a09db0b 100644
--- a/lib/Frontend/DocumentXML.cpp
+++ b/lib/Frontend/DocumentXML.cpp
@@ -14,6 +14,7 @@
#include "clang/Frontend/DocumentXML.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringExtras.h"
@@ -218,6 +219,10 @@
addPtrAttribute(pAttributeName, pNNS->getAsNamespace());
break;
}
+ case NestedNameSpecifier::NamespaceAlias: {
+ addPtrAttribute(pAttributeName, pNNS->getAsNamespaceAlias());
+ break;
+ }
case NestedNameSpecifier::TypeSpec: {
addPtrAttribute(pAttributeName, pNNS->getAsType());
break;
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 3998497..f21d90f 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -74,6 +74,15 @@
Range.setEnd(ColonColonLoc);
}
+void CXXScopeSpec::Extend(ASTContext &Context, NamespaceAliasDecl *Alias,
+ SourceLocation AliasLoc,
+ SourceLocation ColonColonLoc) {
+ ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, Alias);
+ if (Range.getBegin().isInvalid())
+ Range.setBegin(AliasLoc);
+ Range.setEnd(ColonColonLoc);
+}
+
void CXXScopeSpec::MakeGlobal(ASTContext &Context,
SourceLocation ColonColonLoc) {
assert(!ScopeRep && "Already have a nested-name-specifier!?");
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 754c52c..9daec58 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -139,6 +139,9 @@
case NestedNameSpecifier::Namespace:
return NNS->getAsNamespace();
+ case NestedNameSpecifier::NamespaceAlias:
+ return NNS->getAsNamespaceAlias()->getNamespace();
+
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
const TagType *Tag = NNS->getAsType()->getAs<TagType>();
@@ -532,11 +535,8 @@
return false;
}
- // FIXME: It would be nice to maintain the namespace alias name, then
- // see through that alias when resolving the nested-name-specifier down to
- // a declaration context.
if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) {
- SS.Extend(Context, Alias->getNamespace(), IdentifierLoc, CCLoc);
+ SS.Extend(Context, Alias, IdentifierLoc, CCLoc);
return false;
}
@@ -681,6 +681,7 @@
switch (Qualifier->getKind()) {
case NestedNameSpecifier::Global:
case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
// These are always namespace scopes. We never want to enter a
// namespace scope from anything but a file context.
return CurContext->getRedeclContext()->isFileContext();
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index ab6dde5..d75a1f1 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2868,6 +2868,7 @@
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
return false;
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index d30ed74..ba80076 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1895,6 +1895,7 @@
break;
case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
llvm_unreachable("Nested-name-specifier must name a type");
break;
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 7a0754f..1b2822e 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -877,6 +877,16 @@
NamespaceDecl *NS);
/// \brief Build a new nested-name-specifier given the prefix and the
+ /// namespace alias named in the next step in the nested-name-specifier.
+ ///
+ /// By default, performs semantic analysis when building the new
+ /// nested-name-specifier. Subclasses may override this routine to provide
+ /// different behavior.
+ NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
+ NamespaceAliasDecl *Alias);
+
+ /// \brief Build a new nested-name-specifier given the prefix and the
/// type named in the next step in the nested-name-specifier.
///
/// By default, performs semantic analysis when building the new
@@ -2450,6 +2460,19 @@
return getDerived().RebuildNestedNameSpecifier(Prefix, Range, NS);
}
+ case NestedNameSpecifier::NamespaceAlias: {
+ NamespaceAliasDecl *Alias
+ = cast_or_null<NamespaceAliasDecl>(
+ getDerived().TransformDecl(Range.getBegin(),
+ NNS->getAsNamespaceAlias()));
+ if (!getDerived().AlwaysRebuild() &&
+ Prefix == NNS->getPrefix() &&
+ Alias == NNS->getAsNamespaceAlias())
+ return NNS;
+
+ return getDerived().RebuildNestedNameSpecifier(Prefix, Range, Alias);
+ }
+
case NestedNameSpecifier::Global:
// There is no meaningful transformation that one could perform on the
// global scope.
@@ -7571,6 +7594,14 @@
NestedNameSpecifier *
TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
SourceRange Range,
+ NamespaceAliasDecl *Alias) {
+ return NestedNameSpecifier::Create(SemaRef.Context, Prefix, Alias);
+}
+
+template<typename Derived>
+NestedNameSpecifier *
+TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+ SourceRange Range,
bool TemplateKW,
QualType T) {
if (T->isDependentType() || T->isRecordType() ||
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 2e8e8ca..6f8856c 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -4730,6 +4730,13 @@
break;
}
+ case NestedNameSpecifier::NamespaceAlias: {
+ NamespaceAliasDecl *Alias
+ = cast<NamespaceAliasDecl>(GetDecl(Record[Idx++]));
+ NNS = NestedNameSpecifier::Create(*Context, Prev, Alias);
+ break;
+ }
+
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
const Type *T = GetType(Record[Idx++]).getTypePtrOrNull();
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index b1edf95..42ca293 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -3470,6 +3470,10 @@
AddDeclRef(NNS->getAsNamespace(), Record);
break;
+ case NestedNameSpecifier::NamespaceAlias:
+ AddDeclRef(NNS->getAsNamespaceAlias(), Record);
+ break;
+
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
AddTypeRef(QualType(NNS->getAsType(), 0), Record);