When performing unqualified name lookup into a DeclContext, also look into

all of the parent DeclContexts that aren't represented within the
Scope chain. This fixes some name-lookup problems in out-of-line
definitions of members of nested classes.

llvm-svn: 81451
This commit is contained in:
Douglas Gregor 2009-09-10 16:57:35 +00:00
parent 753441e318
commit 7f737c0015
4 changed files with 54 additions and 20 deletions

View File

@ -565,6 +565,12 @@ public:
return const_cast<DeclContext*>(this)->getLexicalParent(); return const_cast<DeclContext*>(this)->getLexicalParent();
} }
DeclContext *getLookupParent();
const DeclContext *getLookupParent() const {
return const_cast<DeclContext*>(this)->getLookupParent();
}
ASTContext &getParentASTContext() const { ASTContext &getParentASTContext() const {
return cast<Decl>(this)->getASTContext(); return cast<Decl>(this)->getASTContext();
} }

View File

@ -420,6 +420,22 @@ void DeclContext::DestroyDecls(ASTContext &C) {
(*D++)->Destroy(C); (*D++)->Destroy(C);
} }
/// \brief Find the parent context of this context that will be
/// used for unqualified name lookup.
///
/// Generally, the parent lookup context is the semantic context. However, for
/// a friend function the parent lookup context is the lexical context, which
/// is the class in which the friend is declared.
DeclContext *DeclContext::getLookupParent() {
// FIXME: Find a better way to identify friends
if (isa<FunctionDecl>(this))
if (getParent()->getLookupContext()->isFileContext() &&
getLexicalParent()->getLookupContext()->isRecord())
return getLexicalParent();
return getParent();
}
bool DeclContext::isDependentContext() const { bool DeclContext::isDependentContext() const {
if (isFileContext()) if (isFileContext())
return false; return false;

View File

@ -636,6 +636,15 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) {
return false; return false;
} }
// Find the next outer declaration context corresponding to this scope.
static DeclContext *findOuterContext(Scope *S) {
for (S = S->getParent(); S; S = S->getParent())
if (S->getEntity())
return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext();
return 0;
}
std::pair<bool, Sema::LookupResult> std::pair<bool, Sema::LookupResult>
Sema::CppLookupName(Scope *S, DeclarationName Name, Sema::CppLookupName(Scope *S, DeclarationName Name,
LookupNameKind NameKind, bool RedeclarationOnly) { LookupNameKind NameKind, bool RedeclarationOnly) {
@ -694,30 +703,23 @@ Sema::CppLookupName(Scope *S, DeclarationName Name,
} }
if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) { if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) {
LookupResult R; LookupResult R;
// Perform member lookup into struct.
DeclContext *OuterCtx = findOuterContext(S);
for (; Ctx && Ctx->getPrimaryContext() != OuterCtx;
Ctx = Ctx->getLookupParent()) {
if (Ctx->isFunctionOrMethod())
continue;
// Perform qualified name lookup into this context.
// FIXME: In some cases, we know that every name that could be found by // FIXME: In some cases, we know that every name that could be found by
// this qualified name lookup will also be on the identifier chain. For // this qualified name lookup will also be on the identifier chain. For
// example, inside a class without any base classes, we never need to // example, inside a class without any base classes, we never need to
// perform qualified lookup because all of the members are on top of the // perform qualified lookup because all of the members are on top of the
// identifier chain. // identifier chain.
if (isa<RecordDecl>(Ctx)) {
R = LookupQualifiedName(Ctx, Name, NameKind, RedeclarationOnly); R = LookupQualifiedName(Ctx, Name, NameKind, RedeclarationOnly);
if (R) if (R)
return std::make_pair(true, R); return std::make_pair(true, R);
} }
if (Ctx->getParent() != Ctx->getLexicalParent()
|| isa<CXXMethodDecl>(Ctx)) {
// It is out of line defined C++ method or struct, we continue
// doing name lookup in parent context. Once we will find namespace
// or translation-unit we save it for possible checking
// using-directives later.
for (OutOfLineCtx = Ctx; OutOfLineCtx && !OutOfLineCtx->isFileContext();
OutOfLineCtx = OutOfLineCtx->getParent()) {
R = LookupQualifiedName(OutOfLineCtx, Name, NameKind, RedeclarationOnly);
if (R)
return std::make_pair(true, R);
}
}
} }
} }

View File

@ -146,3 +146,13 @@ struct HasAnotherMemberType : HasMemberType1, HasMemberType2 {
struct UsesAmbigMemberType : HasMemberType1, HasMemberType2 { struct UsesAmbigMemberType : HasMemberType1, HasMemberType2 {
type t; // expected-error{{member 'type' found in multiple base classes of different types}} type t; // expected-error{{member 'type' found in multiple base classes of different types}}
}; };
struct X0 {
struct Inner {
static const int m;
};
static const int n = 17;
};
const int X0::Inner::m = n;