r305116 - Add -frewrite-imports flag.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 9 14:24:02 PDT 2017


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;
+}
+




More information about the cfe-commits mailing list