[cfe-commits] r146012 - in /cfe/trunk: include/clang/Basic/DiagnosticLexKinds.td lib/Lex/HeaderSearch.cpp lib/Lex/ModuleMap.cpp test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/ test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h test/Modules/Inputs/DependsOnModule.framework/module_private.map test/Modules/auto-module-import.m
Douglas Gregor
dgregor at apple.com
Tue Dec 6 18:23:45 PST 2011
Author: dgregor
Date: Tue Dec 6 20:23:45 2011
New Revision: 146012
URL: http://llvm.org/viewvc/llvm-project?rev=146012&view=rev
Log:
Implement basic support for private headers in frameworks. In essence,
when we load a module map (module.map) from a directory, also load a
private module map (module_private.map) for that directory, if
present. That private module map can inject a new submodule that
captures private headers.
Added:
cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/
cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h
cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module_private.map
Modified:
cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
cfe/trunk/lib/Lex/HeaderSearch.cpp
cfe/trunk/lib/Lex/ModuleMap.cpp
cfe/trunk/test/Modules/auto-module-import.m
Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=146012&r1=146011&r2=146012&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Tue Dec 6 20:23:45 2011
@@ -413,7 +413,11 @@
"expected module export wildcard">;
def err_mmap_expected_export_wildcard : Error<
"only '*' can be exported from an inferred submodule">;
-
+def err_mmap_explicit_top_level : Error<
+ "'explicit' is not permitted on top-level modules">;
+def err_mmap_nested_submodule_id : Error<
+ "qualified module name can only be used to define modules at the top level">;
+
def warn_auto_module_import : Warning<
"treating #%select{include|import|include_next|__include_macros}0 as an "
"import of module '%1'">, InGroup<AutoImport>, DefaultIgnore;
Modified: cfe/trunk/lib/Lex/HeaderSearch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/HeaderSearch.cpp?rev=146012&r1=146011&r2=146012&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/HeaderSearch.cpp (original)
+++ cfe/trunk/lib/Lex/HeaderSearch.cpp Tue Dec 6 20:23:45 2011
@@ -870,15 +870,33 @@
llvm::SmallString<128> ModuleMapFileName;
ModuleMapFileName += Dir->getName();
+ unsigned ModuleMapDirNameLen = ModuleMapFileName.size();
llvm::sys::path::append(ModuleMapFileName, "module.map");
if (const FileEntry *ModuleMapFile = FileMgr.getFile(ModuleMapFileName)) {
// We have found a module map file. Try to parse it.
- if (!ModMap.parseModuleMapFile(ModuleMapFile)) {
- // This directory has a module map.
- DirectoryHasModuleMap[Dir] = true;
-
- return LMM_NewlyLoaded;
+ if (ModMap.parseModuleMapFile(ModuleMapFile)) {
+ // No suitable module map.
+ DirectoryHasModuleMap[Dir] = false;
+ return LMM_InvalidModuleMap;
}
+
+ // This directory has a module map.
+ DirectoryHasModuleMap[Dir] = true;
+
+ // Check whether there is a private module map that we need to load as well.
+ ModuleMapFileName.erase(ModuleMapFileName.begin() + ModuleMapDirNameLen,
+ ModuleMapFileName.end());
+ llvm::sys::path::append(ModuleMapFileName, "module_private.map");
+ if (const FileEntry *PrivateModuleMapFile
+ = FileMgr.getFile(ModuleMapFileName)) {
+ if (ModMap.parseModuleMapFile(PrivateModuleMapFile)) {
+ // No suitable module map.
+ DirectoryHasModuleMap[Dir] = false;
+ return LMM_InvalidModuleMap;
+ }
+ }
+
+ return LMM_NewlyLoaded;
}
// No suitable module map.
Modified: cfe/trunk/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=146012&r1=146011&r2=146012&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Tue Dec 6 20:23:45 2011
@@ -435,7 +435,10 @@
/// \brief Skip tokens until we reach the a token with the given kind
/// (or the end of the file).
void skipUntil(MMToken::TokenKind K);
-
+
+ typedef llvm::SmallVector<std::pair<std::string, SourceLocation>, 2>
+ ModuleId;
+ bool parseModuleId(ModuleId &Id);
void parseModuleDecl();
void parseUmbrellaDecl();
void parseHeaderDecl();
@@ -567,15 +570,42 @@
} while (true);
}
+/// \brief Parse a module-id.
+///
+/// module-id:
+/// identifier
+/// identifier '.' module-id
+///
+/// \returns true if an error occurred, false otherwise.
+bool ModuleMapParser::parseModuleId(ModuleId &Id) {
+ Id.clear();
+ do {
+ if (Tok.is(MMToken::Identifier)) {
+ Id.push_back(std::make_pair(Tok.getString(), Tok.getLocation()));
+ consumeToken();
+ } else {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name);
+ return true;
+ }
+
+ if (!Tok.is(MMToken::Period))
+ break;
+
+ consumeToken();
+ } while (true);
+
+ return false;
+}
+
/// \brief Parse a module declaration.
///
/// module-declaration:
-/// 'framework'[opt] 'module' identifier { module-member* }
+/// 'explicit'[opt] 'framework'[opt] 'module' module-id { module-member* }
///
/// module-member:
/// umbrella-declaration
/// header-declaration
-/// 'explicit'[opt] submodule-declaration
+/// submodule-declaration
/// export-declaration
///
/// submodule-declaration:
@@ -584,14 +614,14 @@
void ModuleMapParser::parseModuleDecl() {
assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
Tok.is(MMToken::FrameworkKeyword));
-
// Parse 'explicit' or 'framework' keyword, if present.
+ SourceLocation ExplicitLoc;
bool Explicit = false;
bool Framework = false;
// Parse 'explicit' keyword, if present.
if (Tok.is(MMToken::ExplicitKeyword)) {
- consumeToken();
+ ExplicitLoc = consumeToken();
Explicit = true;
}
@@ -616,13 +646,52 @@
return parseInferredSubmoduleDecl(Explicit);
// Parse the module name.
- if (!Tok.is(MMToken::Identifier)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name);
+ ModuleId Id;
+ if (parseModuleId(Id)) {
+ HadError = true;
+ return;
+ }
+
+ if (ActiveModule) {
+ if (Id.size() > 1) {
+ Diags.Report(Id.front().second, diag::err_mmap_nested_submodule_id)
+ << SourceRange(Id.front().second, Id.back().second);
+
+ HadError = true;
+ return;
+ }
+ } else if (Id.size() == 1 && Explicit) {
+ // Top-level modules can't be explicit.
+ Diags.Report(ExplicitLoc, diag::err_mmap_explicit_top_level);
+ Explicit = false;
+ ExplicitLoc = SourceLocation();
HadError = true;
- return;
}
- StringRef ModuleName = Tok.getString();
- SourceLocation ModuleNameLoc = consumeToken();
+
+ Module *PreviousActiveModule = ActiveModule;
+ if (Id.size() > 1) {
+ // This module map defines a submodule. Go find the module of which it
+ // is a submodule.
+ ActiveModule = 0;
+ for (unsigned I = 0, N = Id.size() - 1; I != N; ++I) {
+ if (Module *Next = Map.lookupModuleQualified(Id[I].first, ActiveModule)) {
+ ActiveModule = Next;
+ continue;
+ }
+
+ if (ActiveModule) {
+ Diags.Report(Id[I].second, diag::err_mmap_missing_module_qualified)
+ << Id[I].first << ActiveModule->getTopLevelModule();
+ } else {
+ Diags.Report(Id[I].second, diag::err_mmap_expected_module_name);
+ }
+ HadError = true;
+ return;
+ }
+ }
+
+ StringRef ModuleName = Id.back().first;
+ SourceLocation ModuleNameLoc = Id.back().second;
// Parse the opening brace.
if (!Tok.is(MMToken::LBrace)) {
@@ -699,8 +768,8 @@
HadError = true;
}
- // We're done parsing this module. Pop back to our parent scope.
- ActiveModule = ActiveModule->Parent;
+ // We're done parsing this module. Pop back to the previous module.
+ ActiveModule = PreviousActiveModule;
}
/// \brief Append to \p Paths the set of paths needed to get to the
@@ -738,7 +807,7 @@
HadError = true;
return;
}
- StringRef FileName = Tok.getString();
+ std::string FileName = Tok.getString();
SourceLocation FileNameLoc = consumeToken();
// Check whether we already have an umbrella header.
@@ -829,26 +898,45 @@
HadError = true;
return;
}
- StringRef FileName = Tok.getString();
+ std::string FileName = Tok.getString();
SourceLocation FileNameLoc = consumeToken();
// Look for this file.
+ const FileEntry *File = 0;
llvm::SmallString<128> PathName;
- if (llvm::sys::path::is_relative(FileName)) {
- // FIXME: Change this search to also look for private headers!
+ if (llvm::sys::path::is_absolute(FileName)) {
+ PathName = FileName;
+ File = SourceMgr.getFileManager().getFile(PathName);
+ } else {
+ // Search for the header file within the search directory.
PathName += Directory->getName();
+ unsigned PathLength = PathName.size();
if (ActiveModule->isPartOfFramework()) {
appendSubframeworkPaths(ActiveModule, PathName);
+
+ // Check whether this file is in the public headers.
llvm::sys::path::append(PathName, "Headers");
+ llvm::sys::path::append(PathName, FileName);
+ File = SourceMgr.getFileManager().getFile(PathName);
+
+ if (!File) {
+ // Check whether this file is in the private headers.
+ PathName.resize(PathLength);
+ llvm::sys::path::append(PathName, "PrivateHeaders");
+ llvm::sys::path::append(PathName, FileName);
+ File = SourceMgr.getFileManager().getFile(PathName);
+ }
+ } else {
+ // Lookup for normal headers.
+ llvm::sys::path::append(PathName, FileName);
+ File = SourceMgr.getFileManager().getFile(PathName);
}
}
- llvm::sys::path::append(PathName, FileName);
-
// 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 (const FileEntry *File = SourceMgr.getFileManager().getFile(PathName)) {
+ if (File) {
if (const Module *OwningModule = Map.Headers[File]) {
Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
<< FileName << OwningModule->getFullModuleName();
@@ -1012,12 +1100,12 @@
case MMToken::EndOfFile:
return HadError;
+ case MMToken::ExplicitKeyword:
case MMToken::ModuleKeyword:
case MMToken::FrameworkKeyword:
parseModuleDecl();
break;
- case MMToken::ExplicitKeyword:
case MMToken::ExportKeyword:
case MMToken::HeaderKeyword:
case MMToken::Identifier:
Added: cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h?rev=146012&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h (added)
+++ cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h Tue Dec 6 20:23:45 2011
@@ -0,0 +1,2 @@
+int depends_on_module_private;
+
Added: cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module_private.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module_private.map?rev=146012&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module_private.map (added)
+++ cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module_private.map Tue Dec 6 20:23:45 2011
@@ -0,0 +1,6 @@
+explicit module DependsOnModule.Private {
+ explicit module DependsOnModule {
+ header "DependsOnModulePrivate.h"
+ }
+}
+
Modified: cfe/trunk/test/Modules/auto-module-import.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/auto-module-import.m?rev=146012&r1=146011&r2=146012&view=diff
==============================================================================
--- cfe/trunk/test/Modules/auto-module-import.m (original)
+++ cfe/trunk/test/Modules/auto-module-import.m Tue Dec 6 20:23:45 2011
@@ -39,3 +39,6 @@
void testModuleSubFrameworkAgain() {
char *msf = module_subframework;
}
+
+// Test inclusion of private headers.
+#include <DependsOnModule/DependsOnModulePrivate.h> // expected-warning{{treating #include as an import of module 'DependsOnModule.Private.DependsOnModule'}}
More information about the cfe-commits
mailing list