From ecc2c090e7146c029dd9ee9a5a2fd66b275c01c0 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 1 Dec 2011 22:20:10 +0000 Subject: [PATCH] Implement name hiding for declarations deserialized from a non-visible module. When that module becomes visible, so do those declarations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145640 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclBase.h | 1 + include/clang/Serialization/ASTReader.h | 19 ++++++++++++++ lib/Serialization/ASTReader.cpp | 21 ++++++++++++++- lib/Serialization/ASTReaderDecl.cpp | 31 ++++++++++++++++++++--- lib/Serialization/ASTWriter.cpp | 4 +++ test/Modules/Inputs/submodules/hash_map.h | 1 + test/Modules/Inputs/submodules/module.map | 1 + test/Modules/Inputs/submodules/vector.h | 2 +- test/Modules/auto-module-import.c | 1 + test/Modules/diamond.c | 6 +++++ test/Modules/submodules-preprocess.cpp | 14 ++++++++++ test/Modules/submodules.cpp | 23 ++++++++++++++++- 12 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 test/Modules/Inputs/submodules/hash_map.h create mode 100644 test/Modules/submodules-preprocess.cpp diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 313cf606b8..ab36054969 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -278,6 +278,7 @@ protected: friend class ASTDeclWriter; friend class ASTDeclReader; + friend class ASTReader; private: void CheckAccessDeclContext() const; diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 3f66eb5118..bbcead0911 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -383,6 +383,15 @@ private: /// global submodule ID to produce a local ID. GlobalSubmoduleMapType GlobalSubmoduleMap; + /// \brief A set of hidden declarations. + typedef llvm::SmallVector HiddenNames; + + typedef llvm::DenseMap HiddenNamesMapType; + + /// \brief A mapping from each of the hidden submodules to the deserialized + /// declarations in that submodule that could be made visible. + HiddenNamesMapType HiddenNamesMap; + /// \brief A vector containing selectors that have already been loaded. /// /// This vector is indexed by the Selector ID (-1). NULL selector @@ -813,6 +822,9 @@ public: void makeModuleVisible(Module *Mod, Module::NameVisibilityKind NameVisibility); + /// \brief Make the names within this set of hidden names visible. + void makeNamesVisible(const HiddenNames &Names); + /// \brief Set the AST callbacks listener. void setListener(ASTReaderListener *listener) { Listener.reset(listener); @@ -829,6 +841,13 @@ public: ModuleMgr.addInMemoryBuffer(FileName, Buffer); } + /// \brief Finalizes the AST reader's state before writing an AST file to + /// disk. + /// + /// This operation may undo temporary state in the AST that should not be + /// emitted. + void finalizeForWriting(); + /// \brief Retrieve the module manager. ModuleManager &getModuleManager() { return ModuleMgr; } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 258baebc05..a083e24e9e 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -2439,6 +2439,11 @@ ASTReader::ASTReadResult ASTReader::validateFileEntries(ModuleFile &M) { return Success; } +void ASTReader::makeNamesVisible(const HiddenNames &Names) { + for (unsigned I = 0, N = Names.size(); I != N; ++I) + Names[I]->ModulePrivate = false; +} + void ASTReader::makeModuleVisible(Module *Mod, Module::NameVisibilityKind NameVisibility) { llvm::SmallPtrSet Visited; @@ -2457,8 +2462,13 @@ void ASTReader::makeModuleVisible(Module *Mod, // Update the module's name visibility. Mod->NameVisibility = NameVisibility; - // FIXME: If we've already deserialized any names from this module, + // If we've already deserialized any names from this module, // mark them as visible. + HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod); + if (Hidden != HiddenNamesMap.end()) { + makeNamesVisible(Hidden->second); + HiddenNamesMap.erase(Hidden); + } // Push any non-explicit submodules onto the stack to be marked as // visible. @@ -2776,6 +2786,15 @@ void ASTReader::InitializeContext() { } } +void ASTReader::finalizeForWriting() { + for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(), + HiddenEnd = HiddenNamesMap.end(); + Hidden != HiddenEnd; ++Hidden) { + makeNamesVisible(Hidden->second); + } + HiddenNamesMap.clear(); +} + /// \brief Retrieve the name of the original source file name /// directly from the AST file, without actually loading the AST /// file. diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 397671f85e..85cd72840a 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -86,6 +86,14 @@ namespace clang { Reader.ReadDeclarationNameInfo(F, NameInfo, R, I); } + serialization::SubmoduleID readSubmoduleID(const RecordData &R, + unsigned &I) { + if (I >= R.size()) + return 0; + + return Reader.getGlobalSubmoduleID(F, R[I++]); + } + void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data, const RecordData &R, unsigned &I); @@ -253,10 +261,25 @@ void ASTDeclReader::VisitDecl(Decl *D) { D->setAccess((AccessSpecifier)Record[Idx++]); D->FromASTFile = true; D->ModulePrivate = Record[Idx++]; - - unsigned SubmoduleID = Record[Idx++]; - // FIXME: Actual use the submodule ID to determine visibility. - (void)SubmoduleID; + + // Determine whether this declaration is part of a (sub)module. If so, it + // may not yet be visible. + if (unsigned SubmoduleID = readSubmoduleID(Record, Idx)) { + // Module-private declarations are never visible, so there is no work to do. + if (!D->ModulePrivate) { + if (Module *Owner = Reader.getSubmodule(SubmoduleID)) { + if (Owner->NameVisibility != Module::AllVisible) { + // The owning module is not visible. Mark this declaration as + // module-private, + D->ModulePrivate = true; + + // Note that this declaration was hidden because its owning module is + // not yet visible. + Reader.HiddenNamesMap[Owner].push_back(D); + } + } + } + } } void ASTDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index e37aa7320f..1b554ef3c4 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -2958,6 +2958,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, Module *WritingModule) { using namespace llvm; + // Make sure that the AST reader knows to finalize itself. + if (Chain) + Chain->finalizeForWriting(); + ASTContext &Context = SemaRef.Context; Preprocessor &PP = SemaRef.PP; diff --git a/test/Modules/Inputs/submodules/hash_map.h b/test/Modules/Inputs/submodules/hash_map.h new file mode 100644 index 0000000000..56f0749752 --- /dev/null +++ b/test/Modules/Inputs/submodules/hash_map.h @@ -0,0 +1 @@ +template class hash_map { }; diff --git a/test/Modules/Inputs/submodules/module.map b/test/Modules/Inputs/submodules/module.map index 6d19975c96..16cedac231 100644 --- a/test/Modules/Inputs/submodules/module.map +++ b/test/Modules/Inputs/submodules/module.map @@ -1,4 +1,5 @@ module std { module vector { header "vector.h" } module type_traits { header "type_traits.h" } + explicit module hash_map { header "hash_map.h" } } diff --git a/test/Modules/Inputs/submodules/vector.h b/test/Modules/Inputs/submodules/vector.h index 3123dd1c84..2dcf3e5731 100644 --- a/test/Modules/Inputs/submodules/vector.h +++ b/test/Modules/Inputs/submodules/vector.h @@ -1 +1 @@ -template class vector; +template class vector { }; diff --git a/test/Modules/auto-module-import.c b/test/Modules/auto-module-import.c index a161f33efa..1b5ef99590 100644 --- a/test/Modules/auto-module-import.c +++ b/test/Modules/auto-module-import.c @@ -11,3 +11,4 @@ #ifdef DEPENDS_ON_MODULE # error DEPENDS_ON_MODULE should have been hidden #endif + diff --git a/test/Modules/diamond.c b/test/Modules/diamond.c index 59181c533d..93722e9fe2 100644 --- a/test/Modules/diamond.c +++ b/test/Modules/diamond.c @@ -5,6 +5,12 @@ __import_module__ diamond_bottom; +// FIXME: We want 'bottom' to re-export left and right, and both of those to +// re-export 'top'. +__import_module__ diamond_top; +__import_module__ diamond_left; +__import_module__ diamond_right; + void test_diamond(int i, float f, double d, char c) { top(&i); left(&f); diff --git a/test/Modules/submodules-preprocess.cpp b/test/Modules/submodules-preprocess.cpp new file mode 100644 index 0000000000..1f0f37759c --- /dev/null +++ b/test/Modules/submodules-preprocess.cpp @@ -0,0 +1,14 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -Eonly -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/submodules %s -verify + +__import_module__ std.vector; + +vector vi; +remove_reference::type *int_ptr = 0; + +__import_module__ std.typetraits; // expected-error{{no submodule named 'typetraits' in module 'std'; did you mean 'type_traits'?}} + +vector vf; +remove_reference::type *int_ptr2 = 0; + +__import_module__ std.vector.compare; // expected-error{{no submodule named 'compare' in module 'std.vector'}} diff --git a/test/Modules/submodules.cpp b/test/Modules/submodules.cpp index fd1426d012..ce7054f307 100644 --- a/test/Modules/submodules.cpp +++ b/test/Modules/submodules.cpp @@ -1,7 +1,28 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -Eonly -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/submodules %s -verify // RUN: %clang_cc1 -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/submodules %s -verify __import_module__ std.vector; + +vector vi; + +// Note: remove_reference is not visible yet. +remove_reference::type *int_ptr = 0; // expected-error{{unknown type name 'remove_reference'}} \ +// expected-error{{expected unqualified-id}} + __import_module__ std.typetraits; // expected-error{{no submodule named 'typetraits' in module 'std'; did you mean 'type_traits'?}} + +vector vf; +remove_reference::type *int_ptr2 = 0; + __import_module__ std.vector.compare; // expected-error{{no submodule named 'compare' in module 'std.vector'}} + +__import_module__ std; // import everything in 'std' + +// hash_map still isn't available. +hash_map ints_to_floats; // expected-error{{unknown type name 'hash_map'}} \ +// expected-error{{expected unqualified-id}} + +__import_module__ std.hash_map; + +hash_map ints_to_floats2; + -- 2.50.1