mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-24 06:10:12 +00:00
[flang][driver] Add support for -fsyntax-only
The behaviour triggered with this flag is consistent with `-fparse-only` in `flang` (i.e. the throwaway driver). This new spelling is consistent with Clang and gfortran, and was proposed and agreed on for the new driver in [1]. This patch also adds some minimal logic to communicate whether the semantic checks have failed or not. When semantic checks fail, a frontend driver error is generated. The return code from the frontend driver is then determined by checking the driver diagnostics - the presence of driver errors means that the compilation has failed. This logic is consistent with `clang -cc1`. [1] http://lists.llvm.org/pipermail/flang-dev/2020-November/000588.html Differential Revision: https://reviews.llvm.org/D92854
This commit is contained in:
parent
95d3cc67ca
commit
7d246cb19d
@ -2287,7 +2287,7 @@ defm strict_vtable_pointers : BoolFOption<"strict-vtable-pointers",
|
||||
ResetBy<NegFlag>>;
|
||||
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>;
|
||||
|
@ -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 @@ class CompilerInstance {
|
||||
|
||||
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 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
/// 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
|
||||
/// {
|
||||
|
@ -25,6 +25,10 @@ class PrintPreprocessedAction : public FrontendAction {
|
||||
void ExecuteAction() override;
|
||||
};
|
||||
|
||||
class ParseSyntaxOnlyAction : public FrontendAction {
|
||||
void ExecuteAction() override;
|
||||
};
|
||||
|
||||
} // namespace Fortran::frontend
|
||||
|
||||
#endif // LLVM_FLANG_FRONTEND_FRONTENDACTIONS_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 @@ enum ActionKind {
|
||||
|
||||
/// -E mode.
|
||||
PrintPreprocessedInput,
|
||||
/// TODO: RunPreprocessor, ParserSyntaxOnly, EmitLLVM, EmitLLVMOnly,
|
||||
|
||||
/// -fsyntax-only
|
||||
ParseSyntaxOnly,
|
||||
|
||||
/// TODO: RunPreprocessor, EmitLLVM, EmitLLVMOnly,
|
||||
/// EmitCodeGenOnly, EmitAssembly, (...)
|
||||
};
|
||||
|
||||
@ -34,6 +38,8 @@ inline const char *GetActionKindName(const ActionKind ak) {
|
||||
return "InputOutputTest";
|
||||
case PrintPreprocessedInput:
|
||||
return "PrintPreprocessedInput";
|
||||
case ParseSyntaxOnly:
|
||||
return "ParseSyntaxOnly";
|
||||
default:
|
||||
return "<unknown ActionKind>";
|
||||
// TODO:
|
||||
|
@ -13,6 +13,8 @@ add_flang_library(flangFrontend
|
||||
|
||||
LINK_LIBS
|
||||
FortranParser
|
||||
FortranSemantics
|
||||
FortranCommon
|
||||
clangBasic
|
||||
clangDriver
|
||||
|
||||
|
@ -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 @@ void CompilerInstance::set_invocation(
|
||||
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 @@ bool CompilerInstance::ExecuteAction(FrontendAction &act) {
|
||||
act.EndSourceFile();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return !diagnostics().getClient()->getNumErrors();
|
||||
}
|
||||
|
||||
void CompilerInstance::CreateDiagnostics(
|
||||
|
@ -93,6 +93,9 @@ static InputKind ParseFrontendArgs(FrontendOptions &opts,
|
||||
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:
|
||||
|
@ -7,10 +7,12 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "flang/Frontend/FrontendActions.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 "flang/Semantics/semantics.h"
|
||||
|
||||
using namespace Fortran::frontend;
|
||||
|
||||
@ -68,3 +70,33 @@ void PrintPreprocessedAction::ExecuteAction() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,9 @@ static std::unique_ptr<FrontendAction> CreateFrontendBaseAction(
|
||||
case PrintPreprocessedInput:
|
||||
return std::make_unique<PrintPreprocessedAction>();
|
||||
break;
|
||||
case ParseSyntaxOnly:
|
||||
return std::make_unique<ParseSyntaxOnlyAction>();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
// TODO:
|
||||
|
9
flang/test/Flang-Driver/syntax-only.f90
Normal file
9
flang/test/Flang-Driver/syntax-only.f90
Normal file
@ -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
|
@ -76,4 +76,60 @@ TEST(FrontendAction, PrintPreprocessedInput) {
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user