CarolineConcatto created this revision.
Herald added subscribers: cfe-commits, dang, mgorny.
Herald added a reviewer: DavidTruby.
Herald added a reviewer: sscalpone.
Herald added a project: clang.
CarolineConcatto requested review of this revision.

The sole purpose of this action is to read a file from the command line and
 print it either to stdout or the output file. This action runs by using the
`-test-IO` flag introduced in this patch:
`flang-new -test-IO` or `flang-new -fc1 -test-IO`

With this patch, `flang-new -test-IO input-file.f90` will read `input-file.f90` 
and
print it in the output file.

This action has been introduced to facilitate testing. It is hidden from users,
not being shown with `--help`.  It is visible with `--help-hidden`, and only
available for FlangOption and FC1Options in Option.td.

`-IO `is used to run the InputOutputTest action in the Flang frontend driver.
This patch makes sure that "flang-new" will forward it to "flang-new -fc1".
In Flang.cpp -test-IO is passed to "flang-new -fc1",  without `-E` so that the
preprocessor is _not_ run.

This patch introduces the dependencies required to read and manage input files
provided by the command line option. It also adds the structure to create and
write in output files.  The output is sent to either stdout or a file
(specified with -o output_file).


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D87989

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/ToolChains/Flang.cpp
  clang/lib/Driver/Types.cpp
  flang/CMakeLists.txt
  flang/include/flang/Frontend/CompilerInstance.h
  flang/include/flang/Frontend/CompilerInvocation.h
  flang/include/flang/Frontend/FrontendAction.h
  flang/include/flang/Frontend/FrontendActions.h
  flang/include/flang/Frontend/FrontendOptions.h
  flang/include/flang/FrontendTool/Utils.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/Frontend/FrontendOptions.cpp
  flang/lib/FrontendTool/CMakeLists.txt
  flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
  flang/test/Flang-Driver/driver-help-hidden.f90
  flang/test/Flang-Driver/emit-obj.f90
  flang/test/Frontend/Inputs/empty-file.f90
  flang/test/Frontend/input-output-file.f90
  flang/test/Frontend/multiple-input-files.f90
  flang/test/lit.cfg.py
  flang/tools/flang-driver/fc1_main.cpp
  flang/unittests/Frontend/CMakeLists.txt
  flang/unittests/Frontend/CompilerInstanceTest.cpp
  flang/unittests/Frontend/InputOutputTest.cpp

Index: flang/unittests/Frontend/InputOutputTest.cpp
===================================================================
--- /dev/null
+++ flang/unittests/Frontend/InputOutputTest.cpp
@@ -0,0 +1,65 @@
+//===- unittests/Frontend/OutputStreamTest.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/Frontend/CompilerInstance.h"
+#include "flang/Frontend/FrontendOptions.h"
+#include "flang/FrontendTool/Utils.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+#include <filesystem>
+
+using namespace Fortran::frontend;
+
+namespace {
+
+TEST(FrontendOutputTests, TestInputOutputStreamOwned) {
+  // 1. Prepare the input file to be used by IO
+  // Create the file to be used by AllSources
+  // Flang function 'FortranAllSources.Open' needs a physical file
+  // and the full path to work with
+  std::string inputFilename = "io-file-test.f";
+  std::error_code ec;
+  std::unique_ptr<llvm::raw_fd_ostream> os{
+      new llvm::raw_fd_ostream(inputFilename, ec, llvm::sys::fs::OF_None)};
+  if (ec)
+    llvm::errs() << "Fail to create the file need by the test";
+  *(os) << "End Program arithmetic";
+  os.reset();
+  std::string getFileFullPath = std::filesystem::current_path().c_str();
+  getFileFullPath = getFileFullPath + "/" + inputFilename;
+
+  // 2. Prepare the compiler (Invocation + Instance)
+  CompilerInstance compInst;
+  compInst.CreateDiagnostics();
+  auto invocation = std::make_shared<CompilerInvocation>();
+  invocation->GetFrontendOpts().programAction_ = InputOutputTest;
+  compInst.SetInvocation(std::move(invocation));
+  compInst.GetFrontendOpts().inputs_.push_back(
+      FrontendInputFile(/*File=*/getFileFullPath, 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);
+
+  EXPECT_TRUE(success);
+  EXPECT_TRUE(!outputFileBuffer.empty());
+  EXPECT_TRUE(llvm::StringRef(outputFileBuffer.data())
+                  .startswith("End Program arithmetic"));
+
+  // 5. Remove files
+  compInst.ClearOutputFiles(/*EraseFiles=*/false);
+}
+} // namespace
\ No newline at end of file
Index: flang/unittests/Frontend/CompilerInstanceTest.cpp
===================================================================
--- flang/unittests/Frontend/CompilerInstanceTest.cpp
+++ flang/unittests/Frontend/CompilerInstanceTest.cpp
@@ -7,12 +7,13 @@
 //===----------------------------------------------------------------------===//
 
 #include "flang/Frontend/CompilerInstance.h"
-#include "gtest/gtest.h"
 #include "flang/Frontend/CompilerInvocation.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Driver/Options.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
 
 #include <filesystem>
 using namespace llvm;
@@ -20,6 +21,42 @@
 
 namespace {
 
+TEST(CompilerInstance, SanityCheckForInputFile) {
+  // 1. Prepare the input to be stores in a buffer
+  // Create the file to be used by AllSources
+  // Flang function 'FortranAllSources.Open' needs a physical file
+  // and the full path to work with
+  const char *inputSource = "InputSourceFile";
+  std::string inputFilename = "buffer-file-test.f";
+  std::error_code ec;
+  std::unique_ptr<llvm::raw_fd_ostream> os{
+      new llvm::raw_fd_ostream(inputFilename, ec, llvm::sys::fs::OF_None)};
+  if (ec)
+    llvm::errs() << "Fail to create the file need by the test";
+  *(os) << inputSource;
+  os.reset();
+  std::string getFileFullPath = std::filesystem::current_path().c_str();
+  getFileFullPath = getFileFullPath + "/" + inputFilename;
+
+  // 2. Setting up the file/source manager for Compiler Instance
+  std::string buf;
+  llvm::raw_string_ostream error_stream{buf};
+  CompilerInstance compInst;
+  Fortran::parser::AllSources &allSources{compInst.GetAllSources()};
+  const Fortran::parser::SourceFile *sf;
+  sf = allSources.Open(getFileFullPath, error_stream);
+  llvm::ArrayRef<char> fileContent = sf->content();
+
+  // 3. Verifies the content of the buffer in SourceFile
+  // Check that the compiler instance was able to write
+  EXPECT_FALSE(fileContent.size() == 0);
+  EXPECT_TRUE(
+      llvm::StringRef(fileContent.data()).startswith("InputSourceFile"));
+
+  // 4. Delete file
+  llvm::sys::fs::remove(inputFilename);
+}
+
 TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {
   // 1. Set-up a basic DiagnosticConsumer
   std::string diagnosticOutput;
Index: flang/unittests/Frontend/CMakeLists.txt
===================================================================
--- flang/unittests/Frontend/CMakeLists.txt
+++ flang/unittests/Frontend/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_flang_unittest(FlangFrontendTests
   CompilerInstanceTest.cpp
+  InputOutputTest.cpp
 )
 
 target_link_libraries(FlangFrontendTests
Index: flang/tools/flang-driver/fc1_main.cpp
===================================================================
--- flang/tools/flang-driver/fc1_main.cpp
+++ flang/tools/flang-driver/fc1_main.cpp
@@ -52,5 +52,8 @@
   // Execute the frontend actions.
   success = ExecuteCompilerInvocation(flang.get());
 
+  // Delete output files to free Compiler Instance
+  flang->ClearOutputFiles(/*EraseFiles=*/false);
+
   return !success;
 }
Index: flang/test/lit.cfg.py
===================================================================
--- flang/test/lit.cfg.py
+++ flang/test/lit.cfg.py
@@ -43,7 +43,7 @@
 if config.include_flang_new_driver_test:
   config.available_features.add('new-flang-driver')
 else:
-  config.excludes.append('Flang-Driver')
+  config.excludes.append('Flang-Driver','Frontend')
 
 # test_source_root: The root path where tests are located.
 config.test_source_root = os.path.dirname(__file__)
Index: flang/test/Frontend/multiple-input-files.f90
===================================================================
--- /dev/null
+++ flang/test/Frontend/multiple-input-files.f90
@@ -0,0 +1,53 @@
+! RUN: rm -rf %S/multiple-input-files.txt  %S/Inputs/empty-file.txt
+
+! REQUIRES: new-flang-driver
+
+!--------------------------
+! FLANG DRIVER (flang-new)
+!--------------------------
+! TEST 1: Both input files are processed (output is printed to stdout)
+! RUN: %flang-new -test-IO %s %S/Inputs/empty-file.f90 | FileCheck %s  -check-prefix=flang-new
+
+! TEST 2: None of the files is processed (not possible to specify the output file when multiple input files are present)
+! RUN: not %flang-new -test-IO -o - %S/Inputs/empty-file.f90 %s  2>&1 | FileCheck %s -check-prefix=ERROR
+! RUN: not %flang-new -test-IO -o %t %S/Inputs/empty-file.f90 %s 2>&1 | FileCheck %s -check-prefix=ERROR
+
+!----------------------------------------
+! FLANG FRONTEND DRIVER (flang-new -fc1)
+!----------------------------------------
+! TEST 3: Both input files are processed
+! RUN: %flang-new -fc1 -test-IO  %S/Inputs/empty-file.f90 %s 2>&1 \
+! RUN:  && FileCheck %s --input-file=%S/multiple-input-files.txt -check-prefix=flang-new-FC1-OUTPUT1 
+
+! TEST 4: Only the last input file is processed
+! RUN: %flang-new -fc1 -test-IO  %S/Inputs/empty-file.f90 %s -o %t 2>&1 \
+! RUN:  && FileCheck %s --input-file=%t -check-prefix=flang-new-FC1-OUTPUT1
+
+!-----------------------
+! EXPECTED OUTPUT
+!-----------------------
+! TEST 1: By default, `flang-new` prints the output from all input files to
+! stdout
+! flang-new-LABEL: Program arithmetic
+! flang-new-NEXT:    Integer :: i, j
+! flang-new-NEXT:    i = 2; j = 3; i= i * j;
+! flang-new-NEXT:  End Program arithmetic
+
+
+! TEST 2: `-o` does not work for `flang-new` when multiple input files are present
+! ERROR:error: cannot specify -o when generating multiple output files
+
+
+! TEST 3 & TEST 4: Unless the output file is specified, `flang-new -fc1` generates one output file for every input file. If an
+! output file is specified (with `-o`), then only the last input file is processed.
+! flang-new-FC1-OUTPUT1-LABEL: Program arithmetic
+! flang-new-FC1-OUTPUT1-NEXT:    Integer :: i, j
+! flang-new-FC1-OUTPUT1-NEXT:    i = 2; j = 3; i= i * j;
+! flang-new-FC1-OUTPUT1-NEXT:  End Program arithmetic
+
+
+
+Program arithmetic
+  Integer :: i, j
+  i = 2; j = 3; i= i * j;
+End Program arithmetic
\ No newline at end of file
Index: flang/test/Frontend/input-output-file.f90
===================================================================
--- /dev/null
+++ flang/test/Frontend/input-output-file.f90
@@ -0,0 +1,35 @@
+! RUN: rm -rf %S/input-output-file.txt
+
+! REQUIRES: new-flang-driver
+
+!--------------------------
+! FLANG DRIVER (flang-new)
+!--------------------------
+! TEST 1: Print to stdout (implicit)
+! RUN: %flang-new -test-IO %s  2>&1 | FileCheck %s
+! TEST 2: Print to stdout (explicit)
+! RUN: %flang-new -test-IO -o - %s  2>&1 | FileCheck %s
+! TEST 3: Print to a file
+! RUN: %flang-new -test-IO -o %t %s 2>&1 && FileCheck %s --input-file=%t
+
+!----------------------------------------
+! FLANG FRONTEND DRIVER (flang-new -fc1)
+!----------------------------------------
+! TEST 4: Write to a file (implicit)
+! RUN: %flang-new -fc1 -test-IO  %s 2>&1 && FileCheck %s --input-file=%S/input-output-file.txt
+! TEST 5: Write to a file (explicit)
+! RUN: %flang-new -fc1 -test-IO  -o %t %s 2>&1 && FileCheck %s --input-file=%t
+
+
+!-----------------------
+! EXPECTED OUTPUT
+!-----------------------
+! CHECK-LABEL: Program arithmetic
+! CHECK-NEXT:    Integer :: i, j
+! CHECK-NEXT:    i = 2; j = 3; i= i * j;
+! CHECK-NEXT:  End Program arithmetic
+
+Program arithmetic
+  Integer :: i, j
+  i = 2; j = 3; i= i * j;
+End Program arithmetic
\ No newline at end of file
Index: flang/test/Flang-Driver/emit-obj.f90
===================================================================
--- flang/test/Flang-Driver/emit-obj.f90
+++ flang/test/Flang-Driver/emit-obj.f90
@@ -1,5 +1,4 @@
 ! RUN: not %flang-new  %s 2>&1 | FileCheck %s --check-prefix=ERROR-IMPLICIT
-! RUN: not %flang-new  -emit-obj %s 2>&1 | FileCheck %s --check-prefix=ERROR-EXPLICIT
 ! RUN: not %flang-new  -fc1 -emit-obj %s 2>&1 | FileCheck %s --check-prefix=ERROR-FC1
 
 ! REQUIRES: new-flang-driver
@@ -10,8 +9,6 @@
 
 ! ERROR-IMPLICIT: error: unknown argument: '-triple'
 ! ERROR-IMPLICIT: error: unknown argument: '-emit-obj'
-! ERROR-IMPLICIT: error: unknown argument: '-o'
-
-! ERROR-EXPLICIT: error: unknown argument: '-o'
+! ERROR-IMPLICIT-NOT: error: unknown argument: '-o'
 
 ! ERROR-FC1: error: unknown argument: '-emit-obj'
Index: flang/test/Flang-Driver/driver-help-hidden.f90
===================================================================
--- /dev/null
+++ flang/test/Flang-Driver/driver-help-hidden.f90
@@ -0,0 +1,32 @@
+! REQUIRES: new-flang-driver
+
+!--------------------------
+! FLANG DRIVER (flang-new)
+!--------------------------
+! RUN: %flang-new --help-hidden 2>&1 | FileCheck %s
+! RUN: not %flang-new  -help-hidden 2>&1 | FileCheck %s --check-prefix=ERROR
+
+!----------------------------------------
+! FLANG FRONTEND DRIVER (flang-new -fc1)
+!----------------------------------------
+! RUN: not %flang-new -fc1 --help-hidden 2>&1 | FileCheck %s --check-prefix=ERROR-HIDDEN
+! RUN: not %flang-new -fc1  -help-hidden 2>&1 | FileCheck %s --check-prefix=ERROR-HIDDEN
+
+
+!----------------------------------------------------
+! EXPECTED OUTPUT FOR FLANG DRIVER (flang-new)
+!----------------------------------------------------
+! CHECK:USAGE: flang-new
+! CHECK-EMPTY:
+! CHECK-NEXT:OPTIONS:
+! CHECK-NEXT: -help     Display available options
+! CHECK-NEXT: -test-IO       Only run the InputOutputTest action
+! CHECK-NEXT: --version Print version information
+
+!-------------------------------------------------------------
+! EXPECTED OUTPUT FOR FLANG FRONTEND DRIVER (flang-new -fc1)
+!-------------------------------------------------------------
+! Frontend driver -help-hidden is not supported (aking to clang)
+! ERROR-HIDDEN: error: unknown argument: '{{.*}}'
+! ERROR: error: unknown argument '-help-hidden'; did you mean '--help-hidden'?
+
Index: flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
===================================================================
--- flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -12,18 +12,53 @@
 //===----------------------------------------------------------------------===//
 
 #include "flang/Frontend/CompilerInstance.h"
+#include "flang/Frontend/FrontendActions.h"
 #include "clang/Driver/Options.h"
 #include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/BuryPointer.h"
 #include "llvm/Support/CommandLine.h"
 
 namespace Fortran::frontend {
+
+static std::unique_ptr<FrontendAction>
+CreateFrontendBaseAction(CompilerInstance &ci) {
+
+  ActionKind ak = ci.GetFrontendOpts().programAction_;
+  switch (ak) {
+  case InputOutputTest:
+    return std::make_unique<InputOutputTestAction>();
+    break;
+  default:
+    break;
+    // TODO:
+    // case RunPreprocessor:
+    // case ParserSyntaxOnly:
+    // case EmitLLVM:
+    // case EmitLLVMOnly:
+    // case EmitCodeGenOnly:
+    // (...)
+  }
+  return 0;
+}
+
+std::unique_ptr<FrontendAction> CreateFrontendAction(CompilerInstance &ci) {
+  // Create the underlying action.
+  std::unique_ptr<FrontendAction> act = CreateFrontendBaseAction(ci);
+  if (!act)
+    return nullptr;
+
+  return act;
+}
 bool ExecuteCompilerInvocation(CompilerInstance *flang) {
   // Honor -help.
   if (flang->GetFrontendOpts().showHelp_) {
-    clang::driver::getDriverOptTable().PrintHelp(llvm::outs(),
-        "flang-new -fc1 [options] file...", "LLVM 'Flang' Compiler",
+    clang::driver::getDriverOptTable().PrintHelp(
+        llvm::outs(), "flang-new -fc1 [options] file...",
+        "LLVM 'Flang' Compiler",
         /*Include=*/clang::driver::options::FlangOption,
-        /*Exclude=*/0, /*ShowAllAliases=*/false);
+        /*Exclude=*/llvm::opt::DriverFlag::HelpHidden,
+        /*ShowAllAliases=*/false);
     return true;
   }
 
@@ -33,7 +68,13 @@
     return true;
   }
 
-  return true;
+  // Create and execute the frontend action.
+  std::unique_ptr<FrontendAction> act(CreateFrontendAction(*flang));
+  if (!act)
+    return false;
+
+  bool success = flang->ExecuteAction(*act);
+  return success;
 }
 
 } // namespace Fortran::frontend
Index: flang/lib/FrontendTool/CMakeLists.txt
===================================================================
--- flang/lib/FrontendTool/CMakeLists.txt
+++ flang/lib/FrontendTool/CMakeLists.txt
@@ -2,6 +2,7 @@
   ExecuteCompilerInvocation.cpp
 
   LINK_LIBS
+  flangFrontend
   clangBasic
   clangDriver
 
Index: flang/lib/Frontend/FrontendOptions.cpp
===================================================================
--- flang/lib/Frontend/FrontendOptions.cpp
+++ flang/lib/Frontend/FrontendOptions.cpp
@@ -7,3 +7,19 @@
 //===----------------------------------------------------------------------===//
 
 #include "flang/Frontend/FrontendOptions.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace Fortran::frontend;
+
+InputKind FrontendOptions::GetInputKindForExtension(llvm::StringRef extension) {
+  return llvm::StringSwitch<InputKind>(extension)
+      // Spreading in cases to cover more extensions as API allows
+      // at most 9 items per case.
+      .Cases("ff", "fpp", "FPP", "cuf", "CUF", "fir", "FOR", "for",
+             Language::Fortran)
+      .Cases("f", "F", "f77", Language::Fortran77)
+      .Cases("f90", "F90", ".ff90", Language::Fortran90)
+      .Cases("f95", "F95", "ff95", Language::Fortran95)
+      .Cases("f18", "F18", Language::FortranF18)
+      .Default(Language::Unknown);
+}
\ No newline at end of file
Index: flang/lib/Frontend/FrontendActions.cpp
===================================================================
--- /dev/null
+++ flang/lib/Frontend/FrontendActions.cpp
@@ -0,0 +1,45 @@
+//===--- FrontendActions.cpp ----------------------------------------------===//
+//
+// 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/Frontend/FrontendActions.h"
+#include "flang/Common/Fortran-features.h"
+#include "flang/Common/default-kinds.h"
+#include "flang/Frontend/CompilerInstance.h"
+#include "flang/Parser/source.h"
+#include "clang/Serialization/PCHContainerOperations.h"
+
+using namespace Fortran::frontend;
+
+void InputOutputTestAction::ExecuteAction() {
+
+  // Get the name of the file from FrontendInputFile current
+  std::string path{GetCurrentFileOrBufferName()};
+  std::string buf;
+  llvm::raw_string_ostream error_stream{buf};
+  bool binaryMode = true;
+
+  // Set/store input file info into compiler instace
+  CompilerInstance &ci = GetCompilerInstance();
+  Fortran::parser::AllSources &allSources{ci.GetAllSources()};
+  const Fortran::parser::SourceFile *sf;
+  sf = allSources.Open(path, error_stream);
+  llvm::ArrayRef<char> fileContent = sf->content();
+
+  // Output file descriptor to receive the content of input file
+  std::unique_ptr<llvm::raw_ostream> os;
+
+  // Do not write on the output file if using outputStream_
+  if (ci.NullOutputStream()) {
+    os = ci.CreateDefaultOutputFile(binaryMode, GetCurrentFileOrBufferName(),
+                                    "txt");
+    if (!os)
+      return;
+    (*os) << fileContent.data();
+  } else {
+    ci.WriteOutputStream(fileContent.data());
+  }
+}
Index: flang/lib/Frontend/FrontendAction.cpp
===================================================================
--- /dev/null
+++ flang/lib/Frontend/FrontendAction.cpp
@@ -0,0 +1,62 @@
+//===--- FrontendAction.cpp -----------------------------------------------===//
+//
+// 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/Frontend/FrontendAction.h"
+#include "flang/Frontend/CompilerInstance.h"
+#include "flang/Frontend/FrontendActions.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errc.h"
+
+using namespace Fortran::frontend;
+
+void FrontendAction::SetCurrentInput(const FrontendInputFile &currentInput) {
+  this->currentInput_ = currentInput;
+}
+
+// Call this method if BeginSourceFile fails.
+// Deallocate compiler instance, input and output descriptors
+static void BeginSourceFileCleanUp(FrontendAction &fa, CompilerInstance &ci) {
+  ci.ClearOutputFiles(/*EraseFiles=*/true);
+  fa.SetCurrentInput(FrontendInputFile());
+  fa.SetCompilerInstance(nullptr);
+}
+
+bool FrontendAction::BeginSourceFile(CompilerInstance &ci,
+                                     const FrontendInputFile &realInput) {
+
+  FrontendInputFile input(realInput);
+  assert(!instance_ && "Already processing a source file!");
+  assert(!realInput.IsEmpty() && "Unexpected empty filename!");
+  SetCurrentInput(realInput);
+  SetCompilerInstance(&ci);
+  if (!ci.HasAllSources()) {
+    BeginSourceFileCleanUp(*this, ci);
+    return false;
+  }
+  return true;
+}
+
+bool FrontendAction::ShouldEraseOutputFiles() {
+  return GetCompilerInstance().getDiagnostics().hasErrorOccurred();
+}
+
+llvm::Error FrontendAction::Execute() {
+  ExecuteAction();
+  return llvm::Error::success();
+}
+
+void FrontendAction::EndSourceFile() {
+  CompilerInstance &ci = GetCompilerInstance();
+
+  // Cleanup the output streams, and erase the output files if instructed by the
+  // FrontendAction.
+  ci.ClearOutputFiles(/*EraseFiles=*/ShouldEraseOutputFiles());
+
+  SetCompilerInstance(nullptr);
+  SetCurrentInput(FrontendInputFile());
+}
\ No newline at end of file
Index: flang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- flang/lib/Frontend/CompilerInvocation.cpp
+++ flang/lib/Frontend/CompilerInvocation.cpp
@@ -44,6 +44,9 @@
     default: {
       llvm_unreachable("Invalid option in group!");
     }
+    case clang::driver::options::OPT_TEST_IO:
+      opts.programAction_ = InputOutputTest;
+      break;
       // TODO:
       // case clang::driver::options::OPT_E:
       // case clang::driver::options::OPT_emit_obj:
@@ -55,6 +58,7 @@
     }
   }
 
+  opts.outputFile_ = args.getLastArgValue(clang::driver::options::OPT_o);
   opts.showHelp_ = args.hasArg(clang::driver::options::OPT_help);
   opts.showVersion_ = args.hasArg(clang::driver::options::OPT_version);
 
@@ -65,7 +69,7 @@
     llvm::StringRef XValue = a->getValue();
     // Principal languages.
     dashX = llvm::StringSwitch<InputKind>(XValue)
-                .Case("f90", Language::Fortran)
+                .Case("f90", Language::Fortran90)
                 .Default(Language::Unknown);
 
     // Some special cases cannot be combined with suffixes.
@@ -79,6 +83,26 @@
           << a->getAsString(args) << a->getValue();
   }
 
+  // Save input file to FrontendInputFile with kind and name
+  // '-' is the default input if none is given.
+  std::vector<std::string> inputs =
+      args.getAllArgValues(clang::driver::options::OPT_INPUT);
+  opts.inputs_.clear();
+  if (inputs.empty())
+    inputs.push_back("-");
+  for (unsigned i = 0, e = inputs.size(); i != e; ++i) {
+    InputKind ik = dashX;
+    if (ik.IsUnknown()) {
+      ik = FrontendOptions::GetInputKindForExtension(
+          llvm::StringRef(inputs[i]).rsplit('.').second);
+      if (ik.IsUnknown())
+        ik = Language::Unknown;
+      if (i == 0)
+        dashX = ik;
+    }
+
+    opts.inputs_.emplace_back(std::move(inputs[i]), ik);
+  }
   return dashX;
 }
 
Index: flang/lib/Frontend/CompilerInstance.cpp
===================================================================
--- flang/lib/Frontend/CompilerInstance.cpp
+++ flang/lib/Frontend/CompilerInstance.cpp
@@ -8,14 +8,121 @@
 
 #include "flang/Frontend/CompilerInstance.h"
 #include "flang/Frontend/CompilerInvocation.h"
+#include "flang/Parser/provenance.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace Fortran::frontend;
 
-CompilerInstance::CompilerInstance() : invocation_(new CompilerInvocation()) {}
+CompilerInstance::CompilerInstance()
+    : invocation_(new CompilerInvocation()),
+      allSources_(new Fortran::parser::AllSources()) {}
 
-CompilerInstance::~CompilerInstance() = default;
+CompilerInstance::~CompilerInstance() {
+  assert(OutputFiles.empty() && "Still output files in flight?");
+}
+
+void CompilerInstance::SetInvocation(
+    std::shared_ptr<CompilerInvocation> value) {
+  invocation_ = std::move(value);
+}
+
+void CompilerInstance::AddOutputFile(OutputFile &&outFile) {
+  outputFiles_.push_back(std::move(outFile));
+}
+
+std::unique_ptr<llvm::raw_pwrite_stream>
+CompilerInstance::CreateDefaultOutputFile(bool binary, llvm::StringRef inFile,
+                                          llvm::StringRef extension) {
+  return CreateOutputFile(GetFrontendOpts().outputFile_, binary, inFile,
+                          extension);
+}
+
+std::unique_ptr<llvm::raw_pwrite_stream>
+CompilerInstance::CreateOutputFile(llvm::StringRef outputPath, bool binary,
+                                   llvm::StringRef inFile,
+                                   llvm::StringRef extension) {
+  std::string outputPathName;
+  std::error_code ec;
+
+  std::unique_ptr<llvm::raw_pwrite_stream> os = CreateOutputFile(
+      outputPath, ec, binary, inFile, extension, &outputPathName);
+
+  AddOutputFile(OutputFile(outputPathName));
+  return os;
+}
+
+std::unique_ptr<llvm::raw_pwrite_stream> CompilerInstance::CreateOutputFile(
+    llvm::StringRef outputPath, std::error_code &error, bool binary,
+    llvm::StringRef inFile, llvm::StringRef extension,
+    std::string *resultPathName) {
+
+  std::string outFile;
+
+  // Create the name of the output file
+  if (!outputPath.empty()) {
+    outFile = std::string(outputPath);
+  } else if (inFile == "-") {
+    outFile = "-";
+  } else if (!extension.empty()) {
+    llvm::SmallString<128> path(inFile);
+    llvm::sys::path::replace_extension(path, extension);
+    outFile = std::string(path.str());
+  } else {
+    outFile = "-";
+  }
+
+  if (resultPathName)
+    *resultPathName = outFile;
+
+  // Creates the file descriptor for the output file
+  std::unique_ptr<llvm::raw_fd_ostream> os;
+  std::string osFile;
+  if (!os) {
+    osFile = outFile;
+    os.reset(new llvm::raw_fd_ostream(
+        osFile, error,
+        (binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_Text)));
+    if (error)
+      return nullptr;
+  }
+
+  // Flushes the stream
+  if (!binary || os->supportsSeeking())
+    return std::move(os);
+  auto b = std::make_unique<llvm::buffer_ostream>(*os);
+  assert(!nonSeekStream_);
+  nonSeekStream_ = std::move(os);
+
+  return std::move(b);
+}
+
+void CompilerInstance::ClearOutputFiles(bool eraseFiles) {
+  for (OutputFile &of : outputFiles_)
+    if (!of.filename_.empty() && eraseFiles)
+      llvm::sys::fs::remove(of.filename_);
+
+  outputFiles_.clear();
+  nonSeekStream_.reset();
+}
+
+bool CompilerInstance::ExecuteAction(FrontendAction &act) {
+
+  // Connect Input to a CompileInstance
+  for (const FrontendInputFile &fif : GetFrontendOpts().inputs_) {
+    if (act.BeginSourceFile(*this, fif)) {
+      if (llvm::Error err = act.Execute()) {
+        consumeError(std::move(err));
+      }
+      act.EndSourceFile();
+    }
+  }
+  return true;
+}
 
 void CompilerInstance::CreateDiagnostics(
     clang::DiagnosticConsumer *client, bool shouldOwnClient) {
Index: flang/lib/Frontend/CMakeLists.txt
===================================================================
--- flang/lib/Frontend/CMakeLists.txt
+++ flang/lib/Frontend/CMakeLists.txt
@@ -1,13 +1,16 @@
 add_flang_library(flangFrontend
   CompilerInstance.cpp
   CompilerInvocation.cpp
+  FrontendAction.cpp
+  FrontendActions.cpp
   FrontendOptions.cpp
 
+  # ClangFrontend was added to help Diagnostic error
+  # Further work may be required
   LINK_LIBS
+  FortranParser
   clangBasic
   clangDriver
-  # TODO: Added to re-use clang's TextDiagnosticBuffer & TextDiagnosticPrinter.
-  # Add a custom implementation for Flang and remove this dependency.
   clangFrontend
 
   LINK_COMPONENTS
Index: flang/include/flang/FrontendTool/Utils.h
===================================================================
--- flang/include/flang/FrontendTool/Utils.h
+++ flang/include/flang/FrontendTool/Utils.h
@@ -17,6 +17,13 @@
 namespace Fortran::frontend {
 
 class CompilerInstance;
+class FrontendAction;
+
+/// Construct the FrontendAction of a compiler invocation based on the
+/// options specified for the compiler invocation.
+///
+/// \return - The created FrontendAction object
+std::unique_ptr<FrontendAction> CreateFrontendAction(CompilerInstance &ci);
 
 /// ExecuteCompilerInvocation - Execute the given actions described by the
 /// compiler invocation object in the given compiler instance.
Index: flang/include/flang/Frontend/FrontendOptions.h
===================================================================
--- flang/include/flang/Frontend/FrontendOptions.h
+++ flang/include/flang/Frontend/FrontendOptions.h
@@ -8,10 +8,42 @@
 #ifndef LLVM_FLANG_FRONTEND_FRONTENDOPTIONS_H
 #define LLVM_FLANG_FRONTEND_FRONTENDOPTIONS_H
 
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+
 #include <cstdint>
 #include <string>
 namespace Fortran::frontend {
 
+enum ActionKind {
+  // This is temporary solution
+  // Avoids Action = PrintPreprocessedInput as option 0
+  DummyAction = 0,
+
+  /// -IO mode
+  InputOutputTest,
+
+  /// TODO: ADD flags as the Actions are implemented
+  // RunPreprocessor, ParserSyntaxOnly, EmitLLVM, EmitLLVMOnly,
+  // EmitCodeGenOnly, EmitAssembly, (...)
+};
+
+inline const char *GetActionKindName(const ActionKind ak) {
+  switch (ak) {
+  case InputOutputTest:
+    return "InputOutputTest";
+  default:
+    return "<unknown ActionKind>";
+    // TODO:
+    // case RunPreprocessor:
+    // case ParserSyntaxOnly:
+    // case EmitLLVM:
+    // case EmitLLVMOnly:
+    // case EmitCodeGenOnly:
+    // (...)
+  }
+}
+
 enum class Language : uint8_t {
   Unknown,
 
@@ -21,7 +53,10 @@
 
   ///@{ Languages that the frontend can parse and compile.
   Fortran,
-  ///@}
+  Fortran77,
+  Fortran90,
+  Fortran95,
+  FortranF18
 };
 
 /// The kind of a file that we've been handed as an input.
@@ -41,6 +76,43 @@
   bool IsUnknown() const { return lang_ == Language::Unknown; }
 };
 
+/// An input file for the front end.
+class FrontendInputFile {
+  /// The file name, or "-" to read from standard input.
+  std::string file_;
+
+  /// The input, if it comes from a buffer rather than a file. This object
+  /// does not own the buffer, and the caller is responsible for ensuring
+  /// that it outlives any users.
+  const llvm::MemoryBuffer *buffer_ = nullptr;
+
+  /// The kind of input, atm it contains language
+  InputKind kind_;
+
+public:
+  FrontendInputFile() = default;
+  FrontendInputFile(llvm::StringRef file, InputKind kind)
+      : file_(file.str()), kind_(kind) {}
+  FrontendInputFile(const llvm::MemoryBuffer *buffer, InputKind kind)
+      : buffer_(buffer), kind_(kind) {}
+
+  InputKind GetKind() const { return kind_; }
+
+  bool IsEmpty() const { return file_.empty() && buffer_ == nullptr; }
+  bool IsFile() const { return !IsBuffer(); }
+  bool IsBuffer() const { return buffer_ != nullptr; }
+
+  llvm::StringRef GetFile() const {
+    assert(IsFile());
+    return file_;
+  }
+
+  const llvm::MemoryBuffer *GetBuffer() const {
+    assert(IsBuffer());
+    return buffer_;
+  }
+};
+
 /// FrontendOptions - Options for controlling the behavior of the frontend.
 class FrontendOptions {
 public:
@@ -50,8 +122,24 @@
   /// Show the -version text.
   unsigned showVersion_ : 1;
 
+  /// The input files and their types.
+  std::vector<FrontendInputFile> inputs_;
+
+  /// The output file, if any.
+  std::string outputFile_;
+
+  /// The frontend action to perform.
+  frontend::ActionKind programAction_;
+
 public:
   FrontendOptions() : showHelp_(false), showVersion_(false) {}
+
+  // Return the appropriate input kind for a file extension. For example,
+  /// "f90" would return Language::Fortran90.
+  ///
+  /// \return The input kind for the extension, or Language::Unknown if the
+  /// extension is not recognized.
+  static InputKind GetInputKindForExtension(llvm::StringRef extension);
 };
 } // namespace Fortran::frontend
 
Index: flang/include/flang/Frontend/FrontendActions.h
===================================================================
--- /dev/null
+++ flang/include/flang/Frontend/FrontendActions.h
@@ -0,0 +1,22 @@
+//===- FrontendActions.h -----------------------------------------*- C++-*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FLANG_FRONTEND_FRONTENDACTIONS_H
+#define LLVM_FLANG_FRONTEND_FRONTENDACTIONS_H
+
+#include "flang/Frontend/FrontendAction.h"
+
+namespace Fortran::frontend {
+
+class InputOutputTestAction : public FrontendAction {
+  void ExecuteAction() override;
+};
+
+} // namespace Fortran::frontend
+
+#endif // LLVM_FLANG_FRONTEND_FRONTENDACTIONS_H
\ No newline at end of file
Index: flang/include/flang/Frontend/FrontendAction.h
===================================================================
--- /dev/null
+++ flang/include/flang/Frontend/FrontendAction.h
@@ -0,0 +1,95 @@
+//===- FrontendAction.h -----------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FLANG_FRONTEND_FRONTENDACTION_H
+#define LLVM_FLANG_FRONTEND_FRONTENDACTION_H
+
+#include "flang/Frontend/FrontendOptions.h"
+#include "llvm/Support/Error.h"
+
+namespace Fortran::frontend {
+class CompilerInstance;
+
+class FrontendAction {
+  FrontendInputFile currentInput_;
+  CompilerInstance *instance_;
+
+protected:
+  /// @}
+  /// @name Implementation Action Interface
+  /// @{
+
+  /// Callback to run the program action, using the initialized
+  /// compiler instance.
+  ///
+  virtual void ExecuteAction() = 0;
+
+  /// Callback at the end of processing a single input, to determine
+  /// if the output files should be erased or not.
+  ///
+  /// By default it returns true if a compiler error occurred.
+  virtual bool ShouldEraseOutputFiles();
+
+public:
+  FrontendAction() : instance_(nullptr) {}
+  virtual ~FrontendAction() = default;
+
+  /// @}
+  /// @name Compiler Instance Access
+  /// @{
+
+  CompilerInstance &GetCompilerInstance() const {
+    assert(instance_ && "Compiler instance not registered!");
+    return *instance_;
+  }
+  void SetCompilerInstance(CompilerInstance *value) { instance_ = value; }
+
+  /// @}
+  /// @name Current File Information
+  /// @{
+
+  const FrontendInputFile &GetCurrentInput() const { return currentInput_; }
+
+  llvm::StringRef GetCurrentFile() const {
+    assert(!currentInput_.IsEmpty() && "No current file!");
+    return currentInput_.GetFile();
+  }
+
+  llvm::StringRef GetCurrentFileOrBufferName() const {
+    assert(!currentInput_.IsEmpty() && "No current file!");
+    return currentInput_.IsFile()
+               ? currentInput_.GetFile()
+               : currentInput_.GetBuffer()->getBufferIdentifier();
+  }
+  void SetCurrentInput(const FrontendInputFile &currentInput);
+
+  /// @}
+  /// @name Public Action Interface
+  /// @}
+
+  /// Prepare the action for processing the input file \p input.
+  ///
+  /// This is run after the options and frontend have been initialized,
+  /// but prior to executing any per-file processing.
+  /// \param ci - The compiler instance this action is being run from. The
+  /// action may store and use this object.
+  /// \param input - The input filename and kind.
+  /// \return True on success; on failure the compilation of this file should
+  bool BeginSourceFile(CompilerInstance &ci, const FrontendInputFile &input);
+
+  /// Set the source manager's main input file, and run the action.
+  llvm::Error Execute();
+
+  /// Perform any per-file post processing, deallocate per-file
+  /// objects, and run statistics and output file cleanup code.
+  void EndSourceFile();
+};
+
+} // namespace Fortran::frontend
+
+#endif // LLVM_FLANG_FRONTEND_FRONTENDACTION_H
\ No newline at end of file
Index: flang/include/flang/Frontend/CompilerInvocation.h
===================================================================
--- flang/include/flang/Frontend/CompilerInvocation.h
+++ flang/include/flang/Frontend/CompilerInvocation.h
@@ -15,7 +15,7 @@
 namespace Fortran::frontend {
 class CompilerInvocationBase {
 public:
-  /// Options controlling the diagnostic engine.$
+  /// Options controlling the diagnostic engine.
   llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagnosticOpts_;
 
   CompilerInvocationBase();
Index: flang/include/flang/Frontend/CompilerInstance.h
===================================================================
--- flang/include/flang/Frontend/CompilerInstance.h
+++ flang/include/flang/Frontend/CompilerInstance.h
@@ -9,6 +9,9 @@
 #define LLVM_FLANG_FRONTEND_COMPILERINSTANCE_H
 
 #include "flang/Frontend/CompilerInvocation.h"
+#include "flang/Frontend/FrontendAction.h"
+#include "flang/Parser/provenance.h"
+#include "llvm/Support/raw_ostream.h"
 
 #include <cassert>
 #include <memory>
@@ -20,18 +23,63 @@
   /// The options used in this compiler instance.
   std::shared_ptr<CompilerInvocation> invocation_;
 
+  /// The Fortran  file  manager.
+  std::shared_ptr<Fortran::parser::AllSources> allSources_;
+
   /// The diagnostics engine instance.
   llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_;
 
+  /// Holds the name of the output file.
+  /// Helps to go through the list when working with the outputFiles_
+  struct OutputFile {
+    std::string filename_;
+    OutputFile(std::string inputFilename)
+        : filename_(std::move(inputFilename)) {}
+  };
+
+  /// If the output doesn't support seeking (terminal, pipe), we switch
+  /// the stream to a buffer_ostream. These are the buffer and the original
+  /// stream.
+  std::unique_ptr<llvm::raw_fd_ostream> nonSeekStream_;
+
+  /// The list of active output files.
+  std::list<OutputFile> outputFiles_;
+
+  /// Force an output buffer.
+  std::unique_ptr<llvm::raw_pwrite_stream> outputStream_;
+
 public:
   explicit CompilerInstance();
 
   ~CompilerInstance();
+
+  /// }
+  /// @name Compiler Invocation and Options
+  /// {
+
   CompilerInvocation &GetInvocation() {
     assert(invocation_ && "Compiler instance has no invocation!");
     return *invocation_;
   };
 
+  /// setInvocation - Replace the current invocation.
+  void SetInvocation(std::shared_ptr<CompilerInvocation> value);
+
+  /// Return the current source manager.
+  Fortran::parser::AllSources &GetAllSources() const { return *allSources_; }
+
+  bool HasAllSources() const { return allSources_ != nullptr; }
+
+  /// @name High-Level Operations
+  /// {
+
+  /// ExecuteAction - Execute the provided action against the compiler's
+  /// CompilerInvocation object.
+  /// Note that this routine may write output to 'stderr'.
+  /// \param act - The action to execute.
+  /// \return - True on success.
+  bool ExecuteAction(FrontendAction &act);
+
   /// }
   /// @name Forwarding Methods
   /// {
@@ -75,6 +123,66 @@
     return *diagnostics_;
   }
 
+  /// {
+  /// @name Output Files
+  /// {
+
+  /// AddOutputFile - Add an output file onto the list of tracked output files.
+  ///
+  /// \param outFile - The output file info.
+  void AddOutputFile(OutputFile &&outFile);
+
+  /// clearOutputFiles - Clear the output file list.
+  void ClearOutputFiles(bool eraseFiles);
+
+  /// Create the default output file (from the invocation's options) and add it
+  /// to the list of tracked output files.
+  ///
+  /// \return - Null on error.
+  std::unique_ptr<llvm::raw_pwrite_stream>
+  CreateDefaultOutputFile(bool binary = true, llvm::StringRef inFile = "",
+                          llvm::StringRef extension = "");
+
+  /// Has a function to create a new output file and add it to the list of
+  /// tracked output files.
+  ///
+  /// \return - Null on error.
+  std::unique_ptr<llvm::raw_pwrite_stream>
+  CreateOutputFile(llvm::StringRef outputPath, bool binary,
+                   llvm::StringRef inFile, llvm::StringRef extension);
+
+  /// Create a new output file.
+  ///
+  /// \param outputPath - If given, the path to the output file.
+  /// \param error [out] - On failure, the error.
+  /// \param extension - The extension to use for derived output names.
+  /// \param binary - The mode to open the file in.
+  /// \param resultPathName [out] - If given, the result path name will be
+  /// stored here on success.
+  std::unique_ptr<llvm::raw_pwrite_stream>
+  CreateOutputFile(llvm::StringRef outputPath, std::error_code &error,
+                   bool binary, llvm::StringRef inFile,
+                   llvm::StringRef extension, std::string *resultPathName);
+
+  void SetOutputStream(std::unique_ptr<llvm::raw_pwrite_stream> outStream) {
+    outputStream_ = std::move(outStream);
+  }
+
+  // OutputStream is private and its contenct cannot be checked outside
+  // CompilerInstance.
+  bool NullOutputStream() {
+    if (outputStream_ == nullptr)
+      return true;
+    return false;
+  }
+
+  // OutputStream is private and its contenct cannot be written outside
+  // CompilerInstance.
+  // Allow the frontend compiler to write in the output stream
+  void WriteOutputStream(const std::string &message) {
+    *outputStream_ << message;
+  }
+
   /// }
   /// @name Construction Utility Methods
   /// {
Index: flang/CMakeLists.txt
===================================================================
--- flang/CMakeLists.txt
+++ flang/CMakeLists.txt
@@ -17,7 +17,7 @@
 endif()
 
 option(LINK_WITH_FIR "Link driver with FIR and LLVM" ON)
-option(FLANG_BUILD_NEW_DRIVER "Build the flang compiler driver" OFF)
+option(FLANG_BUILD_NEW_DRIVER "Build the flang compiler driver"   OFF)
 
 # Flang requires C++17.
 set(CMAKE_CXX_STANDARD 17)
Index: clang/lib/Driver/Types.cpp
===================================================================
--- clang/lib/Driver/Types.cpp
+++ clang/lib/Driver/Types.cpp
@@ -326,6 +326,7 @@
   // compilation is not an option.
   // -S runs the compiler in Assembly listing mode.
   if (Driver.CCCIsCPP() || DAL.getLastArg(options::OPT_E) ||
+      DAL.getLastArg(options::OPT_TEST_IO) ||
       DAL.getLastArg(options::OPT__SLASH_EP) ||
       DAL.getLastArg(options::OPT_M, options::OPT_MM) ||
       DAL.getLastArg(options::OPT__SLASH_P))
Index: clang/lib/Driver/ToolChains/Flang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Flang.cpp
+++ clang/lib/Driver/ToolChains/Flang.cpp
@@ -30,12 +30,14 @@
 
   CmdArgs.push_back("-fc1");
 
-  CmdArgs.push_back("-triple");
-  CmdArgs.push_back(Args.MakeArgString(TripleStr));
-
   if (isa<PreprocessJobAction>(JA)) {
-    CmdArgs.push_back("-E");
+    if (C.getArgs().hasArg(options::OPT_TEST_IO))
+      CmdArgs.push_back("-test-IO");
+    else
+      CmdArgs.push_back("-E");
   } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) {
+    CmdArgs.push_back("-triple");
+    CmdArgs.push_back(Args.MakeArgString(TripleStr));
     if (JA.getType() == types::TY_Nothing) {
       CmdArgs.push_back("-fsyntax-only");
     } else if (JA.getType() == types::TY_AST) {
@@ -52,6 +54,8 @@
       assert(false && "Unexpected output type!");
     }
   } else if (isa<AssembleJobAction>(JA)) {
+    CmdArgs.push_back("-triple");
+    CmdArgs.push_back(Args.MakeArgString(TripleStr));
     CmdArgs.push_back("-emit-obj");
   } else {
     assert(false && "Unexpected action class for Flang tool.");
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -2781,7 +2781,7 @@
 def nostdlib : Flag<["-"], "nostdlib">, Group<Link_Group>;
 def nostdlibxx : Flag<["-"], "nostdlib++">;
 def object : Flag<["-"], "object">;
-def o : JoinedOrSeparate<["-"], "o">, Flags<[DriverOption, RenderAsInput, CC1Option, CC1AsOption]>,
+def o : JoinedOrSeparate<["-"], "o">, Flags<[DriverOption, RenderAsInput, CC1Option, CC1AsOption, FC1Option]>,
   HelpText<"Write output to <file>">, MetaVarName<"<file>">;
 def pagezero__size : JoinedOrSeparate<["-"], "pagezero_size">;
 def pass_exit_codes : Flag<["-", "--"], "pass-exit-codes">, Flags<[Unsupported]>;
@@ -3508,6 +3508,12 @@
 def sycl_std_EQ : Joined<["-"], "sycl-std=">, Group<sycl_Group>, Flags<[CC1Option, NoArgumentUnused, CoreOption]>,
   HelpText<"SYCL language standard to compile for.">, Values<"2017, 121, 1.2.1, sycl-1.2.1">;
 
+//===----------------------------------------------------------------------===//
+// FlangOption and FC1 Options
+//===----------------------------------------------------------------------===//
+def TEST_IO : Flag<["-"], "test-IO">, Flags<[HelpHidden, FlangOption, FC1Option]>,Group<Action_Group>,
+HelpText<"Only run the InputOutputTest action">;
+
 //===----------------------------------------------------------------------===//
 // CC1 Options
 //===----------------------------------------------------------------------===//
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to