forked from OSchip/llvm-project
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:
parent
753441e318
commit
7f737c0015
|
@ -565,6 +565,12 @@ public:
|
|||
return const_cast<DeclContext*>(this)->getLexicalParent();
|
||||
}
|
||||
|
||||
DeclContext *getLookupParent();
|
||||
|
||||
const DeclContext *getLookupParent() const {
|
||||
return const_cast<DeclContext*>(this)->getLookupParent();
|
||||
}
|
||||
|
||||
ASTContext &getParentASTContext() const {
|
||||
return cast<Decl>(this)->getASTContext();
|
||||
}
|
||||
|
|
|
@ -420,6 +420,22 @@ void DeclContext::DestroyDecls(ASTContext &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 {
|
||||
if (isFileContext())
|
||||
return false;
|
||||
|
|
|
@ -636,6 +636,15 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) {
|
|||
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>
|
||||
Sema::CppLookupName(Scope *S, DeclarationName Name,
|
||||
LookupNameKind NameKind, bool RedeclarationOnly) {
|
||||
|
@ -694,30 +703,23 @@ Sema::CppLookupName(Scope *S, DeclarationName Name,
|
|||
}
|
||||
if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) {
|
||||
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
|
||||
// this qualified name lookup will also be on the identifier chain. For
|
||||
// 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
|
||||
// identifier chain.
|
||||
if (isa<RecordDecl>(Ctx)) {
|
||||
R = LookupQualifiedName(Ctx, Name, NameKind, RedeclarationOnly);
|
||||
if (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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -146,3 +146,13 @@ struct HasAnotherMemberType : HasMemberType1, HasMemberType2 {
|
|||
struct UsesAmbigMemberType : HasMemberType1, HasMemberType2 {
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue