Author: rsmith Date: Fri Jun 9 16:24:02 2017 New Revision: 305116 URL: http://llvm.org/viewvc/llvm-project?rev=305116&view=rev Log: Add -frewrite-imports flag.
If specified, when preprocessing, the contents of imported .pcm files will be included in preprocessed output. The resulting preprocessed file can then be compiled standalone without the module sources or .pcm files. Added: cfe/trunk/test/Modules/preprocess-build-diamond.m Modified: cfe/trunk/include/clang/Driver/Options.td cfe/trunk/include/clang/Frontend/CompilerInstance.h cfe/trunk/include/clang/Frontend/PreprocessorOutputOptions.h cfe/trunk/include/clang/Rewrite/Frontend/FrontendActions.h cfe/trunk/lib/Driver/Driver.cpp cfe/trunk/lib/Driver/ToolChains/Clang.cpp cfe/trunk/lib/Frontend/CompilerInstance.cpp cfe/trunk/lib/Frontend/CompilerInvocation.cpp cfe/trunk/lib/Frontend/Rewrite/FrontendActions.cpp cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp Modified: cfe/trunk/include/clang/Driver/Options.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=305116&r1=305115&r2=305116&view=diff ============================================================================== --- cfe/trunk/include/clang/Driver/Options.td (original) +++ cfe/trunk/include/clang/Driver/Options.td Fri Jun 9 16:24:02 2017 @@ -932,6 +932,10 @@ def frewrite_includes : Flag<["-"], "fre Flags<[CC1Option]>; def fno_rewrite_includes : Flag<["-"], "fno-rewrite-includes">, Group<f_Group>; +def frewrite_imports : Flag<["-"], "frewrite-imports">, Group<f_Group>, + Flags<[CC1Option]>; +def fno_rewrite_imports : Flag<["-"], "fno-rewrite-imports">, Group<f_Group>; + def frewrite_map_file : Separate<["-"], "frewrite-map-file">, Group<f_Group>, Flags<[ DriverOption, CC1Option ]>; Modified: cfe/trunk/include/clang/Frontend/CompilerInstance.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CompilerInstance.h?rev=305116&r1=305115&r2=305116&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/CompilerInstance.h (original) +++ cfe/trunk/include/clang/Frontend/CompilerInstance.h Fri Jun 9 16:24:02 2017 @@ -140,6 +140,9 @@ class CompilerInstance : public ModuleLo /// fly as part of this overall compilation action. std::map<std::string, std::string> BuiltModules; + /// Should we delete the BuiltModules when we're done? + bool DeleteBuiltModules = true; + /// \brief The location of the module-import keyword for the last module /// import. SourceLocation LastModuleImportLoc; Modified: cfe/trunk/include/clang/Frontend/PreprocessorOutputOptions.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PreprocessorOutputOptions.h?rev=305116&r1=305115&r2=305116&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/PreprocessorOutputOptions.h (original) +++ cfe/trunk/include/clang/Frontend/PreprocessorOutputOptions.h Fri Jun 9 16:24:02 2017 @@ -24,6 +24,7 @@ public: unsigned ShowMacros : 1; ///< Print macro definitions. unsigned ShowIncludeDirectives : 1; ///< Print includes, imports etc. within preprocessed output. unsigned RewriteIncludes : 1; ///< Preprocess include directives only. + unsigned RewriteImports : 1; ///< Include contents of transitively-imported modules. public: PreprocessorOutputOptions() { @@ -35,6 +36,7 @@ public: ShowMacros = 0; ShowIncludeDirectives = 0; RewriteIncludes = 0; + RewriteImports = 0; } }; Modified: cfe/trunk/include/clang/Rewrite/Frontend/FrontendActions.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Rewrite/Frontend/FrontendActions.h?rev=305116&r1=305115&r2=305116&view=diff ============================================================================== --- cfe/trunk/include/clang/Rewrite/Frontend/FrontendActions.h (original) +++ cfe/trunk/include/clang/Rewrite/Frontend/FrontendActions.h Fri Jun 9 16:24:02 2017 @@ -11,6 +11,7 @@ #define LLVM_CLANG_REWRITE_FRONTEND_FRONTENDACTIONS_H #include "clang/Frontend/FrontendAction.h" +#include "llvm/Support/raw_ostream.h" namespace clang { class FixItRewriter; @@ -73,7 +74,10 @@ protected: }; class RewriteIncludesAction : public PreprocessorFrontendAction { + std::shared_ptr<raw_ostream> OutputStream; + class RewriteImportsListener; protected: + bool BeginSourceFileAction(CompilerInstance &CI) override; void ExecuteAction() override; }; Modified: cfe/trunk/lib/Driver/Driver.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Driver.cpp?rev=305116&r1=305115&r2=305116&view=diff ============================================================================== --- cfe/trunk/lib/Driver/Driver.cpp (original) +++ cfe/trunk/lib/Driver/Driver.cpp Fri Jun 9 16:24:02 2017 @@ -2672,6 +2672,8 @@ Action *Driver::ConstructPhaseAction(Com OutputTy = Input->getType(); if (!Args.hasFlag(options::OPT_frewrite_includes, options::OPT_fno_rewrite_includes, false) && + !Args.hasFlag(options::OPT_frewrite_imports, + options::OPT_fno_rewrite_imports, false) && !CCGenDiagnostics) OutputTy = types::getPreprocessedType(OutputTy); assert(OutputTy != types::TY_INVALID && Modified: cfe/trunk/lib/Driver/ToolChains/Clang.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChains/Clang.cpp?rev=305116&r1=305115&r2=305116&view=diff ============================================================================== --- cfe/trunk/lib/Driver/ToolChains/Clang.cpp (original) +++ cfe/trunk/lib/Driver/ToolChains/Clang.cpp Fri Jun 9 16:24:02 2017 @@ -4204,13 +4204,18 @@ void Clang::ConstructJob(Compilation &C, } #endif + bool RewriteImports = Args.hasFlag(options::OPT_frewrite_imports, + options::OPT_fno_rewrite_imports, false); + if (RewriteImports) + CmdArgs.push_back("-frewrite-imports"); + // Enable rewrite includes if the user's asked for it or if we're generating // diagnostics. // TODO: Once -module-dependency-dir works with -frewrite-includes it'd be // nice to enable this when doing a crashdump for modules as well. if (Args.hasFlag(options::OPT_frewrite_includes, options::OPT_fno_rewrite_includes, false) || - (C.isForDiagnostics() && !HaveAnyModules)) + (C.isForDiagnostics() && (RewriteImports || !HaveAnyModules))) CmdArgs.push_back("-frewrite-includes"); // Only allow -traditional or -traditional-cpp outside in preprocessing modes. Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=305116&r1=305115&r2=305116&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original) +++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Fri Jun 9 16:24:02 2017 @@ -667,8 +667,11 @@ void CompilerInstance::clearOutputFiles( llvm::sys::fs::remove(OF.Filename); } OutputFiles.clear(); - for (auto &Module : BuiltModules) - llvm::sys::fs::remove(Module.second); + if (DeleteBuiltModules) { + for (auto &Module : BuiltModules) + llvm::sys::fs::remove(Module.second); + BuiltModules.clear(); + } NonSeekStream.reset(); } @@ -1928,12 +1931,11 @@ void CompilerInstance::loadModuleFromSou llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource.c_str())); Other.BuiltModules = std::move(BuiltModules); + Other.DeleteBuiltModules = false; }; auto PostBuildStep = [this](CompilerInstance &Other) { BuiltModules = std::move(Other.BuiltModules); - // Make sure the child build action doesn't delete the .pcms. - Other.BuiltModules.clear(); }; // Build the module, inheriting any modules that we've built locally. Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=305116&r1=305115&r2=305116&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original) +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Fri Jun 9 16:24:02 2017 @@ -2501,6 +2501,7 @@ static void ParsePreprocessorOutputArgs( Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD); Opts.ShowIncludeDirectives = Args.hasArg(OPT_dI); Opts.RewriteIncludes = Args.hasArg(OPT_frewrite_includes); + Opts.RewriteImports = Args.hasArg(OPT_frewrite_imports); Opts.UseLineDirectives = Args.hasArg(OPT_fuse_line_directives); } Modified: cfe/trunk/lib/Frontend/Rewrite/FrontendActions.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/Rewrite/FrontendActions.cpp?rev=305116&r1=305115&r2=305116&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/Rewrite/FrontendActions.cpp (original) +++ cfe/trunk/lib/Frontend/Rewrite/FrontendActions.cpp Fri Jun 9 16:24:02 2017 @@ -18,6 +18,11 @@ #include "clang/Rewrite/Frontend/ASTConsumers.h" #include "clang/Rewrite/Frontend/FixItRewriter.h" #include "clang/Rewrite/Frontend/Rewriters.h" +#include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleManager.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -189,27 +194,112 @@ void RewriteTestAction::ExecuteAction() DoRewriteTest(CI.getPreprocessor(), OS.get()); } -void RewriteIncludesAction::ExecuteAction() { - CompilerInstance &CI = getCompilerInstance(); - std::unique_ptr<raw_ostream> OS = - CI.createDefaultOutputFile(true, getCurrentFile()); - if (!OS) return; +class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener { + CompilerInstance &CI; + std::weak_ptr<raw_ostream> Out; + + llvm::DenseSet<const FileEntry*> Rewritten; + +public: + RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out) + : CI(CI), Out(Out) {} + + void visitModuleFile(StringRef Filename, + serialization::ModuleKind Kind) override { + auto *File = CI.getFileManager().getFile(Filename); + assert(File && "missing file for loaded module?"); + + // Only rewrite each module file once. + if (!Rewritten.insert(File).second) + return; + + serialization::ModuleFile *MF = + CI.getModuleManager()->getModuleManager().lookup(File); + assert(File && "missing module file for loaded module?"); + + // Not interested in PCH / preambles. + if (!MF->isModule()) + return; + + auto OS = Out.lock(); + assert(OS && "loaded module file after finishing rewrite action?"); + + (*OS) << "#pragma clang module build " << MF->ModuleName << "\n"; + + // Rewrite the contents of the module in a separate compiler instance. + CompilerInstance Instance(CI.getPCHContainerOperations(), + &CI.getPreprocessor().getPCMCache()); + Instance.setInvocation( + std::make_shared<CompilerInvocation>(CI.getInvocation())); + Instance.createDiagnostics( + new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()), + /*ShouldOwnClient=*/true); + Instance.getFrontendOpts().Inputs.clear(); + Instance.getFrontendOpts().Inputs.emplace_back( + Filename, InputKind(InputKind::Unknown, InputKind::Precompiled)); + // Don't recursively rewrite imports. We handle them all at the top level. + Instance.getPreprocessorOutputOpts().RewriteImports = false; + + llvm::CrashRecoveryContext().RunSafelyOnThread([&]() { + RewriteIncludesAction Action; + Action.OutputStream = OS; + Instance.ExecuteAction(Action); + }); + + (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n"; + } +}; + +bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) { + if (!OutputStream) { + OutputStream = CI.createDefaultOutputFile(true, getCurrentFile()); + if (!OutputStream) + return false; + } + + auto &OS = *OutputStream; // If we're preprocessing a module map, start by dumping the contents of the // module itself before switching to the input buffer. auto &Input = getCurrentInput(); if (Input.getKind().getFormat() == InputKind::ModuleMap) { if (Input.isFile()) { - (*OS) << "# 1 \""; - OS->write_escaped(Input.getFile()); - (*OS) << "\"\n"; + OS << "# 1 \""; + OS.write_escaped(Input.getFile()); + OS << "\"\n"; } - // FIXME: Include additional information here so that we don't need the - // original source files to exist on disk. - getCurrentModule()->print(*OS); - (*OS) << "#pragma clang module contents\n"; + getCurrentModule()->print(OS); + OS << "#pragma clang module contents\n"; + } + + // If we're rewriting imports, set up a listener to track when we import + // module files. + if (CI.getPreprocessorOutputOpts().RewriteImports) { + CI.createModuleManager(); + CI.getModuleManager()->addListener( + llvm::make_unique<RewriteImportsListener>(CI, OutputStream)); + } + + return true; +} + +void RewriteIncludesAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + + // If we're rewriting imports, emit the module build output first rather + // than switching back and forth (potentially in the middle of a line). + if (CI.getPreprocessorOutputOpts().RewriteImports) { + std::string Buffer; + llvm::raw_string_ostream OS(Buffer); + + RewriteIncludesInInput(CI.getPreprocessor(), &OS, + CI.getPreprocessorOutputOpts()); + + (*OutputStream) << OS.str(); + } else { + RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(), + CI.getPreprocessorOutputOpts()); } - RewriteIncludesInInput(CI.getPreprocessor(), OS.get(), - CI.getPreprocessorOutputOpts()); + OutputStream.reset(); } Modified: cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp?rev=305116&r1=305115&r2=305116&view=diff ============================================================================== --- cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp (original) +++ cfe/trunk/lib/FrontendTool/ExecuteCompilerInvocation.cpp Fri Jun 9 16:24:02 2017 @@ -85,7 +85,8 @@ CreateFrontendBaseAction(CompilerInstanc case PrintDeclContext: return llvm::make_unique<DeclContextPrintAction>(); case PrintPreamble: return llvm::make_unique<PrintPreambleAction>(); case PrintPreprocessedInput: { - if (CI.getPreprocessorOutputOpts().RewriteIncludes) + if (CI.getPreprocessorOutputOpts().RewriteIncludes || + CI.getPreprocessorOutputOpts().RewriteImports) return llvm::make_unique<RewriteIncludesAction>(); return llvm::make_unique<PrintPreprocessedAction>(); } Added: cfe/trunk/test/Modules/preprocess-build-diamond.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/preprocess-build-diamond.m?rev=305116&view=auto ============================================================================== --- cfe/trunk/test/Modules/preprocess-build-diamond.m (added) +++ cfe/trunk/test/Modules/preprocess-build-diamond.m Fri Jun 9 16:24:02 2017 @@ -0,0 +1,26 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -E -o %t/diamond.mi -frewrite-imports +// RUN: FileCheck %s --input-file %t/diamond.mi +// RUN: %clang_cc1 -fmodules %t/diamond.mi -I. -verify + +// CHECK: {{^}}#pragma clang module build diamond_top +// CHECK: {{^}}module diamond_top { +// CHECK: {{^}}#pragma clang module contents + +// FIXME: @import does not work under -frewrite-includes / -frewrite-imports +// because we disable it when macro expansion is disabled. +#include "diamond_bottom.h" + +// expected-no-diagnostics +void test_diamond(int i, float f, double d, char c) { + top(&i); + left(&f); + right(&d); + bottom(&c); + top_left(&c); + left_and_right(&i); + struct left_and_right lr; + lr.left = 17; +} + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits