aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaCXXScopeSpec.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-03-26 23:50:42 +0000
committerDouglas Gregor <dgregor@apple.com>2009-03-26 23:50:42 +0000
commitab452ba8323d1985e08bade2bced588cddf2cc28 (patch)
tree5434985218412826cd26ffd2f8d87857109eb50b /lib/Sema/SemaCXXScopeSpec.cpp
parent5bf17cd277db2a253f6012968471064c4f4537a3 (diff)
Revamp our representation of C++ nested-name-specifiers. We now have a
uniqued representation that should both save some memory and make it far easier to properly build canonical types for types involving dependent nested-name-specifiers, e.g., "typename T::Nested::type". This approach will greatly simplify the representation of CXXScopeSpec. That'll be next. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67799 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaCXXScopeSpec.cpp')
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp87
1 files changed, 63 insertions, 24 deletions
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 9e1196143b..ca864a2a2e 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -24,24 +24,41 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) {
if (!SS.isSet() || SS.isInvalid())
return 0;
- NestedNameSpecifier NNS
- = NestedNameSpecifier::getFromOpaquePtr(SS.getCurrentScopeRep());
- return NNS.computeDeclContext(Context);
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+ if (NNS->isDependent())
+ return 0;
+
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ assert(false && "Dependent nested-name-specifier has no DeclContext");
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ return NNS->getAsNamespace();
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ const TagType *Tag = NNS->getAsType()->getAsTagType();
+ assert(Tag && "Non-tag type in nested-name-specifier");
+ return Tag->getDecl();
+ } break;
+
+ case NestedNameSpecifier::Global:
+ return Context.getTranslationUnitDecl();
+ }
+
+ // Required to silence a GCC warning.
+ return 0;
}
bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
if (!SS.isSet() || SS.isInvalid())
return false;
- NestedNameSpecifier NNS
- = NestedNameSpecifier::getFromOpaquePtr(SS.getCurrentScopeRep());
-
- if (Type *T = NNS.getAsType())
- return T->isDependentType();
-
- // FIXME: What about the injected-class-name of a class template? It
- // is dependent, but we represent it as a declaration.
- return false;
+ NestedNameSpecifier *NNS
+ = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+ return NNS->isDependent();
}
/// \brief Require that the context specified by SS be complete.
@@ -79,7 +96,7 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
/// global scope ('::').
Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
SourceLocation CCLoc) {
- return NestedNameSpecifier(Context.getTranslationUnitDecl()).getAsOpaquePtr();
+ return NestedNameSpecifier::GlobalSpecifier(Context);
}
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
@@ -93,20 +110,38 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II) {
+ NestedNameSpecifier *Prefix
+ = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+
+ // If the prefix is already dependent, there is no name lookup to
+ // perform. Just build the resulting nested-name-specifier.
+ if (Prefix && Prefix->isDependent())
+ return NestedNameSpecifier::Create(Context, Prefix, &II);
+
NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName);
if (SD) {
- if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
- if (TD->getUnderlyingType()->isRecordType())
- return NestedNameSpecifier(Context.getTypeDeclType(TD).getTypePtr())
- .getAsOpaquePtr();
- } else if (isa<NamespaceDecl>(SD) || isa<RecordDecl>(SD)) {
- return NestedNameSpecifier(cast<DeclContext>(SD)).getAsOpaquePtr();
+ if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD))
+ return NestedNameSpecifier::Create(Context, Prefix, Namespace);
+
+ if (TypeDecl *Type = dyn_cast<TypeDecl>(SD)) {
+ // Determine whether we have a class (or, in C++0x, an enum) or
+ // a typedef thereof. If so, build the nested-name-specifier.
+ QualType T;
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+ if (TD->getUnderlyingType()->isRecordType() ||
+ (getLangOptions().CPlusPlus0x &&
+ TD->getUnderlyingType()->isEnumeralType()))
+ T = Context.getTypeDeclType(TD);
+ } else if (isa<RecordDecl>(Type) ||
+ (getLangOptions().CPlusPlus0x && isa<EnumDecl>(Type)))
+ T = Context.getTypeDeclType(Type);
+
+ if (!T.isNull())
+ return NestedNameSpecifier::Create(Context, Prefix, false,
+ T.getTypePtr());
}
- // FIXME: Template parameters and dependent types.
- // FIXME: C++0x scoped enums
-
// Fall through to produce an error: we found something that isn't
// a class or a namespace.
}
@@ -137,8 +172,10 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
TypeTy *Ty,
SourceRange TypeRange,
SourceLocation CCLoc) {
- return NestedNameSpecifier(QualType::getFromOpaquePtr(Ty).getTypePtr())
- .getAsOpaquePtr();
+ NestedNameSpecifier *Prefix
+ = static_cast<NestedNameSpecifier *>(SS.getCurrentScopeRep());
+ return NestedNameSpecifier::Create(Context, Prefix, /*FIXME:*/false,
+ QualType::getFromOpaquePtr(Ty).getTypePtr());
}
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
@@ -152,6 +189,7 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");
PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity());
CurContext = computeDeclContext(SS);
+ assert(CurContext && "No context?");
S->setEntity(CurContext);
}
@@ -170,4 +208,5 @@ void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
while (!S->getEntity() && S->getParent())
S = S->getParent();
CurContext = static_cast<DeclContext*>(S->getEntity());
+ assert(CurContext && "No context?");
}