diff options
| author | Douglas Gregor <dgregor@apple.com> | 2011-12-07 02:23:45 +0000 | 
|---|---|---|
| committer | Douglas Gregor <dgregor@apple.com> | 2011-12-07 02:23:45 +0000 | 
| commit | e7ab36693b68215065f40d3624a9f92673fd277e (patch) | |
| tree | 04a9cb09377c31e03c296c6ad5b50dd3b6219f46 | |
| parent | 9c9e81085fdb7c56ea3cd49c0ef462289d5b2ce7 (diff) | |
| download | bcm5719-llvm-e7ab36693b68215065f40d3624a9f92673fd277e.tar.gz bcm5719-llvm-e7ab36693b68215065f40d3624a9f92673fd277e.zip  | |
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.
llvm-svn: 146012
6 files changed, 147 insertions, 26 deletions
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 7c26aed042a..2cf115d7286 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -413,7 +413,11 @@ def err_mmap_expected_wildcard_member : Error<    "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; diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 1b969b93bef..7035b9c45d9 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -870,15 +870,33 @@ HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir) {    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. diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 9c3a39f4f6c..f6df3020073 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -435,7 +435,10 @@ namespace clang {      /// \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 @@ void ModuleMapParser::skipUntil(MMToken::TokenKind K) {    } 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::skipUntil(MMToken::TokenKind K) {  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 @@ void ModuleMapParser::parseModuleDecl() {      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 @@ void ModuleMapParser::parseModuleDecl() {      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 @@ void ModuleMapParser::parseUmbrellaDecl() {      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 @@ void ModuleMapParser::parseHeaderDecl() {      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 @@ bool ModuleMapParser::parseModuleMapFile() {      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: diff --git a/clang/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h b/clang/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h new file mode 100644 index 00000000000..4b3c30c7d32 --- /dev/null +++ b/clang/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h @@ -0,0 +1,2 @@ +int depends_on_module_private; + diff --git a/clang/test/Modules/Inputs/DependsOnModule.framework/module_private.map b/clang/test/Modules/Inputs/DependsOnModule.framework/module_private.map new file mode 100644 index 00000000000..5ed00290856 --- /dev/null +++ b/clang/test/Modules/Inputs/DependsOnModule.framework/module_private.map @@ -0,0 +1,6 @@ +explicit module DependsOnModule.Private { +  explicit module DependsOnModule { +    header "DependsOnModulePrivate.h" +  } +} + diff --git a/clang/test/Modules/auto-module-import.m b/clang/test/Modules/auto-module-import.m index 52bbcec173e..c1708e8eae2 100644 --- a/clang/test/Modules/auto-module-import.m +++ b/clang/test/Modules/auto-module-import.m @@ -39,3 +39,6 @@ void testModuleSubFramework() {  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'}}  | 

