r279794 - C++ Modules TS: add frontend support for building pcm files from module

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 25 17:14:38 PDT 2016


Author: rsmith
Date: Thu Aug 25 19:14:38 2016
New Revision: 279794

URL: http://llvm.org/viewvc/llvm-project?rev=279794&view=rev
Log:
C++ Modules TS: add frontend support for building pcm files from module
interface files. At the moment, all declarations (and no macros) are exported,
and 'export' declarations are not supported yet.

Added:
    cfe/trunk/test/Parser/cxx-modules-interface.cppm
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/LangOptions.def
    cfe/trunk/include/clang/Basic/LangOptions.h
    cfe/trunk/include/clang/Driver/CC1Options.td
    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/ASTUnit.cpp
    cfe/trunk/lib/Frontend/CompilerInstance.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Frontend/FrontendActions.cpp
    cfe/trunk/lib/Frontend/FrontendOptions.cpp
    cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp
    cfe/trunk/lib/Lex/ModuleMap.cpp
    cfe/trunk/lib/Lex/PPLexerChange.cpp
    cfe/trunk/lib/Lex/PPMacroExpansion.cpp
    cfe/trunk/lib/Lex/Preprocessor.cpp
    cfe/trunk/lib/Parse/ParseAST.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/lib/Serialization/GeneratePCH.cpp
    cfe/trunk/test/Parser/cxx-modules-import.cpp
    cfe/trunk/test/lit.cfg

Modified: cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td Thu Aug 25 19:14:38 2016
@@ -174,6 +174,8 @@ def warn_incompatible_analyzer_plugin_ap
 def note_incompatible_analyzer_plugin_api : Note<
     "current API version is '%0', but plugin was compiled with version '%1'">;
 
+def err_module_interface_requires_modules_ts : Error<
+  "module interface compilation requires '-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;
@@ -217,4 +219,4 @@ def err_invalid_vfs_overlay : Error<
 
 def warn_option_invalid_ocl_version : Warning<
   "OpenCL version %0 does not support the option '%1'">, InGroup<Deprecated>;
-}
\ No newline at end of file
+}

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Thu Aug 25 19:14:38 2016
@@ -1021,6 +1021,10 @@ def warn_pragma_unroll_cuda_value_in_par
 } // end of Parse Issue category.
 
 let CategoryName = "Modules Issue" in {
+def err_expected_module_interface_decl : Error<
+  "expected module declaration at start of module interface">;
+def err_unexpected_module_decl : Error<
+  "module declaration must be the first declaration in the translation unit">;
 def err_module_expected_ident : Error<
   "expected a module name after module%select{| import}0">;
 def err_unexpected_module_kind : Error<

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Aug 25 19:14:38 2016
@@ -8467,6 +8467,10 @@ def err_module_interface_implementation_
   "found while %select{not |not |}0building module interface">;
 def err_current_module_name_mismatch : Error<
   "module name '%0' specified on command line does not match name of module">;
+def err_module_redefinition : Error<
+  "redefinition of module '%0'">;
+def note_prev_module_definition : Note<"previously defined here">;
+def note_prev_module_definition_from_ast_file : Note<"module loaded from '%0'">;
 def err_module_private_specialization : Error<
   "%select{template|partial|member}0 specialization cannot be "
   "declared __module_private__">;

Modified: cfe/trunk/include/clang/Basic/LangOptions.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.def?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.def (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.def Thu Aug 25 19:14:38 2016
@@ -142,8 +142,9 @@ BENIGN_LANGOPT(EmitAllDecls      , 1, 0,
 LANGOPT(MathErrno         , 1, 1, "errno in 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(ModulesTS         , 1, 0, "C++ Modules TS")
-BENIGN_LANGOPT(CompilingModule, 1, 0, "compiling a module interface")
+COMPATIBLE_LANGOPT(ModulesTS  , 1, 0, "C++ Modules TS")
+BENIGN_ENUM_LANGOPT(CompilingModule, CompilingModuleKind, 2, CMK_None,
+                    "compiling a module interface")
 COMPATIBLE_LANGOPT(ModulesDeclUse    , 1, 0, "require declaration of module uses")
 BENIGN_LANGOPT(ModulesSearchAll  , 1, 1, "searching even non-imported modules to find unresolved references")
 COMPATIBLE_LANGOPT(ModulesStrictDeclUse, 1, 0, "requiring declaration of module uses and all headers to be in modules")

Modified: cfe/trunk/include/clang/Basic/LangOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.h?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.h (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.h Thu Aug 25 19:14:38 2016
@@ -58,6 +58,12 @@ public:
     SOB_Trapping    // -ftrapv
   };
 
+  enum CompilingModuleKind {
+    CMK_None,           ///< Not compiling a module interface at all.
+    CMK_ModuleMap,      ///< Compiling a module from a module map.
+    CMK_ModuleInterface ///< Compiling a C++ modules TS module interface unit.
+  };
+
   enum PragmaMSPointersToMembersKind {
     PPTMK_BestCase,
     PPTMK_FullGeneralitySingleInheritance,
@@ -134,7 +140,12 @@ public:
   Type get##Name() const { return static_cast<Type>(Name); } \
   void set##Name(Type Value) { Name = static_cast<unsigned>(Value); }  
 #include "clang/Basic/LangOptions.def"
-  
+
+  /// Are we compiling a module interface (.cppm or module map)?
+  bool isCompilingModule() const {
+    return getCompilingModule() != CMK_None;
+  }
+
   bool isSignedOverflowDefined() const {
     return getSignedOverflowBehavior() == SOB_Defined;
   }

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Thu Aug 25 19:14:38 2016
@@ -459,6 +459,8 @@ def print_decl_contexts : Flag<["-"], "p
   HelpText<"Print DeclContexts and their Decls">;
 def emit_module : Flag<["-"], "emit-module">,
   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_pth : Flag<["-"], "emit-pth">,
   HelpText<"Generate pre-tokenized header file">;
 def emit_pch : Flag<["-"], "emit-pch">,

Modified: cfe/trunk/include/clang/Frontend/FrontendActions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendActions.h?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendActions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendActions.h Thu Aug 25 19:14:38 2016
@@ -91,11 +91,12 @@ public:
 };
 
 class GenerateModuleAction : public ASTFrontendAction {
-  clang::Module *Module;
-  const FileEntry *ModuleMapForUniquing;
-  bool IsSystem;
-  
+  virtual std::unique_ptr<raw_pwrite_stream>
+  CreateOutputFile(CompilerInstance &CI, StringRef InFile) = 0;
+
 protected:
+  bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
+
   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
                                                  StringRef InFile) override;
 
@@ -104,22 +105,31 @@ protected:
   }
 
   bool hasASTFileSupport() const override { return false; }
+};
+
+class GenerateModuleFromModuleMapAction : public GenerateModuleAction {
+  clang::Module *Module = nullptr;
+  const FileEntry *ModuleMapForUniquing = nullptr;
+  bool IsSystem = false;
+
+private:
+  bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
+
+  std::unique_ptr<raw_pwrite_stream>
+  CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
 
 public:
-  GenerateModuleAction(const FileEntry *ModuleMap = nullptr,
-                       bool IsSystem = false)
-    : ASTFrontendAction(), ModuleMapForUniquing(ModuleMap), IsSystem(IsSystem)
-  { }
+  GenerateModuleFromModuleMapAction() {}
+  GenerateModuleFromModuleMapAction(const FileEntry *ModuleMap, bool IsSystem)
+      : ModuleMapForUniquing(ModuleMap), IsSystem(IsSystem) {}
+};
 
+class GenerateModuleInterfaceAction : public GenerateModuleAction {
+private:
   bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
 
-  /// \brief Compute the AST consumer arguments that will be used to
-  /// create the PCHGenerator instance returned by CreateASTConsumer.
-  ///
-  /// \returns true if an error occurred, false otherwise.
   std::unique_ptr<raw_pwrite_stream>
-  ComputeASTConsumerArguments(CompilerInstance &CI, StringRef InFile,
-                              std::string &Sysroot, std::string &OutputFile);
+  CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
 };
 
 class SyntaxOnlyAction : public ASTFrontendAction {

Modified: cfe/trunk/include/clang/Frontend/FrontendOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendOptions.h?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendOptions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendOptions.h Thu Aug 25 19:14:38 2016
@@ -40,7 +40,9 @@ namespace frontend {
     EmitCodeGenOnly,        ///< Generate machine code, but don't emit anything.
     EmitObj,                ///< Emit a .o file.
     FixIt,                  ///< Parse and apply any fixits to the source.
-    GenerateModule,         ///< Generate pre-compiled module.
+    GenerateModule,         ///< Generate pre-compiled module from a module map.
+    GenerateModuleInterface,///< Generate pre-compiled module from a C++ module
+                            ///< interface file.
     GeneratePCH,            ///< Generate pre-compiled header.
     GeneratePTH,            ///< Generate pre-tokenized header.
     InitOnly,               ///< Only execute frontend initialization.

Modified: cfe/trunk/include/clang/Lex/ModuleMap.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleMap.h?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/ModuleMap.h (original)
+++ cfe/trunk/include/clang/Lex/ModuleMap.h Thu Aug 25 19:14:38 2016
@@ -402,6 +402,15 @@ public:
                                                bool IsFramework,
                                                bool IsExplicit);
 
+  /// \brief Create a new module for a C++ Modules TS module interface unit.
+  /// The module must not already exist, and will be configured for the current
+  /// compilation.
+  ///
+  /// Note that this also sets the current module to the newly-created module.
+  ///
+  /// \returns The newly-created module.
+  Module *createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name);
+
   /// \brief Infer the contents of a framework module map from the given
   /// framework directory.
   Module *inferFrameworkModule(const DirectoryEntry *FrameworkDir,

Modified: cfe/trunk/lib/Frontend/ASTUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTUnit.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/ASTUnit.cpp (original)
+++ cfe/trunk/lib/Frontend/ASTUnit.cpp Thu Aug 25 19:14:38 2016
@@ -2825,7 +2825,7 @@ const FileEntry *ASTUnit::getPCHFile() {
 }
 
 bool ASTUnit::isModuleFile() {
-  return isMainFileAST() && ASTFileLangOpts.CompilingModule;
+  return isMainFileAST() && ASTFileLangOpts.isCompilingModule();
 }
 
 void ASTUnit::PreambleData::countLines() const {

Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Thu Aug 25 19:14:38 2016
@@ -1026,7 +1026,7 @@ static bool compileModuleImpl(CompilerIn
 
   // Construct a module-generating action. Passing through the module map is
   // safe because the FileManager is shared between the compiler instances.
-  GenerateModuleAction CreateModuleAction(
+  GenerateModuleFromModuleMapAction CreateModuleAction(
       ModMap.getModuleMapFileForUniquing(Module), Module->IsSystem);
 
   ImportingInstance.getDiagnostics().Report(ImportLoc,

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Thu Aug 25 19:14:38 2016
@@ -1116,6 +1116,8 @@ static InputKind ParseFrontendArgs(Front
       Opts.ProgramAction = frontend::FixIt; break;
     case OPT_emit_module:
       Opts.ProgramAction = frontend::GenerateModule; break;
+    case OPT_emit_module_interface:
+      Opts.ProgramAction = frontend::GenerateModuleInterface; break;
     case OPT_emit_pch:
       Opts.ProgramAction = frontend::GeneratePCH; break;
     case OPT_emit_pth:
@@ -2259,6 +2261,7 @@ static void ParsePreprocessorOutputArgs(
   case frontend::EmitObj:
   case frontend::FixIt:
   case frontend::GenerateModule:
+  case frontend::GenerateModuleInterface:
   case frontend::GeneratePCH:
   case frontend::GeneratePTH:
   case frontend::ParseSyntaxOnly:

Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendActions.cpp Thu Aug 25 19:14:38 2016
@@ -130,13 +130,13 @@ GeneratePCHAction::ComputeASTConsumerArg
 std::unique_ptr<ASTConsumer>
 GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
                                         StringRef InFile) {
-  std::string Sysroot;
-  std::string OutputFile;
-  std::unique_ptr<raw_pwrite_stream> OS =
-      ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile);
+  std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile);
   if (!OS)
     return nullptr;
 
+  std::string OutputFile = CI.getFrontendOpts().OutputFile;
+  std::string Sysroot;
+
   auto Buffer = std::make_shared<PCHBuffer>();
   std::vector<std::unique_ptr<ASTConsumer>> Consumers;
 
@@ -151,6 +151,23 @@ GenerateModuleAction::CreateASTConsumer(
   return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
 }
 
+bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, 
+                                                 StringRef Filename) {
+  // Set up embedding for any specified files. Do this before we load any
+  // source files, including the primary module map for the compilation.
+  for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
+    if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true))
+      CI.getSourceManager().setFileIsTransient(FE);
+    else
+      CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
+  }
+  if (CI.getFrontendOpts().ModulesEmbedAllFiles)
+    CI.getSourceManager().setAllFilesAreTransient(true);
+
+  return true;
+}
+
+
 static SmallVectorImpl<char> &
 operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
   Includes.append(RHS.begin(), RHS.end());
@@ -266,9 +283,12 @@ collectModuleHeaderIncludes(const LangOp
   return std::error_code();
 }
 
-bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, 
-                                                 StringRef Filename) {
-  CI.getLangOpts().CompilingModule = true;
+bool GenerateModuleFromModuleMapAction::BeginSourceFileAction(
+    CompilerInstance &CI, StringRef Filename) {
+  CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap);
+
+  if (!GenerateModuleAction::BeginSourceFileAction(CI, Filename))
+    return false;
 
   // Find the module map file.
   const FileEntry *ModuleMap =
@@ -279,17 +299,6 @@ bool GenerateModuleAction::BeginSourceFi
     return false;
   }
   
-  // Set up embedding for any specified files. Do this before we load any
-  // source files, including the primary module map for the compilation.
-  for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
-    if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true))
-      CI.getSourceManager().setFileIsTransient(FE);
-    else
-      CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
-  }
-  if (CI.getFrontendOpts().ModulesEmbedAllFiles)
-    CI.getSourceManager().setAllFilesAreTransient(true);
-
   // Parse the module map file.
   HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
   if (HS.loadModuleMapFile(ModuleMap, IsSystem))
@@ -381,10 +390,8 @@ bool GenerateModuleAction::BeginSourceFi
 }
 
 std::unique_ptr<raw_pwrite_stream>
-GenerateModuleAction::ComputeASTConsumerArguments(CompilerInstance &CI,
-                                                  StringRef InFile,
-                                                  std::string &Sysroot,
-                                                  std::string &OutputFile) {
+GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI,
+                                                    StringRef InFile) {
   // If no output file was provided, figure out where this module would go
   // in the module cache.
   if (CI.getFrontendOpts().OutputFile.empty()) {
@@ -398,16 +405,28 @@ GenerateModuleAction::ComputeASTConsumer
   // We use createOutputFile here because this is exposed via libclang, and we
   // must disable the RemoveFileOnSignal behavior.
   // We use a temporary to avoid race conditions.
-  std::unique_ptr<raw_pwrite_stream> OS =
-      CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
-                          /*RemoveFileOnSignal=*/false, InFile,
-                          /*Extension=*/"", /*useTemporary=*/true,
-                          /*CreateMissingDirectories=*/true);
-  if (!OS)
-    return nullptr;
+  return CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
+                             /*RemoveFileOnSignal=*/false, InFile,
+                             /*Extension=*/"", /*useTemporary=*/true,
+                             /*CreateMissingDirectories=*/true);
+}
 
-  OutputFile = CI.getFrontendOpts().OutputFile;
-  return OS;
+bool GenerateModuleInterfaceAction::BeginSourceFileAction(CompilerInstance &CI,
+                                                          StringRef Filename) {
+  if (!CI.getLangOpts().ModulesTS) {
+    CI.getDiagnostics().Report(diag::err_module_interface_requires_modules_ts);
+    return false;
+  }
+
+  CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface);
+
+  return GenerateModuleAction::BeginSourceFileAction(CI, Filename);
+}
+
+std::unique_ptr<raw_pwrite_stream>
+GenerateModuleInterfaceAction::CreateOutputFile(CompilerInstance &CI,
+                                                StringRef InFile) {
+  return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm");
 }
 
 SyntaxOnlyAction::~SyntaxOnlyAction() {

Modified: cfe/trunk/lib/Frontend/FrontendOptions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendOptions.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendOptions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendOptions.cpp Thu Aug 25 19:14:38 2016
@@ -25,6 +25,8 @@ InputKind FrontendOptions::getInputKindF
     .Case("mii", IK_PreprocessedObjCXX)
     .Cases("C", "cc", "cp", IK_CXX)
     .Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX)
+    .Case("cppm", IK_CXX)
+    .Case("iim", IK_PreprocessedCXX)
     .Case("cl", IK_OpenCL)
     .Case("cu", IK_CUDA)
     .Cases("ll", "bc", IK_LLVM_IR)

Modified: cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp (original)
+++ cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp Thu Aug 25 19:14:38 2016
@@ -52,7 +52,10 @@ CreateFrontendBaseAction(CompilerInstanc
   case EmitCodeGenOnly:        return llvm::make_unique<EmitCodeGenOnlyAction>();
   case EmitObj:                return llvm::make_unique<EmitObjAction>();
   case FixIt:                  return llvm::make_unique<FixItAction>();
-  case GenerateModule:         return llvm::make_unique<GenerateModuleAction>();
+  case GenerateModule:
+    return llvm::make_unique<GenerateModuleFromModuleMapAction>();
+  case GenerateModuleInterface:
+    return llvm::make_unique<GenerateModuleInterfaceAction>();
   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=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Thu Aug 25 19:14:38 2016
@@ -558,6 +558,25 @@ ModuleMap::findOrCreateModule(StringRef
   return std::make_pair(Result, true);
 }
 
+Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
+                                                StringRef Name) {
+  assert(LangOpts.CurrentModule == Name && "module name mismatch");
+  assert(!Modules[Name] && "redefining existing module");
+
+  auto *Result =
+      new Module(Name, Loc, nullptr, /*IsFramework*/ false,
+                 /*IsExplicit*/ false, NumCreatedModules++);
+  Modules[Name] = SourceModule = Result;
+
+  // Mark the main source file as being within the newly-created module so that
+  // declarations and macros are properly visibility-restricted to it.
+  auto *MainFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
+  assert(MainFile && "no input file for module interface");
+  Headers[MainFile].push_back(KnownHeader(Result, PrivateHeader));
+
+  return Result;
+}
+
 /// \brief For a framework module, infer the framework against which we
 /// should link.
 static void inferFrameworkLink(Module *Mod, const DirectoryEntry *FrameworkDir,
@@ -805,7 +824,7 @@ void ModuleMap::addHeader(Module *Mod, M
   Mod->Headers[headerRoleToKind(Role)].push_back(std::move(Header));
 
   bool isCompilingModuleHeader =
-      LangOpts.CompilingModule && Mod->getTopLevelModule() == SourceModule;
+      LangOpts.isCompilingModule() && Mod->getTopLevelModule() == SourceModule;
   if (!Imported || isCompilingModuleHeader) {
     // When we import HeaderFileInfo, the external source is expected to
     // set the isModuleHeader flag itself.

Modified: cfe/trunk/lib/Lex/PPLexerChange.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPLexerChange.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPLexerChange.cpp (original)
+++ cfe/trunk/lib/Lex/PPLexerChange.cpp Thu Aug 25 19:14:38 2016
@@ -685,7 +685,7 @@ bool Preprocessor::needModuleMacros() co
     return true;
   // Otherwise, we only need module macros if we're actually compiling a module
   // interface.
-  return getLangOpts().CompilingModule;
+  return getLangOpts().isCompilingModule();
 }
 
 void Preprocessor::LeaveSubmodule() {

Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Thu Aug 25 19:14:38 2016
@@ -1795,7 +1795,7 @@ void Preprocessor::ExpandBuiltinMacro(To
       [this](Token &Tok, bool &HasLexedNextToken) -> int {
         IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
                                        diag::err_expected_id_building_module);
-        return getLangOpts().CompilingModule && II &&
+        return getLangOpts().isCompilingModule() && II &&
                (II->getName() == getLangOpts().CurrentModule);
       });
   } else if (II == Ident__MODULE__) {

Modified: cfe/trunk/lib/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Preprocessor.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/lib/Lex/Preprocessor.cpp Thu Aug 25 19:14:38 2016
@@ -480,7 +480,7 @@ void Preprocessor::CreateString(StringRe
 }
 
 Module *Preprocessor::getCurrentModule() {
-  if (!getLangOpts().CompilingModule)
+  if (!getLangOpts().isCompilingModule())
     return nullptr;
 
   return getHeaderSearchInfo().lookupModule(getLangOpts().CurrentModule);
@@ -795,6 +795,23 @@ void Preprocessor::LexAfterModuleImport(
 
   // If we have a non-empty module path, load the named module.
   if (!ModuleImportPath.empty()) {
+    // Under the Modules TS, the dot is just part of the module name, and not
+    // a real hierarachy separator. Flatten such module names now.
+    //
+    // FIXME: Is this the right level to be performing this transformation?
+    std::string FlatModuleName;
+    if (getLangOpts().ModulesTS) {
+      for (auto &Piece : ModuleImportPath) {
+        if (!FlatModuleName.empty())
+          FlatModuleName += ".";
+        FlatModuleName += Piece.first->getName();
+      }
+      SourceLocation FirstPathLoc = ModuleImportPath[0].second;
+      ModuleImportPath.clear();
+      ModuleImportPath.push_back(
+          std::make_pair(getIdentifierInfo(FlatModuleName), FirstPathLoc));
+    }
+
     Module *Imported = nullptr;
     if (getLangOpts().Modules) {
       Imported = TheModuleLoader.loadModule(ModuleImportLoc,

Modified: cfe/trunk/lib/Parse/ParseAST.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseAST.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseAST.cpp (original)
+++ cfe/trunk/lib/Parse/ParseAST.cpp Thu Aug 25 19:14:38 2016
@@ -138,26 +138,18 @@ void clang::ParseAST(Sema &S, bool Print
   S.getPreprocessor().EnterMainSourceFile();
   P.Initialize();
 
-  // C11 6.9p1 says translation units must have at least one top-level
-  // declaration. C++ doesn't have this restriction. We also don't want to
-  // complain if we have a precompiled header, although technically if the PCH
-  // is empty we should still emit the (pedantic) diagnostic.
   Parser::DeclGroupPtrTy ADecl;
   ExternalASTSource *External = S.getASTContext().getExternalSource();
   if (External)
     External->StartTranslationUnit(Consumer);
 
-  if (P.ParseFirstTopLevelDecl(ADecl)) {
-    if (!External && !S.getLangOpts().CPlusPlus)
-      P.Diag(diag::ext_empty_translation_unit);
-  } else {
-    do {
-      // If we got a null return and something *was* parsed, ignore it.  This
-      // is due to a top-level semicolon, an action override, or a parse error
-      // skipping something.
-      if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
-        return;
-    } while (!P.ParseTopLevelDecl(ADecl));
+  for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF;
+       AtEOF = P.ParseTopLevelDecl(ADecl)) {
+    // If we got a null return and something *was* parsed, ignore it.  This
+    // is due to a top-level semicolon, an action override, or a parse error
+    // skipping something.
+    if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
+      return;
   }
 
   // Process any TopLevelDecls generated by #pragma weak.

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Thu Aug 25 19:14:38 2016
@@ -544,11 +544,21 @@ bool Parser::ParseFirstTopLevelDecl(Decl
   if (Tok.is(tok::kw_module)) {
     Result = ParseModuleDecl();
     return false;
+  } else if (getLangOpts().getCompilingModule() ==
+             LangOptions::CMK_ModuleInterface) {
+    Diag(Tok, diag::err_expected_module_interface_decl);
   }
-  // FIXME: If we're parsing a module interface and we don't have a module
-  // declaration here, diagnose.
 
-  return ParseTopLevelDecl(Result);
+  // C11 6.9p1 says translation units must have at least one top-level
+  // declaration. C++ doesn't have this restriction. We also don't want to
+  // complain if we have a precompiled header, although technically if the PCH
+  // is empty we should still emit the (pedantic) diagnostic.
+  bool NoTopLevelDecls = ParseTopLevelDecl(Result);
+  if (NoTopLevelDecls && !Actions.getASTContext().getExternalSource() &&
+      !getLangOpts().CPlusPlus)
+    Diag(diag::ext_empty_translation_unit);
+
+  return NoTopLevelDecls;
 }
 
 /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
@@ -820,6 +830,11 @@ Parser::ParseExternalDeclaration(ParsedA
     ParseMicrosoftIfExistsExternalDeclaration();
     return nullptr;
 
+  case tok::kw_module:
+    Diag(Tok, diag::err_unexpected_module_decl);
+    SkipUntil(tok::semi);
+    return nullptr;
+
   default:
   dont_know:
     // We can't tell whether this is a function-definition or declaration yet.

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Aug 25 19:14:38 2016
@@ -15180,48 +15180,84 @@ void Sema::diagnoseMisplacedModuleImport
 Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation ModuleLoc,
                                            ModuleDeclKind MDK,
                                            ModuleIdPath Path) {
-  // We should see 'module implementation' if and only if we are not compiling
-  // a module interface.
-  if (getLangOpts().CompilingModule ==
-      (MDK == ModuleDeclKind::Implementation)) {
+  // 'module implementation' requires that we are not compiling a module of any
+  // kind. 'module' and 'module partition' require that we are compiling a
+  // module inteface (not a module map).
+  auto CMK = getLangOpts().getCompilingModule();
+  if (MDK == ModuleDeclKind::Implementation
+          ? CMK != LangOptions::CMK_None
+          : CMK != LangOptions::CMK_ModuleInterface) {
     Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch)
       << (unsigned)MDK;
     return nullptr;
   }
 
   // FIXME: Create a ModuleDecl and return it.
-  // FIXME: Teach the lexer to handle this declaration too.
+
+  // FIXME: Most of this work should be done by the preprocessor rather than
+  // here, in case we look ahead across something where the current
+  // module matters (eg a #include).
+
+  // The dots in a module name in the Modules TS are a lie. Unlike Clang's
+  // hierarchical module map modules, the dots here are just another character
+  // that can appear in a module name. Flatten down to the actual module name.
+  std::string ModuleName;
+  for (auto &Piece : Path) {
+    if (!ModuleName.empty())
+      ModuleName += ".";
+    ModuleName += Piece.first->getName();
+  }
+
+  // If a module name was explicitly specified on the command line, it must be
+  // correct.
+  if (!getLangOpts().CurrentModule.empty() &&
+      getLangOpts().CurrentModule != ModuleName) {
+    Diag(Path.front().second, diag::err_current_module_name_mismatch)
+        << SourceRange(Path.front().second, Path.back().second)
+        << getLangOpts().CurrentModule;
+    return nullptr;
+  }
+  const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName;
+
+  auto &Map = PP.getHeaderSearchInfo().getModuleMap();
 
   switch (MDK) {
-  case ModuleDeclKind::Module:
+  case ModuleDeclKind::Module: {
     // FIXME: Check we're not in a submodule.
-    // FIXME: Set CurrentModule and create a corresponding Module object.
+
+    // We can't have imported a definition of this module or parsed a module
+    // map defining it already.
+    if (auto *M = Map.findModule(ModuleName)) {
+      Diag(Path[0].second, diag::err_module_redefinition) << ModuleName;
+      if (M->DefinitionLoc.isValid())
+        Diag(M->DefinitionLoc, diag::note_prev_module_definition);
+      else if (const auto *FE = M->getASTFile())
+        Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file)
+            << FE->getName();
+      return nullptr;
+    }
+
+    // Create a Module for the module that we're defining.
+    Module *Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
+    assert(Mod && "module creation should not fail");
+
+    // Enter the semantic scope of the module.
+    ActOnModuleBegin(ModuleLoc, Mod);
     return nullptr;
+  }
 
   case ModuleDeclKind::Partition:
     // FIXME: Check we are in a submodule of the named module.
     return nullptr;
 
   case ModuleDeclKind::Implementation:
-    DeclResult Import = ActOnModuleImport(ModuleLoc, ModuleLoc, Path);
+    std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc(
+        PP.getIdentifierInfo(ModuleName), Path[0].second);
+
+    DeclResult Import = ActOnModuleImport(ModuleLoc, ModuleLoc, ModuleNameLoc);
     if (Import.isInvalid())
       return nullptr;
-    ImportDecl *ID = cast<ImportDecl>(Import.get());
-
-    // The current module is whatever we just loaded.
-    //
-    // FIXME: We should probably do this from the lexer rather than waiting
-    // until now, in case we look ahead across something where the current
-    // module matters (eg a #include).
-    auto Name = ID->getImportedModule()->getTopLevelModuleName();
-    if (!getLangOpts().CurrentModule.empty() &&
-        getLangOpts().CurrentModule != Name) {
-      Diag(Path.front().second, diag::err_current_module_name_mismatch)
-          << SourceRange(Path.front().second, Path.back().second)
-          << getLangOpts().CurrentModule;
-    }
-    const_cast<LangOptions&>(getLangOpts()).CurrentModule = Name;
-    return ConvertDeclToDeclGroup(ID);
+    return ConvertDeclToDeclGroup(Import.get());
   }
 
   llvm_unreachable("unexpected module decl kind");
@@ -15246,8 +15282,8 @@ DeclResult Sema::ActOnModuleImport(Sourc
   // Import-from-implementation is valid in the Modules TS. FIXME: Should we
   // warn on a redundant import of the current module?
   if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule &&
-      (getLangOpts().CompilingModule || !getLangOpts().ModulesTS))
-    Diag(ImportLoc, getLangOpts().CompilingModule
+      (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS))
+    Diag(ImportLoc, getLangOpts().isCompilingModule()
                         ? diag::err_module_self_import
                         : diag::err_module_import_in_implementation)
         << Mod->getFullModuleName() << getLangOpts().CurrentModule;

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Thu Aug 25 19:14:38 2016
@@ -3217,7 +3217,7 @@ void Sema::addMethodToGlobalList(ObjCMet
   ObjCMethodList *ListWithSameDeclaration = nullptr;
   for (; List; Previous = List, List = List->getNext()) {
     // If we are building a module, keep all of the methods.
-    if (getLangOpts().CompilingModule)
+    if (getLangOpts().isCompilingModule())
       continue;
 
     bool SameDeclaration = MatchTwoMethodDeclarations(Method,

Modified: cfe/trunk/lib/Serialization/GeneratePCH.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/GeneratePCH.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/GeneratePCH.cpp (original)
+++ cfe/trunk/lib/Serialization/GeneratePCH.cpp Thu Aug 25 19:14:38 2016
@@ -46,10 +46,13 @@ void PCHGenerator::HandleTranslationUnit
     return;
 
   Module *Module = nullptr;
-  if (PP.getLangOpts().CompilingModule) {
+  if (PP.getLangOpts().isCompilingModule()) {
     Module = PP.getHeaderSearchInfo().lookupModule(
         PP.getLangOpts().CurrentModule, /*AllowSearch*/ false);
-    assert(Module && "emitting module but current module doesn't exist");
+    if (!Module) {
+      assert(hasErrors && "emitting module but current module doesn't exist");
+      return;
+    }
   }
 
   // Emit the PCH file to the Buffer.

Modified: cfe/trunk/test/Parser/cxx-modules-import.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-modules-import.cpp?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx-modules-import.cpp (original)
+++ cfe/trunk/test/Parser/cxx-modules-import.cpp Thu Aug 25 19:14:38 2016
@@ -1,22 +1,26 @@
 // RUN: rm -rf %t
 // RUN: mkdir -p %t
-// RUN: echo 'int a, b;' > %t/x.h
-// RUN: echo 'module x { header "x.h" module y {} } module z {}' > %t/map
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
+// RUN: echo 'module x; int a, b;' > %t/x.cppm
+// RUN: echo 'module x.y; int c;' > %t/x.y.cppm
+//
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %t/x.cppm -o %t/x.pcm
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface -fmodule-file=%t/x.pcm %t/x.y.cppm -o %t/x.y.pcm
+//
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
 // RUN:            -DTEST=1 -DMODULE_KIND=implementation -DMODULE_NAME=z
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
 // RUN:            -DTEST=2 -DMODULE_KIND=implementation -DMODULE_NAME=x
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
 // RUN:            -DTEST=3 -DMODULE_KIND= -DMODULE_NAME=z
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
 // RUN:            -DTEST=4 -DMODULE_KIND=partition -DMODULE_NAME=z
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
 // RUN:            -DTEST=5 -DMODULE_KIND=elderberry -DMODULE_NAME=z
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
 // RUN:            -DTEST=1 -DMODULE_KIND=implementation -DMODULE_NAME='z [[]]'
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
 // RUN:            -DTEST=6 -DMODULE_KIND=implementation -DMODULE_NAME='z [[fancy]]'
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%S/Inputs -fmodules-cache-path=%t -fmodule-map-file=%t/map -verify %s \
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
 // RUN:            -DTEST=7 -DMODULE_KIND=implementation -DMODULE_NAME='z [[maybe_unused]]'
 
 module MODULE_KIND MODULE_NAME;
@@ -34,7 +38,8 @@ module MODULE_KIND MODULE_NAME;
 
 int use_1 = a;
 #if TEST != 2
-// expected-error at -2 {{undeclared}}
+// expected-error at -2 {{declaration of 'a' must be imported from module 'x' before it is required}}
+// expected-note at x.cppm:1 {{here}}
 #endif
 
 import x;

Added: cfe/trunk/test/Parser/cxx-modules-interface.cppm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-modules-interface.cppm?rev=279794&view=auto
==============================================================================
--- cfe/trunk/test/Parser/cxx-modules-interface.cppm (added)
+++ cfe/trunk/test/Parser/cxx-modules-interface.cppm Thu Aug 25 19:14:38 2016
@@ -0,0 +1,21 @@
+// RUN:     %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -DTEST=0
+// RUN:     %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -Dmodule=int -DTEST=1
+// RUN: not %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.pcm -o %t.pcm -DTEST=2 2>&1 | FileCheck %s --check-prefix=CHECK-2
+// RUN:     %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.pcm -o %t.pcm -verify -Dfoo=bar -DTEST=3
+
+#if TEST == 0
+// expected-no-diagnostics
+#endif
+
+module foo;
+#if TEST == 1
+// expected-error at -2 {{expected module declaration at start of module interface}}
+#elif TEST == 2
+// CHECK-2: error: redefinition of module 'foo'
+#endif
+
+int n;
+#if TEST == 3
+// expected-error at -2 {{redefinition of 'n'}}
+// expected-note at -3 {{previous}}
+#endif

Modified: cfe/trunk/test/lit.cfg
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/lit.cfg?rev=279794&r1=279793&r2=279794&view=diff
==============================================================================
--- cfe/trunk/test/lit.cfg (original)
+++ cfe/trunk/test/lit.cfg Thu Aug 25 19:14:38 2016
@@ -44,7 +44,7 @@ else:
 config.test_format = lit.formats.ShTest(execute_external)
 
 # suffixes: A list of file extensions to treat as test files.
-config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s', '.S', '.modulemap', '.test', '.rs']
+config.suffixes = ['.c', '.cpp', '.cppm', '.m', '.mm', '.cu', '.ll', '.cl', '.s', '.S', '.modulemap', '.test', '.rs']
 
 # excludes: A list of directories to exclude from the testsuite. The 'Inputs'
 # subdirectories contain auxiliary inputs for various tests in their parent




More information about the cfe-commits mailing list