The scope representation can now be either a DeclContext pointer or a

Type pointer. This allows our nested-name-specifiers to retain more
information about the actual spelling (e.g., which typedef did the
user name, or what exact template arguments were used in the
template-id?). It will also allow us to have dependent
nested-name-specifiers that don't map to any DeclContext.

llvm-svn: 67140
This commit is contained in:
Douglas Gregor 2009-03-18 00:36:05 +00:00
parent a15ce21135
commit 6bfde496ee
8 changed files with 75 additions and 20 deletions

View File

@ -1452,6 +1452,21 @@ public:
bool RequireCompleteDeclContext(const CXXScopeSpec &SS); bool RequireCompleteDeclContext(const CXXScopeSpec &SS);
/// \brief Build a scope representation from a declaration context.
CXXScopeTy *createScopeRep(DeclContext *DC) {
return static_cast<CXXScopeTy *>(DC);
}
/// \brief Build a scope representation from a type.
CXXScopeTy *createScopeRep(QualType T);
DeclContext *getScopeRepAsDeclContext(const CXXScopeSpec &SS);
QualType getScopeRepAsType(const CXXScopeSpec &SS);
/// \brief Determines whether this scope specifier is represented as
/// a type.
bool isScopeRepType(const CXXScopeSpec &SS);
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
/// global scope ('::'). /// global scope ('::').
virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S, virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,

View File

@ -17,6 +17,49 @@
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
using namespace clang; 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())
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;
}
/// \brief Require that the context specified by SS be complete. /// \brief Require that the context specified by SS be complete.
/// ///
/// If SS refers to a type, this routine checks whether the type is /// If SS refers to a type, this routine checks whether the type is
@ -30,7 +73,7 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
if (!SS.isSet() || SS.isInvalid()) if (!SS.isSet() || SS.isInvalid())
return false; return false;
DeclContext *DC = static_cast<DeclContext *>(SS.getScopeRep()); DeclContext *DC = getScopeRepAsDeclContext(SS);
if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
// If we're currently defining this type, then lookup into the // If we're currently defining this type, then lookup into the
// type is okay: don't complain that it isn't complete yet. // type is okay: don't complain that it isn't complete yet.
@ -52,7 +95,7 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
/// global scope ('::'). /// global scope ('::').
Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
SourceLocation CCLoc) { SourceLocation CCLoc) {
return cast<DeclContext>(Context.getTranslationUnitDecl()); return createScopeRep(Context.getTranslationUnitDecl());
} }
/// ActOnCXXNestedNameSpecifier - Called during parsing of a /// ActOnCXXNestedNameSpecifier - Called during parsing of a
@ -70,10 +113,10 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
if (SD) { if (SD) {
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
if (const RecordType* Record = TD->getUnderlyingType()->getAsRecordType()) if (TD->getUnderlyingType()->isRecordType())
return cast<DeclContext>(Record->getDecl()); return createScopeRep(Context.getTypeDeclType(TD));
} else if (isa<NamespaceDecl>(SD) || isa<RecordDecl>(SD)) { } else if (isa<NamespaceDecl>(SD) || isa<RecordDecl>(SD)) {
return cast<DeclContext>(SD); return createScopeRep(cast<DeclContext>(SD));
} }
// FIXME: Template parameters and dependent types. // FIXME: Template parameters and dependent types.
@ -109,10 +152,7 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
TypeTy *Ty, TypeTy *Ty,
SourceRange TypeRange, SourceRange TypeRange,
SourceLocation CCLoc) { SourceLocation CCLoc) {
QualType Type = QualType::getFromOpaquePtr(Ty); return createScopeRep(QualType::getFromOpaquePtr(Ty));
assert(Type->isRecordType() &&
"Types in a nested-name-specifier always refer to a record type");
return cast<DeclContext>(Type->getAsRecordType()->getDecl());
} }
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
@ -125,7 +165,7 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?"); assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");
PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity()); PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity());
CurContext = static_cast<DeclContext*>(SS.getScopeRep()); CurContext = getScopeRepAsDeclContext(SS);
S->setEntity(CurContext); S->setEntity(CurContext);
} }
@ -136,7 +176,8 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
/// defining scope. /// defining scope.
void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
assert(S->getEntity() == SS.getScopeRep() && "Context imbalance!"); assert(S->getEntity() == getScopeRepAsDeclContext(SS) &&
"Context imbalance!");
S->setEntity(PreDeclaratorDC); S->setEntity(PreDeclaratorDC);
PreDeclaratorDC = 0; PreDeclaratorDC = 0;

View File

@ -1257,7 +1257,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
DeclSpec::SCS_static, DeclSpec::SCS_static,
D.getIdentifierLoc()); D.getIdentifierLoc());
} else { // Something like "int foo::x;" } else { // Something like "int foo::x;"
DC = static_cast<DeclContext*>(D.getCXXScopeSpec().getScopeRep()); DC = getScopeRepAsDeclContext(D.getCXXScopeSpec());
// FIXME: RequireCompleteDeclContext(D.getCXXScopeSpec()); ? // FIXME: RequireCompleteDeclContext(D.getCXXScopeSpec()); ?
PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true); PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
@ -3020,7 +3020,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
} }
// FIXME: RequireCompleteDeclContext(SS)? // FIXME: RequireCompleteDeclContext(SS)?
DC = static_cast<DeclContext*>(SS.getScopeRep()); DC = getScopeRepAsDeclContext(SS);
SearchDC = DC; SearchDC = DC;
// Look-up name inside 'foo::'. // Look-up name inside 'foo::'.
PrevDecl = dyn_cast_or_null<TagDecl>( PrevDecl = dyn_cast_or_null<TagDecl>(

View File

@ -300,7 +300,7 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
const CXXScopeSpec *SS) { const CXXScopeSpec *SS) {
CXXRecordDecl *CurDecl; CXXRecordDecl *CurDecl;
if (SS) { if (SS) {
DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep()); DeclContext *DC = getScopeRepAsDeclContext(*SS);
CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC); CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC);
} else } else
CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext); CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);

View File

@ -727,7 +727,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// implicit member ref, because we want a pointer to the member in general, // implicit member ref, because we want a pointer to the member in general,
// not any specific instance's member. // not any specific instance's member.
if (isAddressOfOperand && SS && !SS->isEmpty() && !HasTrailingLParen) { if (isAddressOfOperand && SS && !SS->isEmpty() && !HasTrailingLParen) {
DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep()); DeclContext *DC = getScopeRepAsDeclContext(*SS);
if (D && isa<CXXRecordDecl>(DC)) { if (D && isa<CXXRecordDecl>(DC)) {
QualType DType; QualType DType;
if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
@ -942,7 +942,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// - a nested-name-specifier that contains a class-name that // - a nested-name-specifier that contains a class-name that
// names a dependent type. // names a dependent type.
else if (SS && !SS->isEmpty()) { else if (SS && !SS->isEmpty()) {
for (DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep()); for (DeclContext *DC = getScopeRepAsDeclContext(*SS);
DC; DC = DC->getParent()) { DC; DC = DC->getParent()) {
// FIXME: could stop early at namespace scope. // FIXME: could stop early at namespace scope.
if (DC->isRecord()) { if (DC->isRecord()) {

View File

@ -1039,7 +1039,7 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS,
return LookupResult::CreateLookupResult(Context, 0); return LookupResult::CreateLookupResult(Context, 0);
if (SS->isSet()) if (SS->isSet())
return LookupQualifiedName(static_cast<DeclContext *>(SS->getScopeRep()), return LookupQualifiedName(getScopeRepAsDeclContext(*SS),
Name, NameKind, RedeclarationOnly); Name, NameKind, RedeclarationOnly);
} }

View File

@ -399,7 +399,7 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
DeclContext *SemanticContext = CurContext; DeclContext *SemanticContext = CurContext;
if (SS.isNotEmpty() && !SS.isInvalid()) { if (SS.isNotEmpty() && !SS.isInvalid()) {
SemanticContext = static_cast<DeclContext*>(SS.getScopeRep()); SemanticContext = getScopeRepAsDeclContext(SS);
// FIXME: need to match up several levels of template parameter // FIXME: need to match up several levels of template parameter
// lists here. // lists here.

View File

@ -742,8 +742,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
} }
case DeclaratorChunk::MemberPointer: case DeclaratorChunk::MemberPointer:
// The scope spec must refer to a class, or be dependent. // The scope spec must refer to a class, or be dependent.
DeclContext *DC = static_cast<DeclContext*>( DeclContext *DC = getScopeRepAsDeclContext(DeclType.Mem.Scope());
DeclType.Mem.Scope().getScopeRep());
QualType ClsType; QualType ClsType;
// FIXME: Extend for dependent types when it's actually supported. // FIXME: Extend for dependent types when it's actually supported.
// See ActOnCXXNestedNameSpecifier. // See ActOnCXXNestedNameSpecifier.