]> granicus.if.org Git - clang/commitdiff
Module use declarations (II)
authorDaniel Jasper <djasper@google.com>
Tue, 24 Sep 2013 09:14:14 +0000 (09:14 +0000)
committerDaniel Jasper <djasper@google.com>
Tue, 24 Sep 2013 09:14:14 +0000 (09:14 +0000)
Review: http://llvm-reviews.chandlerc.com/D1546.

I have picked up this patch form Lawrence
(http://llvm-reviews.chandlerc.com/D1063) and did a few changes.

From the original change description (updated as appropriate):
This patch adds a check that ensures that modules only use modules they
have so declared. To this end, it adds a statement on intended module
use to the module.map grammar:

  use module-id

A module can then only use headers from other modules if it 'uses' them.
This enforcement is off by default, but may be turned on with the new
option -fmodules-decluse.

When enforcing the module semantics, we also need to consider a source
file part of a module. This is achieved with a compiler option

-fmodule-name=<module-id>.

The compiler at present only applies restrictions to the module directly
being built.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191283 91177308-0d34-0410-b5e6-96231b3b80d8

29 files changed:
docs/Modules.rst
include/clang/Basic/DiagnosticLexKinds.td
include/clang/Basic/LangOptions.def
include/clang/Basic/Module.h
include/clang/Driver/Options.td
include/clang/Lex/ModuleMap.h
include/clang/Lex/Preprocessor.h
lib/Basic/Module.cpp
lib/Driver/Tools.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Lex/HeaderSearch.cpp
lib/Lex/ModuleMap.cpp
lib/Lex/PPDirectives.cpp
lib/Sema/Sema.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/Modules/Inputs/declare-use/a.h [new file with mode: 0644]
test/Modules/Inputs/declare-use/b.h [new file with mode: 0644]
test/Modules/Inputs/declare-use/c.h [new file with mode: 0644]
test/Modules/Inputs/declare-use/d.h [new file with mode: 0644]
test/Modules/Inputs/declare-use/e.h [new file with mode: 0644]
test/Modules/Inputs/declare-use/f.h [new file with mode: 0644]
test/Modules/Inputs/declare-use/g.h [new file with mode: 0644]
test/Modules/Inputs/declare-use/g1.h [new file with mode: 0644]
test/Modules/Inputs/declare-use/h.h [new file with mode: 0644]
test/Modules/Inputs/declare-use/h1.h [new file with mode: 0644]
test/Modules/Inputs/declare-use/module.map [new file with mode: 0644]
test/Modules/declare-use1.cpp [new file with mode: 0644]
test/Modules/declare-use2.cpp [new file with mode: 0644]

index 8c20301315c4a25fe0956813971e76b3885dc082..02393d7ba9f6997d67464d4f838fe20dfb53ceb7 100644 (file)
@@ -188,6 +188,12 @@ Command-line parameters
 ``-module-file-info <module file name>``
   Debugging aid that prints information about a given module file (with a ``.pcm`` extension), including the language and preprocessor options that particular module variant was built with.
 
+``-fmodules-decluse``
+  Enable checking of module ``use`` declarations.
+
+``-fmodule-name=module-id``
+  Consider a source file as a part of the given module.
+
 Module Map Language
 ===================
 
@@ -238,7 +244,7 @@ Module map files use a simplified form of the C99 lexer, with the same rules for
   ``conflict``      ``framework``  ``requires``
   ``exclude``       ``header``     ``private``
   ``explicit``      ``link``       ``umbrella``
-  ``extern``
+  ``extern``        ``use``
 
 Module map file
 ---------------
@@ -293,6 +299,7 @@ Modules can have a number of different kinds of members, each of which is descri
     *umbrella-dir-declaration*
     *submodule-declaration*
     *export-declaration*
+    *use-declaration*
     *link-declaration*
     *config-macros-declaration*
     *conflict-declaration*
@@ -533,6 +540,36 @@ Note that, if ``Derived.h`` includes ``Base.h``, one can simply use a wildcard e
   compatibility for programs that rely on transitive inclusion (i.e.,
   all of them).
 
+Use declaration
+~~~~~~~~~~~~~~~
+A *use-declaration* specifies one of the other modules that the module is allowed to use. An import or include not matching one of these is rejected when the option *-fmodules-decluse*.
+
+.. parsed-literal::
+
+  *use-declaration*:
+    ``use`` *module-id*
+
+**Example**:: In the following example, use of A from C is not declared, so will trigger a warning.
+
+.. parsed-literal::
+
+  module A {
+    header "a.h"
+  }
+
+  module B {
+    header "b.h"
+  }
+
+  module C {
+    header "c.h"
+    use B
+  }
+
+When compiling a source file that implements a module, use the option ``-fmodule-name=``module-id to indicate that the source file is logically part of that module.
+
+The compiler at present only applies restrictions to the module directly being built.
+
 Link declaration
 ~~~~~~~~~~~~~~~~
 A *link-declaration* specifies a library or framework against which a program should be linked if the enclosing module is imported in any translation unit in that program.
index 3abbb8574fb5ef9bde3e2fd6b3b386546d8f64ba..9a40fe75a528f4fd6e7e21ef85ef74beca829c84 100644 (file)
@@ -554,8 +554,8 @@ def err_mmap_umbrella_dir_not_found : Error<
   "umbrella directory '%0' not found">;
 def err_mmap_umbrella_clash : Error<
   "umbrella for module '%0' already covers this directory">;
-def err_mmap_export_module_id : Error<
-  "expected an exported module name or '*'">;
+def err_mmap_module_id : Error<
+  "expected a module name or '*'">;
 def err_mmap_expected_library_name : Error<
   "expected %select{library|framework}0 name as a string">;
 def err_mmap_config_macro_submodule : Error<
@@ -610,7 +610,9 @@ def err_expected_id_building_module : Error<
   "expected a module name in '__building_module' expression">;
 def error_use_of_private_header_outside_module : Error<
   "use of private header from outside its module: '%0'">;
-  
+def error_undeclared_use_of_module : Error<
+  "use of a module not declared used: '%0'">;
+
 def warn_header_guard : Warning<
   "%0 is used as a header guard here, followed by #define of a different macro">,
   InGroup<DiagGroup<"header-guard">>;
index 55db34ce304e394e94b98576409ff0e876a407d2..f992a3e1785ba3b296435f7cbd49d1716c035185 100644 (file)
@@ -94,6 +94,7 @@ BENIGN_LANGOPT(EmitAllDecls      , 1, 0, "support for emitting all declarations"
 LANGOPT(MathErrno         , 1, 1, "errno support for math functions")
 BENIGN_LANGOPT(HeinousExtensions , 1, 0, "Extensions that we really don't like and may be ripped out at any time")
 LANGOPT(Modules           , 1, 0, "modules extension to C")
+LANGOPT(ModulesDeclUse    , 1, 0, "require declaration of module uses")
 LANGOPT(Optimize          , 1, 0, "__OPTIMIZE__ predefined macro")
 LANGOPT(OptimizeSize      , 1, 0, "__OPTIMIZE_SIZE__ predefined macro")
 LANGOPT(Static            , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)")
index 26466be7e4976bf34004a5246e0b54bbef11dd55..e6913d847041992c5fec3c7445a21930b64d3e06 100644 (file)
@@ -183,6 +183,12 @@ public:
   /// \brief The set of export declarations that have yet to be resolved.
   SmallVector<UnresolvedExportDecl, 2> UnresolvedExports;
 
+  /// \brief The directly used modules.
+  SmallVector<Module *, 2> DirectUses;
+
+  /// \brief The set of use declarations that have yet to be resolved.
+  SmallVector<ModuleId, 2> UnresolvedDirectUses;
+
   /// \brief A library or framework to link against when an entity from this
   /// module is used.
   struct LinkLibrary {
index 81221f87db3ecc00cb8eda2111d3a6f2c890041b..529d03c4224e8777c4324a80d34cf902db895a5d 100644 (file)
@@ -561,6 +561,9 @@ def fmodule_maps : Flag <["-"], "fmodule-maps">, Group<f_Group>,
   HelpText<"Read module maps to understand the structure of library headers">;
 def fmodules_ignore_macro : Joined<["-"], "fmodules-ignore-macro=">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Ignore the definition of the given macro when building and loading modules">;
+def fmodules_decluse : Flag <["-"], "fmodules-decluse">, Group<f_Group>,
+  Flags<[DriverOption,CC1Option]>,
+  HelpText<"Require declaration of modules used within a module">;
 def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Flags<[CC1Option]>;
 
 def fmudflapth : Flag<["-"], "fmudflapth">, Group<f_Group>;
@@ -621,6 +624,8 @@ def fno_modules : Flag <["-"], "fno-modules">, Group<f_Group>,
   Flags<[DriverOption]>;
 def fno_module_maps : Flag <["-"], "fno-module-maps">, Group<f_Group>,
   Flags<[DriverOption]>;
+def fno_modules_decluse : Flag <["-"], "fno-modules-decluse">, Group<f_Group>,
+  Flags<[DriverOption]>;
 def fno_ms_extensions : Flag<["-"], "fno-ms-extensions">, Group<f_Group>;
 def fno_ms_compatibility : Flag<["-"], "fno-ms-compatibility">, Group<f_Group>;
 def fno_delayed_template_parsing : Flag<["-"], "fno-delayed-template-parsing">, Group<f_Group>;
index 8e588bfdc1ccd04bccc6253e9086c52be19120a7..90cfc6c7e1828c2bda0aa6f16265c49f074e6edd 100644 (file)
@@ -55,6 +55,12 @@ class ModuleMap {
   // The module that we are building; related to \c LangOptions::CurrentModule.
   Module *CompilingModule;
 
+public:
+  // The module that the .cc source file is associated with.
+  Module *SourceModule;
+  std::string SourceModuleName;
+
+private:
   /// \brief The top-level modules that are known.
   llvm::StringMap<Module *> Modules;
 
@@ -299,6 +305,16 @@ public:
   /// false otherwise.
   bool resolveExports(Module *Mod, bool Complain);
 
+  /// \brief Resolve all of the unresolved uses in the given module.
+  ///
+  /// \param Mod The module whose uses should be resolved.
+  ///
+  /// \param Complain Whether to emit diagnostics for failures.
+  ///
+  /// \returns true if any errors were encountered while resolving uses,
+  /// false otherwise.
+  bool resolveUses(Module *Mod, bool Complain);
+
   /// \brief Resolve all of the unresolved conflicts in the given module.
   ///
   /// \param Mod The module whose conflicts should be resolved.
index d1e16f152fd56386d05b5f5b850cd9902b278a44..f9eae9763482a35dbaf69f8a24ea1e9fef2c7fab 100644 (file)
@@ -1441,6 +1441,31 @@ private:
   void HandleImportDirective(SourceLocation HashLoc, Token &Tok);
   void HandleMicrosoftImportDirective(Token &Tok);
 
+  // Module inclusion testing.
+  /// \brief Find the module for the source or header file that \p FilenameLoc
+  /// points to.
+  Module *getModuleForLocation(SourceLocation FilenameLoc);
+
+  /// \brief Verify that a private header is included only from within its
+  /// module.
+  bool violatesPrivateInclude(Module *RequestingModule,
+                              const FileEntry *IncFileEnt,
+                              ModuleMap::ModuleHeaderRole Role,
+                              Module *RequestedModule);
+
+  /// \brief Verify that a module includes headers only from modules that it
+  /// has declared that it uses.
+  bool violatesUseDeclarations(Module *RequestingModule,
+                               Module *RequestedModule);
+
+  /// \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.
+  void verifyModuleInclude(SourceLocation FilenameLoc, StringRef Filename,
+                           const FileEntry *IncFileEnt,
+                           ModuleMap::KnownHeader *SuggestedModule);
+
   // Macro handling.
   void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef);
   void HandleUndefDirective(Token &Tok);
index 7ec5e68fc45b0259effaf2a021d13381fce0513e..8c35b342ecb063620c15e68291fd3522c6670149 100644 (file)
@@ -362,6 +362,20 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
     OS << "\n";
   }
 
+  for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) {
+    OS.indent(Indent + 2);
+    OS << "use ";
+    OS << DirectUses[I]->getFullModuleName();
+    OS << "\n";
+  }
+
+  for (unsigned I = 0, N = UnresolvedDirectUses.size(); I != N; ++I) {
+    OS.indent(Indent + 2);
+    OS << "use ";
+    printModuleId(OS, UnresolvedDirectUses[I]);
+    OS << "\n";
+  }
+
   for (unsigned I = 0, N = LinkLibraries.size(); I != N; ++I) {
     OS.indent(Indent + 2);
     OS << "link ";
index 23f3648ddbae0ffc54fb32080c394ca50816047a..6a803cc17d1f29e1605dd6fdc1583984bb0b0b56 100644 (file)
@@ -3034,6 +3034,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     CmdArgs.push_back("-fmodule-maps");
   }
 
+  // -fmodule-decluse checks that modules used are declared so (off by default).
+  if (Args.hasFlag(options::OPT_fmodules_decluse,
+                   options::OPT_fno_modules_decluse,
+                   false)) {
+    CmdArgs.push_back("-fmodule-decluse");
+  }
+
   // If a module path was provided, pass it along. Otherwise, use a temporary
   // directory.
   if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) {
index b13507a5ef19fb7483aaaa55a64bf47592b9d624..c8c676899c57d7f300cc74c6bfe8893d97154f04 100644 (file)
@@ -1280,6 +1280,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
   Opts.Blocks = Args.hasArg(OPT_fblocks);
   Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
   Opts.Modules = Args.hasArg(OPT_fmodules);
+  Opts.ModulesDeclUse = Args.hasArg(OPT_fmodules_decluse);
   Opts.CharIsSigned = Opts.OpenCL || !Args.hasArg(OPT_fno_signed_char);
   Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar);
   Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
index 631a7fd1dab207e6556695f6369cd3a4eb57f1c0..ec84bb16d60608865aee4607b43a768dcaad0420 100644 (file)
@@ -22,6 +22,7 @@
 #include "llvm/Support/Capacity.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
 #include <cstdio>
 #if defined(LLVM_ON_UNIX)
 #include <limits.h>
index df80a93e4db84d66df2d346feae96836900eb4d4..0f12af361a45acb006ff4e3484c126c3cdffe6a0 100644 (file)
@@ -387,6 +387,10 @@ ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
   // Create a new module with this name.
   Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework, 
                               IsExplicit);
+  if (LangOpts.CurrentModule == Name) {
+    SourceModule = Result;
+    SourceModuleName = Name;
+  }
   if (!Parent) {
     Modules[Name] = Result;
     if (!LangOpts.CurrentModule.empty() && !CompilingModule &&
@@ -518,6 +522,10 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
   
   Module *Result = new Module(ModuleName, SourceLocation(), Parent,
                               /*IsFramework=*/true, /*IsExplicit=*/false);
+  if (LangOpts.CurrentModule == ModuleName) {
+    SourceModule = Result;
+    SourceModuleName = ModuleName;
+  }
   if (IsSystem)
     Result->IsSystem = IsSystem;
   
@@ -653,6 +661,20 @@ bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
   return HadError;
 }
 
+bool ModuleMap::resolveUses(Module *Mod, bool Complain) {
+  bool HadError = false;
+  for (unsigned I = 0, N = Mod->UnresolvedDirectUses.size(); I != N; ++I) {
+    Module *DirectUse =
+        resolveModuleId(Mod->UnresolvedDirectUses[I], Mod, Complain);
+    if (DirectUse)
+      Mod->DirectUses.push_back(DirectUse);
+    else
+      HadError = true;
+  }
+  Mod->UnresolvedDirectUses.clear();
+  return HadError;
+}
+
 bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
   bool HadError = false;
   for (unsigned I = 0, N = Mod->UnresolvedConflicts.size(); I != N; ++I) {
@@ -727,6 +749,7 @@ namespace clang {
       Period,
       PrivateKeyword,
       UmbrellaKeyword,
+      UseKeyword,
       RequiresKeyword,
       Star,
       StringLiteral,
@@ -819,6 +842,7 @@ namespace clang {
                          SourceLocation LeadingLoc);
     void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
     void parseExportDecl();
+    void parseUseDecl();
     void parseLinkDecl();
     void parseConfigMacros();
     void parseConflict();
@@ -873,6 +897,7 @@ retry:
                  .Case("private", MMToken::PrivateKeyword)
                  .Case("requires", MMToken::RequiresKeyword)
                  .Case("umbrella", MMToken::UmbrellaKeyword)
+                 .Case("use", MMToken::UseKeyword)
                  .Default(MMToken::Identifier);
     break;
 
@@ -1209,6 +1234,10 @@ void ModuleMapParser::parseModuleDecl() {
     case MMToken::ExportKeyword:
       parseExportDecl();
       break;
+
+    case MMToken::UseKeyword:
+      parseUseDecl();
+      break;
         
     case MMToken::RequiresKeyword:
       parseRequiresDecl();
@@ -1593,7 +1622,7 @@ void ModuleMapParser::parseExportDecl() {
       break;
     }
     
-    Diags.Report(Tok.getLocation(), diag::err_mmap_export_module_id);
+    Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
     HadError = true;
     return;
   } while (true);
@@ -1604,6 +1633,38 @@ void ModuleMapParser::parseExportDecl() {
   ActiveModule->UnresolvedExports.push_back(Unresolved);
 }
 
+/// \brief Parse a module uses declaration.
+///
+///   uses-declaration:
+///     'uses' wildcard-module-id
+void ModuleMapParser::parseUseDecl() {
+  assert(Tok.is(MMToken::UseKeyword));
+  consumeToken();
+  // Parse the module-id.
+  ModuleId ParsedModuleId;
+
+  do {
+    if (Tok.is(MMToken::Identifier)) {
+      ParsedModuleId.push_back(
+          std::make_pair(Tok.getString(), Tok.getLocation()));
+      consumeToken();
+
+      if (Tok.is(MMToken::Period)) {
+        consumeToken();
+        continue;
+      }
+
+      break;
+    }
+
+    Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
+    HadError = true;
+    return;
+  } while (true);
+
+  ActiveModule->UnresolvedDirectUses.push_back(ParsedModuleId);
+}
+
 /// \brief Parse a link declaration.
 ///
 ///   module-declaration:
@@ -2001,6 +2062,7 @@ bool ModuleMapParser::parseModuleMapFile() {
     case MMToken::Star:
     case MMToken::StringLiteral:
     case MMToken::UmbrellaKeyword:
+    case MMToken::UseKeyword:
       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
       HadError = true;
       consumeToken();
index 86d6ad9eb868e495b8c0ef54dd9c473bed0c73e3..759199259614b5342a72b5fa1c9a3aed757de74b 100644 (file)
@@ -532,6 +532,88 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
   }
 }
 
+Module *Preprocessor::getModuleForLocation(SourceLocation FilenameLoc) {
+  ModuleMap &ModMap = HeaderInfo.getModuleMap();
+  if (SourceMgr.isInMainFile(FilenameLoc)) {
+    if (Module *CurMod = getCurrentModule())
+      return CurMod;                               // Compiling a module.
+    return HeaderInfo.getModuleMap().SourceModule; // Compiling a source.
+  }
+  // Try to determine the module of the include directive.
+  FileID IDOfIncl = SourceMgr.getFileID(FilenameLoc);
+  if (const FileEntry *EntryOfIncl = SourceMgr.getFileEntryForID(IDOfIncl)) {
+    // The include comes from a file.
+    return ModMap.findModuleForHeader(EntryOfIncl).getModule();
+  } else {
+    // The include does not come from a file,
+    // so it is probably a module compilation.
+    return getCurrentModule();
+  }
+}
+
+bool Preprocessor::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;
+}
+
+bool Preprocessor::violatesUseDeclarations(
+    Module *RequestingModule,
+    Module *RequestedModule) {
+  ModuleMap &ModMap = HeaderInfo.getModuleMap();
+  ModMap.resolveUses(RequestingModule, /*Complain=*/false);
+  const SmallVectorImpl<Module *> &AllowedUses = RequestingModule->DirectUses;
+  SmallVectorImpl<Module *>::const_iterator Declared =
+      std::find(AllowedUses.begin(), AllowedUses.end(), RequestedModule);
+  return Declared == AllowedUses.end();
+}
+
+void Preprocessor::verifyModuleInclude(
+    SourceLocation FilenameLoc,
+    StringRef Filename,
+    const FileEntry *IncFileEnt,
+    ModuleMap::KnownHeader *SuggestedModule) {
+  Module *RequestingModule = getModuleForLocation(FilenameLoc);
+  Module *RequestedModule = SuggestedModule->getModule();
+  if (!RequestedModule)
+    RequestedModule = HeaderInfo.findModuleForHeader(IncFileEnt).getModule();
+
+  if (RequestingModule == RequestedModule)
+    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))
+    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))
+    Diag(FilenameLoc, diag::error_undeclared_use_of_module)
+        << Filename;
+}
+
 const FileEntry *Preprocessor::LookupFile(
     SourceLocation FilenameLoc,
     StringRef Filename,
@@ -567,29 +649,8 @@ const FileEntry *Preprocessor::LookupFile(
       Filename, isAngled, FromDir, CurDir, CurFileEnt,
       SearchPath, RelativePath, SuggestedModule, SkipCache);
   if (FE) {
-    if (SuggestedModule) {
-      Module *RequestedModule = SuggestedModule->getModule();
-      if (RequestedModule) {
-        ModuleMap::ModuleHeaderRole Role = SuggestedModule->getRole();
-        #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(), FE);
-        bool IsPrivate = Look != PvtHdrs.end();
-        assert((IsPrivate && Role == ModuleMap::PrivateHeader)
-               || (!IsPrivate && Role != ModuleMap::PrivateHeader));
-        #endif
-        if (Role == ModuleMap::PrivateHeader) {
-          if (RequestedModule->getTopLevelModule() != getCurrentModule())
-            Diag(FilenameLoc, diag::error_use_of_private_header_outside_module)
-                 << Filename;
-        }
-      }
-    }
+    if (SuggestedModule)
+      verifyModuleInclude(FilenameLoc, Filename, FE, SuggestedModule);
     return FE;
   }
 
index 72fdc528fd4bee5586b15747ab556dc2058c1940..00f38bfa8c6b70f577aab193a01d7d8da6ccd903 100644 (file)
@@ -654,6 +654,7 @@ void Sema::ActOnEndOfTranslationUnit() {
         // diagnostic client to deal with complaints in the module map at this
         // point.
         ModMap.resolveExports(Mod, /*Complain=*/false);
+        ModMap.resolveUses(Mod, /*Complain=*/false);
         ModMap.resolveConflicts(Mod, /*Complain=*/false);
 
         // Queue the submodules, so their exports will also be resolved.
index 5b55390730d6587a9c098d549380e47db13b6282..9bb9a7a8632365aea69e24fa3d82fc94d0b38230 100644 (file)
@@ -3028,6 +3028,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
     }
   }
   UnresolvedModuleRefs.clear();
+
+  // FIXME: How do we load the 'use'd modules? They may not be submodules.
+  // Might be unnecessary as use declarations are only used to build the
+  // module itself.
   
   InitializeContext();
 
index a4879226f971f3522c61ad44e172ea3cf54329e9..409c9a18a50920f3dd64c141ee78370ca051e21f 100644 (file)
@@ -2421,6 +2421,10 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
       Stream.EmitRecord(SUBMODULE_EXPORTS, Record);
     }
 
+    //FIXME: How do we emit the 'use'd modules?  They may not be submodules.
+    // Might be unnecessary as use declarations are only used to build the
+    // module itself.
+
     // Emit the link libraries.
     for (unsigned I = 0, N = Mod->LinkLibraries.size(); I != N; ++I) {
       Record.clear();
diff --git a/test/Modules/Inputs/declare-use/a.h b/test/Modules/Inputs/declare-use/a.h
new file mode 100644 (file)
index 0000000..a36dc1b
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef A_H
+#define A_H
+const int a = 2;
+#endif
diff --git a/test/Modules/Inputs/declare-use/b.h b/test/Modules/Inputs/declare-use/b.h
new file mode 100644 (file)
index 0000000..55daf72
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef B_H
+#define B_H
+const int b = 3;
+#endif
diff --git a/test/Modules/Inputs/declare-use/c.h b/test/Modules/Inputs/declare-use/c.h
new file mode 100644 (file)
index 0000000..a24cd5a
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef C_H
+#define C_H
+#include "a.h"
+#include "b.h"
+const int c = a+b;
+#endif
diff --git a/test/Modules/Inputs/declare-use/d.h b/test/Modules/Inputs/declare-use/d.h
new file mode 100644 (file)
index 0000000..a597b01
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef D_H
+#define D_H
+#include "a.h"
+#include "b.h"
+const int d = a+b;
+#endif
diff --git a/test/Modules/Inputs/declare-use/e.h b/test/Modules/Inputs/declare-use/e.h
new file mode 100644 (file)
index 0000000..ed8d843
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef E_H
+#define E_H
+#include "a.h"
+#include "b.h"
+const int e = a*b;
+#endif
diff --git a/test/Modules/Inputs/declare-use/f.h b/test/Modules/Inputs/declare-use/f.h
new file mode 100644 (file)
index 0000000..1d8e2fd
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef F_H
+#define F_H
+#include "a.h"
+#include "b.h"
+const int f = a+b;
+#endif
diff --git a/test/Modules/Inputs/declare-use/g.h b/test/Modules/Inputs/declare-use/g.h
new file mode 100644 (file)
index 0000000..2a59017
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef G_H
+#define G_H
+#include "c.h"
+#include "g1.h"
+const int g1 = aux_g*c*7;
+#endif
diff --git a/test/Modules/Inputs/declare-use/g1.h b/test/Modules/Inputs/declare-use/g1.h
new file mode 100644 (file)
index 0000000..78a0724
--- /dev/null
@@ -0,0 +1 @@
+int aux_g = 11;
diff --git a/test/Modules/Inputs/declare-use/h.h b/test/Modules/Inputs/declare-use/h.h
new file mode 100644 (file)
index 0000000..df99a6d
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef H_H
+#define H_H
+#include "c.h"
+#include "d.h" // expected-error {{use of a module not declared used}}
+#include "h1.h"
+const int h1 = aux_h*c*7*d;
+#endif
diff --git a/test/Modules/Inputs/declare-use/h1.h b/test/Modules/Inputs/declare-use/h1.h
new file mode 100644 (file)
index 0000000..a9275d5
--- /dev/null
@@ -0,0 +1 @@
+int aux_h = 13;
diff --git a/test/Modules/Inputs/declare-use/module.map b/test/Modules/Inputs/declare-use/module.map
new file mode 100644 (file)
index 0000000..ae3e908
--- /dev/null
@@ -0,0 +1,43 @@
+module A {
+  header "a.h"
+}
+
+module B {
+  header "b.h"
+}
+
+module C {
+  header "c.h"
+  use A
+}
+
+module D {
+  header "d.h"
+  use A
+}
+
+module E {
+  header "e.h"
+  use A
+  use B
+}
+
+module F {
+  header "f.h"
+  use A
+  use B
+}
+
+module G {
+  header "g.h"
+  header "g1.h"
+  use C
+  use E
+}
+
+module H {
+  header "h.h"
+  header "h1.h"
+  use C
+  use E
+}
diff --git a/test/Modules/declare-use1.cpp b/test/Modules/declare-use1.cpp
new file mode 100644 (file)
index 0000000..5bb7e2a
--- /dev/null
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=G -I %S/Inputs/declare-use %s -verify
+
+#include "g.h"
+#include "e.h"
+#include "f.h" // expected-error {{use of a module not declared used}}
+const int g2 = g1+e+f;
diff --git a/test/Modules/declare-use2.cpp b/test/Modules/declare-use2.cpp
new file mode 100644 (file)
index 0000000..807962c
--- /dev/null
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=H -I %S/Inputs/declare-use %s -verify
+
+#include "h.h"
+#include "e.h"
+#include "f.h" // expected-error {{use of a module not declared used}}
+const int h2 = h1+e+f;