]> granicus.if.org Git - clang/commitdiff
Add -frewrite-imports flag.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 9 Jun 2017 21:24:02 +0000 (21:24 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 9 Jun 2017 21:24:02 +0000 (21:24 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@305116 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Driver/Options.td
include/clang/Frontend/CompilerInstance.h
include/clang/Frontend/PreprocessorOutputOptions.h
include/clang/Rewrite/Frontend/FrontendActions.h
lib/Driver/Driver.cpp
lib/Driver/ToolChains/Clang.cpp
lib/Frontend/CompilerInstance.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Frontend/Rewrite/FrontendActions.cpp
lib/FrontendTool/ExecuteCompilerInvocation.cpp
test/Modules/preprocess-build-diamond.m [new file with mode: 0644]

index 7b9137e18c3f0bec0c7be90bdbab9bf6a791dd6d..6c51976e98febed5393869538604f232968511d1 100644 (file)
@@ -932,6 +932,10 @@ def frewrite_includes : Flag<["-"], "frewrite-includes">, Group<f_Group>,
   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 ]>;
index 3c7a8ef362f6495889d45b8a26daf088cf73c754..5b5c75298a31363ae0aecbded00061c7df41d756 100644 (file)
@@ -140,6 +140,9 @@ class CompilerInstance : public ModuleLoader {
   /// 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;
index 3261b665380941d64e5c086277c135f05bfe2ca2..94afcd06a3989c34b274388e784736192deb2e65 100644 (file)
@@ -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;
   }
 };
 
index 9a8330fefa238f3b329dc80151d55adfacfebf49..5f83ac16fedf6485eee7f836174c9b7c5d6152d6 100644 (file)
@@ -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;
 };
 
index 63496af3f3d7aea96cc8ec0889cdf196268519ce..eb504fd4e54134cfd8df1845a897e1ba95cd0363 100644 (file)
@@ -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 &&
index 698c3aa326cbfd56ca2cd9a955e182bad9f49156..6d3dbb5b52043541d29f0927f728baa706fccab6 100644 (file)
@@ -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.
index 406149b8c3009f7909b0144e546c0cd255799b39..72a8c38180931c1346fba21dd1dbe88be097af6d 100644 (file)
@@ -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.
index 6e52e7e62eb17bbe1a4aaae4b75ed09284ff4e4c..bb635b7ad714e39db7efc4c3a708e5c0a574a03b 100644 (file)
@@ -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);
 }
 
index 76eb07e981dc0fc82a8288e5a9be6d169aa0cb5c..45feffbcb5b543b4f374a6d63d7a60c71b9c13ec 100644 (file)
 #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();
 }
index 1f7493c9e398e81a2ed342980d4a67ffc7b65336..a7c140188b35b6b30339ff29579369c196d2c874 100644 (file)
@@ -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>();
   }
diff --git a/test/Modules/preprocess-build-diamond.m b/test/Modules/preprocess-build-diamond.m
new file mode 100644 (file)
index 0000000..b031a0a
--- /dev/null
@@ -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;
+}
+