[modules] Consistently construct a buffer as input to build the module.

This means the main file for modules will always be a virtual one.

llvm-svn: 165591
This commit is contained in:
Argyrios Kyrtzidis 2012-10-10 02:12:39 +00:00
parent 0f2e44a1cb
commit 130190ffff
3 changed files with 46 additions and 82 deletions

View File

@ -290,6 +290,10 @@ public:
submodule_iterator submodule_end() { return SubModules.end(); } submodule_iterator submodule_end() { return SubModules.end(); }
submodule_const_iterator submodule_end() const { return SubModules.end(); } submodule_const_iterator submodule_end() const { return SubModules.end(); }
static StringRef getModuleInputBufferName() {
return "<module-includes>";
}
/// \brief Print the module map for this module to the given stream. /// \brief Print the module map for this module to the given stream.
/// ///
void print(llvm::raw_ostream &OS, unsigned Indent = 0) const; void print(llvm::raw_ostream &OS, unsigned Indent = 0) const;

View File

@ -131,6 +131,29 @@ ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
Sysroot, OS); Sysroot, OS);
} }
static SmallVectorImpl<char> &
operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
Includes.append(RHS.begin(), RHS.end());
return Includes;
}
static void addHeaderInclude(StringRef HeaderName,
SmallVectorImpl<char> &Includes,
const LangOptions &LangOpts) {
if (LangOpts.ObjC1)
Includes += "#import \"";
else
Includes += "#include \"";
Includes += HeaderName;
Includes += "\"\n";
}
static void addHeaderInclude(const FileEntry *Header,
SmallVectorImpl<char> &Includes,
const LangOptions &LangOpts) {
addHeaderInclude(Header->getName(), Includes, LangOpts);
}
/// \brief Collect the set of header includes needed to construct the given /// \brief Collect the set of header includes needed to construct the given
/// module and update the TopHeaders file set of the module. /// module and update the TopHeaders file set of the module.
/// ///
@ -142,7 +165,7 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
FileManager &FileMgr, FileManager &FileMgr,
ModuleMap &ModMap, ModuleMap &ModMap,
clang::Module *Module, clang::Module *Module,
SmallString<256> &Includes) { SmallVectorImpl<char> &Includes) {
// Don't collect any headers for unavailable modules. // Don't collect any headers for unavailable modules.
if (!Module->isAvailable()) if (!Module->isAvailable())
return; return;
@ -151,24 +174,14 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) { for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) {
const FileEntry *Header = Module->Headers[I]; const FileEntry *Header = Module->Headers[I];
Module->TopHeaders.insert(Header); Module->TopHeaders.insert(Header);
if (LangOpts.ObjC1) addHeaderInclude(Header, Includes, LangOpts);
Includes += "#import \"";
else
Includes += "#include \"";
Includes += Header->getName();
Includes += "\"\n";
} }
if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) { if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) {
Module->TopHeaders.insert(UmbrellaHeader); Module->TopHeaders.insert(UmbrellaHeader);
if (Module->Parent) { if (Module->Parent) {
// Include the umbrella header for submodules. // Include the umbrella header for submodules.
if (LangOpts.ObjC1) addHeaderInclude(UmbrellaHeader, Includes, LangOpts);
Includes += "#import \"";
else
Includes += "#include \"";
Includes += UmbrellaHeader->getName();
Includes += "\"\n";
} }
} else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) { } else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) {
// Add all of the headers we find in this subdirectory. // Add all of the headers we find in this subdirectory.
@ -194,12 +207,7 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
} }
// Include this header umbrella header for submodules. // Include this header umbrella header for submodules.
if (LangOpts.ObjC1) addHeaderInclude(Dir->path(), Includes, LangOpts);
Includes += "#import \"";
else
Includes += "#include \"";
Includes += Dir->path();
Includes += "\"\n";
} }
} }
@ -255,77 +263,29 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
return false; return false;
} }
// Do we have an umbrella header for this module? FileManager &FileMgr = CI.getFileManager();
const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader();
// Collect the set of #includes we need to build the module. // Collect the set of #includes we need to build the module.
SmallString<256> HeaderContents; SmallString<256> HeaderContents;
collectModuleHeaderIncludes(CI.getLangOpts(), CI.getFileManager(), if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader())
addHeaderInclude(UmbrellaHeader, HeaderContents, CI.getLangOpts());
collectModuleHeaderIncludes(CI.getLangOpts(), FileMgr,
CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(),
Module, HeaderContents); Module, HeaderContents);
if (UmbrellaHeader && HeaderContents.empty()) {
// Simple case: we have an umbrella header and there are no additional
// includes, we can just parse the umbrella header directly.
setCurrentInput(FrontendInputFile(UmbrellaHeader->getName(),
getCurrentFileKind(),
Module->IsSystem));
return true;
}
FileManager &FileMgr = CI.getFileManager(); StringRef InputName = Module::getModuleInputBufferName();
SmallString<128> HeaderName;
time_t ModTime;
if (UmbrellaHeader) {
// Read in the umbrella header.
// FIXME: Go through the source manager; the umbrella header may have
// been overridden.
std::string ErrorStr;
llvm::MemoryBuffer *UmbrellaContents
= FileMgr.getBufferForFile(UmbrellaHeader, &ErrorStr);
if (!UmbrellaContents) {
CI.getDiagnostics().Report(diag::err_missing_umbrella_header)
<< UmbrellaHeader->getName() << ErrorStr;
return false;
}
// Combine the contents of the umbrella header with the automatically- // We consistently construct a buffer as input to build the module.
// generated includes. // This means the main file for modules will always be a virtual one.
SmallString<256> OldContents = HeaderContents; // FIXME: Maybe allow using a memory buffer as input directly instead of
HeaderContents = UmbrellaContents->getBuffer(); // messing with virtual files.
HeaderContents += "\n\n"; const FileEntry *HeaderFile = FileMgr.getVirtualFile(InputName,
HeaderContents += "/* Module includes */\n";
HeaderContents += OldContents;
// Pretend that we're parsing the umbrella header.
HeaderName = UmbrellaHeader->getName();
ModTime = UmbrellaHeader->getModificationTime();
delete UmbrellaContents;
} else {
// Pick an innocuous-sounding name for the umbrella header.
HeaderName = Module->Name + ".h";
if (FileMgr.getFile(HeaderName, /*OpenFile=*/false,
/*CacheFailure=*/false)) {
// Try again!
HeaderName = Module->Name + "-module.h";
if (FileMgr.getFile(HeaderName, /*OpenFile=*/false,
/*CacheFailure=*/false)) {
// Pick something ridiculous and go with it.
HeaderName = Module->Name + "-module.hmod";
}
}
ModTime = time(0);
}
// Remap the contents of the header name we're using to our synthesized
// buffer.
const FileEntry *HeaderFile = FileMgr.getVirtualFile(HeaderName,
HeaderContents.size(), HeaderContents.size(),
ModTime); time(0));
llvm::MemoryBuffer *HeaderContentsBuf llvm::MemoryBuffer *HeaderContentsBuf
= llvm::MemoryBuffer::getMemBufferCopy(HeaderContents); = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents);
CI.getSourceManager().overrideFileContents(HeaderFile, HeaderContentsBuf); CI.getSourceManager().overrideFileContents(HeaderFile, HeaderContentsBuf);
setCurrentInput(FrontendInputFile(HeaderName, getCurrentFileKind(), setCurrentInput(FrontendInputFile(InputName, getCurrentFileKind(),
Module->IsSystem)); Module->IsSystem));
return true; return true;
} }

View File

@ -1111,7 +1111,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
return Failure; return Failure;
} }
if (!DisableValidation && if (!DisableValidation && !OverriddenBuffer &&
((off_t)Record[4] != File->getSize() ((off_t)Record[4] != File->getSize()
#if !defined(LLVM_ON_WIN32) #if !defined(LLVM_ON_WIN32)
// In our regression testing, the Windows file system seems to // In our regression testing, the Windows file system seems to