awarzynski updated this revision to Diff 311925. awarzynski added a comment.
Address comment from @CarolineConcatto + rebase Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D92854/new/ https://reviews.llvm.org/D92854 Files: clang/include/clang/Driver/Options.td flang/include/flang/Frontend/CompilerInstance.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/FrontendActions.cpp flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp flang/test/Flang-Driver/syntax-only.f90 flang/unittests/Frontend/PrintPreprocessedTest.cpp
Index: flang/unittests/Frontend/PrintPreprocessedTest.cpp =================================================================== --- flang/unittests/Frontend/PrintPreprocessedTest.cpp +++ flang/unittests/Frontend/PrintPreprocessedTest.cpp @@ -76,4 +76,60 @@ llvm::sys::fs::remove(inputFile); compInst.ClearOutputFiles(/*EraseFiles=*/true); } + +TEST(FrontendAction, ParseSyntaxOnly) { + 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) << "! if_stmt.f90:\n" + << "IF (A > 0.0) IF (B < 0.0) A = LOG (A)\n" + << "END"; + 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->frontendOpts().programAction_ = ParseSyntaxOnly; + + compInst.set_invocation(std::move(invocation)); + compInst.frontendOpts().inputs_.push_back( + FrontendInputFile(testFilePath, Language::Fortran)); + + // 3. Set-up the output stream for the semantic diagnostics. + llvm::SmallVector<char, 256> outputDiagBuffer; + std::unique_ptr<llvm::raw_pwrite_stream> outputStream( + new llvm::raw_svector_ostream(outputDiagBuffer)); + compInst.set_semaOutputStream(std::move(outputStream)); + + // 4. Execute the ParseSyntaxOnly action + bool success = ExecuteCompilerInvocation(&compInst); + + // 5. Validate the expected output + EXPECT_FALSE(success); + EXPECT_TRUE(!outputDiagBuffer.empty()); + EXPECT_TRUE( + llvm::StringRef(outputDiagBuffer.data()) + .startswith( + ":2:14: error: IF statement is not allowed in IF statement\n")); + + // 6. Clear the input files. + llvm::sys::fs::remove(inputFile); +} } // namespace Index: flang/test/Flang-Driver/syntax-only.f90 =================================================================== --- /dev/null +++ flang/test/Flang-Driver/syntax-only.f90 @@ -0,0 +1,9 @@ +! RUN: not %flang-new -fc1 -fsyntax-only %s 2>&1 | FileCheck %s +! RUN: not %f18 -fparse-only %s 2>&1 | FileCheck %s + +! REQUIRES: new-flang-driver + +! CHECK: IF statement is not allowed in IF statement +! CHECK: semantic errors in {{.*}}syntax-only.f90 +IF (A > 0.0) IF (B < 0.0) A = LOG (A) +END Index: flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp =================================================================== --- flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -32,6 +32,9 @@ case PrintPreprocessedInput: return std::make_unique<PrintPreprocessedAction>(); break; + case ParseSyntaxOnly: + return std::make_unique<ParseSyntaxOnlyAction>(); + break; default: break; // TODO: Index: flang/lib/Frontend/FrontendActions.cpp =================================================================== --- flang/lib/Frontend/FrontendActions.cpp +++ flang/lib/Frontend/FrontendActions.cpp @@ -11,6 +11,7 @@ #include "flang/Parser/parsing.h" #include "flang/Parser/provenance.h" #include "flang/Parser/source.h" +#include "flang/Semantics/semantics.h" using namespace Fortran::frontend; @@ -68,3 +69,33 @@ return; } } + +void ParseSyntaxOnlyAction::ExecuteAction() { + CompilerInstance &ci = this->instance(); + + // TODO: These should be specifiable by users. For now just use the defaults. + common::LanguageFeatureControl features; + Fortran::common::IntrinsicTypeDefaultKinds defaultKinds; + + // Parse + ci.parsing().Parse(llvm::outs()); + auto &parseTree{*ci.parsing().parseTree()}; + + // Prepare semantics + Fortran::semantics::SemanticsContext semanticsContext{ + defaultKinds, features, ci.allCookedSources()}; + Fortran::semantics::Semantics semantics{ + semanticsContext, parseTree, ci.parsing().cooked().AsCharBlock()}; + + // Run semantic checks + semantics.Perform(); + + // Report the diagnostics from the semantic checks + semantics.EmitMessages(ci.semaOutputStream()); + + if (semantics.AnyFatalError()) { + unsigned DiagID = ci.diagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Error, "semantic errors in %0"); + ci.diagnostics().Report(DiagID) << GetCurrentFileOrBufferName(); + } +} Index: flang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- flang/lib/Frontend/CompilerInvocation.cpp +++ flang/lib/Frontend/CompilerInvocation.cpp @@ -93,6 +93,9 @@ case clang::driver::options::OPT_E: opts.programAction_ = PrintPreprocessedInput; break; + case clang::driver::options::OPT_fsyntax_only: + opts.programAction_ = ParseSyntaxOnly; + break; // TODO: // case clang::driver::options::OPT_emit_obj: Index: flang/lib/Frontend/CompilerInstance.cpp =================================================================== --- flang/lib/Frontend/CompilerInstance.cpp +++ flang/lib/Frontend/CompilerInstance.cpp @@ -11,6 +11,7 @@ #include "flang/Frontend/TextDiagnosticPrinter.h" #include "flang/Parser/parsing.h" #include "flang/Parser/provenance.h" +#include "flang/Semantics/semantics.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" @@ -39,6 +40,17 @@ invocation_ = std::move(value); } +void CompilerInstance::set_semaOutputStream(raw_ostream &Value) { + ownedSemaOutputStream_.release(); + semaOutputStream_ = &Value; +} + +void CompilerInstance::set_semaOutputStream( + std::unique_ptr<raw_ostream> Value) { + ownedSemaOutputStream_.swap(Value); + semaOutputStream_ = ownedSemaOutputStream_.get(); +} + void CompilerInstance::AddOutputFile(OutputFile &&outFile) { outputFiles_.push_back(std::move(outFile)); } @@ -140,7 +152,7 @@ act.EndSourceFile(); } } - return true; + return !diagnostics().getClient()->getNumErrors(); } void CompilerInstance::CreateDiagnostics( Index: flang/lib/Frontend/CMakeLists.txt =================================================================== --- flang/lib/Frontend/CMakeLists.txt +++ flang/lib/Frontend/CMakeLists.txt @@ -13,6 +13,8 @@ LINK_LIBS FortranParser + FortranSemantics + FortranCommon clangBasic clangDriver Index: flang/include/flang/Frontend/FrontendOptions.h =================================================================== --- flang/include/flang/Frontend/FrontendOptions.h +++ flang/include/flang/Frontend/FrontendOptions.h @@ -1,4 +1,4 @@ -//===- FrontendOptions.h ----------------------------------------*- C -*-===// +//===- FrontendOptions.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. @@ -24,7 +24,11 @@ /// -E mode. PrintPreprocessedInput, - /// TODO: RunPreprocessor, ParserSyntaxOnly, EmitLLVM, EmitLLVMOnly, + + /// -fsyntax-only + ParseSyntaxOnly, + + /// TODO: RunPreprocessor, EmitLLVM, EmitLLVMOnly, /// EmitCodeGenOnly, EmitAssembly, (...) }; @@ -34,6 +38,8 @@ return "InputOutputTest"; case PrintPreprocessedInput: return "PrintPreprocessedInput"; + case ParseSyntaxOnly: + return "ParseSyntaxOnly"; default: return "<unknown ActionKind>"; // TODO: Index: flang/include/flang/Frontend/FrontendActions.h =================================================================== --- flang/include/flang/Frontend/FrontendActions.h +++ flang/include/flang/Frontend/FrontendActions.h @@ -10,6 +10,7 @@ #define LLVM_FLANG_FRONTEND_FRONTENDACTIONS_H #include "flang/Frontend/FrontendAction.h" +#include "llvm/Support/raw_ostream.h" namespace Fortran::frontend { @@ -25,6 +26,10 @@ void ExecuteAction() override; }; +class ParseSyntaxOnlyAction : public FrontendAction { + void ExecuteAction() override; +}; + } // namespace Fortran::frontend #endif // LLVM_FLANG_FRONTEND_FRONTENDACTIONS_H Index: flang/include/flang/Frontend/CompilerInstance.h =================================================================== --- flang/include/flang/Frontend/CompilerInstance.h +++ flang/include/flang/Frontend/CompilerInstance.h @@ -12,6 +12,7 @@ #include "flang/Frontend/FrontendAction.h" #include "flang/Parser/parsing.h" #include "flang/Parser/provenance.h" +#include "flang/Semantics/semantics.h" #include "llvm/Support/raw_ostream.h" namespace Fortran::frontend { @@ -28,6 +29,12 @@ std::shared_ptr<Fortran::parser::Parsing> parsing_; + /// The stream for diagnostics from Semantics + llvm::raw_ostream *semaOutputStream_ = &llvm::errs(); + + /// The stream for diagnostics from Semantics if owned, otherwise nullptr. + std::unique_ptr<llvm::raw_ostream> ownedSemaOutputStream_; + /// The diagnostics engine instance. llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_; @@ -77,6 +84,11 @@ bool HasAllSources() const { return allSources_ != nullptr; } + parser::AllCookedSources &allCookedSources() { + assert(allCookedSources_ && "Compiler instance has no AllCookedSources!"); + return *allCookedSources_; + }; + /// } /// @name Parser Operations /// { @@ -84,6 +96,19 @@ /// Return parsing to be used by Actions. Fortran::parser::Parsing &parsing() const { return *parsing_; } + /// } + /// @name Semantic analysis + /// { + + /// Replace the current stream for verbose output. + void set_semaOutputStream(llvm::raw_ostream &Value); + + /// Replace the current stream for verbose output. + void set_semaOutputStream(std::unique_ptr<llvm::raw_ostream> Value); + + /// Get the current stream for verbose output. + llvm::raw_ostream &semaOutputStream() { return *semaOutputStream_; } + /// } /// @name High-Level Operations /// { Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2206,7 +2206,7 @@ "polymorphic C++ objects">; def fstrict_overflow : Flag<["-"], "fstrict-overflow">, Group<f_Group>; def fsyntax_only : Flag<["-"], "fsyntax-only">, - Flags<[NoXarchOption,CoreOption,CC1Option]>, Group<Action_Group>; + Flags<[NoXarchOption,CoreOption,CC1Option,FC1Option]>, Group<Action_Group>; def ftabstop_EQ : Joined<["-"], "ftabstop=">, Group<f_Group>; def ftemplate_depth_EQ : Joined<["-"], "ftemplate-depth=">, Group<f_Group>; def ftemplate_depth_ : Joined<["-"], "ftemplate-depth-">, Group<f_Group>;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits