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@-2 {{undeclared}} +// expected-error@-2 {{declaration of 'a' must be imported from module 'x' before it is required}} +// expected-n...@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@-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@-2 {{redefinition of 'n'}} +// expected-note@-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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits