diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Driver/Driver.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/Clang.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInstance.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Frontend/Rewrite/FrontendActions.cpp | 118 | ||||
-rw-r--r-- | clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp | 3 |
6 files changed, 121 insertions, 20 deletions
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 63496af3f3d..eb504fd4e54 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -2672,6 +2672,8 @@ Action *Driver::ConstructPhaseAction(Compilation &C, const ArgList &Args, 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 && diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 698c3aa326c..6d3dbb5b520 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4204,13 +4204,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } #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. diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 406149b8c30..72a8c381809 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -667,8 +667,11 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) { 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::loadModuleFromSource(SourceLocation ImportLoc, 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. diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 6e52e7e62eb..bb635b7ad71 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2501,6 +2501,7 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, 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); } diff --git a/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/clang/lib/Frontend/Rewrite/FrontendActions.cpp index 76eb07e981d..45feffbcb5b 100644 --- a/clang/lib/Frontend/Rewrite/FrontendActions.cpp +++ b/clang/lib/Frontend/Rewrite/FrontendActions.cpp @@ -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(); } diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 1f7493c9e39..a7c140188b3 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -85,7 +85,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) { 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>(); } |