diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4166,7 +4166,8 @@ def whyload : Flag<["-"], "whyload">, Alias; def w : Flag<["-"], "w">, HelpText<"Suppress all warnings">, Flags<[CC1Option]>, MarshallingInfoFlag>; -def x : JoinedOrSeparate<["-"], "x">, Flags<[NoXarchOption,CC1Option]>, +def x : JoinedOrSeparate<["-"], "x">, +Flags<[NoXarchOption,CC1Option,FlangOption,FC1Option]>, HelpText<"Treat subsequent input files as having type ">, MetaVarName<"">; def y : Joined<["-"], "y">; diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -19,6 +19,14 @@ using namespace clang; using namespace llvm::opt; +/// Add -x lang to \p CmdArgs for \p Input. +static void addDashXForInput(const ArgList &Args, const InputInfo &Input, + ArgStringList &CmdArgs) { + CmdArgs.push_back("-x"); + // Map the driver type to the frontend type. + CmdArgs.push_back(types::getTypeName(Input.getType())); +} + void Flang::AddFortranDialectOptions(const ArgList &Args, ArgStringList &CmdArgs) const { Args.AddAllArgs( @@ -126,6 +134,9 @@ } assert(Input.isFilename() && "Invalid input."); + + addDashXForInput(Args, Input, CmdArgs); + CmdArgs.push_back(Input.getFilename()); const auto& D = C.getDriver(); diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -263,7 +263,10 @@ llvm::StringRef xValue = a->getValue(); // Principal languages. dashX = llvm::StringSwitch(xValue) - .Case("f90", Language::Fortran) + // Flang does not differentiate between pre-processed and not + // pre-processed inputs. + .Case("f95", Language::Fortran) + .Case("f95-cpp-input", Language::Fortran) .Default(Language::Unknown); // Some special cases cannot be combined with suffixes. diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -41,6 +41,7 @@ #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Passes/PassBuilder.h" @@ -78,25 +79,36 @@ bool CodeGenAction::beginSourceFileAction() { llvmCtx = std::make_unique(); + CompilerInstance &ci = this->getInstance(); // If the input is an LLVM file, just parse it and return. if (this->getCurrentInput().getKind().getLanguage() == Language::LLVM_IR) { llvm::SMDiagnostic err; llvmModule = llvm::parseIRFile(getCurrentInput().getFile(), err, *llvmCtx); + if (!llvmModule || llvm::verifyModule(*llvmModule, &llvm::errs())) { + err.print("flang-new", llvm::errs()); + unsigned diagID = ci.getDiagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Error, "Could not parse IR"); + ci.getDiagnostics().Report(diagID); + return false; + } - return (nullptr != llvmModule); + return true; } // Otherwise, generate an MLIR module from the input Fortran source - assert(getCurrentInput().getKind().getLanguage() == Language::Fortran && - "Invalid input type - expecting a Fortran file"); + if (getCurrentInput().getKind().getLanguage() != Language::Fortran) { + unsigned diagID = ci.getDiagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Error, + "Invalid input type - expecting a Fortran file"); + ci.getDiagnostics().Report(diagID); + return false; + } bool res = runPrescan() && runParse() && runSemanticChecks() && generateRtTypeTables(); if (!res) return res; - CompilerInstance &ci = this->getInstance(); - // Load the MLIR dialects required by Flang mlir::DialectRegistry registry; mlirCtx = std::make_unique(registry); diff --git a/flang/test/Driver/input-from-stdin-llvm.ll b/flang/test/Driver/input-from-stdin-llvm.ll new file mode 100644 --- /dev/null +++ b/flang/test/Driver/input-from-stdin-llvm.ll @@ -0,0 +1,26 @@ +; Verify that reading from stdin works as expected - LLVM input + +;---------- +; RUN LINES +;---------- +; Input type is implicit - assumed to be Fortran. As the input is provided via +; stdin, the file extension is not relevant here. +; RUN: cat %s | not %flang -S - -o - +; RUN: cat %s | not %flang_fc1 -S - -o - + +; Input type is explicit +; RUN: cat %s | %flang -x ir -S - -o - | FileCheck %s +; RUN: cat %s | %flang_fc1 -x ir -S - -o - | FileCheck %s + +;---------------- +; EXPECTED OUTPUT +;---------------- +; CHECK-LABEL: foo: +; CHECK: ret + +;------ +; INPUT +;------ +define void @foo() { + ret void +} diff --git a/flang/test/Driver/input-from-stdin.f90 b/flang/test/Driver/input-from-stdin.f90 --- a/flang/test/Driver/input-from-stdin.f90 +++ b/flang/test/Driver/input-from-stdin.f90 @@ -1,4 +1,4 @@ -! Verify that reading from stdin works as expected +! Verify that reading from stdin works as expected - Fortran input !-------------------------- ! FLANG DRIVER (flang) diff --git a/flang/test/Driver/linker-flags.f90 b/flang/test/Driver/linker-flags.f90 --- a/flang/test/Driver/linker-flags.f90 +++ b/flang/test/Driver/linker-flags.f90 @@ -20,7 +20,7 @@ !---------------- ! Compiler invocation to generate the object file ! CHECK-LABEL: {{.*}} "-emit-obj" -! CHECK-SAME: "-o" "[[object_file:.*]]" {{.*}}Inputs/hello.f90 +! CHECK-SAME: "-o" "[[object_file:.*\.o]]" {{.*}}Inputs/hello.f90 ! Linker invocation to generate the executable ! CHECK-LABEL: "/usr/bin/ld" diff --git a/flang/test/Driver/parse-error.f95 b/flang/test/Driver/parse-error.f95 deleted file mode 100644 --- a/flang/test/Driver/parse-error.f95 +++ /dev/null @@ -1,11 +0,0 @@ -! Verify that parsing errors are correctly reported by the driver -! Focuses on actions inheriting from the following: -! * PrescanAndSemaAction (-fsyntax-only) -! * PrescanAndParseAction (-fdebug-unparse-no-sema) - -! RUN: not %flang_fc1 -fdebug-unparse-no-sema %s 2>&1 | FileCheck %s --check-prefix=ERROR -! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=ERROR - -! ERROR: Could not parse {{.*}}parse-error.f95 - -"This file will not parse" diff --git a/flang/test/Driver/parse-error.ll b/flang/test/Driver/parse-error.ll new file mode 100644 --- /dev/null +++ b/flang/test/Driver/parse-error.ll @@ -0,0 +1,23 @@ +; This file is a valid LLVM IR file, but we force the driver to treat it as +; Fortran (with the `-x` flag). This way we verify that the driver +; correctly rejects invalid Fortran input. + +;---------- +; RUN LINES +;---------- +; Input type is implicit (correctly assumed to be LLVM IR) +; RUN: %flang_fc1 -S %s -o - + +; Input type is explicitly set as Fortran +; Verify that parsing errors are correctly reported by the driver +; Focuses on actions inheriting from the following: +; * PrescanAndSemaAction (-fsyntax-only) +; * PrescanAndParseAction (-fdebug-unparse-no-sema) +; RUN: not %flang_fc1 -fdebug-unparse-no-sema -x f95 %s 2>&1 | FileCheck %s --check-prefix=ERROR +; RUN: not %flang_fc1 -fsyntax-only %s -x f95 2>&1 | FileCheck %s --check-prefix=ERROR + +; ERROR: Could not parse {{.*}}parse-error.f95 + +define void @foo() { + ret void +} diff --git a/flang/test/Driver/parse-ir-error.f95 b/flang/test/Driver/parse-ir-error.f95 new file mode 100644 --- /dev/null +++ b/flang/test/Driver/parse-ir-error.f95 @@ -0,0 +1,18 @@ +! This file is a valid Fortran file, but we force the driver to treat it as an +! LLVM file (with the `-x` flag). This way we verify that the driver correctly +! rejects invalid LLVM IR input. + +!---------- +! RUN LINES +!---------- +! Input type is implicit (correctly assumed to be Fortran) +! RUN: %flang_fc1 -S %s +! Input type is explicitly set as LLVM IR +! RUN: not %flang -S -x ir %s 2>&1 | FileCheck %s + +!---------------- +! EXPECTED OUTPUT +!---------------- +! CHECK: error: Could not parse IR + +end program