1 //===--- FrontendAction.cpp -----------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "flang/Frontend/FrontendAction.h" 10 #include "flang/Frontend/CompilerInstance.h" 11 #include "flang/Frontend/FrontendActions.h" 12 #include "flang/Frontend/FrontendOptions.h" 13 #include "flang/FrontendTool/Utils.h" 14 #include "clang/Basic/DiagnosticFrontend.h" 15 #include "llvm/Support/Errc.h" 16 #include "llvm/Support/VirtualFileSystem.h" 17 18 using namespace Fortran::frontend; 19 20 void FrontendAction::set_currentInput(const FrontendInputFile ¤tInput) { 21 this->currentInput_ = currentInput; 22 } 23 24 // Call this method if BeginSourceFile fails. 25 // Deallocate compiler instance, input and output descriptors 26 static void BeginSourceFileCleanUp(FrontendAction &fa, CompilerInstance &ci) { 27 ci.ClearOutputFiles(/*EraseFiles=*/true); 28 fa.set_currentInput(FrontendInputFile()); 29 fa.set_instance(nullptr); 30 } 31 32 bool FrontendAction::BeginSourceFile( 33 CompilerInstance &ci, const FrontendInputFile &realInput) { 34 35 FrontendInputFile input(realInput); 36 37 // Return immediately if the input file does not exist or is not a file. Note 38 // that we cannot check this for input from stdin. 39 if (input.file() != "-") { 40 if (!llvm::sys::fs::is_regular_file(input.file())) { 41 // Create an diagnostic ID to report 42 unsigned diagID; 43 if (llvm::vfs::getRealFileSystem()->exists(input.file())) { 44 ci.diagnostics().Report(clang::diag::err_fe_error_reading) 45 << input.file(); 46 diagID = ci.diagnostics().getCustomDiagID( 47 clang::DiagnosticsEngine::Error, "%0 is not a regular file"); 48 } else { 49 diagID = ci.diagnostics().getCustomDiagID( 50 clang::DiagnosticsEngine::Error, "%0 does not exist"); 51 } 52 53 // Report the diagnostic and return 54 ci.diagnostics().Report(diagID) << input.file(); 55 BeginSourceFileCleanUp(*this, ci); 56 return false; 57 } 58 } 59 60 assert(!instance_ && "Already processing a source file!"); 61 assert(!realInput.IsEmpty() && "Unexpected empty filename!"); 62 set_currentInput(realInput); 63 set_instance(&ci); 64 if (!ci.HasAllSources()) { 65 BeginSourceFileCleanUp(*this, ci); 66 return false; 67 } 68 return true; 69 } 70 71 bool FrontendAction::ShouldEraseOutputFiles() { 72 return instance().diagnostics().hasErrorOccurred(); 73 } 74 75 llvm::Error FrontendAction::Execute() { 76 CompilerInstance &ci = this->instance(); 77 78 std::string currentInputPath{GetCurrentFileOrBufferName()}; 79 80 Fortran::parser::Options parserOptions = 81 this->instance().invocation().fortranOpts(); 82 83 // Prescan. In case of failure, report and return. 84 ci.parsing().Prescan(currentInputPath, parserOptions); 85 86 if (ci.parsing().messages().AnyFatalError()) { 87 const unsigned diagID = ci.diagnostics().getCustomDiagID( 88 clang::DiagnosticsEngine::Error, "Could not scan %0"); 89 ci.diagnostics().Report(diagID) << GetCurrentFileOrBufferName(); 90 ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources()); 91 92 return llvm::Error::success(); 93 } 94 95 ExecuteAction(); 96 97 return llvm::Error::success(); 98 } 99 100 void FrontendAction::EndSourceFile() { 101 CompilerInstance &ci = instance(); 102 103 // Cleanup the output streams, and erase the output files if instructed by the 104 // FrontendAction. 105 ci.ClearOutputFiles(/*EraseFiles=*/ShouldEraseOutputFiles()); 106 107 set_instance(nullptr); 108 set_currentInput(FrontendInputFile()); 109 } 110