diff options
-rw-r--r-- | clang/include/clang/Sema/Lookup.h | 31 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 83 | ||||
-rw-r--r-- | clang/test/Modules/Inputs/decl.h | 2 | ||||
-rw-r--r-- | clang/test/Modules/Inputs/def.h | 7 | ||||
-rw-r--r-- | clang/test/Modules/Inputs/module.map | 5 | ||||
-rw-r--r-- | clang/test/Modules/decldef.mm | 17 |
6 files changed, 116 insertions, 29 deletions
diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h index 6630bb2981e..9f8a239d9f2 100644 --- a/clang/include/clang/Sema/Lookup.h +++ b/clang/include/clang/Sema/Lookup.h @@ -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; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 9f1e9a5516b..a6ad8f8fcf5 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -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); } diff --git a/clang/test/Modules/Inputs/decl.h b/clang/test/Modules/Inputs/decl.h new file mode 100644 index 00000000000..8dbe11eccc7 --- /dev/null +++ b/clang/test/Modules/Inputs/decl.h @@ -0,0 +1,2 @@ +@class A; +typedef struct B B; diff --git a/clang/test/Modules/Inputs/def.h b/clang/test/Modules/Inputs/def.h new file mode 100644 index 00000000000..c9bc36d61da --- /dev/null +++ b/clang/test/Modules/Inputs/def.h @@ -0,0 +1,7 @@ +@interface A +@end + +struct B { + int b1; +}; + diff --git a/clang/test/Modules/Inputs/module.map b/clang/test/Modules/Inputs/module.map index f25a36edfbd..6b93a6acef4 100644 --- a/clang/test/Modules/Inputs/module.map +++ b/clang/test/Modules/Inputs/module.map @@ -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" } +}
\ No newline at end of file diff --git a/clang/test/Modules/decldef.mm b/clang/test/Modules/decldef.mm new file mode 100644 index 00000000000..bbdcd9cb8fa --- /dev/null +++ b/clang/test/Modules/decldef.mm @@ -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. +} |