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.

llvm-svn: 184471
This commit is contained in:
Lawrence Crowl 2013-06-20 21:14:14 +00:00
parent 664c4c678b
commit b53e5483b0
18 changed files with 229 additions and 91 deletions

View File

@ -231,8 +231,8 @@ Module map files use a simplified form of the C99 lexer, with the same rules for
``config_macros`` ``export`` ``module`` ``config_macros`` ``export`` ``module``
``conflict`` ``framework`` ``requires`` ``conflict`` ``framework`` ``requires``
``exclude`` ``header`` ``umbrella`` ``exclude`` ``header`` ``private``
``explicit`` ``link`` ``explicit`` ``link`` ``umbrella``
Module map file Module map file
--------------- ---------------
@ -360,6 +360,7 @@ A header declaration specifies that a particular header is associated with the e
*header-declaration*: *header-declaration*:
``umbrella``:sub:`opt` ``header`` *string-literal* ``umbrella``:sub:`opt` ``header`` *string-literal*
``private`` ``header`` *string-literal*
``exclude`` ``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. 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 ``-Wincomplete-umbrella`` warning option to ask Clang to complain
about headers not covered by the umbrella header or the module map. 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. 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). **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).

View File

@ -585,7 +585,9 @@ def warn_forgotten_module_header : Warning<
InGroup<IncompleteModule>, DefaultIgnore; InGroup<IncompleteModule>, DefaultIgnore;
def err_expected_id_building_module : Error< def err_expected_id_building_module : Error<
"expected a module name in '__building_module' expression">; "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< def warn_header_guard : Warning<
"%0 is used as a header guard here, followed by #define of a different macro">, "%0 is used as a header guard here, followed by #define of a different macro">,
InGroup<DiagGroup<"header-guard">>; InGroup<DiagGroup<"header-guard">>;

View File

@ -77,11 +77,14 @@ private:
public: public:
/// \brief The headers that are part of this module. /// \brief The headers that are part of this module.
SmallVector<const FileEntry *, 2> Headers; SmallVector<const FileEntry *, 2> NormalHeaders;
/// \brief The headers that are explicitly excluded from this module. /// \brief The headers that are explicitly excluded from this module.
SmallVector<const FileEntry *, 2> ExcludedHeaders; SmallVector<const FileEntry *, 2> ExcludedHeaders;
/// \brief The headers that are private to this module.
llvm::SmallVector<const FileEntry *, 2> PrivateHeaders;
/// \brief The set of language features required to use this module. /// \brief The set of language features required to use this module.
/// ///
/// If any of these features is not present, the \c IsAvailable bit /// If any of these features is not present, the \c IsAvailable bit

View File

@ -16,6 +16,7 @@
#include "clang/Basic/LLVM.h" #include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManager.h"
#include "clang/Lex/ModuleMap.h"
namespace clang { namespace clang {
class HeaderMap; class HeaderMap;
@ -158,7 +159,7 @@ public:
const FileEntry *LookupFile(StringRef Filename, HeaderSearch &HS, const FileEntry *LookupFile(StringRef Filename, HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath, SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule, ModuleMap::KnownHeader *SuggestedModule,
bool &InUserSpecifiedSystemFramework) const; bool &InUserSpecifiedSystemFramework) const;
private: private:
@ -166,7 +167,7 @@ private:
StringRef Filename, HeaderSearch &HS, StringRef Filename, HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath, SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule, ModuleMap::KnownHeader *SuggestedModule,
bool &InUserSpecifiedSystemHeader) const; bool &InUserSpecifiedSystemHeader) const;
}; };

View File

@ -56,6 +56,10 @@ struct HeaderFileInfo {
/// \brief Whether this header is part of the module that we are building. /// \brief Whether this header is part of the module that we are building.
unsigned isCompilingModuleHeader : 1; 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 /// \brief Whether this structure is considered to already have been
/// "resolved", meaning that it was loaded from the external source. /// "resolved", meaning that it was loaded from the external source.
@ -97,6 +101,7 @@ struct HeaderFileInfo {
HeaderFileInfo() HeaderFileInfo()
: isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User), : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User),
External(false), isModuleHeader(false), isCompilingModuleHeader(false), External(false), isModuleHeader(false), isCompilingModuleHeader(false),
HeaderRole(ModuleMap::NormalHeader),
Resolved(false), IndexHeaderMapHeader(false), Resolved(false), IndexHeaderMapHeader(false),
NumIncludes(0), ControllingMacroID(0), ControllingMacro(0) {} NumIncludes(0), ControllingMacroID(0), ControllingMacro(0) {}
@ -110,6 +115,16 @@ struct HeaderFileInfo {
return isImport || isPragmaOnce || NumIncludes || ControllingMacro || return isImport || isPragmaOnce || NumIncludes || ControllingMacro ||
ControllingMacroID; ControllingMacroID;
} }
/// \brief Get the HeaderRole properly typed.
ModuleMap::ModuleHeaderRole getHeaderRole() const {
return static_cast<ModuleMap::ModuleHeaderRole>(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 /// \brief An external source of header file information, which may supply
@ -357,7 +372,7 @@ public:
const FileEntry *CurFileEnt, const FileEntry *CurFileEnt,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath, SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule, ModuleMap::KnownHeader *SuggestedModule,
bool SkipCache = false); bool SkipCache = false);
/// \brief Look up a subframework for the specified \#include file. /// \brief Look up a subframework for the specified \#include file.
@ -371,7 +386,7 @@ public:
const FileEntry *RelativeFileEnt, const FileEntry *RelativeFileEnt,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath, SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule); ModuleMap::KnownHeader *SuggestedModule);
/// \brief Look up the specified framework name in our framework cache. /// \brief Look up the specified framework name in our framework cache.
/// \returns The DirectoryEntry it is in if we know, null otherwise. /// \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. /// \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 /// \brief Increment the count for the number of times the specified
/// FileEntry has been entered. /// FileEntry has been entered.
@ -484,7 +501,7 @@ public:
/// \brief Retrieve the module that corresponds to the given file, if any. /// \brief Retrieve the module that corresponds to the given file, if any.
/// ///
/// \param File The header that we wish to map to a module. /// \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. /// \brief Read the contents of the given module map file.
/// ///

View File

@ -58,24 +58,40 @@ class ModuleMap {
/// \brief The top-level modules that are known. /// \brief The top-level modules that are known.
llvm::StringMap<Module *> Modules; llvm::StringMap<Module *> 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, /// \brief A header that is known to reside within a given module,
/// whether it was included or excluded. /// whether it was included or excluded.
class KnownHeader { class KnownHeader {
llvm::PointerIntPair<Module *, 1, bool> Storage; llvm::PointerIntPair<Module *, 2, ModuleHeaderRole> Storage;
public: public:
KnownHeader() : Storage(0, false) { } KnownHeader() : Storage(0, NormalHeader) { }
KnownHeader(Module *M, bool Excluded) : Storage(M, Excluded) { } KnownHeader(Module *M, ModuleHeaderRole Role) : Storage(M, Role) { }
/// \brief Retrieve the module the header is stored in. /// \brief Retrieve the module the header is stored in.
Module *getModule() const { return Storage.getPointer(); } Module *getModule() const { return Storage.getPointer(); }
/// \brief Whether this header is explicitly excluded from the module. /// \brief The role of this header within the module.
bool isExcluded() const { return Storage.getInt(); } ModuleHeaderRole getRole() const { return Storage.getInt(); }
/// \brief Whether this header is available in the module. /// \brief Whether this header is available in the module.
bool isAvailable() const { bool isAvailable() const {
return !isExcluded() && getModule()->isAvailable(); return getRole() != ExcludedHeader && getModule()->isAvailable();
} }
// \brief Whether this known header is valid (i.e., it has an // \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; } LLVM_EXPLICIT operator bool() const { return Storage.getPointer() != 0; }
}; };
private:
typedef llvm::DenseMap<const FileEntry *, KnownHeader> HeadersMap; typedef llvm::DenseMap<const FileEntry *, KnownHeader> HeadersMap;
/// \brief Mapping from each header to the module that owns the contents of /// \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. /// \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. /// 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 /// \brief Determine whether the given header is part of a module
/// marked 'unavailable'. /// marked 'unavailable'.
@ -310,9 +328,9 @@ public:
void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir); void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir);
/// \brief Adds this header to the given module. /// \brief Adds this header to the given module.
/// \param Excluded Whether this header is explicitly excluded from the /// \param Role The role of the header wrt the module.
/// module; otherwise, it's included in the module. void addHeader(Module *Mod, const FileEntry *Header,
void addHeader(Module *Mod, const FileEntry *Header, bool Excluded); ModuleHeaderRole Role);
/// \brief Parse the given module map file, and record any modules we /// \brief Parse the given module map file, and record any modules we
/// encounter. /// encounter.

View File

@ -20,6 +20,7 @@
#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceLocation.h"
#include "clang/Lex/Lexer.h" #include "clang/Lex/Lexer.h"
#include "clang/Lex/MacroInfo.h" #include "clang/Lex/MacroInfo.h"
#include "clang/Lex/ModuleMap.h"
#include "clang/Lex/PPCallbacks.h" #include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/PTHLexer.h" #include "clang/Lex/PTHLexer.h"
#include "clang/Lex/PTHManager.h" #include "clang/Lex/PTHManager.h"
@ -1227,12 +1228,12 @@ public:
/// ///
/// Returns null on failure. \p isAngled indicates whether the file /// Returns null on failure. \p isAngled indicates whether the file
/// reference is for system \#include's or not (i.e. using <> instead of ""). /// 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, bool isAngled, const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir, const DirectoryLookup *&CurDir,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath, SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule, ModuleMap::KnownHeader *SuggestedModule,
bool SkipCache = false); bool SkipCache = false);
/// GetCurLookup - The DirectoryLookup structure used to find the current /// GetCurLookup - The DirectoryLookup structure used to find the current

View File

@ -623,7 +623,9 @@ namespace clang {
/// \brief Specifies a configuration macro for this module. /// \brief Specifies a configuration macro for this module.
SUBMODULE_CONFIG_MACRO = 11, SUBMODULE_CONFIG_MACRO = 11,
/// \brief Specifies a conflict with another module. /// \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. /// \brief Record types used within a comments block.

View File

@ -293,10 +293,10 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS << "\n"; 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.indent(Indent + 2);
OS << "header \""; OS << "header \"";
OS.write_escaped(Headers[I]->getName()); OS.write_escaped(NormalHeaders[I]->getName());
OS << "\"\n"; OS << "\"\n";
} }
@ -306,6 +306,13 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS.write_escaped(ExcludedHeaders[I]->getName()); OS.write_escaped(ExcludedHeaders[I]->getName());
OS << "\"\n"; 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(); for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end();
MI != MIEnd; ++MI) MI != MIEnd; ++MI)

View File

@ -172,11 +172,12 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
return; return;
// Add includes for each of these headers. // Add includes for each of these headers.
for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) { for (unsigned I = 0, N = Module->NormalHeaders.size(); I != N; ++I) {
const FileEntry *Header = Module->Headers[I]; const FileEntry *Header = Module->NormalHeaders[I];
Module->addTopHeader(Header); Module->addTopHeader(Header);
addHeaderInclude(Header, Includes, LangOpts); addHeaderInclude(Header, Includes, LangOpts);
} }
// Note that Module->PrivateHeaders will not be a TopHeader.
if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) { if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) {
Module->addTopHeader(UmbrellaHeader); Module->addTopHeader(UmbrellaHeader);

View File

@ -371,7 +371,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
// Lookup file via Preprocessor, like a #include. // Lookup file via Preprocessor, like a #include.
const DirectoryLookup *CurDir; 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); NULL, NULL, 0);
if (!FE) { if (!FE) {
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),

View File

@ -223,7 +223,7 @@ const FileEntry *DirectoryLookup::LookupFile(
HeaderSearch &HS, HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath, SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule, ModuleMap::KnownHeader *SuggestedModule,
bool &InUserSpecifiedSystemFramework) const { bool &InUserSpecifiedSystemFramework) const {
InUserSpecifiedSystemFramework = false; InUserSpecifiedSystemFramework = false;
@ -337,7 +337,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
HeaderSearch &HS, HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath, SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule, ModuleMap::KnownHeader *SuggestedModule,
bool &InUserSpecifiedSystemFramework) const bool &InUserSpecifiedSystemFramework) const
{ {
FileManager &FileMgr = HS.getFileMgr(); FileManager &FileMgr = HS.getFileMgr();
@ -496,11 +496,11 @@ const FileEntry *HeaderSearch::LookupFile(
const FileEntry *CurFileEnt, const FileEntry *CurFileEnt,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath, SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule, ModuleMap::KnownHeader *SuggestedModule,
bool SkipCache) bool SkipCache)
{ {
if (SuggestedModule) if (SuggestedModule)
*SuggestedModule = 0; *SuggestedModule = ModuleMap::KnownHeader();
// If 'Filename' is absolute, check to see if it exists and no searching. // If 'Filename' is absolute, check to see if it exists and no searching.
if (llvm::sys::path::is_absolute(Filename)) { if (llvm::sys::path::is_absolute(Filename)) {
@ -676,7 +676,7 @@ LookupSubframeworkHeader(StringRef Filename,
const FileEntry *ContextFileEnt, const FileEntry *ContextFileEnt,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath, SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule) { ModuleMap::KnownHeader *SuggestedModule) {
assert(ContextFileEnt && "No context file?"); assert(ContextFileEnt && "No context file?");
// Framework names must have a '/' in the filename. Find it. // 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, void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE,
ModuleMap::ModuleHeaderRole Role,
bool isCompilingModuleHeader) { bool isCompilingModuleHeader) {
if (FE->getUID() >= FileInfo.size()) if (FE->getUID() >= FileInfo.size())
FileInfo.resize(FE->getUID()+1); FileInfo.resize(FE->getUID()+1);
@ -874,6 +875,7 @@ void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE,
HeaderFileInfo &HFI = FileInfo[FE->getUID()]; HeaderFileInfo &HFI = FileInfo[FE->getUID()];
HFI.isModuleHeader = true; HFI.isModuleHeader = true;
HFI.isCompilingModuleHeader = isCompilingModuleHeader; HFI.isCompilingModuleHeader = isCompilingModuleHeader;
HFI.setHeaderRole(Role);
} }
bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){ bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
@ -966,16 +968,14 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
} while (true); } while (true);
} }
Module *HeaderSearch::findModuleForHeader(const FileEntry *File) const { ModuleMap::KnownHeader
HeaderSearch::findModuleForHeader(const FileEntry *File) const {
if (ExternalSource) { if (ExternalSource) {
// Make sure the external source has handled header info about this file, // Make sure the external source has handled header info about this file,
// which includes whether the file is part of a module. // which includes whether the file is part of a module.
(void)getFileInfo(File); (void)getFileInfo(File);
} }
if (Module *Mod = ModMap.findModuleForHeader(File)) return ModMap.findModuleForHeader(File);
return Mod;
return 0;
} }
bool HeaderSearch::loadModuleMapFile(const FileEntry *File) { bool HeaderSearch::loadModuleMapFile(const FileEntry *File) {

View File

@ -168,14 +168,14 @@ static bool isBuiltinHeader(StringRef FileName) {
.Default(false); .Default(false);
} }
Module *ModuleMap::findModuleForHeader(const FileEntry *File) { ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File) {
HeadersMap::iterator Known = Headers.find(File); HeadersMap::iterator Known = Headers.find(File);
if (Known != Headers.end()) { if (Known != Headers.end()) {
// If a header is not available, don't report that it maps to anything. // If a header is not available, don't report that it maps to anything.
if (!Known->second.isAvailable()) 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, // 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 (Known != Headers.end()) {
// If a header is not available, don't report that it maps to anything. // If a header is not available, don't report that it maps to anything.
if (!Known->second.isAvailable()) 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; 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 // If a header corresponds to an unavailable module, don't report
// that it maps to anything. // that it maps to anything.
if (!Result->isAvailable()) if (!Result->isAvailable())
return 0; return KnownHeader();
return Result; return Headers[File];
} }
SkippedDirs.push_back(Dir); SkippedDirs.push_back(Dir);
@ -283,7 +283,7 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
Dir = SourceMgr->getFileManager().getDirectory(DirName); Dir = SourceMgr->getFileManager().getDirectory(DirName);
} while (Dir); } while (Dir);
return 0; return KnownHeader();
} }
bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const { bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
@ -527,7 +527,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// umbrella header "umbrella-header-name" // umbrella header "umbrella-header-name"
Result->Umbrella = UmbrellaHeader; Result->Umbrella = UmbrellaHeader;
Headers[UmbrellaHeader] = KnownHeader(Result, /*Excluded=*/false); Headers[UmbrellaHeader] = KnownHeader(Result, NormalHeader);
UmbrellaDirs[UmbrellaHeader->getDir()] = Result; UmbrellaDirs[UmbrellaHeader->getDir()] = Result;
// export * // export *
@ -593,7 +593,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
} }
void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){ void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
Headers[UmbrellaHeader] = KnownHeader(Mod, /*Excluded=*/false); Headers[UmbrellaHeader] = KnownHeader(Mod, NormalHeader);
Mod->Umbrella = UmbrellaHeader; Mod->Umbrella = UmbrellaHeader;
UmbrellaDirs[UmbrellaHeader->getDir()] = Mod; UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
} }
@ -604,15 +604,18 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
} }
void ModuleMap::addHeader(Module *Mod, const FileEntry *Header, void ModuleMap::addHeader(Module *Mod, const FileEntry *Header,
bool Excluded) { ModuleHeaderRole Role) {
if (Excluded) { if (Role == ExcludedHeader) {
Mod->ExcludedHeaders.push_back(Header); Mod->ExcludedHeaders.push_back(Header);
} else { } 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; 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 * const FileEntry *
@ -688,7 +691,7 @@ Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) {
while (const FileEntry *ExpansionFile while (const FileEntry *ExpansionFile
= SrcMgr.getFileEntryForID(ExpansionFileID)) { = SrcMgr.getFileEntryForID(ExpansionFileID)) {
// Find the module that owns this header (if any). // Find the module that owns this header (if any).
if (Module *Mod = findModuleForHeader(ExpansionFile)) if (Module *Mod = findModuleForHeader(ExpansionFile).getModule())
return Mod; return Mod;
// No module owns this header, so look up the inclusion chain to see if // No module owns this header, so look up the inclusion chain to see if
@ -724,6 +727,7 @@ namespace clang {
LinkKeyword, LinkKeyword,
ModuleKeyword, ModuleKeyword,
Period, Period,
PrivateKeyword,
UmbrellaKeyword, UmbrellaKeyword,
RequiresKeyword, RequiresKeyword,
Star, Star,
@ -809,7 +813,8 @@ namespace clang {
bool parseModuleId(ModuleId &Id); bool parseModuleId(ModuleId &Id);
void parseModuleDecl(); void parseModuleDecl();
void parseRequiresDecl(); void parseRequiresDecl();
void parseHeaderDecl(SourceLocation UmbrellaLoc, SourceLocation ExcludeLoc); void parseHeaderDecl(clang::MMToken::TokenKind,
SourceLocation LeadingLoc);
void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc); void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
void parseExportDecl(); void parseExportDecl();
void parseLinkDecl(); void parseLinkDecl();
@ -861,6 +866,7 @@ retry:
.Case("header", MMToken::HeaderKeyword) .Case("header", MMToken::HeaderKeyword)
.Case("link", MMToken::LinkKeyword) .Case("link", MMToken::LinkKeyword)
.Case("module", MMToken::ModuleKeyword) .Case("module", MMToken::ModuleKeyword)
.Case("private", MMToken::PrivateKeyword)
.Case("requires", MMToken::RequiresKeyword) .Case("requires", MMToken::RequiresKeyword)
.Case("umbrella", MMToken::UmbrellaKeyword) .Case("umbrella", MMToken::UmbrellaKeyword)
.Default(MMToken::Identifier); .Default(MMToken::Identifier);
@ -1200,7 +1206,7 @@ void ModuleMapParser::parseModuleDecl() {
case MMToken::UmbrellaKeyword: { case MMToken::UmbrellaKeyword: {
SourceLocation UmbrellaLoc = consumeToken(); SourceLocation UmbrellaLoc = consumeToken();
if (Tok.is(MMToken::HeaderKeyword)) if (Tok.is(MMToken::HeaderKeyword))
parseHeaderDecl(UmbrellaLoc, SourceLocation()); parseHeaderDecl(MMToken::UmbrellaKeyword, UmbrellaLoc);
else else
parseUmbrellaDirDecl(UmbrellaLoc); parseUmbrellaDirDecl(UmbrellaLoc);
break; break;
@ -1209,7 +1215,7 @@ void ModuleMapParser::parseModuleDecl() {
case MMToken::ExcludeKeyword: { case MMToken::ExcludeKeyword: {
SourceLocation ExcludeLoc = consumeToken(); SourceLocation ExcludeLoc = consumeToken();
if (Tok.is(MMToken::HeaderKeyword)) { if (Tok.is(MMToken::HeaderKeyword)) {
parseHeaderDecl(SourceLocation(), ExcludeLoc); parseHeaderDecl(MMToken::ExcludeKeyword, ExcludeLoc);
} else { } else {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
<< "exclude"; << "exclude";
@ -1217,8 +1223,19 @@ void ModuleMapParser::parseModuleDecl() {
break; 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: case MMToken::HeaderKeyword:
parseHeaderDecl(SourceLocation(), SourceLocation()); parseHeaderDecl(MMToken::HeaderKeyword, SourceLocation());
break; break;
case MMToken::LinkKeyword: case MMToken::LinkKeyword:
@ -1314,14 +1331,11 @@ static void appendSubframeworkPaths(Module *Mod,
/// header-declaration: /// header-declaration:
/// 'umbrella'[opt] 'header' string-literal /// 'umbrella'[opt] 'header' string-literal
/// 'exclude'[opt] 'header' string-literal /// 'exclude'[opt] 'header' string-literal
void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc, void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
SourceLocation ExcludeLoc) { SourceLocation LeadingLoc) {
assert(Tok.is(MMToken::HeaderKeyword)); assert(Tok.is(MMToken::HeaderKeyword));
consumeToken(); consumeToken();
bool Umbrella = UmbrellaLoc.isValid();
bool Exclude = ExcludeLoc.isValid();
assert(!(Umbrella && Exclude) && "Cannot have both 'umbrella' and 'exclude'");
// Parse the header name. // Parse the header name.
if (!Tok.is(MMToken::StringLiteral)) { if (!Tok.is(MMToken::StringLiteral)) {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
@ -1333,7 +1347,7 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
SourceLocation FileNameLoc = consumeToken(); SourceLocation FileNameLoc = consumeToken();
// Check whether we already have an umbrella. // 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) Diags.Report(FileNameLoc, diag::err_mmap_umbrella_clash)
<< ActiveModule->getFullModuleName(); << ActiveModule->getFullModuleName();
HadError = true; HadError = true;
@ -1379,8 +1393,9 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
// If this is a system module with a top-level header, this header // If this is a system module with a top-level header, this header
// may have a counterpart (or replacement) in the set of headers // may have a counterpart (or replacement) in the set of headers
// supplied by Clang. Find that builtin header. // supplied by Clang. Find that builtin header.
if (ActiveModule->IsSystem && !Umbrella && BuiltinIncludeDir && if (ActiveModule->IsSystem && LeadingToken != MMToken::UmbrellaKeyword &&
BuiltinIncludeDir != Directory && isBuiltinHeader(FileName)) { BuiltinIncludeDir && BuiltinIncludeDir != Directory &&
isBuiltinHeader(FileName)) {
SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName()); SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName());
llvm::sys::path::append(BuiltinPathName, FileName); llvm::sys::path::append(BuiltinPathName, FileName);
BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName); BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName);
@ -1403,10 +1418,10 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
Diags.Report(FileNameLoc, diag::err_mmap_header_conflict) Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
<< FileName << OwningModule.getModule()->getFullModuleName(); << FileName << OwningModule.getModule()->getFullModuleName();
HadError = true; HadError = true;
} else if (Umbrella) { } else if (LeadingToken == MMToken::UmbrellaKeyword) {
const DirectoryEntry *UmbrellaDir = File->getDir(); const DirectoryEntry *UmbrellaDir = File->getDir();
if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) { if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) {
Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash) Diags.Report(LeadingLoc, diag::err_mmap_umbrella_clash)
<< UmbrellaModule->getFullModuleName(); << UmbrellaModule->getFullModuleName();
HadError = true; HadError = true;
} else { } else {
@ -1415,17 +1430,25 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
} }
} else { } else {
// Record this header. // 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 there is a builtin counterpart to this file, add it now.
if (BuiltinFile) 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. // Ignore excluded header files. They're optional anyway.
Diags.Report(FileNameLoc, diag::err_mmap_header_not_found) Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
<< Umbrella << FileName; << (LeadingToken == MMToken::UmbrellaKeyword) << FileName;
HadError = true; HadError = true;
} }
} }
@ -1792,6 +1815,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
case MMToken::ExplicitKeyword: case MMToken::ExplicitKeyword:
case MMToken::ModuleKeyword: case MMToken::ModuleKeyword:
case MMToken::HeaderKeyword: case MMToken::HeaderKeyword:
case MMToken::PrivateKeyword:
case MMToken::UmbrellaKeyword: case MMToken::UmbrellaKeyword:
default: default:
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member) Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
@ -1918,6 +1942,7 @@ bool ModuleMapParser::parseModuleMapFile() {
case MMToken::LinkKeyword: case MMToken::LinkKeyword:
case MMToken::LSquare: case MMToken::LSquare:
case MMToken::Period: case MMToken::Period:
case MMToken::PrivateKeyword:
case MMToken::RBrace: case MMToken::RBrace:
case MMToken::RSquare: case MMToken::RSquare:
case MMToken::RequiresKeyword: case MMToken::RequiresKeyword:

View File

@ -532,13 +532,14 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
} }
const FileEntry *Preprocessor::LookupFile( const FileEntry *Preprocessor::LookupFile(
SourceLocation FilenameLoc,
StringRef Filename, StringRef Filename,
bool isAngled, bool isAngled,
const DirectoryLookup *FromDir, const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir, const DirectoryLookup *&CurDir,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath, SmallVectorImpl<char> *RelativePath,
Module **SuggestedModule, ModuleMap::KnownHeader *SuggestedModule,
bool SkipCache) { bool SkipCache) {
// If the header lookup mechanism may be relative to the current file, pass in // If the header lookup mechanism may be relative to the current file, pass in
// info about where the current file is. // info about where the current file is.
@ -564,7 +565,32 @@ const FileEntry *Preprocessor::LookupFile(
const FileEntry *FE = HeaderInfo.LookupFile( const FileEntry *FE = HeaderInfo.LookupFile(
Filename, isAngled, FromDir, CurDir, CurFileEnt, Filename, isAngled, FromDir, CurDir, CurFileEnt,
SearchPath, RelativePath, SuggestedModule, SkipCache); 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<const FileEntry *> &PvtHdrs
= RequestedModule->PrivateHeaders;
SmallVectorImpl<const FileEntry *>::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 // 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 // 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; SmallString<1024> RelativePath;
// We get the raw path only if we have 'Callbacks' to which we later pass // We get the raw path only if we have 'Callbacks' to which we later pass
// the path. // the path.
Module *SuggestedModule = 0; ModuleMap::KnownHeader SuggestedModule;
SourceLocation FilenameLoc = FilenameTok.getLocation();
const FileEntry *File = LookupFile( const FileEntry *File = LookupFile(
Filename, isAngled, LookupFrom, CurDir, FilenameLoc, Filename, isAngled, LookupFrom, CurDir,
Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL, Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL,
getLangOpts().Modules? &SuggestedModule : 0); getLangOpts().Modules? &SuggestedModule : 0);
@ -1407,8 +1434,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
HeaderInfo.AddSearchPath(DL, isAngled); HeaderInfo.AddSearchPath(DL, isAngled);
// Try the lookup again, skipping the cache. // Try the lookup again, skipping the cache.
File = LookupFile(Filename, isAngled, LookupFrom, CurDir, 0, 0, File = LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, CurDir,
getLangOpts().Modules? &SuggestedModule : 0, 0, 0, getLangOpts().Modules? &SuggestedModule : 0,
/*SkipCache*/true); /*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 // brackets, we can attempt a lookup as though it were a quoted path to
// provide the user with a possible fixit. // provide the user with a possible fixit.
if (isAngled) { if (isAngled) {
File = LookupFile(Filename, false, LookupFrom, CurDir, File = LookupFile(FilenameLoc, Filename, false, LookupFrom, CurDir,
Callbacks ? &SearchPath : 0, Callbacks ? &SearchPath : 0,
Callbacks ? &RelativePath : 0, Callbacks ? &RelativePath : 0,
getLangOpts().Modules ? &SuggestedModule : 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 // FIXME: Should we have a second loadModule() overload to avoid this
// extra lookup step? // extra lookup step?
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path; SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 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), Path.push_back(std::make_pair(getIdentifierInfo(Mod->Name),
FilenameTok.getLocation())); FilenameTok.getLocation()));
std::reverse(Path.begin(), Path.end()); std::reverse(Path.begin(), Path.end());
@ -1514,7 +1541,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
ModuleLoadResult Imported ModuleLoadResult Imported
= TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility, = TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility,
/*IsIncludeDirective=*/true); /*IsIncludeDirective=*/true);
assert((Imported == 0 || Imported == SuggestedModule) && assert((Imported == 0 || Imported == SuggestedModule.getModule()) &&
"the imported module is different than the suggested one"); "the imported module is different than the suggested one");
if (!Imported && hadModuleLoaderFatalFailure()) { if (!Imported && hadModuleLoaderFatalFailure()) {

View File

@ -992,7 +992,8 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// Search include directories. // Search include directories.
const DirectoryLookup *CurDir; const DirectoryLookup *CurDir;
const FileEntry *File = 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. // Get the result value. A result of true means the file exists.
return File != 0; return File != 0;

View File

@ -466,8 +466,8 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// Search include directories for this file. // Search include directories for this file.
const DirectoryLookup *CurDir; const DirectoryLookup *CurDir;
const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir, NULL, NULL, const FileEntry *File = LookupFile(FilenameTok.getLocation(), Filename,
NULL); isAngled, 0, CurDir, NULL, NULL, NULL);
if (File == 0) { if (File == 0) {
if (!SuppressIncludeNotFoundError) if (!SuppressIncludeNotFoundError)
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;

View File

@ -1281,6 +1281,8 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
using namespace clang::io; using namespace clang::io;
HeaderFileInfo HFI; HeaderFileInfo HFI;
unsigned Flags = *d++; unsigned Flags = *d++;
HFI.HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>
((Flags >> 6) & 0x03);
HFI.isImport = (Flags >> 5) & 0x01; HFI.isImport = (Flags >> 5) & 0x01;
HFI.isPragmaOnce = (Flags >> 4) & 0x01; HFI.isPragmaOnce = (Flags >> 4) & 0x01;
HFI.DirInfo = (Flags >> 2) & 0x03; HFI.DirInfo = (Flags >> 2) & 0x03;
@ -1307,7 +1309,7 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
FileManager &FileMgr = Reader.getFileManager(); FileManager &FileMgr = Reader.getFileManager();
ModuleMap &ModMap = ModuleMap &ModMap =
Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap(); 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; 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: { case SUBMODULE_TOPHEADER: {
if (First) { if (First) {
Error("missing submodule metadata record at beginning of block"); Error("missing submodule metadata record at beginning of block");

View File

@ -1476,7 +1476,8 @@ namespace {
using namespace clang::io; using namespace clang::io;
uint64_t Start = Out.tell(); (void)Start; 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.isPragmaOnce << 4)
| (Data.DirInfo << 2) | (Data.DirInfo << 2)
| (Data.Resolved << 1) | (Data.Resolved << 1)
@ -1507,7 +1508,7 @@ namespace {
Emit32(Out, Offset); Emit32(Out, Offset);
if (Data.isModuleHeader) { if (Data.isModuleHeader) {
Module *Mod = HS.findModuleForHeader(key.FE); Module *Mod = HS.findModuleForHeader(key.FE).getModule();
Emit32(Out, Writer.getExistingSubmoduleID(Mod)); Emit32(Out, Writer.getExistingSubmoduleID(Mod));
} }
@ -2260,6 +2261,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev); 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 = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY)); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
@ -2333,11 +2339,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
} }
// Emit the headers. // 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.clear();
Record.push_back(SUBMODULE_HEADER); Record.push_back(SUBMODULE_HEADER);
Stream.EmitRecordWithBlob(HeaderAbbrev, Record, Stream.EmitRecordWithBlob(HeaderAbbrev, Record,
Mod->Headers[I]->getName()); Mod->NormalHeaders[I]->getName());
} }
// Emit the excluded headers. // Emit the excluded headers.
for (unsigned I = 0, N = Mod->ExcludedHeaders.size(); I != N; ++I) { for (unsigned I = 0, N = Mod->ExcludedHeaders.size(); I != N; ++I) {
@ -2346,6 +2352,13 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record, Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record,
Mod->ExcludedHeaders[I]->getName()); 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<const FileEntry *> ArrayRef<const FileEntry *>
TopHeaders = Mod->getTopHeaders(PP->getFileManager()); TopHeaders = Mod->getTopHeaders(PP->getFileManager());
for (unsigned I = 0, N = TopHeaders.size(); I != N; ++I) { for (unsigned I = 0, N = TopHeaders.size(); I != N; ++I) {