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();
|
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue