CarolineConcatto updated this revision to Diff 294356.
CarolineConcatto added a comment.

Rebase on top of master


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87989

Files:
  clang/include/clang/Driver/Options.td
  clang/lib/Driver/Driver.cpp
  clang/lib/Driver/ToolChains/Flang.cpp
  clang/lib/Driver/Types.cpp
  clang/test/Driver/immediate-options.c
  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/driver-help.f90
  flang/test/Flang-Driver/emit-obj.f90
  flang/test/Frontend/Inputs/hello-world.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
  llvm/lib/Option/OptTable.cpp

Index: llvm/lib/Option/OptTable.cpp
===================================================================
--- llvm/lib/Option/OptTable.cpp
+++ llvm/lib/Option/OptTable.cpp
@@ -639,6 +639,7 @@
       continue;
 
     unsigned Flags = getInfo(Id).Flags;
+
     if (FlagsToInclude && !(Flags & FlagsToInclude))
       continue;
     if (Flags & FlagsToExclude)
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/CompilerInvocation.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"
+
+using namespace Fortran::frontend;
+#include <filesystem>
+
+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
@@ -9,14 +9,52 @@
 #include "flang/Frontend/CompilerInstance.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
-
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
 #include "gtest/gtest.h"
 
 using namespace llvm;
 using namespace Fortran::frontend;
+#include <filesystem>
 
 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,62 @@
+! RUN: rm -rf %S/multiple-input-files.txt  %S/Inputs/hello-world.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/hello-world.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/hello-world.f90 %s  2>&1 | FileCheck %s -check-prefix=ERROR
+! RUN: not %flang-new -test-io -o %t %S/Inputs/hello-world.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/hello-world.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/hello-world.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
+! flang-new-NEXT: !This is a test file with a hello world in Fortran
+! flang-new-NEXT:program hello
+! flang-new-NEXT:  implicit none
+! flang-new-NEXT:  write(*,*) 'Hello world!'
+! flang-new-NEXT:end program hello
+
+
+! 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
+! flang-new-FC1-OUTPUT1-NEXT: !This is a test file with a hello world in Fortran
+! flang-new-FC1-OUTPUT1-NEXT:program hello
+! flang-new-FC1-OUTPUT1-NEXT:  implicit none
+! flang-new-FC1-OUTPUT1-NEXT:  write(*,*) 'Hello world!'
+! flang-new-FC1-OUTPUT1-NEXT:end program hello
+
+
+Program arithmetic
+  Integer :: i, j
+  i = 2; j = 3; i= i * j;
+End Program arithmetic
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/Frontend/Inputs/hello-world.f90
===================================================================
--- /dev/null
+++ flang/test/Frontend/Inputs/hello-world.f90
@@ -0,0 +1,5 @@
+!This is a test file with a hello world in Fortran
+program hello
+  implicit none
+  write(*,*) 'Hello world!'
+end program hello
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,5 @@
 
 ! 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-FC1: error: unknown argument: '-emit-obj'
Index: flang/test/Flang-Driver/driver-help.f90
===================================================================
--- flang/test/Flang-Driver/driver-help.f90
+++ flang/test/Flang-Driver/driver-help.f90
@@ -1,13 +1,35 @@
-! RUN: %flang-new -help 2>&1 | FileCheck %s
-! RUN: %flang-new -fc1 -help 2>&1 | FileCheck %s
+
+!--------------------------
+! FLANG DRIVER (flang-new)
+!--------------------------
+! RUN: %flang-new -help 2>&1 | FileCheck %s --check-prefix=CHECK-FLANG
 ! RUN: not %flang-new -helps 2>&1 | FileCheck %s --check-prefix=ERROR
 
+!----------------------------------------
+! FLANG FRONTEND DRIVER (flang-new -fc1)
+!----------------------------------------
+! RUN: %flang-new -fc1 -help 2>&1 | FileCheck %s --check-prefix=CHECK-FLANG-FC1
+
+
 ! REQUIRES: new-flang-driver
 
-! CHECK:USAGE: flang-new
-! CHECK-EMPTY:
-! CHECK-NEXT:OPTIONS:
-! CHECK-NEXT: -help     Display available options
-! CHECK-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: -help     Display available options
+! CHECK-FLANG-NEXT: --version Print version information
 
 ! ERROR: error: unknown argument '-helps'; did you mean '-help'
+
+!-------------------------------------------------------------
+! EXPECTED OUTPUT FOR FLANG FRONTEND DRIVER (flang-new -fc1)
+!-------------------------------------------------------------
+! CHECK-FLANG-FC1: USAGE: flang-new
+! CHECK-FLANG-FC1-EMPTY:
+! CHECK-FLANG-FC1-NEXT:OPTIONS:
+! CHECK-FLANG-FC1-NEXT: -help     Display available options
+! CHECK-FLANG-FC1-NEXT: -o <file> Write output to <file>
+! CHECK-FLANG-FC1-NEXT: --version Print version information
Index: flang/test/Flang-Driver/driver-help-hidden.f90
===================================================================
--- /dev/null
+++ flang/test/Flang-Driver/driver-help-hidden.f90
@@ -0,0 +1,37 @@
+! 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
+
+!----------------------------------------
+! FLANG FRONTEND DRIVER (flang-new -fc1)
+!----------------------------------------
+! RUN: not %flang-new -fc1 --help-hidden 2>&1 | FileCheck %s --check-prefix=ERROR-FLANG-FC1
+! RUN: not %flang-new -fc1  -help-hidden 2>&1 | FileCheck %s --check-prefix=ERROR-FLANG-FC1
+
+
+!----------------------------------------------------
+! 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  Use for Flang development and testing only. Only read and write files.
+! CHECK-NEXT: --version Print version information
+
+!-------------------------------------------------------------
+! EXPECTED OUTPUT FOR FLANG DRIVER (flang-new)
+!-------------------------------------------------------------
+! ERROR-FLANG: error: unknown argument '-help-hidden'; did you mean '--help-hidden'?
+
+!-------------------------------------------------------------
+! EXPECTED OUTPUT FOR FLANG FRONTEND DRIVER (flang-new -fc1)
+!-------------------------------------------------------------
+! Frontend driver -help-hidden is not supported (aking to clang)
+! ERROR-FLANG-FC1: error: unknown argument: '{{.*}}'
+
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::FC1Option,
-        /*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
@@ -5,6 +5,7 @@
   clangBasic
 
   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.IsOutputStreamNull()) {
+    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,122 @@
 
 #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;
+  }
+
+  // Return the stream corresponding to the output file.
+  // For non-seekable streams, wrap it in llvm::buffer_ostream first.
+  if (!binary || os->supportsSeeking())
+    return std::move(os);
+
+  assert(!nonSeekStream_ && "The non-seek stream has already been set!");
+  auto b = std::make_unique<llvm::buffer_ostream>(*os);
+  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,12 +1,15 @@
 add_flang_library(flangFrontend
   CompilerInstance.cpp
   CompilerInvocation.cpp
+  FrontendAction.cpp
+  FrontendActions.cpp
   FrontendOptions.cpp
 
   DEPENDS
   clangBasic
 
   LINK_LIBS
+  FortranParser
   clangBasic
   clangDriver
   # TODO: Added to re-use clang's TextDiagnosticBuffer & TextDiagnosticPrinter.
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 = InputOutputTest as option 0
+  InvalidAction = 0,
+
+  /// -test-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() && "Requested buffer_, but it is empty!");
+    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,96 @@
+//===- 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);
+
+  /// 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
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,70 @@
   /// The options used in this compiler instance.
   std::shared_ptr<CompilerInvocation> invocation_;
 
+  /// Flang 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 outputFiles_
+  struct OutputFile {
+    std::string filename_;
+    OutputFile(std::string inputFilename)
+        : filename_(std::move(inputFilename)) {}
+  };
+
+  /// Output stream that doesn't support seeking (e.g. terminal, pipe).
+  /// This stream is normally wrapped in buffer_ostream before being passed
+  /// to users (e.g. via CreateOutputFile).
+  std::unique_ptr<llvm::raw_fd_ostream> nonSeekStream_;
+
+  /// The list of active output files.
+  std::list<OutputFile> outputFiles_;
+
+  /// Holds the output stream provided by the user.
+  /// Allows to check the output without creating the outputFile_.
+  /// It is optional and will normally be just a nullptr.
+  std::unique_ptr<llvm::raw_pwrite_stream> outputStream_;
+
 public:
   explicit CompilerInstance();
 
   ~CompilerInstance();
+
+  /// }
+  /// @name Compiler Invocation
+  /// {
+
   CompilerInvocation &GetInvocation() {
     assert(invocation_ && "Compiler instance has no invocation!");
     return *invocation_;
   };
 
+  /// Replace the current invocation.
+  void SetInvocation(std::shared_ptr<CompilerInvocation> value);
+
+  /// }
+  /// @name File manager
+  /// {
+
+  /// Return the current allSources.
+  Fortran::parser::AllSources &GetAllSources() const { return *allSources_; }
+
+  bool HasAllSources() const { return allSources_ != nullptr; }
+
+  /// }
+  /// @name High-Level Operations
+  /// {
+
+  /// 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
   /// {
@@ -60,7 +115,7 @@
     return *diagnostics_;
   }
 
-  /// SetDiagnostics - Replace the current diagnostics engine.
+  /// Replace the current diagnostics engine.
   void SetDiagnostics(clang::DiagnosticsEngine *value);
 
   clang::DiagnosticConsumer &GetDiagnosticClient() const {
@@ -75,6 +130,60 @@
     return *diagnostics_;
   }
 
+  /// {
+  /// @name Output Files
+  /// {
+
+  /// Add an output file onto the list of tracked output files.
+  ///
+  /// \param outFile - The output file info.
+  void AddOutputFile(OutputFile &&outFile);
+
+  /// Clear the output file list.
+  void ClearOutputFiles(bool eraseFiles);
+
+  /// Return the newly created default output file (from the invocation's
+  /// options) that was  added 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 = "");
+
+  /// Function a new output file and _adds_ it to the list of
+  /// tracked output files inside the compiler instance.
+  ///
+  /// \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, but does _not_ add to the list of
+  /// tracked output files inside the compiler instance
+  ///
+  /// \param outputPath - If given, the path to the output file.
+  /// \param error [out] - On failure, the error.
+  /// \param binary - The mode to open the file in.
+  /// \param inFile - The input file's name. Could be used to generate the
+  /// output file name. \param extension - The extension to use for derived
+  /// output names. \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);
+  }
+
+  bool IsOutputStreamNull() { return (outputStream_ == nullptr); }
+
+  // Allow the frontend compiler to write in the output stream
+  void WriteOutputStream(const std::string &message) {
+    *outputStream_ << message;
+  }
+
   /// }
   /// @name Construction Utility Methods
   /// {
Index: clang/test/Driver/immediate-options.c
===================================================================
--- clang/test/Driver/immediate-options.c
+++ clang/test/Driver/immediate-options.c
@@ -2,9 +2,11 @@
 // HELP: isystem
 // HELP-NOT: ast-dump
 // HELP-NOT: driver-mode
+// HEKP-NOT: test-io
 
 // RUN: %clang --help-hidden | FileCheck %s -check-prefix=HELP-HIDDEN
 // HELP-HIDDEN: driver-mode
+// HELP-HIDDEN-NOT: test-io
 
 // RUN: %clang -dumpversion | FileCheck %s -check-prefix=DUMPVERSION
 // DUMPVERSION: {{[0-9]+\.[0-9.]+}}
Index: clang/lib/Driver/Types.cpp
===================================================================
--- clang/lib/Driver/Types.cpp
+++ clang/lib/Driver/Types.cpp
@@ -325,10 +325,12 @@
   // Filter to compiler mode. When the compiler is run as a preprocessor then
   // compilation is not an option.
   // -S runs the compiler in Assembly listing mode.
+  // -test-io is used by Flang to run InputOutputTest action
   if (Driver.CCCIsCPP() || DAL.getLastArg(options::OPT_E) ||
       DAL.getLastArg(options::OPT__SLASH_EP) ||
       DAL.getLastArg(options::OPT_M, options::OPT_MM) ||
-      DAL.getLastArg(options::OPT__SLASH_P))
+      DAL.getLastArg(options::OPT__SLASH_P) ||
+      DAL.getLastArg(options::OPT_TEST_IO))
     LastPhase = phases::Preprocess;
 
   // --precompile only runs up to precompilation.
Index: clang/lib/Driver/ToolChains/Flang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Flang.cpp
+++ clang/lib/Driver/ToolChains/Flang.cpp
@@ -30,12 +30,18 @@
 
   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)) {
+    // TODO: Note that eventually all actions will require a triple
+    // (e.g. `-triple aarch64-unknown-linux-gnu`).
+    // However, `-triple` is currently not supported by `flang-new -fc1`,
+    // FIX IT when actions are supported/executed.
+    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 +58,12 @@
       assert(false && "Unexpected output type!");
     }
   } else if (isa<AssembleJobAction>(JA)) {
+    // TODO: Note that eventually all actions will require a triple
+    // (e.g. `-triple aarch64-unknown-linux-gnu`).
+    // However, `-triple` is currently not supported by `flang-new -fc1`,
+    // FIX IT when actions are supported/executed.
+    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/lib/Driver/Driver.cpp
===================================================================
--- clang/lib/Driver/Driver.cpp
+++ clang/lib/Driver/Driver.cpp
@@ -1571,8 +1571,12 @@
   if (!ShowHidden)
     ExcludedFlagsBitmask |= HelpHidden;
 
-  if (IsFlangMode())
+  if (IsFlangMode()) {
     IncludedFlagsBitmask |= options::FlangOption;
+  } else {
+    ExcludedFlagsBitmask |= options::FlangOption;
+    ExcludedFlagsBitmask |= options::FC1Option;
+  }
 
   std::string Usage = llvm::formatv("{0} [options] file...", Name).str();
   getOpts().PrintHelp(llvm::outs(), Usage.c_str(), DriverTitle.c_str(),
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -2792,7 +2792,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]>;
@@ -3519,6 +3519,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<"Use for Flang development and testing only. Only read and write files.">;
+
 //===----------------------------------------------------------------------===//
 // 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