def err_mmap_module_redefinition : Error<
"redefinition of module '%0'">;
def note_mmap_prev_definition : Note<"previously defined here">;
-def err_mmap_header_conflict : Error<
- "header '%0' is already part of module '%1'">;
def err_mmap_header_not_found : Error<
"%select{|umbrella }0header '%1' not found">;
def err_mmap_umbrella_dir_not_found : Error<
};
private:
- typedef llvm::DenseMap<const FileEntry *, KnownHeader> HeadersMap;
+ typedef llvm::DenseMap<const FileEntry *, SmallVector<KnownHeader, 1> >
+ HeadersMap;
/// \brief Mapping from each header to the module that owns the contents of
/// that header.
///
/// \param File The header file that is likely to be included.
///
+ /// \param RequestingModule Specifies the module the header is intended to be
+ /// used from. Used to disambiguate if a header is present in multiple
+ /// modules.
+ ///
/// \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.
- KnownHeader findModuleForHeader(const FileEntry *File);
+ KnownHeader findModuleForHeader(const FileEntry *File,
+ Module *RequestingModule = NULL);
/// \brief Determine whether the given header is part of a module
/// marked 'unavailable'.
/// \brief Verify that it is legal for the source file that \p FilenameLoc
/// points to to include the file \p Filename.
///
- /// Tries to reuse \p IncFileEnt and \p SuggestedModule.
+ /// Tries to reuse \p IncFileEnt.
void verifyModuleInclude(SourceLocation FilenameLoc, StringRef Filename,
- const FileEntry *IncFileEnt,
- ModuleMap::KnownHeader *SuggestedModule);
+ const FileEntry *IncFileEnt);
// Macro handling.
void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef);
// If we have a module map that might map this header, load it and
// check whether we'll have a suggestion for a module.
- if (SuggestedModule &&
- HS.hasModuleMap(TmpDir, getDir(), isSystemHeaderDirectory())) {
- const FileEntry *File = HS.getFileMgr().getFile(TmpDir.str(),
+ HS.hasModuleMap(TmpDir, getDir(), isSystemHeaderDirectory());
+ if (SuggestedModule) {
+ const FileEntry *File = HS.getFileMgr().getFile(TmpDir.str(),
/*openFile=*/false);
if (!File)
return File;
- // If there is a module that corresponds to this header,
- // suggest it.
+ // If there is a module that corresponds to this header, suggest it.
*SuggestedModule = HS.findModuleForHeader(File);
+ if (!SuggestedModule->getModule() &&
+ HS.hasModuleMap(TmpDir, getDir(), isSystemHeaderDirectory()))
+ *SuggestedModule = HS.findModuleForHeader(File);
return File;
}
ModuleMap::KnownHeader *SuggestedModule,
bool SkipCache)
{
+ if (!HSOpts->ModuleMapFiles.empty()) {
+ // Preload all explicitly specified module map files. This enables modules
+ // map files lying in a directory structure separate from the header files
+ // that they describe. These cannot be loaded lazily upon encountering a
+ // header file, as there is no other knwon mapping from a header file to its
+ // module map file.
+ for (llvm::SetVector<std::string>::iterator
+ I = HSOpts->ModuleMapFiles.begin(),
+ E = HSOpts->ModuleMapFiles.end();
+ I != E; ++I) {
+ const FileEntry *File = FileMgr.getFile(*I);
+ if (!File)
+ continue;
+ loadModuleMapFile(File, /*IsSystem=*/false);
+ }
+ HSOpts->ModuleMapFiles.clear();
+ }
+
if (SuggestedModule)
*SuggestedModule = ModuleMap::KnownHeader();
const DirectoryEntry *Dir = FileMgr.getDirectory(DirName);
if (!Dir)
return false;
-
- // Load user-specified module map files in 'Dir'.
- bool ModuleMapFound = false;
- for (llvm::SetVector<std::string>::iterator
- I = HSOpts->ModuleMapFiles.begin(),
- E = HSOpts->ModuleMapFiles.end();
- I != E; ++I) {
- StringRef ModuleMapFileDir = llvm::sys::path::parent_path(*I);
- if (!llvm::sys::fs::equivalent(ModuleMapFileDir, DirName))
- continue;
-
- const FileEntry *File = FileMgr.getFile(*I);
- if (!File)
- continue;
-
- loadModuleMapFile(File, /*IsSystem=*/false);
- ModuleMapFound = true;
- }
// Try to load the "module.map" file in this directory.
switch (loadModuleMapFile(Dir, IsSystem)) {
case LMM_NewlyLoaded:
case LMM_AlreadyLoaded:
- ModuleMapFound = true;
- break;
-
- case LMM_NoDirectory:
- case LMM_InvalidModuleMap:
- break;
- }
-
- if (ModuleMapFound) {
// Success. All of the directories we stepped through inherit this module
// map file.
for (unsigned I = 0, N = FixUpDirectories.size(); I != N; ++I)
DirectoryHasModuleMap[FixUpDirectories[I]] = true;
return true;
+
+ case LMM_NoDirectory:
+ case LMM_InvalidModuleMap:
+ break;
}
// If we hit the top of our search, we're done.
.Default(false);
}
-ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File) {
+ModuleMap::KnownHeader
+ModuleMap::findModuleForHeader(const FileEntry *File,
+ Module *RequestingModule) {
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 KnownHeader();
+ ModuleMap::KnownHeader Result = KnownHeader();
+
+ // Iterate over all modules that 'File' is part of to find the best fit.
+ for (SmallVectorImpl<KnownHeader>::iterator I = Known->second.begin(),
+ E = Known->second.end();
+ I != E; ++I) {
+ // Cannot use a module if the header is excluded or unavailable in it.
+ if (I->getRole() == ModuleMap::ExcludedHeader ||
+ !I->getModule()->isAvailable())
+ continue;
- return Known->second;
+ // If 'File' is part of 'RequestingModule', 'RequestingModule' is the
+ // module we are looking for.
+ if (I->getModule() == RequestingModule)
+ return *I;
+
+ // If uses need to be specified explicitly, we are only allowed to return
+ // modules that are explicitly used by the requesting module.
+ if (RequestingModule && LangOpts.ModulesDeclUse &&
+ std::find(RequestingModule->DirectUses.begin(),
+ RequestingModule->DirectUses.end(),
+ I->getModule()) == RequestingModule->DirectUses.end())
+ continue;
+ Result = *I;
+ // If 'File' is a public header of this module, this is as good as we
+ // are going to get.
+ if (I->getRole() == ModuleMap::NormalHeader)
+ break;
+ }
+ return Result;
}
// If we've found a builtin header within Clang's builtin include directory,
HeaderInfo.loadTopLevelSystemModules();
// Check again.
- 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 KnownHeader();
-
- return Known->second;
- }
+ if (Headers.find(File) != Headers.end())
+ return findModuleForHeader(File, RequestingModule);
}
const DirectoryEntry *Dir = File->getDir();
UmbrellaDirs[SkippedDirs[I]] = Result;
}
- Headers[File] = KnownHeader(Result, NormalHeader);
+ Headers[File].push_back(KnownHeader(Result, NormalHeader));
// If a header corresponds to an unavailable module, don't report
// that it maps to anything.
if (!Result->isAvailable())
return KnownHeader();
- return Headers[File];
+ return Headers[File].back();
}
SkippedDirs.push_back(Dir);
bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
HeadersMap::const_iterator Known = Headers.find(Header);
- if (Known != Headers.end())
- return !Known->second.isAvailable();
+ if (Known != Headers.end()) {
+ for (SmallVectorImpl<KnownHeader>::const_iterator
+ I = Known->second.begin(),
+ E = Known->second.end();
+ I != E; ++I) {
+ if (I->isAvailable())
+ return false;
+ }
+ return true;
+ }
const DirectoryEntry *Dir = Header->getDir();
SmallVector<const DirectoryEntry *, 2> SkippedDirs;
// umbrella header "umbrella-header-name"
Result->Umbrella = UmbrellaHeader;
- Headers[UmbrellaHeader] = KnownHeader(Result, NormalHeader);
+ Headers[UmbrellaHeader].push_back(KnownHeader(Result, NormalHeader));
UmbrellaDirs[UmbrellaHeader->getDir()] = Result;
// export *
}
void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
- Headers[UmbrellaHeader] = KnownHeader(Mod, NormalHeader);
+ Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader));
Mod->Umbrella = UmbrellaHeader;
UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
}
bool isCompilingModuleHeader = Mod->getTopLevelModule() == CompilingModule;
HeaderInfo.MarkFileModuleHeader(Header, Role, isCompilingModuleHeader);
}
- Headers[Header] = KnownHeader(Mod, Role);
+ Headers[Header].push_back(KnownHeader(Mod, Role));
}
const FileEntry *
llvm::errs() << "Headers:";
for (HeadersMap::iterator H = Headers.begin(), HEnd = Headers.end();
H != HEnd; ++H) {
- llvm::errs() << " \"" << H->first->getName() << "\" -> "
- << H->second.getModule()->getFullModuleName() << "\n";
+ llvm::errs() << " \"" << H->first->getName() << "\" -> ";
+ for (SmallVectorImpl<KnownHeader>::const_iterator I = H->second.begin(),
+ E = H->second.end();
+ I != E; ++I) {
+ if (I != H->second.begin())
+ llvm::errs() << ",";
+ llvm::errs() << I->getModule()->getFullModuleName();
+ }
+ llvm::errs() << "\n";
}
}
// FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
// Come up with a lazy way to do this.
if (File) {
- if (ModuleMap::KnownHeader OwningModule = Map.Headers[File]) {
- Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
- << FileName << OwningModule.getModule()->getFullModuleName();
- HadError = true;
- } else if (LeadingToken == MMToken::UmbrellaKeyword) {
+ if (LeadingToken == MMToken::UmbrellaKeyword) {
const DirectoryEntry *UmbrellaDir = File->getDir();
if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) {
Diags.Report(LeadingLoc, diag::err_mmap_umbrella_clash)
return Declared == AllowedUses.end();
}
-void Preprocessor::verifyModuleInclude(
- SourceLocation FilenameLoc,
- StringRef Filename,
- const FileEntry *IncFileEnt,
- ModuleMap::KnownHeader *SuggestedModule) {
+void Preprocessor::verifyModuleInclude(SourceLocation FilenameLoc,
+ StringRef Filename,
+ const FileEntry *IncFileEnt) {
Module *RequestingModule = getModuleForLocation(FilenameLoc);
- Module *RequestedModule = SuggestedModule->getModule();
- if (!RequestedModule)
- RequestedModule = HeaderInfo.findModuleForHeader(IncFileEnt).getModule();
+ if (RequestingModule)
+ HeaderInfo.getModuleMap().resolveUses(RequestingModule, /*Complain=*/false);
+ ModuleMap::KnownHeader RequestedModule =
+ HeaderInfo.getModuleMap().findModuleForHeader(IncFileEnt,
+ RequestingModule);
- if (RequestingModule == RequestedModule)
+ if (RequestingModule == RequestedModule.getModule())
return; // No faults wihin a module, or between files both not in modules.
if (RequestingModule != HeaderInfo.getModuleMap().SourceModule)
return; // No errors for indirect modules.
// This may be a bit of a problem for modules with no source files.
- if (RequestedModule &&
- violatesPrivateInclude(RequestingModule, IncFileEnt,
- SuggestedModule->getRole(), RequestedModule))
+ if (RequestedModule && violatesPrivateInclude(RequestingModule, IncFileEnt,
+ RequestedModule.getRole(),
+ RequestedModule.getModule()))
Diag(FilenameLoc, diag::error_use_of_private_header_outside_module)
<< Filename;
// FIXME: Add support for FixIts in module map files and offer adding the
// required use declaration.
if (RequestingModule && getLangOpts().ModulesDeclUse &&
- violatesUseDeclarations(RequestingModule, RequestedModule))
+ violatesUseDeclarations(RequestingModule, RequestedModule.getModule()))
Diag(FilenameLoc, diag::error_undeclared_use_of_module)
<< Filename;
}
SearchPath, RelativePath, SuggestedModule, SkipCache);
if (FE) {
if (SuggestedModule)
- verifyModuleInclude(FilenameLoc, Filename, FE, SuggestedModule);
+ verifyModuleInclude(FilenameLoc, Filename, FE);
return FE;
}
--- /dev/null
+#ifndef COMMON_H
+#define COMMON_H
+const int c = 2;
+#endif
module A {
+ header "common.h"
header "a.h"
}
module B {
+ header "common.h"
private header "b.h"
}
--- /dev/null
+module D {
+ header "../src/common.h"
+}
+
+module A {
+ header "../src/common.h"
+ use C
+}
+
+extern module B "moduleb.map"
+extern module C "modulec.map"
+
--- /dev/null
+module B {
+ header "../src/public-in-b.h"
+ private header "../src/public-in-c.h"
+}
--- /dev/null
+module C {
+ header "../src/public-in-c.h"
+ private header "../src/public-in-b.h"
+ private header "../src/private-in-c.h"
+}
--- /dev/null
+#ifndef COMMON_H
+#define COMMON_H
+const int common = 2;
+#endif
--- /dev/null
+#ifndef PRIVATE_IN_C_H
+#define PRIVATE_IN_C_H
+const int c_ = 2;
+#endif
--- /dev/null
+#ifndef PUBLIC_IN_B_H
+#define PUBLIC_IN_B_H
+const int b = 3;
+#endif
--- /dev/null
+#ifndef PUBLIC_IN_C_H
+#define PUBLIC_IN_C_H
+const int c = 2;
+#endif
// RUN: rm -rf %t
// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodule-map-file=%S/Inputs/modular_maps/modulea.map -I %S/Inputs/modular_maps %s -verify
+#include "common.h"
#include "a.h"
#include "b.h" // expected-error {{private header}}
-const int val = a + b; // expected-error {{undeclared identifier}}
+const int v = a + c;
+const int val = a + b + c; // expected-error {{undeclared identifier}}
--- /dev/null
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=A -fmodule-map-file=%S/Inputs/separate_map_tree/maps/modulea.map -I %S/Inputs/separate_map_tree/src %s -verify
+
+#include "common.h"
+#include "public-in-b.h" // expected-error {{private header}}
+#include "public-in-c.h"
+#include "private-in-c.h" // expected-error {{private header}}
+const int val = common + b + c + c_; // expected-error {{undeclared identifier}}