From 760e6c4ce58324856d8f105b37bb974564e0f170 Mon Sep 17 00:00:00 2001 From: Andrzej Warzynski Date: Tue, 2 Feb 2021 09:07:33 +0000 Subject: [PATCH] [flang][driver] Disallow non-existent input files in the frontend driver This patch adds a check that verifies that the input file used when calling the frontend driver (i.e. `flang-new -fc1`) actually exists. This was not required for the compiler driver, `flang-new`, as that's already handled in libclangDriver. Once all input/output file management is moved to the driver, we should also check that for input from `stdin` the corresponding file descriptor was successfully acquired. This patch also makes sure that the default action in the frontend is `ParseSyntaxOnly`. This is consistent with Clang. Before this change `flang-new -fc1` would do nothing, which makes testing changes like the one introduced here a bit tricky. Reviewed By: SouraVX Differential Revision: https://reviews.llvm.org/D95127 --- flang/lib/Frontend/CompilerInvocation.cpp | 4 +++ flang/lib/Frontend/FrontendAction.cpp | 26 ++++++++++++++++++ flang/test/Flang-Driver/missing-input.f90 | 32 ++++++++++++++++++++--- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index b34b47a18b85..5077d068b36c 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -84,6 +84,10 @@ bool Fortran::frontend::ParseDiagnosticArgs(clang::DiagnosticOptions &opts, static InputKind ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args, clang::DiagnosticsEngine &diags) { + + // By default the frontend driver creates a ParseSyntaxOnly action. + opts.programAction_ = ParseSyntaxOnly; + // Identify the action (i.e. opts.ProgramAction) if (const llvm::opt::Arg *a = args.getLastArg(clang::driver::options::OPT_Action_Group)) { diff --git a/flang/lib/Frontend/FrontendAction.cpp b/flang/lib/Frontend/FrontendAction.cpp index 1a403bb56a26..027024b8e12b 100644 --- a/flang/lib/Frontend/FrontendAction.cpp +++ b/flang/lib/Frontend/FrontendAction.cpp @@ -11,7 +11,9 @@ #include "flang/Frontend/FrontendActions.h" #include "flang/Frontend/FrontendOptions.h" #include "flang/FrontendTool/Utils.h" +#include "clang/Basic/DiagnosticFrontend.h" #include "llvm/Support/Errc.h" +#include "llvm/Support/VirtualFileSystem.h" using namespace Fortran::frontend; @@ -31,6 +33,30 @@ bool FrontendAction::BeginSourceFile( CompilerInstance &ci, const FrontendInputFile &realInput) { FrontendInputFile input(realInput); + + // Return immediately if the input file does not exist or is not a file. Note + // that we cannot check this for input from stdin. + if (input.file() != "-") { + if (!llvm::sys::fs::is_regular_file(input.file())) { + // Create an diagnostic ID to report + unsigned diagID; + if (llvm::vfs::getRealFileSystem()->exists(input.file())) { + ci.diagnostics().Report(clang::diag::err_fe_error_reading) + << input.file(); + diagID = ci.diagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Error, "%0 is not a regular file"); + } else { + diagID = ci.diagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Error, "%0 does not exist"); + } + + // Report the diagnostic and return + ci.diagnostics().Report(diagID) << input.file(); + BeginSourceFileCleanUp(*this, ci); + return false; + } + } + assert(!instance_ && "Already processing a source file!"); assert(!realInput.IsEmpty() && "Unexpected empty filename!"); set_currentInput(realInput); diff --git a/flang/test/Flang-Driver/missing-input.f90 b/flang/test/Flang-Driver/missing-input.f90 index 5e46395e8de6..962b304582c8 100644 --- a/flang/test/Flang-Driver/missing-input.f90 +++ b/flang/test/Flang-Driver/missing-input.f90 @@ -1,5 +1,31 @@ -! RUN: not %flang-new 2>&1 | FileCheck %s - ! REQUIRES: new-flang-driver -! CHECK: flang-new: error: no input files +! Test the behaviour of the driver when input is missing or is invalid. Note +! that with the compiler driver (flang-new), the input _has_ to be specified. +! Indeed, the driver decides what "job/command" to create based on the input +! file's extension. No input file means that it doesn't know what to do +! (compile? preprocess? link?). The frontend driver (flang-new -fc1) simply +! assumes that "no explicit input == read from stdin" + +!-------------------------- +! FLANG DRIVER (flang-new) +!-------------------------- +! RUN: not %flang-new 2>&1 | FileCheck %s --check-prefix=FLANG-NO-FILE +! RUN: not %flang-new %t 2>&1 | FileCheck %s --check-prefix=FLANG-NONEXISTENT-FILE + +!----------------------------------------- +! FLANG FRONTEND DRIVER (flang-new -fc1) +!----------------------------------------- +! RUN: not %flang-new -fc1 %t 2>&1 | FileCheck %s --check-prefix=FLANG-FC1-NONEXISTENT-FILE +! RUN: not %flang-new -fc1 %S 2>&1 | FileCheck %s --check-prefix=FLANG-FC1-DIR + +!----------------------- +! EXPECTED OUTPUT +!----------------------- +! FLANG-NO-FILE: flang-new: error: no input files + +! FLANG-NONEXISTENT-FILE: flang-new: error: no such file or directory: {{.*}} +! FLANG-NONEXISTENT-FILE: flang-new: error: no input files + +! FLANG-FC1-NONEXISTENT-FILE: error: {{.*}} does not exist +! FLANG-FC1-DIR: error: {{.*}} is not a regular file