awarzynski updated this revision to Diff 298635.
awarzynski added a comment.

Rebase + refector the unit test

This is re-based on top of the latest version of D87989 
<https://reviews.llvm.org/D87989>. The unit test is
update for consistency with D87989 <https://reviews.llvm.org/D87989>.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D88381/new/

https://reviews.llvm.org/D88381

Files:
  clang/include/clang/Driver/Options.td
  flang/include/flang/Frontend/CompilerInstance.h
  flang/include/flang/Frontend/CompilerInvocation.h
  flang/include/flang/Frontend/FrontendActions.h
  flang/include/flang/Frontend/FrontendOptions.h
  flang/lib/Frontend/CMakeLists.txt
  flang/lib/Frontend/CompilerInstance.cpp
  flang/lib/Frontend/CompilerInvocation.cpp
  flang/lib/Frontend/FrontendAction.cpp
  flang/lib/Frontend/FrontendActions.cpp
  flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
  flang/test/Flang-Driver/driver-help-hidden.f90
  flang/test/Flang-Driver/driver-help.f90
  flang/test/Frontend/Inputs/hello-world.c
  flang/test/Frontend/print-preprocess-C-file.f90
  flang/test/Frontend/print-preprocessed-file.f90
  flang/unittests/Frontend/CMakeLists.txt
  flang/unittests/Frontend/PrintPreprocessedTest.cpp

Index: flang/unittests/Frontend/PrintPreprocessedTest.cpp
===================================================================
--- /dev/null
+++ flang/unittests/Frontend/PrintPreprocessedTest.cpp
@@ -0,0 +1,79 @@
+//===- unittests/Frontend/PrintPreprocessedTest.cpp  FrontendAction tests --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/unittests/Frontend/PrintPreprocessedTest.cpp"
+#include "gtest/gtest.h"
+#include "flang/Frontend/CompilerInstance.h"
+#include "flang/Frontend/FrontendOptions.h"
+#include "flang/FrontendTool/Utils.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace Fortran::frontend;
+
+namespace {
+
+TEST(FrontendAction, PrintPreprocessedInput) {
+  std::string inputFile = "test-file.f";
+  std::error_code ec;
+
+  // 1. Create the input file for the file manager
+  // AllSources (which is used to manage files inside every compiler instance),
+  // works with paths. This means that it requires a physical file. Create one.
+  std::unique_ptr<llvm::raw_fd_ostream> os{
+      new llvm::raw_fd_ostream(inputFile, ec, llvm::sys::fs::OF_None)};
+  if (ec)
+    FAIL() << "Fail to create the file need by the test";
+
+  // Populate the input file with the pre-defined input and flush it.
+  *(os) << "! test-file.F:\n"
+        << "#ifdef NEW\n"
+        << "  Program A \n"
+        << "#else\n"
+        << "  Program B\n"
+        << "#endif";
+  os.reset();
+
+  // Get the path of the input file
+  llvm::SmallString<64> cwd;
+  if (std::error_code ec = llvm::sys::fs::current_path(cwd))
+    FAIL() << "Failed to obtain the current working directory";
+  std::string testFilePath(cwd.c_str());
+  testFilePath += "/" + inputFile;
+
+  // 2. Prepare the compiler (CompilerInvocation + CompilerInstance)
+  CompilerInstance compInst;
+  compInst.CreateDiagnostics();
+  auto invocation = std::make_shared<CompilerInvocation>();
+  invocation->GetFrontendOpts().programAction_ = PrintPreprocessedInput;
+
+  compInst.SetInvocation(std::move(invocation));
+  compInst.GetFrontendOpts().inputs_.push_back(
+      FrontendInputFile(testFilePath, Language::Fortran));
+
+  // 3. Set-up the output stream. Using output buffer wrapped as an output
+  // stream, as opposed to an actual file (or a file descriptor).
+  llvm::SmallVector<char, 256> outputFileBuffer;
+  std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream(
+      new llvm::raw_svector_ostream(outputFileBuffer));
+  compInst.SetOutputStream(std::move(outputFileStream));
+
+  // 4. Run the earlier defined FrontendAction
+  bool success = ExecuteCompilerInvocation(&compInst);
+
+  // 5. Validate the expected output
+  EXPECT_TRUE(success);
+  EXPECT_TRUE(!outputFileBuffer.empty());
+  EXPECT_TRUE(llvm::StringRef(outputFileBuffer.data()).equals("program b"));
+
+  // 6. Clear the input and the output files. Since we used an output buffer,
+  // there are no physical output files to delete.
+  llvm::sys::fs::remove(inputFile);
+  compInst.ClearOutputFiles(/*EraseFiles=*/true);
+}
+} // namespace
Index: flang/unittests/Frontend/CMakeLists.txt
===================================================================
--- flang/unittests/Frontend/CMakeLists.txt
+++ flang/unittests/Frontend/CMakeLists.txt
@@ -1,11 +1,13 @@
 add_flang_unittest(FlangFrontendTests
   CompilerInstanceTest.cpp
   InputOutputTest.cpp
+  PrintPreprocessedTest.cpp
 )
 
 target_link_libraries(FlangFrontendTests
   PRIVATE
   clangBasic
   clangFrontend
+  FortranParser
   flangFrontend
   flangFrontendTool)
Index: flang/test/Frontend/print-preprocessed-file.f90
===================================================================
--- /dev/null
+++ flang/test/Frontend/print-preprocessed-file.f90
@@ -0,0 +1,39 @@
+! Test printpreprocessed action
+
+! REQUIRES: new-flang-driver
+
+!--------------------------
+! FLANG DRIVER (flang-new)
+!--------------------------
+! RUN: %flang-new -E %s  2>&1 | FileCheck %s
+! RUN: %flang-new -E  -o - %s 2>&1 | FileCheck %s
+! RUN: %flang-new -E -o %t  %s 2>&1 && FileCheck %s --input-file=%t
+
+!-----------------------------------------
+!   FRONTEND FLANG DRIVER (flang-new -fc1)
+!-----------------------------------------
+! RUN: %flang-new -fc1 -E %s  2>&1 | FileCheck %s
+! RUN: %flang-new -fc1 -E  -o - %s 2>&1 | FileCheck %s
+! RUN: %flang-new -fc1 -E -o %t  %s 2>&1 && FileCheck %s --input-file=%t
+
+
+!-----------------------
+! EXPECTED OUTPUT
+!-----------------------
+! flang-new -E  %s
+! CHECK:program a
+! CHECK-NOT:program b
+! CHECK-NEXT:x = 1
+! CHECK-NEXT:write(*,*) x
+! CHECK-NEXT:end
+
+! Preprocessed-file.F:
+#define NEW
+#ifdef NEW
+  program A
+#else
+  program B
+#endif
+    x = 1
+    write(*,*) x
+  end
\ No newline at end of file
Index: flang/test/Frontend/print-preprocess-C-file.f90
===================================================================
--- /dev/null
+++ flang/test/Frontend/print-preprocess-C-file.f90
@@ -0,0 +1,16 @@
+! Test preprocessing for C files using Flang driver
+
+! REQUIRES: new-flang-driver
+
+!--------------------------
+! FLANG DRIVER (flang-new)
+!--------------------------
+! TEST 1: Print to stdout (implicit)
+! RUN: not %flang-new -E %S/Inputs/hello-world.c  2>&1 | FileCheck %s
+! RUN: not %flang-new -E %S/Inputs/hello-world.c -o - 2>&1 | FileCheck %s
+! RUN: not %flang-new -E %S/Inputs/hello-world.c -o test.F90 2>&1 | FileCheck %s 
+
+!-----------------------
+! EXPECTED OUTPUT
+!-----------------------
+! CHECK: error: unknown integrated tool '-cc1'. Valid tools include '-fc1'.
\ No newline at end of file
Index: flang/test/Frontend/Inputs/hello-world.c
===================================================================
--- /dev/null
+++ flang/test/Frontend/Inputs/hello-world.c
@@ -0,0 +1,5 @@
+a #include<stdio.h> int main() {
+  // printf() displays the string inside quotation
+  printf("Hello, World!");
+  return 0;
+}
\ No newline at end of file
Index: flang/test/Flang-Driver/driver-help.f90
===================================================================
--- flang/test/Flang-Driver/driver-help.f90
+++ flang/test/Flang-Driver/driver-help.f90
@@ -24,16 +24,27 @@
 ! HELP-NEXT: -o <file>              Write output to <file>
 ! HELP-NEXT: --version              Print version information
 
-!----------------------------------
-! EXPECTED OUTPUT (flang-new -fc1)
-!----------------------------------
+!-------------------------------------------------------------
+! EXPECTED OUTPUT FOR FLANG FRONTEND DRIVER (flang-new -fc1)
+!-------------------------------------------------------------
 ! HELP-FC1:USAGE: flang-new
 ! HELP-FC1-EMPTY:
 ! HELP-FC1-NEXT:OPTIONS:
+! HELP-FC1-NEXT: -E        Only run the preprocessor
 ! HELP-FC1-NEXT: -help     Display available options
 ! HELP-FC1-NEXT: -o <file> Write output to <file>
 ! HELP-FC1-NEXT: --version Print version information
 
+!----------------------------------------------------
+! EXPECTED OUTPUT FOR FLANG DRIVER (flang-new)
+!----------------------------------------------------
+! CHECK-FLANG: USAGE: flang-new
+! CHECK-FLANG-EMPTY:
+! CHECK-FLANG-NEXT:OPTIONS:
+! CHECK-FLANG-NEXT: -E        Only run the preprocessor
+! CHECK-FLANG-NEXT: -help     Display available options
+! CHECK-FLANG-NEXT: --version Print version information
+
 !---------------
 ! EXPECTED ERROR
 !---------------
Index: flang/test/Flang-Driver/driver-help-hidden.f90
===================================================================
--- flang/test/Flang-Driver/driver-help-hidden.f90
+++ flang/test/Flang-Driver/driver-help-hidden.f90
@@ -18,6 +18,7 @@
 ! CHECK:USAGE: flang-new
 ! CHECK-EMPTY:
 ! CHECK-NEXT:OPTIONS:
+! CHECK-NEXT: -E        Only run the preprocessor
 ! CHECK-NEXT: -fcolor-diagnostics    Enable colors in diagnostics
 ! CHECK-NEXT: -fno-color-diagnostics Disable colors in diagnostics
 ! CHECK-NEXT: -help     Display available options
Index: flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
===================================================================
--- flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -29,6 +29,9 @@
   case InputOutputTest:
     return std::make_unique<InputOutputTestAction>();
     break;
+  case PrintPreprocessedInput:
+    return std::make_unique<PrintPreprocessedAction>();
+    break;
   default:
     break;
     // TODO:
Index: flang/lib/Frontend/FrontendActions.cpp
===================================================================
--- flang/lib/Frontend/FrontendActions.cpp
+++ flang/lib/Frontend/FrontendActions.cpp
@@ -5,12 +5,12 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+
 #include "flang/Frontend/FrontendActions.h"
-#include "flang/Common/Fortran-features.h"
-#include "flang/Common/default-kinds.h"
 #include "flang/Frontend/CompilerInstance.h"
+#include "flang/Parser/parsing.h"
+#include "flang/Parser/provenance.h"
 #include "flang/Parser/source.h"
-#include "clang/Serialization/PCHContainerOperations.h"
 
 using namespace Fortran::frontend;
 
@@ -43,3 +43,29 @@
     ci.WriteOutputStream(fileContent.data());
   }
 }
+
+void PrintPreprocessedAction::ExecuteAction() {
+
+  std::string buf;
+  llvm::raw_string_ostream out{buf};
+
+  // Fortran::parser writes on out the parseState content
+  CompilerInstance &ci = GetCompilerInstance();
+  ci.GetParsing().DumpCookedChars(out);
+
+  // Writes the preprocessed content into the output
+  if (!ci.IsOutputStreamNull()) {
+    // Send the output to the pre-defined output buffer.
+    ci.WriteOutputStream(out.str());
+  } else {
+    std::unique_ptr<llvm::raw_pwrite_stream> os;
+    os = ci.CreateDefaultOutputFile(
+        /*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName());
+    if (!os) {
+      llvm::errs() << "Unable to create the output file\n";
+      return;
+    }
+
+    (*os) << out.str();
+  }
+}
Index: flang/lib/Frontend/FrontendAction.cpp
===================================================================
--- flang/lib/Frontend/FrontendAction.cpp
+++ flang/lib/Frontend/FrontendAction.cpp
@@ -5,7 +5,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-
 #include "flang/Frontend/FrontendAction.h"
 #include "flang/Frontend/CompilerInstance.h"
 #include "flang/Frontend/FrontendActions.h"
@@ -45,6 +44,19 @@
 }
 
 llvm::Error FrontendAction::Execute() {
+
+  // Get file's name from FrontendInputFile current
+  std::string path{GetCurrentFileOrBufferName()};
+
+  // Option is used inside Parser::Prescan
+  // Frontend driver use Fortran::parser::Option to have the 2 drivers working
+  Fortran::parser::Options options =
+      GetCompilerInstance().GetInvocation().GetFortranOpts();
+
+  // Read files, scan and run preprocessor
+  // Needed by all next fases of the frontend
+  GetCompilerInstance().GetParsing().Prescan(path, options);
+
   ExecuteAction();
   return llvm::Error::success();
 }
Index: flang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- flang/lib/Frontend/CompilerInvocation.cpp
+++ flang/lib/Frontend/CompilerInvocation.cpp
@@ -90,8 +90,11 @@
     case clang::driver::options::OPT_test_io:
       opts.programAction_ = InputOutputTest;
       break;
+    case clang::driver::options::OPT_E:
+      opts.programAction_ = PrintPreprocessedInput;
+      break;
+
       // TODO:
-      // case clang::driver::options::OPT_E:
       // case clang::driver::options::OPT_emit_obj:
       // case calng::driver::options::OPT_emit_llvm:
       // case clang::driver::options::OPT_emit_llvm_only:
Index: flang/lib/Frontend/CompilerInstance.cpp
===================================================================
--- flang/lib/Frontend/CompilerInstance.cpp
+++ flang/lib/Frontend/CompilerInstance.cpp
@@ -9,6 +9,7 @@
 #include "flang/Frontend/CompilerInstance.h"
 #include "flang/Frontend/CompilerInvocation.h"
 #include "flang/Frontend/TextDiagnosticPrinter.h"
+#include "flang/Parser/parsing.h"
 #include "flang/Parser/provenance.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/Error.h"
@@ -20,7 +21,9 @@
 
 CompilerInstance::CompilerInstance()
     : invocation_(new CompilerInvocation()),
-      allSources_(new Fortran::parser::AllSources()) {}
+      allSources_(new Fortran::parser::AllSources()),
+      allCookedSources_(new Fortran::parser::AllCookedSources(*allSources_)),
+      parsing_(new Fortran::parser::Parsing(*allCookedSources_)) {}
 
 CompilerInstance::~CompilerInstance() {
   assert(outputFiles_.empty() && "Still output files in flight?");
@@ -110,6 +113,15 @@
 
 bool CompilerInstance::ExecuteAction(FrontendAction &act) {
 
+  // TODO:Remove once ExecuteCompilerInvocation maps driver::option to
+  // Fortran::parser::option
+  // Set defaults for Parser, as it use as flang options
+  // Default consistent with the temporary driver in f18/f18.cpp
+  std::vector<std::string> searchDirectories{"."s};
+  GetInvocation().GetFortranOpts().searchDirectories = searchDirectories;
+  GetInvocation().GetFortranOpts().isFixedForm = false;
+  GetAllSources().set_encoding(Fortran::parser::Encoding::UTF_8);
+
   // Connect Input to a CompileInstance
   for (const FrontendInputFile &fif : GetFrontendOpts().inputs_) {
     if (act.BeginSourceFile(*this, fif)) {
Index: flang/lib/Frontend/CMakeLists.txt
===================================================================
--- flang/lib/Frontend/CMakeLists.txt
+++ flang/lib/Frontend/CMakeLists.txt
@@ -12,7 +12,9 @@
   clangBasic
 
   LINK_LIBS
+  FortranCommon
   FortranParser
+  FortranSemantics
   clangBasic
   clangDriver
 
Index: flang/include/flang/Frontend/FrontendOptions.h
===================================================================
--- flang/include/flang/Frontend/FrontendOptions.h
+++ flang/include/flang/Frontend/FrontendOptions.h
@@ -22,15 +22,18 @@
   /// -test-io mode
   InputOutputTest,
 
-  // TODO: ADD flags as the Actions are implemented, e.g.
-  // RunPreprocessor, ParserSyntaxOnly, EmitLLVM, EmitLLVMOnly,
-  // EmitCodeGenOnly, EmitAssembly, (...)
+  /// -E mode.
+  PrintPreprocessedInput,
+  /// TODO: RunPreprocessor, ParserSyntaxOnly, EmitLLVM, EmitLLVMOnly,
+  /// EmitCodeGenOnly, EmitAssembly, (...)
 };
 
 inline const char *GetActionKindName(const ActionKind ak) {
   switch (ak) {
   case InputOutputTest:
     return "InputOutputTest";
+  case PrintPreprocessedInput:
+    return "PrintPreprocessedInput";
   default:
     return "<unknown ActionKind>";
     // TODO:
Index: flang/include/flang/Frontend/FrontendActions.h
===================================================================
--- flang/include/flang/Frontend/FrontendActions.h
+++ flang/include/flang/Frontend/FrontendActions.h
@@ -21,6 +21,10 @@
   void ExecuteAction() override;
 };
 
+class PrintPreprocessedAction : public FrontendAction {
+  void ExecuteAction() override;
+};
+
 } // namespace Fortran::frontend
 
 #endif // LLVM_FLANG_FRONTEND_FRONTENDACTIONS_H
Index: flang/include/flang/Frontend/CompilerInvocation.h
===================================================================
--- flang/include/flang/Frontend/CompilerInvocation.h
+++ flang/include/flang/Frontend/CompilerInvocation.h
@@ -9,6 +9,7 @@
 #define LLVM_FLANG_FRONTEND_COMPILERINVOCATION_H
 
 #include "flang/Frontend/FrontendOptions.h"
+#include "flang/Parser/parsing.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "llvm/Option/ArgList.h"
@@ -43,12 +44,20 @@
   /// Options controlling the frontend itself.
   FrontendOptions frontendOpts_;
 
+  // Maps clang::driver options to frontend options use by
+  // Fortran::parser::Prescan
+  // TODO: map the option needed by the frontend
+  Fortran::parser::Options options_;
+
 public:
   CompilerInvocation() = default;
 
   FrontendOptions &GetFrontendOpts() { return frontendOpts_; }
   const FrontendOptions &GetFrontendOpts() const { return frontendOpts_; }
 
+  Fortran::parser::Options &GetFortranOpts() { return options_; }
+  const Fortran::parser::Options &GetFortranOpts() const { return options_; }
+
   /// Create a compiler invocation from a list of input options.
   /// \returns true on success.
   /// \returns false if an error was encountered while parsing the arguments
Index: flang/include/flang/Frontend/CompilerInstance.h
===================================================================
--- flang/include/flang/Frontend/CompilerInstance.h
+++ flang/include/flang/Frontend/CompilerInstance.h
@@ -10,12 +10,10 @@
 
 #include "flang/Frontend/CompilerInvocation.h"
 #include "flang/Frontend/FrontendAction.h"
+#include "flang/Parser/parsing.h"
 #include "flang/Parser/provenance.h"
 #include "llvm/Support/raw_ostream.h"
 
-#include <cassert>
-#include <memory>
-
 namespace Fortran::frontend {
 
 class CompilerInstance {
@@ -26,6 +24,10 @@
   /// Flang file  manager.
   std::shared_ptr<Fortran::parser::AllSources> allSources_;
 
+  std::shared_ptr<Fortran::parser::AllCookedSources> allCookedSources_;
+
+  std::shared_ptr<Fortran::parser::Parsing> parsing_;
+
   /// The diagnostics engine instance.
   llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_;
 
@@ -75,6 +77,13 @@
 
   bool HasAllSources() const { return allSources_ != nullptr; }
 
+  /// }
+  /// @name Parser Operations
+  /// {
+
+  /// Return parsing to be used by Actions.
+  Fortran::parser::Parsing &GetParsing() const { return *parsing_; }
+
   /// }
   /// @name High-Level Operations
   /// {
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -390,7 +390,7 @@
 def D : JoinedOrSeparate<["-"], "D">, Group<Preprocessor_Group>,
     Flags<[CC1Option]>, MetaVarName<"<macro>=<value>">,
     HelpText<"Define <macro> to <value> (or 1 if <value> omitted)">;
-def E : Flag<["-"], "E">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
+def E : Flag<["-"], "E">, Flags<[DriverOption,CC1Option, FlangOption, FC1Option]>, Group<Action_Group>,
     HelpText<"Only run the preprocessor">;
 def F : JoinedOrSeparate<["-"], "F">, Flags<[RenderJoined,CC1Option]>,
     HelpText<"Add directory to framework include search path">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D88381: [Flang][... Andrzej Warzynski via Phabricator via cfe-commits

Reply via email to