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