Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67265 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index e30ec2a..156f3a1 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -13,51 +13,20 @@
#include "Sema.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/NestedNameSpecifier.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
-/// \brief Retrieve the scope represented by this scope specifier as a
-/// DeclContext.
-DeclContext *Sema::getScopeRepAsDeclContext(const CXXScopeSpec &SS) {
- if (SS.isInvalid() || !SS.getScopeRep())
+/// \brief Compute the DeclContext that is associated with the given
+/// scope specifier.
+DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) {
+ if (!SS.isSet() || SS.isInvalid())
return 0;
- uintptr_t Rep = reinterpret_cast<uintptr_t>(SS.getScopeRep());
- if ((Rep & 0x01) == 0)
- return reinterpret_cast<DeclContext *>(Rep);
- // Retrieve the DeclContext associated with this type.
- QualType T = QualType(reinterpret_cast<Type *>(Rep & ~0x01), 0);
- const TagType *TagT = T->getAsTagType();
- assert(TagT && "No DeclContext from a non-tag type");
- return TagT->getDecl();
-}
-
-/// \brief Retrieve the scope represented by this scope specifier as a
-/// type.
-QualType Sema::getScopeRepAsType(const CXXScopeSpec &SS) {
- if (SS.isInvalid() || !SS.getScopeRep())
- return QualType();
-
- uintptr_t Rep = reinterpret_cast<uintptr_t>(SS.getScopeRep());
- if ((Rep & 0x01) == 0)
- return QualType();
- return QualType(reinterpret_cast<Type *>(Rep & ~0x01), 0);
-}
-
-Action::CXXScopeTy *Sema::createScopeRep(QualType T) {
- assert(((reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()) & 0x01) == 0) &&
- "Scope type with cv-qualifiers");
- if (T.isNull())
- return 0;
-
- return reinterpret_cast<CXXScopeTy *>(
- reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()) | 0x01);
-}
-
-bool Sema::isScopeRepType(const CXXScopeSpec &SS) {
- uintptr_t Rep = reinterpret_cast<uintptr_t>(SS.getScopeRep());
- return Rep & 0x01;
+ NestedNameSpecifier NNS
+ = NestedNameSpecifier::getFromOpaquePtr(SS.getCurrentScopeRep());
+ return NNS.computeDeclContext(Context);
}
/// \brief Require that the context specified by SS be complete.
@@ -73,7 +42,7 @@
if (!SS.isSet() || SS.isInvalid())
return false;
- DeclContext *DC = getScopeRepAsDeclContext(SS);
+ DeclContext *DC = computeDeclContext(SS);
if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
// If we're currently defining this type, then lookup into the
// type is okay: don't complain that it isn't complete yet.
@@ -95,7 +64,7 @@
/// global scope ('::').
Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
SourceLocation CCLoc) {
- return createScopeRep(Context.getTranslationUnitDecl());
+ return NestedNameSpecifier(Context.getTranslationUnitDecl()).getAsOpaquePtr();
}
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
@@ -114,9 +83,10 @@
if (SD) {
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
if (TD->getUnderlyingType()->isRecordType())
- return createScopeRep(Context.getTypeDeclType(TD));
+ return NestedNameSpecifier(Context.getTypeDeclType(TD).getTypePtr())
+ .getAsOpaquePtr();
} else if (isa<NamespaceDecl>(SD) || isa<RecordDecl>(SD)) {
- return createScopeRep(cast<DeclContext>(SD));
+ return NestedNameSpecifier(cast<DeclContext>(SD)).getAsOpaquePtr();
}
// FIXME: Template parameters and dependent types.
@@ -152,7 +122,8 @@
TypeTy *Ty,
SourceRange TypeRange,
SourceLocation CCLoc) {
- return createScopeRep(QualType::getFromOpaquePtr(Ty));
+ return NestedNameSpecifier(QualType::getFromOpaquePtr(Ty).getTypePtr())
+ .getAsOpaquePtr();
}
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
@@ -165,7 +136,7 @@
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");
PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity());
- CurContext = getScopeRepAsDeclContext(SS);
+ CurContext = computeDeclContext(SS);
S->setEntity(CurContext);
}
@@ -176,8 +147,7 @@
/// defining scope.
void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
- assert(S->getEntity() == getScopeRepAsDeclContext(SS) &&
- "Context imbalance!");
+ assert(S->getEntity() == computeDeclContext(SS) && "Context imbalance!");
S->setEntity(PreDeclaratorDC);
PreDeclaratorDC = 0;