When name lookup comes across a declaration that is in a module that
is not visible, look for any previous declarations of that entity that might be visible. llvm-svn: 146563
This commit is contained in:
parent
5533a55172
commit
4a814568b2
|
@ -266,23 +266,36 @@ public:
|
|||
return Paths;
|
||||
}
|
||||
|
||||
/// \brief Tests whether the given declaration is acceptable.
|
||||
bool isAcceptableDecl(NamedDecl *D) const {
|
||||
if (!D->isInIdentifierNamespace(IDNS))
|
||||
return false;
|
||||
|
||||
/// \brief Determine whether the given declaration is visible to the
|
||||
/// program.
|
||||
static bool isVisible(NamedDecl *D) {
|
||||
// So long as this declaration is not module-private or was parsed as
|
||||
// part of this translation unit (i.e., in the module), we're allowed to
|
||||
// find it.
|
||||
// part of this translation unit (i.e., in the module), it's visible.
|
||||
if (!D->isModulePrivate() || !D->isFromASTFile())
|
||||
return true;
|
||||
|
||||
|
||||
// FIXME: We should be allowed to refer to a module-private name from
|
||||
// within the same module, e.g., during template instantiation.
|
||||
// This requires us know which module a particular declaration came from.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Retrieve the accepted (re)declaration of the given declaration,
|
||||
/// if there is one.
|
||||
NamedDecl *getAcceptableDecl(NamedDecl *D) const {
|
||||
if (!D->isInIdentifierNamespace(IDNS))
|
||||
return 0;
|
||||
|
||||
if (isVisible(D))
|
||||
return D;
|
||||
|
||||
return getAcceptableDeclSlow(D);
|
||||
}
|
||||
|
||||
private:
|
||||
NamedDecl *getAcceptableDeclSlow(NamedDecl *D) const;
|
||||
public:
|
||||
|
||||
/// \brief Returns the identifier namespace mask for this lookup.
|
||||
unsigned getIdentifierNamespace() const {
|
||||
return IDNS;
|
||||
|
|
|
@ -321,6 +321,12 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) {
|
|||
delete Paths;
|
||||
}
|
||||
|
||||
static NamedDecl *getVisibleDecl(NamedDecl *D);
|
||||
|
||||
NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
|
||||
return getVisibleDecl(D);
|
||||
}
|
||||
|
||||
/// Resolves the result kind of this lookup.
|
||||
void LookupResult::resolveKind() {
|
||||
unsigned N = Decls.size();
|
||||
|
@ -649,7 +655,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
|
|||
DeclContext::lookup_const_iterator I, E;
|
||||
for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
|
||||
NamedDecl *D = *I;
|
||||
if (R.isAcceptableDecl(D)) {
|
||||
if ((D = R.getAcceptableDecl(D))) {
|
||||
R.addDecl(D);
|
||||
Found = true;
|
||||
}
|
||||
|
@ -875,9 +881,9 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
|
|||
// Check whether the IdResolver has anything in this scope.
|
||||
bool Found = false;
|
||||
for (; I != IEnd && S->isDeclScope(*I); ++I) {
|
||||
if (R.isAcceptableDecl(*I)) {
|
||||
if (NamedDecl *ND = R.getAcceptableDecl(*I)) {
|
||||
Found = true;
|
||||
R.addDecl(*I);
|
||||
R.addDecl(ND);
|
||||
}
|
||||
}
|
||||
if (Found) {
|
||||
|
@ -926,8 +932,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
|
|||
if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable(
|
||||
Name.getAsIdentifierInfo(),
|
||||
ClassDeclared)) {
|
||||
if (R.isAcceptableDecl(Ivar)) {
|
||||
R.addDecl(Ivar);
|
||||
if (NamedDecl *ND = R.getAcceptableDecl(Ivar)) {
|
||||
R.addDecl(ND);
|
||||
R.resolveKind();
|
||||
return true;
|
||||
}
|
||||
|
@ -977,13 +983,13 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
|
|||
// Check whether the IdResolver has anything in this scope.
|
||||
bool Found = false;
|
||||
for (; I != IEnd && S->isDeclScope(*I); ++I) {
|
||||
if (R.isAcceptableDecl(*I)) {
|
||||
if (NamedDecl *ND = R.getAcceptableDecl(*I)) {
|
||||
// We found something. Look for anything else in our scope
|
||||
// with this same name and in an acceptable identifier
|
||||
// namespace, so that we can construct an overload set if we
|
||||
// need to.
|
||||
Found = true;
|
||||
R.addDecl(*I);
|
||||
R.addDecl(ND);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1047,6 +1053,40 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
|
|||
return !R.empty();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the previous declaration of D.
|
||||
static NamedDecl *getPreviousDeclaration(NamedDecl *D) {
|
||||
if (TagDecl *TD = dyn_cast<TagDecl>(D))
|
||||
return TD->getPreviousDeclaration();
|
||||
if (VarDecl *VD = dyn_cast<VarDecl>(D))
|
||||
return VD->getPreviousDeclaration();
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
|
||||
return FD->getPreviousDeclaration();
|
||||
if (RedeclarableTemplateDecl *RTD = dyn_cast<RedeclarableTemplateDecl>(D))
|
||||
return RTD->getPreviousDeclaration();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the visible declaration corresponding to D, if any.
|
||||
///
|
||||
/// This routine determines whether the declaration D is visible in the current
|
||||
/// module, with the current imports. If not, it checks whether any
|
||||
/// redeclaration of D is visible, and if so, returns that declaration.
|
||||
///
|
||||
/// \returns D, or a visible previous declaration of D, whichever is more recent
|
||||
/// and visible. If no declaration of D is visible, returns null.
|
||||
static NamedDecl *getVisibleDecl(NamedDecl *D) {
|
||||
if (LookupResult::isVisible(D))
|
||||
return D;
|
||||
|
||||
while ((D = getPreviousDeclaration(D))) {
|
||||
if (LookupResult::isVisible(D))
|
||||
return D;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Perform unqualified name lookup starting from a given
|
||||
/// scope.
|
||||
///
|
||||
|
@ -1125,10 +1165,11 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
|
|||
|
||||
// If this declaration is module-private and it came from an AST
|
||||
// file, we can't see it.
|
||||
if ((*I)->isModulePrivate() && (*I)->isFromASTFile())
|
||||
NamedDecl *D = getVisibleDecl(*I);
|
||||
if (!D)
|
||||
continue;
|
||||
|
||||
R.addDecl(*I);
|
||||
|
||||
R.addDecl(D);
|
||||
|
||||
if ((*I)->getAttr<OverloadableAttr>()) {
|
||||
// If this declaration has the "overloadable" attribute, we
|
||||
|
@ -1145,7 +1186,10 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
|
|||
for (++LastI; LastI != IEnd; ++LastI) {
|
||||
if (!S->isDeclScope(*LastI))
|
||||
break;
|
||||
R.addDecl(*LastI);
|
||||
|
||||
D = getVisibleDecl(*LastI);
|
||||
if (D)
|
||||
R.addDecl(D);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2712,7 +2756,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
|
|||
DEnd = CurCtx->decls_end();
|
||||
D != DEnd; ++D) {
|
||||
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) {
|
||||
if (Result.isAcceptableDecl(ND)) {
|
||||
if ((ND = Result.getAcceptableDecl(ND))) {
|
||||
Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
|
||||
Visited.add(ND);
|
||||
}
|
||||
|
@ -2723,17 +2767,16 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
|
|||
PEnd = ForwardProto->protocol_end();
|
||||
P != PEnd;
|
||||
++P) {
|
||||
if (Result.isAcceptableDecl(*P)) {
|
||||
Consumer.FoundDecl(*P, Visited.checkHidden(*P), Ctx, InBaseClass);
|
||||
Visited.add(*P);
|
||||
if (NamedDecl *ND = Result.getAcceptableDecl(*P)) {
|
||||
Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
|
||||
Visited.add(ND);
|
||||
}
|
||||
}
|
||||
} else if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) {
|
||||
ObjCInterfaceDecl *IFace = Class->getForwardInterfaceDecl();
|
||||
if (Result.isAcceptableDecl(IFace)) {
|
||||
Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), Ctx,
|
||||
InBaseClass);
|
||||
Visited.add(IFace);
|
||||
if (NamedDecl *ND = Result.getAcceptableDecl(IFace)) {
|
||||
Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
|
||||
Visited.add(ND);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2873,7 +2916,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
|
|||
for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
|
||||
D != DEnd; ++D) {
|
||||
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
|
||||
if (Result.isAcceptableDecl(ND)) {
|
||||
if ((ND = Result.getAcceptableDecl(ND))) {
|
||||
Consumer.FoundDecl(ND, Visited.checkHidden(ND), 0, false);
|
||||
Visited.add(ND);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
@class A;
|
||||
typedef struct B B;
|
|
@ -0,0 +1,7 @@
|
|||
@interface A
|
||||
@end
|
||||
|
||||
struct B {
|
||||
int b1;
|
||||
};
|
||||
|
|
@ -36,3 +36,8 @@ module category_bottom {
|
|||
module redeclarations_left { header "redeclarations_left.h" }
|
||||
module redeclarations_right { header "redeclarations_right.h" }
|
||||
module load_failure { header "load_failure.h" }
|
||||
|
||||
module decldef {
|
||||
explicit module Decl { header "decl.h" }
|
||||
explicit module Def { header "def.h" }
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: %clang_cc1 -I %S/Inputs -fmodule-cache-path %t %s -verify
|
||||
|
||||
__import_module__ decldef;
|
||||
A *a1; // expected-error{{unknown type name 'A'}}
|
||||
B *b1; // expected-error{{unknown type name 'B'}}
|
||||
|
||||
__import_module__ decldef.Decl;
|
||||
|
||||
// FIXME: No link between @interface (which we can't see) and @class
|
||||
// (which we can).
|
||||
// A *a2;
|
||||
B *b;
|
||||
|
||||
void testB() {
|
||||
B b; // FIXME: Should error, because we can't see the definition.
|
||||
}
|
Loading…
Reference in New Issue