From: Lawrence Crowl Date: Thu, 20 Jun 2013 21:14:14 +0000 (+0000) Subject: This patch adds new private headers to the module map. Private X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bc3f628815b3841dc99109e7f67f9afa7793bc94;p=clang This patch adds new private headers to the module map. Private headers may be included from within the module, but not from outside the module. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184471 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/Modules.rst b/docs/Modules.rst index fdf597a5a9..cd430a2ad2 100644 --- a/docs/Modules.rst +++ b/docs/Modules.rst @@ -231,8 +231,8 @@ Module map files use a simplified form of the C99 lexer, with the same rules for ``config_macros`` ``export`` ``module`` ``conflict`` ``framework`` ``requires`` - ``exclude`` ``header`` ``umbrella`` - ``explicit`` ``link`` + ``exclude`` ``header`` ``private`` + ``explicit`` ``link`` ``umbrella`` Module map file --------------- @@ -360,6 +360,7 @@ A header declaration specifies that a particular header is associated with the e *header-declaration*: ``umbrella``:sub:`opt` ``header`` *string-literal* + ``private`` ``header`` *string-literal* ``exclude`` ``header`` *string-literal* A header declaration that does not contain ``exclude`` specifies a header that contributes to the enclosing module. Specifically, when the module is built, the named header will be parsed and its declarations will be (logically) placed into the enclosing submodule. @@ -372,6 +373,8 @@ A header with the ``umbrella`` specifier is called an umbrella header. An umbrel ``-Wincomplete-umbrella`` warning option to ask Clang to complain about headers not covered by the umbrella header or the module map. +A header with the ``private`` specifier may not be included from outside the module itself. + A header with the ``exclude`` specifier is excluded from the module. It will not be included when the module is built, nor will it be considered to be part of the module. **Example**: The C header ``assert.h`` is an excellent candidate for an excluded header, because it is meant to be included multiple times (possibly with different ``NDEBUG`` settings). diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 49acbd5a31..8d1d18bb97 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -585,7 +585,9 @@ def warn_forgotten_module_header : Warning< InGroup, DefaultIgnore; def err_expected_id_building_module : Error< "expected a module name in '__building_module' expression">; - +def error_use_of_private_header_outside_module : Error< + "use of private header from outside its module: '%0'">; + def warn_header_guard : Warning< "%0 is used as a header guard here, followed by #define of a different macro">, InGroup>; diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h index d2a43f0219..8d7913d709 100644 --- a/include/clang/Basic/Module.h +++ b/include/clang/Basic/Module.h @@ -77,11 +77,14 @@ private: public: /// \brief The headers that are part of this module. - SmallVector Headers; + SmallVector NormalHeaders; /// \brief The headers that are explicitly excluded from this module. SmallVector ExcludedHeaders; + /// \brief The headers that are private to this module. + llvm::SmallVector PrivateHeaders; + /// \brief The set of language features required to use this module. /// /// If any of these features is not present, the \c IsAvailable bit diff --git a/include/clang/Lex/DirectoryLookup.h b/include/clang/Lex/DirectoryLookup.h index 261dfabc0f..6675ea22a7 100644 --- a/include/clang/Lex/DirectoryLookup.h +++ b/include/clang/Lex/DirectoryLookup.h @@ -16,6 +16,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceManager.h" +#include "clang/Lex/ModuleMap.h" namespace clang { class HeaderMap; @@ -158,7 +159,7 @@ public: const FileEntry *LookupFile(StringRef Filename, HeaderSearch &HS, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, - Module **SuggestedModule, + ModuleMap::KnownHeader *SuggestedModule, bool &InUserSpecifiedSystemFramework) const; private: @@ -166,7 +167,7 @@ private: StringRef Filename, HeaderSearch &HS, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, - Module **SuggestedModule, + ModuleMap::KnownHeader *SuggestedModule, bool &InUserSpecifiedSystemHeader) const; }; diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h index 838df6831a..4e54fe0b2c 100644 --- a/include/clang/Lex/HeaderSearch.h +++ b/include/clang/Lex/HeaderSearch.h @@ -56,6 +56,10 @@ struct HeaderFileInfo { /// \brief Whether this header is part of the module that we are building. unsigned isCompilingModuleHeader : 1; + + /// \brief Whether this header is part of the module that we are building. + /// This is an instance of ModuleMap::ModuleHeaderRole. + unsigned HeaderRole : 2; /// \brief Whether this structure is considered to already have been /// "resolved", meaning that it was loaded from the external source. @@ -97,6 +101,7 @@ struct HeaderFileInfo { HeaderFileInfo() : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User), External(false), isModuleHeader(false), isCompilingModuleHeader(false), + HeaderRole(ModuleMap::NormalHeader), Resolved(false), IndexHeaderMapHeader(false), NumIncludes(0), ControllingMacroID(0), ControllingMacro(0) {} @@ -110,6 +115,16 @@ struct HeaderFileInfo { return isImport || isPragmaOnce || NumIncludes || ControllingMacro || ControllingMacroID; } + + /// \brief Get the HeaderRole properly typed. + ModuleMap::ModuleHeaderRole getHeaderRole() const { + return static_cast(HeaderRole); + } + + /// \brief Set the HeaderRole properly typed. + void setHeaderRole(ModuleMap::ModuleHeaderRole Role) { + HeaderRole = Role; + } }; /// \brief An external source of header file information, which may supply @@ -357,7 +372,7 @@ public: const FileEntry *CurFileEnt, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, - Module **SuggestedModule, + ModuleMap::KnownHeader *SuggestedModule, bool SkipCache = false); /// \brief Look up a subframework for the specified \#include file. @@ -371,7 +386,7 @@ public: const FileEntry *RelativeFileEnt, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, - Module **SuggestedModule); + ModuleMap::KnownHeader *SuggestedModule); /// \brief Look up the specified framework name in our framework cache. /// \returns The DirectoryEntry it is in if we know, null otherwise. @@ -408,7 +423,9 @@ public: } /// \brief Mark the specified file as part of a module. - void MarkFileModuleHeader(const FileEntry *File, bool IsCompiledModuleHeader); + void MarkFileModuleHeader(const FileEntry *File, + ModuleMap::ModuleHeaderRole Role, + bool IsCompiledModuleHeader); /// \brief Increment the count for the number of times the specified /// FileEntry has been entered. @@ -484,7 +501,7 @@ public: /// \brief Retrieve the module that corresponds to the given file, if any. /// /// \param File The header that we wish to map to a module. - Module *findModuleForHeader(const FileEntry *File) const; + ModuleMap::KnownHeader findModuleForHeader(const FileEntry *File) const; /// \brief Read the contents of the given module map file. /// diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h index b33b9e5ba6..924e696672 100644 --- a/include/clang/Lex/ModuleMap.h +++ b/include/clang/Lex/ModuleMap.h @@ -58,24 +58,40 @@ class ModuleMap { /// \brief The top-level modules that are known. llvm::StringMap Modules; +public: + /// \brief Describes the role of a module header. + enum ModuleHeaderRole { + /// \brief This header is normally included in the module. + NormalHeader, + /// \brief This header is included but private. + PrivateHeader, + /// \brief This header is explicitly excluded from the module. + ExcludedHeader + // Caution: Adding an enumerator needs other changes. + // Adjust the number of bits for KnownHeader::Storage. + // Adjust the bitfield HeaderFileInfo::HeaderRole size. + // Adjust the HeaderFileInfoTrait::ReadData streaming. + // Adjust the HeaderFileInfoTrait::EmitData streaming. + }; + /// \brief A header that is known to reside within a given module, /// whether it was included or excluded. class KnownHeader { - llvm::PointerIntPair Storage; + llvm::PointerIntPair Storage; public: - KnownHeader() : Storage(0, false) { } - KnownHeader(Module *M, bool Excluded) : Storage(M, Excluded) { } + KnownHeader() : Storage(0, NormalHeader) { } + KnownHeader(Module *M, ModuleHeaderRole Role) : Storage(M, Role) { } /// \brief Retrieve the module the header is stored in. Module *getModule() const { return Storage.getPointer(); } - /// \brief Whether this header is explicitly excluded from the module. - bool isExcluded() const { return Storage.getInt(); } + /// \brief The role of this header within the module. + ModuleHeaderRole getRole() const { return Storage.getInt(); } /// \brief Whether this header is available in the module. bool isAvailable() const { - return !isExcluded() && getModule()->isAvailable(); + return getRole() != ExcludedHeader && getModule()->isAvailable(); } // \brief Whether this known header is valid (i.e., it has an @@ -83,6 +99,7 @@ class ModuleMap { LLVM_EXPLICIT operator bool() const { return Storage.getPointer() != 0; } }; +private: typedef llvm::DenseMap HeadersMap; /// \brief Mapping from each header to the module that owns the contents of @@ -185,9 +202,10 @@ public: /// /// \param File The header file that is likely to be included. /// - /// \returns The module that owns the given header file, or null to indicate + /// \returns The module KnownHeader, which provides the module that owns the + /// given header file. The KnownHeader is default constructed to indicate /// that no module owns this header file. - Module *findModuleForHeader(const FileEntry *File); + KnownHeader findModuleForHeader(const FileEntry *File); /// \brief Determine whether the given header is part of a module /// marked 'unavailable'. @@ -310,9 +328,9 @@ public: void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir); /// \brief Adds this header to the given module. - /// \param Excluded Whether this header is explicitly excluded from the - /// module; otherwise, it's included in the module. - void addHeader(Module *Mod, const FileEntry *Header, bool Excluded); + /// \param Role The role of the header wrt the module. + void addHeader(Module *Mod, const FileEntry *Header, + ModuleHeaderRole Role); /// \brief Parse the given module map file, and record any modules we /// encounter. diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index e993ce762f..60051ec112 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -20,6 +20,7 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/MacroInfo.h" +#include "clang/Lex/ModuleMap.h" #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/PTHLexer.h" #include "clang/Lex/PTHManager.h" @@ -1227,12 +1228,12 @@ public: /// /// Returns null on failure. \p isAngled indicates whether the file /// reference is for system \#include's or not (i.e. using <> instead of ""). - const FileEntry *LookupFile(StringRef Filename, + const FileEntry *LookupFile(SourceLocation FilenameLoc, StringRef Filename, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, - Module **SuggestedModule, + ModuleMap::KnownHeader *SuggestedModule, bool SkipCache = false); /// GetCurLookup - The DirectoryLookup structure used to find the current diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index b6ab2d8347..651b4a9df2 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -623,7 +623,9 @@ namespace clang { /// \brief Specifies a configuration macro for this module. SUBMODULE_CONFIG_MACRO = 11, /// \brief Specifies a conflict with another module. - SUBMODULE_CONFLICT = 12 + SUBMODULE_CONFLICT = 12, + /// \brief Specifies a header that is private to this submodule. + SUBMODULE_PRIVATE_HEADER = 13 }; /// \brief Record types used within a comments block. diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp index 13518cde66..8ac098ca79 100644 --- a/lib/Basic/Module.cpp +++ b/lib/Basic/Module.cpp @@ -293,10 +293,10 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { OS << "\n"; } - for (unsigned I = 0, N = Headers.size(); I != N; ++I) { + for (unsigned I = 0, N = NormalHeaders.size(); I != N; ++I) { OS.indent(Indent + 2); OS << "header \""; - OS.write_escaped(Headers[I]->getName()); + OS.write_escaped(NormalHeaders[I]->getName()); OS << "\"\n"; } @@ -306,6 +306,13 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { OS.write_escaped(ExcludedHeaders[I]->getName()); OS << "\"\n"; } + + for (unsigned I = 0, N = PrivateHeaders.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "private header \""; + OS.write_escaped(PrivateHeaders[I]->getName()); + OS << "\"\n"; + } for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end(); MI != MIEnd; ++MI) diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 5c7567fa8c..91eccbb26f 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -172,11 +172,12 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts, return; // Add includes for each of these headers. - for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) { - const FileEntry *Header = Module->Headers[I]; + for (unsigned I = 0, N = Module->NormalHeaders.size(); I != N; ++I) { + const FileEntry *Header = Module->NormalHeaders[I]; Module->addTopHeader(Header); addHeaderInclude(Header, Includes, LangOpts); } + // Note that Module->PrivateHeaders will not be a TopHeader. if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) { Module->addTopHeader(UmbrellaHeader); diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp index 46745b6b9a..efe6005ed7 100644 --- a/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -371,7 +371,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, // Lookup file via Preprocessor, like a #include. const DirectoryLookup *CurDir; - const FileEntry *FE = PP->LookupFile(Filename, false, NULL, CurDir, + const FileEntry *FE = PP->LookupFile(Pos, Filename, false, NULL, CurDir, NULL, NULL, 0); if (!FE) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index 8a99ed2988..d2bc5ad5e5 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -223,7 +223,7 @@ const FileEntry *DirectoryLookup::LookupFile( HeaderSearch &HS, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, - Module **SuggestedModule, + ModuleMap::KnownHeader *SuggestedModule, bool &InUserSpecifiedSystemFramework) const { InUserSpecifiedSystemFramework = false; @@ -337,7 +337,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( HeaderSearch &HS, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, - Module **SuggestedModule, + ModuleMap::KnownHeader *SuggestedModule, bool &InUserSpecifiedSystemFramework) const { FileManager &FileMgr = HS.getFileMgr(); @@ -496,11 +496,11 @@ const FileEntry *HeaderSearch::LookupFile( const FileEntry *CurFileEnt, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, - Module **SuggestedModule, + ModuleMap::KnownHeader *SuggestedModule, bool SkipCache) { if (SuggestedModule) - *SuggestedModule = 0; + *SuggestedModule = ModuleMap::KnownHeader(); // If 'Filename' is absolute, check to see if it exists and no searching. if (llvm::sys::path::is_absolute(Filename)) { @@ -676,7 +676,7 @@ LookupSubframeworkHeader(StringRef Filename, const FileEntry *ContextFileEnt, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, - Module **SuggestedModule) { + ModuleMap::KnownHeader *SuggestedModule) { assert(ContextFileEnt && "No context file?"); // Framework names must have a '/' in the filename. Find it. @@ -867,6 +867,7 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) { } void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE, + ModuleMap::ModuleHeaderRole Role, bool isCompilingModuleHeader) { if (FE->getUID() >= FileInfo.size()) FileInfo.resize(FE->getUID()+1); @@ -874,6 +875,7 @@ void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE, HeaderFileInfo &HFI = FileInfo[FE->getUID()]; HFI.isModuleHeader = true; HFI.isCompilingModuleHeader = isCompilingModuleHeader; + HFI.setHeaderRole(Role); } bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){ @@ -966,16 +968,14 @@ bool HeaderSearch::hasModuleMap(StringRef FileName, } while (true); } -Module *HeaderSearch::findModuleForHeader(const FileEntry *File) const { +ModuleMap::KnownHeader +HeaderSearch::findModuleForHeader(const FileEntry *File) const { if (ExternalSource) { // Make sure the external source has handled header info about this file, // which includes whether the file is part of a module. (void)getFileInfo(File); } - if (Module *Mod = ModMap.findModuleForHeader(File)) - return Mod; - - return 0; + return ModMap.findModuleForHeader(File); } bool HeaderSearch::loadModuleMapFile(const FileEntry *File) { diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index acb5694191..f46a87abc9 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -168,14 +168,14 @@ static bool isBuiltinHeader(StringRef FileName) { .Default(false); } -Module *ModuleMap::findModuleForHeader(const FileEntry *File) { +ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File) { HeadersMap::iterator Known = Headers.find(File); if (Known != Headers.end()) { // If a header is not available, don't report that it maps to anything. if (!Known->second.isAvailable()) - return 0; + return KnownHeader(); - return Known->second.getModule(); + return Known->second; } // If we've found a builtin header within Clang's builtin include directory, @@ -190,9 +190,9 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) { if (Known != Headers.end()) { // If a header is not available, don't report that it maps to anything. if (!Known->second.isAvailable()) - return 0; + return KnownHeader(); - return Known->second.getModule(); + return Known->second; } } @@ -262,14 +262,14 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) { UmbrellaDirs[SkippedDirs[I]] = Result; } - Headers[File] = KnownHeader(Result, /*Excluded=*/false); + Headers[File] = KnownHeader(Result, NormalHeader); // If a header corresponds to an unavailable module, don't report // that it maps to anything. if (!Result->isAvailable()) - return 0; + return KnownHeader(); - return Result; + return Headers[File]; } SkippedDirs.push_back(Dir); @@ -283,7 +283,7 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) { Dir = SourceMgr->getFileManager().getDirectory(DirName); } while (Dir); - return 0; + return KnownHeader(); } bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const { @@ -527,7 +527,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, // umbrella header "umbrella-header-name" Result->Umbrella = UmbrellaHeader; - Headers[UmbrellaHeader] = KnownHeader(Result, /*Excluded=*/false); + Headers[UmbrellaHeader] = KnownHeader(Result, NormalHeader); UmbrellaDirs[UmbrellaHeader->getDir()] = Result; // export * @@ -593,7 +593,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, } void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){ - Headers[UmbrellaHeader] = KnownHeader(Mod, /*Excluded=*/false); + Headers[UmbrellaHeader] = KnownHeader(Mod, NormalHeader); Mod->Umbrella = UmbrellaHeader; UmbrellaDirs[UmbrellaHeader->getDir()] = Mod; } @@ -604,15 +604,18 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) { } void ModuleMap::addHeader(Module *Mod, const FileEntry *Header, - bool Excluded) { - if (Excluded) { + ModuleHeaderRole Role) { + if (Role == ExcludedHeader) { Mod->ExcludedHeaders.push_back(Header); } else { - Mod->Headers.push_back(Header); + if (Role == PrivateHeader) + Mod->PrivateHeaders.push_back(Header); + else + Mod->NormalHeaders.push_back(Header); bool isCompilingModuleHeader = Mod->getTopLevelModule() == CompilingModule; - HeaderInfo.MarkFileModuleHeader(Header, isCompilingModuleHeader); + HeaderInfo.MarkFileModuleHeader(Header, Role, isCompilingModuleHeader); } - Headers[Header] = KnownHeader(Mod, Excluded); + Headers[Header] = KnownHeader(Mod, Role); } const FileEntry * @@ -688,7 +691,7 @@ Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) { while (const FileEntry *ExpansionFile = SrcMgr.getFileEntryForID(ExpansionFileID)) { // Find the module that owns this header (if any). - if (Module *Mod = findModuleForHeader(ExpansionFile)) + if (Module *Mod = findModuleForHeader(ExpansionFile).getModule()) return Mod; // No module owns this header, so look up the inclusion chain to see if @@ -724,6 +727,7 @@ namespace clang { LinkKeyword, ModuleKeyword, Period, + PrivateKeyword, UmbrellaKeyword, RequiresKeyword, Star, @@ -809,7 +813,8 @@ namespace clang { bool parseModuleId(ModuleId &Id); void parseModuleDecl(); void parseRequiresDecl(); - void parseHeaderDecl(SourceLocation UmbrellaLoc, SourceLocation ExcludeLoc); + void parseHeaderDecl(clang::MMToken::TokenKind, + SourceLocation LeadingLoc); void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc); void parseExportDecl(); void parseLinkDecl(); @@ -861,6 +866,7 @@ retry: .Case("header", MMToken::HeaderKeyword) .Case("link", MMToken::LinkKeyword) .Case("module", MMToken::ModuleKeyword) + .Case("private", MMToken::PrivateKeyword) .Case("requires", MMToken::RequiresKeyword) .Case("umbrella", MMToken::UmbrellaKeyword) .Default(MMToken::Identifier); @@ -1200,7 +1206,7 @@ void ModuleMapParser::parseModuleDecl() { case MMToken::UmbrellaKeyword: { SourceLocation UmbrellaLoc = consumeToken(); if (Tok.is(MMToken::HeaderKeyword)) - parseHeaderDecl(UmbrellaLoc, SourceLocation()); + parseHeaderDecl(MMToken::UmbrellaKeyword, UmbrellaLoc); else parseUmbrellaDirDecl(UmbrellaLoc); break; @@ -1209,7 +1215,7 @@ void ModuleMapParser::parseModuleDecl() { case MMToken::ExcludeKeyword: { SourceLocation ExcludeLoc = consumeToken(); if (Tok.is(MMToken::HeaderKeyword)) { - parseHeaderDecl(SourceLocation(), ExcludeLoc); + parseHeaderDecl(MMToken::ExcludeKeyword, ExcludeLoc); } else { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) << "exclude"; @@ -1217,8 +1223,19 @@ void ModuleMapParser::parseModuleDecl() { break; } + case MMToken::PrivateKeyword: { + SourceLocation PrivateLoc = consumeToken(); + if (Tok.is(MMToken::HeaderKeyword)) { + parseHeaderDecl(MMToken::PrivateKeyword, PrivateLoc); + } else { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) + << "private"; + } + break; + } + case MMToken::HeaderKeyword: - parseHeaderDecl(SourceLocation(), SourceLocation()); + parseHeaderDecl(MMToken::HeaderKeyword, SourceLocation()); break; case MMToken::LinkKeyword: @@ -1314,14 +1331,11 @@ static void appendSubframeworkPaths(Module *Mod, /// header-declaration: /// 'umbrella'[opt] 'header' string-literal /// 'exclude'[opt] 'header' string-literal -void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc, - SourceLocation ExcludeLoc) { +void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, + SourceLocation LeadingLoc) { assert(Tok.is(MMToken::HeaderKeyword)); consumeToken(); - bool Umbrella = UmbrellaLoc.isValid(); - bool Exclude = ExcludeLoc.isValid(); - assert(!(Umbrella && Exclude) && "Cannot have both 'umbrella' and 'exclude'"); // Parse the header name. if (!Tok.is(MMToken::StringLiteral)) { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) @@ -1333,7 +1347,7 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc, SourceLocation FileNameLoc = consumeToken(); // Check whether we already have an umbrella. - if (Umbrella && ActiveModule->Umbrella) { + if (LeadingToken == MMToken::UmbrellaKeyword && ActiveModule->Umbrella) { Diags.Report(FileNameLoc, diag::err_mmap_umbrella_clash) << ActiveModule->getFullModuleName(); HadError = true; @@ -1379,8 +1393,9 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc, // If this is a system module with a top-level header, this header // may have a counterpart (or replacement) in the set of headers // supplied by Clang. Find that builtin header. - if (ActiveModule->IsSystem && !Umbrella && BuiltinIncludeDir && - BuiltinIncludeDir != Directory && isBuiltinHeader(FileName)) { + if (ActiveModule->IsSystem && LeadingToken != MMToken::UmbrellaKeyword && + BuiltinIncludeDir && BuiltinIncludeDir != Directory && + isBuiltinHeader(FileName)) { SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName()); llvm::sys::path::append(BuiltinPathName, FileName); BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName); @@ -1403,10 +1418,10 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc, Diags.Report(FileNameLoc, diag::err_mmap_header_conflict) << FileName << OwningModule.getModule()->getFullModuleName(); HadError = true; - } else if (Umbrella) { + } else if (LeadingToken == MMToken::UmbrellaKeyword) { const DirectoryEntry *UmbrellaDir = File->getDir(); if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) { - Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash) + Diags.Report(LeadingLoc, diag::err_mmap_umbrella_clash) << UmbrellaModule->getFullModuleName(); HadError = true; } else { @@ -1415,17 +1430,25 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc, } } else { // Record this header. - Map.addHeader(ActiveModule, File, Exclude); + ModuleMap::ModuleHeaderRole Role = ModuleMap::NormalHeader; + if (LeadingToken == MMToken::ExcludeKeyword) + Role = ModuleMap::ExcludedHeader; + else if (LeadingToken == MMToken::PrivateKeyword) + Role = ModuleMap::PrivateHeader; + else + assert(LeadingToken == MMToken::HeaderKeyword); + + Map.addHeader(ActiveModule, File, Role); // If there is a builtin counterpart to this file, add it now. if (BuiltinFile) - Map.addHeader(ActiveModule, BuiltinFile, Exclude); + Map.addHeader(ActiveModule, BuiltinFile, Role); } - } else if (!Exclude) { + } else if (LeadingToken != MMToken::ExcludeKeyword) { // Ignore excluded header files. They're optional anyway. Diags.Report(FileNameLoc, diag::err_mmap_header_not_found) - << Umbrella << FileName; + << (LeadingToken == MMToken::UmbrellaKeyword) << FileName; HadError = true; } } @@ -1792,6 +1815,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) { case MMToken::ExplicitKeyword: case MMToken::ModuleKeyword: case MMToken::HeaderKeyword: + case MMToken::PrivateKeyword: case MMToken::UmbrellaKeyword: default: Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member) @@ -1918,6 +1942,7 @@ bool ModuleMapParser::parseModuleMapFile() { case MMToken::LinkKeyword: case MMToken::LSquare: case MMToken::Period: + case MMToken::PrivateKeyword: case MMToken::RBrace: case MMToken::RSquare: case MMToken::RequiresKeyword: diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index c25e317b42..026a7e7228 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -532,13 +532,14 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() { } const FileEntry *Preprocessor::LookupFile( + SourceLocation FilenameLoc, StringRef Filename, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, - Module **SuggestedModule, + ModuleMap::KnownHeader *SuggestedModule, bool SkipCache) { // If the header lookup mechanism may be relative to the current file, pass in // info about where the current file is. @@ -564,7 +565,32 @@ const FileEntry *Preprocessor::LookupFile( const FileEntry *FE = HeaderInfo.LookupFile( Filename, isAngled, FromDir, CurDir, CurFileEnt, SearchPath, RelativePath, SuggestedModule, SkipCache); - if (FE) return FE; + if (FE) { + if (SuggestedModule) { + Module *RequestedModule = SuggestedModule->getModule(); + if (RequestedModule) { + ModuleMap::ModuleHeaderRole Role = SuggestedModule->getRole(); + #ifndef NDEBUG + // Check for consistency between the module header role + // as obtained from the lookup and as obtained from the module. + // This check is not cheap, so enable it only for debugging. + SmallVectorImpl &PvtHdrs + = RequestedModule->PrivateHeaders; + SmallVectorImpl::iterator Look + = std::find(PvtHdrs.begin(), PvtHdrs.end(), FE); + bool IsPrivate = Look != PvtHdrs.end(); + assert((IsPrivate && Role == ModuleMap::PrivateHeader) + || (!IsPrivate && Role != ModuleMap::PrivateHeader)); + #endif + if (Role == ModuleMap::PrivateHeader) { + if (RequestedModule->getTopLevelModule() != getCurrentModule()) + Diag(FilenameLoc, diag::error_use_of_private_header_outside_module) + << Filename; + } + } + } + return FE; + } // Otherwise, see if this is a subframework header. If so, this is relative // to one of the headers on the #include stack. Walk the list of the current @@ -1390,9 +1416,10 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, SmallString<1024> RelativePath; // We get the raw path only if we have 'Callbacks' to which we later pass // the path. - Module *SuggestedModule = 0; + ModuleMap::KnownHeader SuggestedModule; + SourceLocation FilenameLoc = FilenameTok.getLocation(); const FileEntry *File = LookupFile( - Filename, isAngled, LookupFrom, CurDir, + FilenameLoc, Filename, isAngled, LookupFrom, CurDir, Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL, getLangOpts().Modules? &SuggestedModule : 0); @@ -1407,8 +1434,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, HeaderInfo.AddSearchPath(DL, isAngled); // Try the lookup again, skipping the cache. - File = LookupFile(Filename, isAngled, LookupFrom, CurDir, 0, 0, - getLangOpts().Modules? &SuggestedModule : 0, + File = LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, CurDir, + 0, 0, getLangOpts().Modules? &SuggestedModule : 0, /*SkipCache*/true); } } @@ -1429,7 +1456,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // brackets, we can attempt a lookup as though it were a quoted path to // provide the user with a possible fixit. if (isAngled) { - File = LookupFile(Filename, false, LookupFrom, CurDir, + File = LookupFile(FilenameLoc, Filename, false, LookupFrom, CurDir, Callbacks ? &SearchPath : 0, Callbacks ? &RelativePath : 0, getLangOpts().Modules ? &SuggestedModule : 0); @@ -1455,7 +1482,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // FIXME: Should we have a second loadModule() overload to avoid this // extra lookup step? SmallVector, 2> Path; - for (Module *Mod = SuggestedModule; Mod; Mod = Mod->Parent) + for (Module *Mod = SuggestedModule.getModule(); Mod; Mod = Mod->Parent) Path.push_back(std::make_pair(getIdentifierInfo(Mod->Name), FilenameTok.getLocation())); std::reverse(Path.begin(), Path.end()); @@ -1514,7 +1541,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, ModuleLoadResult Imported = TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility, /*IsIncludeDirective=*/true); - assert((Imported == 0 || Imported == SuggestedModule) && + assert((Imported == 0 || Imported == SuggestedModule.getModule()) && "the imported module is different than the suggested one"); if (!Imported && hadModuleLoaderFatalFailure()) { diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 3abca1f149..13fdf854fd 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -992,7 +992,8 @@ static bool EvaluateHasIncludeCommon(Token &Tok, // Search include directories. const DirectoryLookup *CurDir; const FileEntry *File = - PP.LookupFile(Filename, isAngled, LookupFrom, CurDir, NULL, NULL, NULL); + PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, CurDir, NULL, + NULL, NULL); // Get the result value. A result of true means the file exists. return File != 0; diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index b2ae4c9c44..4ba461a8a3 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -466,8 +466,8 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { // Search include directories for this file. const DirectoryLookup *CurDir; - const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir, NULL, NULL, - NULL); + const FileEntry *File = LookupFile(FilenameTok.getLocation(), Filename, + isAngled, 0, CurDir, NULL, NULL, NULL); if (File == 0) { if (!SuppressIncludeNotFoundError) Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index fd4f90e3ef..f33e0e14cf 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -1281,6 +1281,8 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d, using namespace clang::io; HeaderFileInfo HFI; unsigned Flags = *d++; + HFI.HeaderRole = static_cast + ((Flags >> 6) & 0x03); HFI.isImport = (Flags >> 5) & 0x01; HFI.isPragmaOnce = (Flags >> 4) & 0x01; HFI.DirInfo = (Flags >> 2) & 0x03; @@ -1307,7 +1309,7 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d, FileManager &FileMgr = Reader.getFileManager(); ModuleMap &ModMap = Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap(); - ModMap.addHeader(Mod, FileMgr.getFile(key.Filename), /*Excluded=*/false); + ModMap.addHeader(Mod, FileMgr.getFile(key.Filename), HFI.getHeaderRole()); } } @@ -3767,6 +3769,21 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { break; } + case SUBMODULE_PRIVATE_HEADER: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + // We lazily associate headers with their modules via the HeaderInfoTable. + // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead + // of complete filenames or remove it entirely. + break; + } + case SUBMODULE_TOPHEADER: { if (First) { Error("missing submodule metadata record at beginning of block"); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index ece297f3e5..3654ec27f4 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1476,7 +1476,8 @@ namespace { using namespace clang::io; uint64_t Start = Out.tell(); (void)Start; - unsigned char Flags = (Data.isImport << 5) + unsigned char Flags = (Data.HeaderRole << 6) + | (Data.isImport << 5) | (Data.isPragmaOnce << 4) | (Data.DirInfo << 2) | (Data.Resolved << 1) @@ -1507,7 +1508,7 @@ namespace { Emit32(Out, Offset); if (Data.isModuleHeader) { - Module *Mod = HS.findModuleForHeader(key.FE); + Module *Mod = HS.findModuleForHeader(key.FE).getModule(); Emit32(Out, Writer.getExistingSubmoduleID(Mod)); } @@ -2260,6 +2261,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev); + Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_PRIVATE_HEADER)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned PrivateHeaderAbbrev = Stream.EmitAbbrev(Abbrev); + Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework @@ -2333,11 +2339,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { } // Emit the headers. - for (unsigned I = 0, N = Mod->Headers.size(); I != N; ++I) { + for (unsigned I = 0, N = Mod->NormalHeaders.size(); I != N; ++I) { Record.clear(); Record.push_back(SUBMODULE_HEADER); Stream.EmitRecordWithBlob(HeaderAbbrev, Record, - Mod->Headers[I]->getName()); + Mod->NormalHeaders[I]->getName()); } // Emit the excluded headers. for (unsigned I = 0, N = Mod->ExcludedHeaders.size(); I != N; ++I) { @@ -2346,6 +2352,13 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record, Mod->ExcludedHeaders[I]->getName()); } + // Emit the private headers. + for (unsigned I = 0, N = Mod->PrivateHeaders.size(); I != N; ++I) { + Record.clear(); + Record.push_back(SUBMODULE_PRIVATE_HEADER); + Stream.EmitRecordWithBlob(PrivateHeaderAbbrev, Record, + Mod->PrivateHeaders[I]->getName()); + } ArrayRef TopHeaders = Mod->getTopHeaders(PP->getFileManager()); for (unsigned I = 0, N = TopHeaders.size(); I != N; ++I) {