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 65 if (!ci.HasAllSources()) { 66 BeginSourceFileCleanUp(*this, ci); 67 return false; 68 } 69 70 auto &invoc = ci.invocation(); 71 72 // Include command-line and predefined preprocessor macros. Use either: 73 // * `-cpp/-nocpp`, or 74 // * the file extension (if the user didn't express any preference) 75 // to decide whether to include them or not. 76 if ((invoc.preprocessorOpts().macrosFlag_ == PPMacrosFlag::Include) || 77 (invoc.preprocessorOpts().macrosFlag_ == PPMacrosFlag::Unknown && 78 currentInput().MustBePreprocessed())) { 79 invoc.setDefaultPredefinitions(); 80 invoc.collectMacroDefinitions(); 81 } 82 83 // Decide between fixed and free form (if the user didn't express any 84 // preference, use the file extension to decide) 85 if (invoc.frontendOpts().fortranForm_ == FortranForm::Unknown) { 86 invoc.fortranOpts().isFixedForm = currentInput().IsFixedForm(); 87 } 88 89 if (!BeginSourceFileAction(ci)) { 90 BeginSourceFileCleanUp(*this, ci); 91 return false; 92 } 93 94 return true; 95 } 96 97 bool FrontendAction::ShouldEraseOutputFiles() { 98 return instance().diagnostics().hasErrorOccurred(); 99 } 100 101 llvm::Error FrontendAction::Execute() { 102 ExecuteAction(); 103 104 return llvm::Error::success(); 105 } 106 107 void FrontendAction::EndSourceFile() { 108 CompilerInstance &ci = instance(); 109 110 // Cleanup the output streams, and erase the output files if instructed by the 111 // FrontendAction. 112 ci.ClearOutputFiles(/*EraseFiles=*/ShouldEraseOutputFiles()); 113 114 set_instance(nullptr); 115 set_currentInput(FrontendInputFile()); 116 } 117