r342304 - [modules] Frontend support for building a header module from a list of

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 14 18:21:15 PDT 2018


Author: rsmith
Date: Fri Sep 14 18:21:15 2018
New Revision: 342304

URL: http://llvm.org/viewvc/llvm-project?rev=342304&view=rev
Log:
[modules] Frontend support for building a header module from a list of
headaer files.

Added:
    cfe/trunk/test/Modules/Inputs/no-module-map/
    cfe/trunk/test/Modules/Inputs/no-module-map/a.h
    cfe/trunk/test/Modules/Inputs/no-module-map/b.h
    cfe/trunk/test/Modules/no-module-map.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticIDs.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/LangOptions.h
    cfe/trunk/include/clang/Driver/CC1Options.td
    cfe/trunk/include/clang/Frontend/FrontendAction.h
    cfe/trunk/include/clang/Frontend/FrontendActions.h
    cfe/trunk/include/clang/Frontend/FrontendOptions.h
    cfe/trunk/include/clang/Lex/ModuleMap.h
    cfe/trunk/lib/Frontend/CompilerInstance.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Frontend/FrontendAction.cpp
    cfe/trunk/lib/Frontend/FrontendActions.cpp
    cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp
    cfe/trunk/lib/Lex/ModuleMap.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td Fri Sep 14 18:21:15 2018
@@ -187,6 +187,8 @@ def err_module_build_requires_fmodules :
   "module compilation requires '-fmodules'">;
 def err_module_interface_requires_modules_ts : Error<
   "module interface compilation requires '-fmodules-ts'">;
+def err_header_module_requires_modules : Error<
+  "header module compilation requires '-fmodules' or '-fmodules-ts'">;
 def warn_module_config_mismatch : Warning<
   "module file %0 cannot be loaded due to a configuration mismatch with the current "
   "compilation">, InGroup<DiagGroup<"module-file-config-mismatch">>, DefaultError;
@@ -224,6 +226,10 @@ def remark_module_build_done : Remark<"f
 def err_modules_embed_file_not_found :
   Error<"file '%0' specified by '-fmodules-embed-file=' not found">,
   DefaultFatal;
+def err_module_header_file_not_found :
+  Error<"module header file '%0' not found">, DefaultFatal;
+def err_module_header_file_invalid :
+  Error<"unexpected module header file input '%0'">, DefaultFatal;
 
 def err_test_module_file_extension_version : Error<
   "test module file extension '%0' has different version (%1.%2) than expected "

Modified: cfe/trunk/include/clang/Basic/DiagnosticIDs.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticIDs.h?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticIDs.h (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticIDs.h Fri Sep 14 18:21:15 2018
@@ -30,7 +30,7 @@ namespace clang {
     enum {
       DIAG_SIZE_COMMON        =  300,
       DIAG_SIZE_DRIVER        =  200,
-      DIAG_SIZE_FRONTEND      =  100,
+      DIAG_SIZE_FRONTEND      =  150,
       DIAG_SIZE_SERIALIZATION =  120,
       DIAG_SIZE_LEX           =  400,
       DIAG_SIZE_PARSE         =  500,

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Sep 14 18:21:15 2018
@@ -9090,6 +9090,8 @@ def err_invalid_type_for_program_scope_v
 let CategoryName = "Modules Issue" in {
 def err_module_decl_in_module_map_module : Error<
   "'module' declaration found while building module from module map">;
+def err_module_decl_in_header_module : Error<
+  "'module' declaration found while building header module">;
 def err_module_interface_implementation_mismatch : Error<
   "missing 'export' specifier in module declaration while "
   "building module interface">;

Modified: cfe/trunk/include/clang/Basic/LangOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.h?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.h (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.h Fri Sep 14 18:21:15 2018
@@ -73,8 +73,11 @@ public:
     /// Compiling a module from a module map.
     CMK_ModuleMap,
 
+    /// Compiling a module from a list of header files.
+    CMK_HeaderModule,
+
     /// Compiling a C++ modules TS module interface unit.
-    CMK_ModuleInterface
+    CMK_ModuleInterface,
   };
 
   enum PragmaMSPointersToMembersKind {

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Fri Sep 14 18:21:15 2018
@@ -543,6 +543,8 @@ def emit_module : Flag<["-"], "emit-modu
   HelpText<"Generate pre-compiled module file from a module map">;
 def emit_module_interface : Flag<["-"], "emit-module-interface">,
   HelpText<"Generate pre-compiled module file from a C++ module interface">;
+def emit_header_module : Flag<["-"], "emit-header-module">,
+  HelpText<"Generate pre-compiled module file from a set of header files">;
 def emit_pth : Flag<["-"], "emit-pth">,
   HelpText<"Generate pre-tokenized header file">;
 def emit_pch : Flag<["-"], "emit-pch">,

Modified: cfe/trunk/include/clang/Frontend/FrontendAction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendAction.h?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendAction.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendAction.h Fri Sep 14 18:21:15 2018
@@ -48,6 +48,12 @@ protected:
   /// @name Implementation Action Interface
   /// @{
 
+  /// Prepare to execute the action on the given CompilerInstance.
+  ///
+  /// This is called before executing the action on any inputs, and can modify
+  /// the configuration as needed (including adjusting the input list).
+  virtual bool PrepareToExecuteAction(CompilerInstance &CI) { return true; }
+
   /// Create the AST consumer object for this action, if supported.
   ///
   /// This routine is called as part of BeginSourceFile(), which will
@@ -130,11 +136,18 @@ public:
     return CurrentInput;
   }
 
-  const StringRef getCurrentFile() const {
+  StringRef getCurrentFile() const {
     assert(!CurrentInput.isEmpty() && "No current file!");
     return CurrentInput.getFile();
   }
 
+  StringRef getCurrentFileOrBufferName() const {
+    assert(!CurrentInput.isEmpty() && "No current file!");
+    return CurrentInput.isFile()
+               ? CurrentInput.getFile()
+               : CurrentInput.getBuffer()->getBufferIdentifier();
+  }
+
   InputKind getCurrentFileKind() const {
     assert(!CurrentInput.isEmpty() && "No current file!");
     return CurrentInput.getKind();
@@ -190,6 +203,11 @@ public:
   /// @name Public Action Interface
   /// @{
 
+  /// Prepare the action to execute on the given compiler instance.
+  bool PrepareToExecute(CompilerInstance &CI) {
+    return PrepareToExecuteAction(CI);
+  }
+
   /// Prepare the action for processing the input file \p Input.
   ///
   /// This is run after the options and frontend have been initialized,

Modified: cfe/trunk/include/clang/Frontend/FrontendActions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendActions.h?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendActions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendActions.h Fri Sep 14 18:21:15 2018
@@ -142,6 +142,19 @@ private:
   CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
 };
 
+class GenerateHeaderModuleAction : public GenerateModuleAction {
+  /// The synthesized module input buffer for the current compilation.
+  std::unique_ptr<llvm::MemoryBuffer> Buffer;
+  std::vector<std::string> ModuleHeaders;
+
+private:
+  bool PrepareToExecuteAction(CompilerInstance &CI) override;
+  bool BeginSourceFileAction(CompilerInstance &CI) override;
+
+  std::unique_ptr<raw_pwrite_stream>
+  CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
+};
+
 class SyntaxOnlyAction : public ASTFrontendAction {
 protected:
   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,

Modified: cfe/trunk/include/clang/Frontend/FrontendOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendOptions.h?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendOptions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendOptions.h Fri Sep 14 18:21:15 2018
@@ -82,6 +82,9 @@ enum ActionKind {
   /// Generate pre-compiled module from a C++ module interface file.
   GenerateModuleInterface,
 
+  /// Generate pre-compiled module from a set of header files.
+  GenerateHeaderModule,
+
   /// Generate pre-compiled header.
   GeneratePCH,
 

Modified: cfe/trunk/include/clang/Lex/ModuleMap.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleMap.h?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/ModuleMap.h (original)
+++ cfe/trunk/include/clang/Lex/ModuleMap.h Fri Sep 14 18:21:15 2018
@@ -92,9 +92,9 @@ class ModuleMap {
   /// named LangOpts::CurrentModule, if we've loaded it).
   Module *SourceModule = nullptr;
 
-  /// The global module for the current TU, if we still own it. (Ownership is
-  /// transferred if/when we create an enclosing module.
-  std::unique_ptr<Module> PendingGlobalModule;
+  /// Submodules of the current module that have not yet been attached to it.
+  /// (Ownership is transferred if/when we create an enclosing module.)
+  llvm::SmallVector<std::unique_ptr<Module>, 8> PendingSubmodules;
 
   /// The top-level modules that are known.
   llvm::StringMap<Module *> Modules;
@@ -519,8 +519,7 @@ public:
                                                bool IsFramework,
                                                bool IsExplicit);
 
-  /// Create a 'global module' for a C++ Modules TS module interface
-  /// unit.
+  /// Create a 'global module' for a C++ Modules TS module interface unit.
   ///
   /// We model the global module as a submodule of the module interface unit.
   /// Unfortunately, we can't create the module interface unit's Module until
@@ -537,6 +536,9 @@ public:
   Module *createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name,
                                        Module *GlobalModule);
 
+  /// Create a header module from the specified list of headers.
+  Module *createHeaderModule(StringRef Name, ArrayRef<Module::Header> Headers);
+
   /// Infer the contents of a framework module map from the given
   /// framework directory.
   Module *inferFrameworkModule(const DirectoryEntry *FrameworkDir,

Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Fri Sep 14 18:21:15 2018
@@ -911,6 +911,9 @@ bool CompilerInstance::ExecuteAction(Fro
   // taking it as an input instead of hard-coding llvm::errs.
   raw_ostream &OS = llvm::errs();
 
+  if (!Act.PrepareToExecute(*this))
+    return false;
+
   // Create the target instance.
   setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(),
                                          getInvocation().TargetOpts));
@@ -1615,22 +1618,7 @@ CompilerInstance::loadModule(SourceLocat
                              Module::NameVisibilityKind Visibility,
                              bool IsInclusionDirective) {
   // Determine what file we're searching from.
-  // FIXME: Should we be deciding whether this is a submodule (here and
-  // below) based on -fmodules-ts or should we pass a flag and make the
-  // caller decide?
-  std::string ModuleName;
-  if (getLangOpts().ModulesTS) {
-    // FIXME: Same code as Sema::ActOnModuleDecl() so there is probably a
-    // better place/way to do this.
-    for (auto &Piece : Path) {
-      if (!ModuleName.empty())
-        ModuleName += ".";
-      ModuleName += Piece.first->getName();
-    }
-  }
-  else
-    ModuleName = Path[0].first->getName();
-
+  StringRef ModuleName = Path[0].first->getName();
   SourceLocation ModuleNameLoc = Path[0].second;
 
   // If we've already handled this import, just return the cached result.
@@ -1859,7 +1847,7 @@ CompilerInstance::loadModule(SourceLocat
   // Verify that the rest of the module path actually corresponds to
   // a submodule.
   bool MapPrivateSubModToTopLevel = false;
-  if (!getLangOpts().ModulesTS && Path.size() > 1) {
+  if (Path.size() > 1) {
     for (unsigned I = 1, N = Path.size(); I != N; ++I) {
       StringRef Name = Path[I].first->getName();
       clang::Module *Sub = Module->findSubmodule(Name);

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Fri Sep 14 18:21:15 2018
@@ -1454,6 +1454,8 @@ static InputKind ParseFrontendArgs(Front
       Opts.ProgramAction = frontend::GenerateModule; break;
     case OPT_emit_module_interface:
       Opts.ProgramAction = frontend::GenerateModuleInterface; break;
+    case OPT_emit_header_module:
+      Opts.ProgramAction = frontend::GenerateHeaderModule; break;
     case OPT_emit_pch:
       Opts.ProgramAction = frontend::GeneratePCH; break;
     case OPT_emit_pth:
@@ -2830,6 +2832,7 @@ static bool isStrictlyPreprocessorAction
   case frontend::FixIt:
   case frontend::GenerateModule:
   case frontend::GenerateModuleInterface:
+  case frontend::GenerateHeaderModule:
   case frontend::GeneratePCH:
   case frontend::GeneratePTH:
   case frontend::ParseSyntaxOnly:

Modified: cfe/trunk/lib/Frontend/FrontendAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendAction.cpp?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendAction.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendAction.cpp Fri Sep 14 18:21:15 2018
@@ -523,7 +523,6 @@ bool FrontendAction::BeginSourceFile(Com
   setCurrentInput(Input);
   setCompilerInstance(&CI);
 
-  StringRef InputFile = Input.getFile();
   bool HasBegunSourceFile = false;
   bool ReplayASTFile = Input.getKind().getFormat() == InputKind::Precompiled &&
                        usesPreprocessorOnly();
@@ -541,6 +540,9 @@ bool FrontendAction::BeginSourceFile(Com
                               &Diags->getDiagnosticOptions()));
     ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false);
 
+    // FIXME: What if the input is a memory buffer?
+    StringRef InputFile = Input.getFile();
+
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
         InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly,
         ASTDiags, CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs);
@@ -604,6 +606,9 @@ bool FrontendAction::BeginSourceFile(Com
 
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
 
+    // FIXME: What if the input is a memory buffer?
+    StringRef InputFile = Input.getFile();
+
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
         InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
         CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs);
@@ -791,7 +796,7 @@ bool FrontendAction::BeginSourceFile(Com
 
     // For preprocessed files, check if the first line specifies the original
     // source file name with a linemarker.
-    std::string PresumedInputFile = InputFile;
+    std::string PresumedInputFile = getCurrentFileOrBufferName();
     if (Input.isPreprocessed())
       ReadOriginalFileName(CI, PresumedInputFile);
 

Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendActions.cpp Fri Sep 14 18:21:15 2018
@@ -242,6 +242,76 @@ GenerateModuleInterfaceAction::CreateOut
   return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm");
 }
 
+bool GenerateHeaderModuleAction::PrepareToExecuteAction(
+    CompilerInstance &CI) {
+  if (!CI.getLangOpts().Modules && !CI.getLangOpts().ModulesTS) {
+    CI.getDiagnostics().Report(diag::err_header_module_requires_modules);
+    return false;
+  }
+
+  auto &Inputs = CI.getFrontendOpts().Inputs;
+  if (Inputs.empty())
+    return GenerateModuleAction::BeginInvocation(CI);
+
+  auto Kind = Inputs[0].getKind();
+
+  // Convert the header file inputs into a single module input buffer.
+  SmallString<256> HeaderContents;
+  ModuleHeaders.reserve(Inputs.size());
+  for (const FrontendInputFile &FIF : Inputs) {
+    // FIXME: We should support re-compiling from an AST file.
+    if (FIF.getKind().getFormat() != InputKind::Source || !FIF.isFile()) {
+      CI.getDiagnostics().Report(diag::err_module_header_file_not_found)
+          << (FIF.isFile() ? FIF.getFile()
+                           : FIF.getBuffer()->getBufferIdentifier());
+      return true;
+    }
+
+    HeaderContents += "#include \"";
+    HeaderContents += FIF.getFile();
+    HeaderContents += "\"\n";
+    ModuleHeaders.push_back(FIF.getFile());
+  }
+  Buffer = llvm::MemoryBuffer::getMemBufferCopy(
+      HeaderContents, Module::getModuleInputBufferName());
+
+  // Set that buffer up as our "real" input.
+  Inputs.clear();
+  Inputs.push_back(FrontendInputFile(Buffer.get(), Kind, /*IsSystem*/false));
+
+  return GenerateModuleAction::PrepareToExecuteAction(CI);
+}
+
+bool GenerateHeaderModuleAction::BeginSourceFileAction(
+    CompilerInstance &CI) {
+  CI.getLangOpts().setCompilingModule(LangOptions::CMK_HeaderModule);
+
+  // Synthesize a Module object for the given headers.
+  auto &HS = CI.getPreprocessor().getHeaderSearchInfo();
+  SmallVector<Module::Header, 16> Headers;
+  for (StringRef Name : ModuleHeaders) {
+    const DirectoryLookup *CurDir = nullptr;
+    const FileEntry *FE = HS.LookupFile(
+        Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir,
+        None, nullptr, nullptr, nullptr, nullptr, nullptr);
+    if (!FE) {
+      CI.getDiagnostics().Report(diag::err_module_header_file_not_found)
+        << Name;
+      continue;
+    }
+    Headers.push_back({Name, FE});
+  }
+  HS.getModuleMap().createHeaderModule(CI.getLangOpts().CurrentModule, Headers);
+
+  return GenerateModuleAction::BeginSourceFileAction(CI);
+}
+
+std::unique_ptr<raw_pwrite_stream>
+GenerateHeaderModuleAction::CreateOutputFile(CompilerInstance &CI,
+                                             StringRef InFile) {
+  return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm");
+}
+
 SyntaxOnlyAction::~SyntaxOnlyAction() {
 }
 

Modified: cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp (original)
+++ cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp Fri Sep 14 18:21:15 2018
@@ -61,6 +61,8 @@ CreateFrontendBaseAction(CompilerInstanc
     return llvm::make_unique<GenerateModuleFromModuleMapAction>();
   case GenerateModuleInterface:
     return llvm::make_unique<GenerateModuleInterfaceAction>();
+  case GenerateHeaderModule:
+    return llvm::make_unique<GenerateHeaderModuleAction>();
   case GeneratePCH:            return llvm::make_unique<GeneratePCHAction>();
   case GeneratePTH:            return llvm::make_unique<GeneratePTHAction>();
   case InitOnly:               return llvm::make_unique<InitOnlyAction>();

Modified: cfe/trunk/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Fri Sep 14 18:21:15 2018
@@ -806,12 +806,11 @@ std::pair<Module *, bool> ModuleMap::fin
 }
 
 Module *ModuleMap::createGlobalModuleForInterfaceUnit(SourceLocation Loc) {
-  assert(!PendingGlobalModule && "created multiple global modules");
-  PendingGlobalModule.reset(
+  PendingSubmodules.emplace_back(
       new Module("<global>", Loc, nullptr, /*IsFramework*/ false,
                  /*IsExplicit*/ true, NumCreatedModules++));
-  PendingGlobalModule->Kind = Module::GlobalModuleFragment;
-  return PendingGlobalModule.get();
+  PendingSubmodules.back()->Kind = Module::GlobalModuleFragment;
+  return PendingSubmodules.back().get();
 }
 
 Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
@@ -827,10 +826,11 @@ Module *ModuleMap::createModuleForInterf
   Modules[Name] = SourceModule = Result;
 
   // Reparent the current global module fragment as a submodule of this module.
-  assert(GlobalModule == PendingGlobalModule.get() &&
-         "unexpected global module");
-  GlobalModule->setParent(Result);
-  PendingGlobalModule.release(); // now owned by parent
+  for (auto &Submodule : PendingSubmodules) {
+    Submodule->setParent(Result);
+    Submodule.release(); // now owned by parent
+  }
+  PendingSubmodules.clear();
 
   // Mark the main source file as being within the newly-created module so that
   // declarations and macros are properly visibility-restricted to it.
@@ -840,6 +840,29 @@ Module *ModuleMap::createModuleForInterf
 
   return Result;
 }
+
+Module *ModuleMap::createHeaderModule(StringRef Name,
+                                      ArrayRef<Module::Header> Headers) {
+  assert(LangOpts.CurrentModule == Name && "module name mismatch");
+  assert(!Modules[Name] && "redefining existing module");
+
+  auto *Result =
+      new Module(Name, SourceLocation(), nullptr, /*IsFramework*/ false,
+                 /*IsExplicit*/ false, NumCreatedModules++);
+  Result->Kind = Module::ModuleInterfaceUnit;
+  Modules[Name] = SourceModule = Result;
+
+  for (const Module::Header &H : Headers) {
+    auto *M = new Module(H.NameAsWritten, SourceLocation(), Result,
+                         /*IsFramework*/ false,
+                         /*IsExplicit*/ true, NumCreatedModules++);
+    // Header modules are implicitly 'export *'.
+    M->Exports.push_back(Module::ExportDecl(nullptr, true));
+    addHeader(M, H, NormalHeader);
+  }
+
+  return Result;
+}
 
 /// For a framework module, infer the framework against which we
 /// should link.

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Fri Sep 14 18:21:15 2018
@@ -977,7 +977,8 @@ void Sema::ActOnEndOfTranslationUnit() {
     // module declaration by now.
     if (getLangOpts().getCompilingModule() ==
             LangOptions::CMK_ModuleInterface &&
-        ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) {
+        (ModuleScopes.empty() ||
+         ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit)) {
       // FIXME: Make a better guess as to where to put the module declaration.
       Diag(getSourceManager().getLocForStartOfFile(
                getSourceManager().getMainFileID()),

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=342304&r1=342303&r2=342304&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Sep 14 18:21:15 2018
@@ -16832,6 +16832,10 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDe
   case LangOptions::CMK_ModuleMap:
     Diag(ModuleLoc, diag::err_module_decl_in_module_map_module);
     return nullptr;
+
+  case LangOptions::CMK_HeaderModule:
+    Diag(ModuleLoc, diag::err_module_decl_in_header_module);
+    return nullptr;
   }
 
   assert(ModuleScopes.size() == 1 && "expected to be at global module scope");
@@ -16900,7 +16904,8 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDe
   case ModuleDeclKind::Implementation:
     std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc(
         PP.getIdentifierInfo(ModuleName), Path[0].second);
-    Mod = getModuleLoader().loadModule(ModuleLoc, Path, Module::AllVisible,
+    Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc},
+                                       Module::AllVisible,
                                        /*IsIncludeDirective=*/false);
     if (!Mod) {
       Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
@@ -16930,6 +16935,19 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDe
 DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
                                    SourceLocation ImportLoc,
                                    ModuleIdPath Path) {
+  // Flatten the module path for a Modules TS module name.
+  std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc;
+  if (getLangOpts().ModulesTS) {
+    std::string ModuleName;
+    for (auto &Piece : Path) {
+      if (!ModuleName.empty())
+        ModuleName += ".";
+      ModuleName += Piece.first->getName();
+    }
+    ModuleNameLoc = {PP.getIdentifierInfo(ModuleName), Path[0].second};
+    Path = ModuleIdPath(ModuleNameLoc);
+  }
+
   Module *Mod =
       getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible,
                                    /*IsIncludeDirective=*/false);

Added: cfe/trunk/test/Modules/Inputs/no-module-map/a.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/no-module-map/a.h?rev=342304&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/no-module-map/a.h (added)
+++ cfe/trunk/test/Modules/Inputs/no-module-map/a.h Fri Sep 14 18:21:15 2018
@@ -0,0 +1,4 @@
+#ifndef A_H
+#define A_H
+void a();
+#endif

Added: cfe/trunk/test/Modules/Inputs/no-module-map/b.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/no-module-map/b.h?rev=342304&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/no-module-map/b.h (added)
+++ cfe/trunk/test/Modules/Inputs/no-module-map/b.h Fri Sep 14 18:21:15 2018
@@ -0,0 +1,5 @@
+#ifndef B_H
+#define B_H
+#include "a.h"
+void b();
+#endif

Added: cfe/trunk/test/Modules/no-module-map.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/no-module-map.cpp?rev=342304&view=auto
==============================================================================
--- cfe/trunk/test/Modules/no-module-map.cpp (added)
+++ cfe/trunk/test/Modules/no-module-map.cpp Fri Sep 14 18:21:15 2018
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -fmodules-ts -fmodule-name=ab -x c++-header %S/Inputs/no-module-map/a.h %S/Inputs/no-module-map/b.h -emit-header-module -o %t.pcm
+// RUN: %clang_cc1 -fmodules-ts -fmodule-file=%t.pcm %s -I%S/Inputs/no-module-map -verify
+// RUN: %clang_cc1 -fmodules-ts -fmodule-file=%t.pcm %s -I%S/Inputs/no-module-map -verify -DA
+// RUN: %clang_cc1 -fmodules-ts -fmodule-file=%t.pcm %s -I%S/Inputs/no-module-map -verify -DB
+// RUN: %clang_cc1 -fmodules-ts -fmodule-file=%t.pcm %s -I%S/Inputs/no-module-map -verify -DA -DB
+
+#ifdef B
+// expected-no-diagnostics
+#endif
+
+#ifdef A
+#include "a.h"
+#endif
+
+#ifdef B
+#include "b.h"
+#endif
+
+#if defined(A) || defined(B)
+#ifndef A_H
+#error A_H should be defined
+#endif
+#else
+#ifdef A_H
+#error A_H should not be defined
+#endif
+// expected-error at +3 {{must be imported from}}
+// expected-note@* {{previous declaration}}
+#endif
+void use_a() { a(); }
+
+#if defined(B)
+#ifndef B_H
+#error B_H should be defined
+#endif
+#else
+#ifdef B_H
+#error B_H should not be defined
+#endif
+// expected-error at +3 {{must be imported from}}
+// expected-note@* {{previous declaration}}
+#endif
+void use_b() { b(); }




More information about the cfe-commits mailing list