aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Lex/ModuleMap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Lex/ModuleMap.cpp')
-rw-r--r--clang/lib/Lex/ModuleMap.cpp119
1 files changed, 104 insertions, 15 deletions
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index b9a4703..0523827 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -159,21 +159,115 @@ static bool isBuiltinHeader(StringRef FileName) {
.Default(false);
}
-ModuleMap::KnownHeader
-ModuleMap::findModuleForHeader(const FileEntry *File,
- Module *RequestingModule,
- bool *FoundInModule) {
+ModuleMap::HeadersMap::iterator
+ModuleMap::findKnownHeader(const FileEntry *File) {
HeadersMap::iterator Known = Headers.find(File);
-
- // If we've found a builtin header within Clang's builtin include directory,
- // load all of the module maps to see if it will get associated with a
- // specific module (e.g., in /usr/include).
if (Known == Headers.end() && File->getDir() == BuiltinIncludeDir &&
isBuiltinHeader(llvm::sys::path::filename(File->getName()))) {
HeaderInfo.loadTopLevelSystemModules();
- Known = Headers.find(File);
+ return Headers.find(File);
+ }
+ return Known;
+}
+
+// Returns 'true' if 'RequestingModule directly uses 'RequestedModule'.
+static bool directlyUses(const Module *RequestingModule,
+ const Module *RequestedModule) {
+ return std::find(RequestingModule->DirectUses.begin(),
+ RequestingModule->DirectUses.end(),
+ RequestedModule) != RequestingModule->DirectUses.end();
+}
+
+static bool violatesPrivateInclude(Module *RequestingModule,
+ const FileEntry *IncFileEnt,
+ ModuleMap::ModuleHeaderRole Role,
+ Module *RequestedModule) {
+ #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(), IncFileEnt);
+ bool IsPrivate = Look != PvtHdrs.end();
+ assert((IsPrivate && Role == ModuleMap::PrivateHeader)
+ || (!IsPrivate && Role != ModuleMap::PrivateHeader));
+ #endif
+ return Role == ModuleMap::PrivateHeader &&
+ RequestedModule->getTopLevelModule() != RequestingModule;
+}
+
+void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
+ SourceLocation FilenameLoc,
+ StringRef Filename,
+ const FileEntry *File) {
+ // No errors for indirect modules. This may be a bit of a problem for modules
+ // with no source files.
+ if (RequestingModule != SourceModule)
+ return;
+
+ if (RequestingModule)
+ resolveUses(RequestingModule, /*Complain=*/false);
+
+ HeadersMap::iterator Known = findKnownHeader(File);
+ if (Known == Headers.end())
+ return;
+
+ Module *Private = NULL;
+ Module *NotUsed = NULL;
+ for (SmallVectorImpl<KnownHeader>::iterator I = Known->second.begin(),
+ E = Known->second.end();
+ I != E; ++I) {
+ // Excluded headers don't really belong to a module.
+ if (I->getRole() == ModuleMap::ExcludedHeader)
+ continue;
+
+ // If 'File' is part of 'RequestingModule' we can definitely include it.
+ if (I->getModule() == RequestingModule)
+ return;
+
+ // Remember private headers for later printing of a diagnostic.
+ if (violatesPrivateInclude(RequestingModule, File, I->getRole(),
+ I->getModule())) {
+ Private = I->getModule();
+ continue;
+ }
+
+ // 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 &&
+ !directlyUses(RequestingModule, I->getModule())) {
+ NotUsed = I->getModule();
+ continue;
+ }
+
+ // We have found a module that we can happily use.
+ return;
+ }
+
+ // We have found a header, but it is private.
+ if (Private != NULL) {
+ Diags.Report(FilenameLoc, diag::error_use_of_private_header_outside_module)
+ << Filename;
+ return;
}
+ // We have found a module, but we don't use it.
+ if (NotUsed != NULL) {
+ Diags.Report(FilenameLoc, diag::error_undeclared_use_of_module)
+ << RequestingModule->getFullModuleName() << Filename;
+ return;
+ }
+
+ // Headers for which we have not found a module are fine to include.
+}
+
+ModuleMap::KnownHeader
+ModuleMap::findModuleForHeader(const FileEntry *File,
+ Module *RequestingModule) {
+ HeadersMap::iterator Known = findKnownHeader(File);
+
if (Known != Headers.end()) {
ModuleMap::KnownHeader Result = KnownHeader();
@@ -185,9 +279,6 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
if (I->getRole() == ModuleMap::ExcludedHeader)
continue;
- if (FoundInModule)
- *FoundInModule = true;
-
// Cannot use a module if it is unavailable.
if (!I->getModule()->isAvailable())
continue;
@@ -200,9 +291,7 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
// 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())
+ !directlyUses(RequestingModule, I->getModule()))
continue;
Result = *I;