r191283 - Module use declarations (II)

Daniel Jasper djasper at google.com
Tue Sep 24 02:14:15 PDT 2013


Author: djasper
Date: Tue Sep 24 04:14:14 2013
New Revision: 191283

URL: http://llvm.org/viewvc/llvm-project?rev=191283&view=rev
Log:
Module use declarations (II)

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.

Added:
    cfe/trunk/test/Modules/Inputs/declare-use/
    cfe/trunk/test/Modules/Inputs/declare-use/a.h
    cfe/trunk/test/Modules/Inputs/declare-use/b.h
    cfe/trunk/test/Modules/Inputs/declare-use/c.h
    cfe/trunk/test/Modules/Inputs/declare-use/d.h
    cfe/trunk/test/Modules/Inputs/declare-use/e.h
    cfe/trunk/test/Modules/Inputs/declare-use/f.h
    cfe/trunk/test/Modules/Inputs/declare-use/g.h
    cfe/trunk/test/Modules/Inputs/declare-use/g1.h
    cfe/trunk/test/Modules/Inputs/declare-use/h.h
    cfe/trunk/test/Modules/Inputs/declare-use/h1.h
    cfe/trunk/test/Modules/Inputs/declare-use/module.map
    cfe/trunk/test/Modules/declare-use1.cpp
    cfe/trunk/test/Modules/declare-use2.cpp
Modified:
    cfe/trunk/docs/Modules.rst
    cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
    cfe/trunk/include/clang/Basic/LangOptions.def
    cfe/trunk/include/clang/Basic/Module.h
    cfe/trunk/include/clang/Driver/Options.td
    cfe/trunk/include/clang/Lex/ModuleMap.h
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/lib/Basic/Module.cpp
    cfe/trunk/lib/Driver/Tools.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Lex/HeaderSearch.cpp
    cfe/trunk/lib/Lex/ModuleMap.cpp
    cfe/trunk/lib/Lex/PPDirectives.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp

Modified: cfe/trunk/docs/Modules.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/Modules.rst?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/docs/Modules.rst (original)
+++ cfe/trunk/docs/Modules.rst Tue Sep 24 04:14:14 2013
@@ -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 o
   ``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 k
     *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 ``B
   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.

Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Tue Sep 24 04:14:14 2013
@@ -554,8 +554,8 @@ def err_mmap_umbrella_dir_not_found : Er
   "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 : Er
   "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">>;

Modified: cfe/trunk/include/clang/Basic/LangOptions.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.def?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.def (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.def Tue Sep 24 04:14:14 2013
@@ -94,6 +94,7 @@ BENIGN_LANGOPT(EmitAllDecls      , 1, 0,
 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__)")

Modified: cfe/trunk/include/clang/Basic/Module.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Module.h?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Module.h (original)
+++ cfe/trunk/include/clang/Basic/Module.h Tue Sep 24 04:14:14 2013
@@ -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 {

Modified: cfe/trunk/include/clang/Driver/Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/Options.td (original)
+++ cfe/trunk/include/clang/Driver/Options.td Tue Sep 24 04:14:14 2013
@@ -561,6 +561,9 @@ def fmodule_maps : Flag <["-"], "fmodule
   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-modu
   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>;

Modified: cfe/trunk/include/clang/Lex/ModuleMap.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleMap.h?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/ModuleMap.h (original)
+++ cfe/trunk/include/clang/Lex/ModuleMap.h Tue Sep 24 04:14:14 2013
@@ -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.

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Tue Sep 24 04:14:14 2013
@@ -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);

Modified: cfe/trunk/lib/Basic/Module.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Module.cpp?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Module.cpp (original)
+++ cfe/trunk/lib/Basic/Module.cpp Tue Sep 24 04:14:14 2013
@@ -362,6 +362,20 @@ void Module::print(raw_ostream &OS, unsi
     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 ";

Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Tue Sep 24 04:14:14 2013
@@ -3034,6 +3034,13 @@ void Clang::ConstructJob(Compilation &C,
     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)) {

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Tue Sep 24 04:14:14 2013
@@ -1280,6 +1280,7 @@ static void ParseLangArgs(LangOptions &O
   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);

Modified: cfe/trunk/lib/Lex/HeaderSearch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/HeaderSearch.cpp?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/HeaderSearch.cpp (original)
+++ cfe/trunk/lib/Lex/HeaderSearch.cpp Tue Sep 24 04:14:14 2013
@@ -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>

Modified: cfe/trunk/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Tue Sep 24 04:14:14 2013
@@ -387,6 +387,10 @@ ModuleMap::findOrCreateModule(StringRef
   // 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(StringRe
   
   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 *M
   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();

Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
+++ cfe/trunk/lib/Lex/PPDirectives.cpp Tue Sep 24 04:14:14 2013
@@ -532,6 +532,88 @@ void Preprocessor::PTHSkipExcludedCondit
   }
 }
 
+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::LookupFil
       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;
   }
 

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Tue Sep 24 04:14:14 2013
@@ -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.

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Tue Sep 24 04:14:14 2013
@@ -3028,6 +3028,10 @@ ASTReader::ASTReadResult ASTReader::Read
     }
   }
   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();
 

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=191283&r1=191282&r2=191283&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Sep 24 04:14:14 2013
@@ -2421,6 +2421,10 @@ void ASTWriter::WriteSubmodules(Module *
       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();

Added: cfe/trunk/test/Modules/Inputs/declare-use/a.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/declare-use/a.h?rev=191283&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/declare-use/a.h (added)
+++ cfe/trunk/test/Modules/Inputs/declare-use/a.h Tue Sep 24 04:14:14 2013
@@ -0,0 +1,4 @@
+#ifndef A_H
+#define A_H
+const int a = 2;
+#endif

Added: cfe/trunk/test/Modules/Inputs/declare-use/b.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/declare-use/b.h?rev=191283&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/declare-use/b.h (added)
+++ cfe/trunk/test/Modules/Inputs/declare-use/b.h Tue Sep 24 04:14:14 2013
@@ -0,0 +1,4 @@
+#ifndef B_H
+#define B_H
+const int b = 3;
+#endif

Added: cfe/trunk/test/Modules/Inputs/declare-use/c.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/declare-use/c.h?rev=191283&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/declare-use/c.h (added)
+++ cfe/trunk/test/Modules/Inputs/declare-use/c.h Tue Sep 24 04:14:14 2013
@@ -0,0 +1,6 @@
+#ifndef C_H
+#define C_H
+#include "a.h"
+#include "b.h"
+const int c = a+b;
+#endif

Added: cfe/trunk/test/Modules/Inputs/declare-use/d.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/declare-use/d.h?rev=191283&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/declare-use/d.h (added)
+++ cfe/trunk/test/Modules/Inputs/declare-use/d.h Tue Sep 24 04:14:14 2013
@@ -0,0 +1,6 @@
+#ifndef D_H
+#define D_H
+#include "a.h"
+#include "b.h"
+const int d = a+b;
+#endif

Added: cfe/trunk/test/Modules/Inputs/declare-use/e.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/declare-use/e.h?rev=191283&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/declare-use/e.h (added)
+++ cfe/trunk/test/Modules/Inputs/declare-use/e.h Tue Sep 24 04:14:14 2013
@@ -0,0 +1,6 @@
+#ifndef E_H
+#define E_H
+#include "a.h"
+#include "b.h"
+const int e = a*b;
+#endif

Added: cfe/trunk/test/Modules/Inputs/declare-use/f.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/declare-use/f.h?rev=191283&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/declare-use/f.h (added)
+++ cfe/trunk/test/Modules/Inputs/declare-use/f.h Tue Sep 24 04:14:14 2013
@@ -0,0 +1,6 @@
+#ifndef F_H
+#define F_H
+#include "a.h"
+#include "b.h"
+const int f = a+b;
+#endif

Added: cfe/trunk/test/Modules/Inputs/declare-use/g.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/declare-use/g.h?rev=191283&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/declare-use/g.h (added)
+++ cfe/trunk/test/Modules/Inputs/declare-use/g.h Tue Sep 24 04:14:14 2013
@@ -0,0 +1,6 @@
+#ifndef G_H
+#define G_H
+#include "c.h"
+#include "g1.h"
+const int g1 = aux_g*c*7;
+#endif

Added: cfe/trunk/test/Modules/Inputs/declare-use/g1.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/declare-use/g1.h?rev=191283&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/declare-use/g1.h (added)
+++ cfe/trunk/test/Modules/Inputs/declare-use/g1.h Tue Sep 24 04:14:14 2013
@@ -0,0 +1 @@
+int aux_g = 11;

Added: cfe/trunk/test/Modules/Inputs/declare-use/h.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/declare-use/h.h?rev=191283&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/declare-use/h.h (added)
+++ cfe/trunk/test/Modules/Inputs/declare-use/h.h Tue Sep 24 04:14:14 2013
@@ -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

Added: cfe/trunk/test/Modules/Inputs/declare-use/h1.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/declare-use/h1.h?rev=191283&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/declare-use/h1.h (added)
+++ cfe/trunk/test/Modules/Inputs/declare-use/h1.h Tue Sep 24 04:14:14 2013
@@ -0,0 +1 @@
+int aux_h = 13;

Added: cfe/trunk/test/Modules/Inputs/declare-use/module.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/declare-use/module.map?rev=191283&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/declare-use/module.map (added)
+++ cfe/trunk/test/Modules/Inputs/declare-use/module.map Tue Sep 24 04:14:14 2013
@@ -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
+}

Added: cfe/trunk/test/Modules/declare-use1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/declare-use1.cpp?rev=191283&view=auto
==============================================================================
--- cfe/trunk/test/Modules/declare-use1.cpp (added)
+++ cfe/trunk/test/Modules/declare-use1.cpp Tue Sep 24 04:14:14 2013
@@ -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;

Added: cfe/trunk/test/Modules/declare-use2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/declare-use2.cpp?rev=191283&view=auto
==============================================================================
--- cfe/trunk/test/Modules/declare-use2.cpp (added)
+++ cfe/trunk/test/Modules/declare-use2.cpp Tue Sep 24 04:14:14 2013
@@ -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;





More information about the cfe-commits mailing list