14c5906cfSCaroline Concatto //===--- FrontendAction.cpp -----------------------------------------------===// 24c5906cfSCaroline Concatto // 34c5906cfSCaroline Concatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 44c5906cfSCaroline Concatto // See https://llvm.org/LICENSE.txt for license information. 54c5906cfSCaroline Concatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64c5906cfSCaroline Concatto // 74c5906cfSCaroline Concatto //===----------------------------------------------------------------------===// 81e462fafSAndrzej Warzynski // 91e462fafSAndrzej Warzynski // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 101e462fafSAndrzej Warzynski // 111e462fafSAndrzej Warzynski //===----------------------------------------------------------------------===// 124c5906cfSCaroline Concatto 134c5906cfSCaroline Concatto #include "flang/Frontend/FrontendAction.h" 144c5906cfSCaroline Concatto #include "flang/Frontend/CompilerInstance.h" 154c5906cfSCaroline Concatto #include "flang/Frontend/FrontendActions.h" 16cea3abc2SAndrzej Warzynski #include "flang/Frontend/FrontendOptions.h" 17f52fc591SStuart Ellis #include "flang/Frontend/FrontendPluginRegistry.h" 18760e6c4cSAndrzej Warzynski #include "clang/Basic/DiagnosticFrontend.h" 194c5906cfSCaroline Concatto #include "llvm/Support/Errc.h" 20760e6c4cSAndrzej Warzynski #include "llvm/Support/VirtualFileSystem.h" 214c5906cfSCaroline Concatto 224c5906cfSCaroline Concatto using namespace Fortran::frontend; 234c5906cfSCaroline Concatto 24f52fc591SStuart Ellis LLVM_INSTANTIATE_REGISTRY(FrontendPluginRegistry) 25f52fc591SStuart Ellis 261e462fafSAndrzej Warzynski void FrontendAction::setCurrentInput(const FrontendInputFile &input) { 271e462fafSAndrzej Warzynski this->currentInput = input; 284c5906cfSCaroline Concatto } 294c5906cfSCaroline Concatto 304c5906cfSCaroline Concatto // Call this method if BeginSourceFile fails. 314c5906cfSCaroline Concatto // Deallocate compiler instance, input and output descriptors 321e462fafSAndrzej Warzynski static void beginSourceFileCleanUp(FrontendAction &fa, CompilerInstance &ci) { 331e462fafSAndrzej Warzynski ci.clearOutputFiles(/*EraseFiles=*/true); 341e462fafSAndrzej Warzynski fa.setCurrentInput(FrontendInputFile()); 351e462fafSAndrzej Warzynski fa.setInstance(nullptr); 364c5906cfSCaroline Concatto } 374c5906cfSCaroline Concatto 381e462fafSAndrzej Warzynski bool FrontendAction::beginSourceFile(CompilerInstance &ci, 391e462fafSAndrzej Warzynski const FrontendInputFile &realInput) { 404c5906cfSCaroline Concatto 414c5906cfSCaroline Concatto FrontendInputFile input(realInput); 42760e6c4cSAndrzej Warzynski 43760e6c4cSAndrzej Warzynski // Return immediately if the input file does not exist or is not a file. Note 44760e6c4cSAndrzej Warzynski // that we cannot check this for input from stdin. 451e462fafSAndrzej Warzynski if (input.getFile() != "-") { 461e462fafSAndrzej Warzynski if (!llvm::sys::fs::is_regular_file(input.getFile())) { 47760e6c4cSAndrzej Warzynski // Create an diagnostic ID to report 48760e6c4cSAndrzej Warzynski unsigned diagID; 491e462fafSAndrzej Warzynski if (llvm::vfs::getRealFileSystem()->exists(input.getFile())) { 501e462fafSAndrzej Warzynski ci.getDiagnostics().Report(clang::diag::err_fe_error_reading) 51e495eabdSHans Wennborg << input.getFile() << "not a regular file"; 521e462fafSAndrzej Warzynski diagID = ci.getDiagnostics().getCustomDiagID( 53760e6c4cSAndrzej Warzynski clang::DiagnosticsEngine::Error, "%0 is not a regular file"); 54760e6c4cSAndrzej Warzynski } else { 551e462fafSAndrzej Warzynski diagID = ci.getDiagnostics().getCustomDiagID( 56760e6c4cSAndrzej Warzynski clang::DiagnosticsEngine::Error, "%0 does not exist"); 57760e6c4cSAndrzej Warzynski } 58760e6c4cSAndrzej Warzynski 59760e6c4cSAndrzej Warzynski // Report the diagnostic and return 601e462fafSAndrzej Warzynski ci.getDiagnostics().Report(diagID) << input.getFile(); 611e462fafSAndrzej Warzynski beginSourceFileCleanUp(*this, ci); 62760e6c4cSAndrzej Warzynski return false; 63760e6c4cSAndrzej Warzynski } 64760e6c4cSAndrzej Warzynski } 65760e6c4cSAndrzej Warzynski 661e462fafSAndrzej Warzynski assert(!instance && "Already processing a source file!"); 671e462fafSAndrzej Warzynski assert(!realInput.isEmpty() && "Unexpected empty filename!"); 681e462fafSAndrzej Warzynski setCurrentInput(realInput); 691e462fafSAndrzej Warzynski setInstance(&ci); 70d06e9403SAndrzej Warzynski 711e462fafSAndrzej Warzynski if (!ci.hasAllSources()) { 721e462fafSAndrzej Warzynski beginSourceFileCleanUp(*this, ci); 734c5906cfSCaroline Concatto return false; 744c5906cfSCaroline Concatto } 75d06e9403SAndrzej Warzynski 761e462fafSAndrzej Warzynski auto &invoc = ci.getInvocation(); 77b83a4450SAndrzej Warzynski 78b83a4450SAndrzej Warzynski // Include command-line and predefined preprocessor macros. Use either: 79b83a4450SAndrzej Warzynski // * `-cpp/-nocpp`, or 80b83a4450SAndrzej Warzynski // * the file extension (if the user didn't express any preference) 81b83a4450SAndrzej Warzynski // to decide whether to include them or not. 821e462fafSAndrzej Warzynski if ((invoc.getPreprocessorOpts().macrosFlag == PPMacrosFlag::Include) || 831e462fafSAndrzej Warzynski (invoc.getPreprocessorOpts().macrosFlag == PPMacrosFlag::Unknown && 841e462fafSAndrzej Warzynski getCurrentInput().getMustBePreprocessed())) { 851e462fafSAndrzej Warzynski invoc.setDefaultPredefinitions(); 861e462fafSAndrzej Warzynski invoc.collectMacroDefinitions(); 87b83a4450SAndrzej Warzynski } 88b83a4450SAndrzej Warzynski 898a8ef1caSValentin Clement (バレンタイン クレメン) if (!invoc.getFortranOpts().features.IsEnabled( 908a8ef1caSValentin Clement (バレンタイン クレメン) Fortran::common::LanguageFeature::CUDA)) { 918a8ef1caSValentin Clement (バレンタイン クレメン) // Enable CUDA Fortran if source file is *.cuf/*.CUF and not already 928a8ef1caSValentin Clement (バレンタイン クレメン) // enabled. 938a8ef1caSValentin Clement (バレンタイン クレメン) invoc.getFortranOpts().features.Enable( 948a8ef1caSValentin Clement (バレンタイン クレメン) Fortran::common::LanguageFeature::CUDA, 954ad72793SPeter Klausler getCurrentInput().getIsCUDAFortran()); 968a8ef1caSValentin Clement (バレンタイン クレメン) } 974ad72793SPeter Klausler 984dfed691SPeter Klausler // -fpreprocess-include-lines 994dfed691SPeter Klausler invoc.getFortranOpts().expandIncludeLinesInPreprocessedOutput = 1004dfed691SPeter Klausler invoc.getPreprocessorOpts().preprocessIncludeLines; 1014dfed691SPeter Klausler 102b83a4450SAndrzej Warzynski // Decide between fixed and free form (if the user didn't express any 103b83a4450SAndrzej Warzynski // preference, use the file extension to decide) 1041e462fafSAndrzej Warzynski if (invoc.getFrontendOpts().fortranForm == FortranForm::Unknown) { 1051e462fafSAndrzej Warzynski invoc.getFortranOpts().isFixedForm = getCurrentInput().getIsFixedForm(); 106b83a4450SAndrzej Warzynski } 107b83a4450SAndrzej Warzynski 1081e462fafSAndrzej Warzynski if (!beginSourceFileAction()) { 1091e462fafSAndrzej Warzynski beginSourceFileCleanUp(*this, ci); 110d06e9403SAndrzej Warzynski return false; 111d06e9403SAndrzej Warzynski } 112d06e9403SAndrzej Warzynski 1134c5906cfSCaroline Concatto return true; 1144c5906cfSCaroline Concatto } 1154c5906cfSCaroline Concatto 1161e462fafSAndrzej Warzynski bool FrontendAction::shouldEraseOutputFiles() { 1171e462fafSAndrzej Warzynski return getInstance().getDiagnostics().hasErrorOccurred(); 1184c5906cfSCaroline Concatto } 1194c5906cfSCaroline Concatto 1201e462fafSAndrzej Warzynski llvm::Error FrontendAction::execute() { 1211e462fafSAndrzej Warzynski executeAction(); 122d28de0d7SCaroline Concatto 1234c5906cfSCaroline Concatto return llvm::Error::success(); 1244c5906cfSCaroline Concatto } 1254c5906cfSCaroline Concatto 1261e462fafSAndrzej Warzynski void FrontendAction::endSourceFile() { 1271e462fafSAndrzej Warzynski CompilerInstance &ci = getInstance(); 1284c5906cfSCaroline Concatto 1294c5906cfSCaroline Concatto // Cleanup the output streams, and erase the output files if instructed by the 1304c5906cfSCaroline Concatto // FrontendAction. 1311e462fafSAndrzej Warzynski ci.clearOutputFiles(/*EraseFiles=*/shouldEraseOutputFiles()); 1324c5906cfSCaroline Concatto 1331e462fafSAndrzej Warzynski setInstance(nullptr); 1341e462fafSAndrzej Warzynski setCurrentInput(FrontendInputFile()); 1354c5906cfSCaroline Concatto } 1364f21e6aeSAndrzej Warzynski 1371e462fafSAndrzej Warzynski bool FrontendAction::runPrescan() { 1381e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 1391e462fafSAndrzej Warzynski std::string currentInputPath{getCurrentFileOrBufferName()}; 1401e462fafSAndrzej Warzynski Fortran::parser::Options parserOptions = ci.getInvocation().getFortranOpts(); 1414f21e6aeSAndrzej Warzynski 1421e462fafSAndrzej Warzynski if (ci.getInvocation().getFrontendOpts().fortranForm == 1431e462fafSAndrzej Warzynski FortranForm::Unknown) { 1444f21e6aeSAndrzej Warzynski // Switch between fixed and free form format based on the input file 1454f21e6aeSAndrzej Warzynski // extension. 1464f21e6aeSAndrzej Warzynski // 1474f21e6aeSAndrzej Warzynski // Ideally we should have all Fortran options set before entering this 1484f21e6aeSAndrzej Warzynski // method (i.e. before processing any specific input files). However, we 1494f21e6aeSAndrzej Warzynski // can't decide between fixed and free form based on the file extension 1504f21e6aeSAndrzej Warzynski // earlier than this. 1511e462fafSAndrzej Warzynski parserOptions.isFixedForm = getCurrentInput().getIsFixedForm(); 1524f21e6aeSAndrzej Warzynski } 1534f21e6aeSAndrzej Warzynski 1544f21e6aeSAndrzej Warzynski // Prescan. In case of failure, report and return. 1551e462fafSAndrzej Warzynski ci.getParsing().Prescan(currentInputPath, parserOptions); 1564f21e6aeSAndrzej Warzynski 1574f21e6aeSAndrzej Warzynski return !reportFatalScanningErrors(); 1584f21e6aeSAndrzej Warzynski } 1594f21e6aeSAndrzej Warzynski 160f2e80893SPeter Klausler bool FrontendAction::runParse(bool emitMessages) { 1611e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 1624f21e6aeSAndrzej Warzynski 1634f21e6aeSAndrzej Warzynski // Parse. In case of failure, report and return. 1641e462fafSAndrzej Warzynski ci.getParsing().Parse(llvm::outs()); 1654f21e6aeSAndrzej Warzynski 1664f21e6aeSAndrzej Warzynski if (reportFatalParsingErrors()) { 1674f21e6aeSAndrzej Warzynski return false; 1684f21e6aeSAndrzej Warzynski } 1694f21e6aeSAndrzej Warzynski 170f2e80893SPeter Klausler if (emitMessages) { 171f2e80893SPeter Klausler // Report any non-fatal diagnostics from getParsing now rather than 172f2e80893SPeter Klausler // combining them with messages from semantics. 1731e462fafSAndrzej Warzynski ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources()); 174f2e80893SPeter Klausler } 1754f21e6aeSAndrzej Warzynski return true; 1764f21e6aeSAndrzej Warzynski } 1774f21e6aeSAndrzej Warzynski 1781e462fafSAndrzej Warzynski bool FrontendAction::runSemanticChecks() { 1791e462fafSAndrzej Warzynski CompilerInstance &ci = this->getInstance(); 1801e462fafSAndrzej Warzynski std::optional<parser::Program> &parseTree{ci.getParsing().parseTree()}; 1814f21e6aeSAndrzej Warzynski assert(parseTree && "Cannot run semantic checks without a parse tree!"); 1824f21e6aeSAndrzej Warzynski 183f2e80893SPeter Klausler // Transfer any pending non-fatal messages from parsing to semantics 184f2e80893SPeter Klausler // so that they are merged and all printed in order. 185f2e80893SPeter Klausler auto &semanticsCtx{ci.getSemanticsContext()}; 186f2e80893SPeter Klausler semanticsCtx.messages().Annex(std::move(ci.getParsing().messages())); 18765987954SPeter Klausler semanticsCtx.set_debugModuleWriter(ci.getInvocation().getDebugModuleDir()); 188f2e80893SPeter Klausler 1894f21e6aeSAndrzej Warzynski // Prepare semantics 19065987954SPeter Klausler ci.setSemantics(std::make_unique<Fortran::semantics::Semantics>(semanticsCtx, 19165987954SPeter Klausler *parseTree)); 1921e462fafSAndrzej Warzynski auto &semantics = ci.getSemantics(); 19365987954SPeter Klausler semantics.set_hermeticModuleFileOutput( 19465987954SPeter Klausler ci.getInvocation().getHermeticModuleFileOutput()); 1954f21e6aeSAndrzej Warzynski 1964f21e6aeSAndrzej Warzynski // Run semantic checks 1974f21e6aeSAndrzej Warzynski semantics.Perform(); 1984f21e6aeSAndrzej Warzynski 1994f21e6aeSAndrzej Warzynski if (reportFatalSemanticErrors()) { 2004f21e6aeSAndrzej Warzynski return false; 2014f21e6aeSAndrzej Warzynski } 2024f21e6aeSAndrzej Warzynski 203f2e80893SPeter Klausler // Report the diagnostics from parsing and the semantic checks 2041e462fafSAndrzej Warzynski semantics.EmitMessages(ci.getSemaOutputStream()); 2054f21e6aeSAndrzej Warzynski 2064f21e6aeSAndrzej Warzynski return true; 2074f21e6aeSAndrzej Warzynski } 2084f21e6aeSAndrzej Warzynski 2091e462fafSAndrzej Warzynski bool FrontendAction::generateRtTypeTables() { 2101e462fafSAndrzej Warzynski getInstance().setRtTyTables( 21116a91a1cSAndrzej Warzynski std::make_unique<Fortran::semantics::RuntimeDerivedTypeTables>( 212ae4d7ac9SAndrzej Warzyński BuildRuntimeDerivedTypeTables(getInstance().getSemanticsContext()))); 21316a91a1cSAndrzej Warzynski 21416a91a1cSAndrzej Warzynski // The runtime derived type information table builder may find additional 21516a91a1cSAndrzej Warzynski // semantic errors. Report them. 21616a91a1cSAndrzej Warzynski if (reportFatalSemanticErrors()) { 21716a91a1cSAndrzej Warzynski return false; 21816a91a1cSAndrzej Warzynski } 21916a91a1cSAndrzej Warzynski 22016a91a1cSAndrzej Warzynski return true; 22116a91a1cSAndrzej Warzynski } 22216a91a1cSAndrzej Warzynski 2234f21e6aeSAndrzej Warzynski template <unsigned N> 2244f21e6aeSAndrzej Warzynski bool FrontendAction::reportFatalErrors(const char (&message)[N]) { 2251e462fafSAndrzej Warzynski if (!instance->getParsing().messages().empty() && 2261e462fafSAndrzej Warzynski (instance->getInvocation().getWarnAsErr() || 2271e462fafSAndrzej Warzynski instance->getParsing().messages().AnyFatalError())) { 2281e462fafSAndrzej Warzynski const unsigned diagID = instance->getDiagnostics().getCustomDiagID( 2294f21e6aeSAndrzej Warzynski clang::DiagnosticsEngine::Error, message); 2301e462fafSAndrzej Warzynski instance->getDiagnostics().Report(diagID) << getCurrentFileOrBufferName(); 2311e462fafSAndrzej Warzynski instance->getParsing().messages().Emit(llvm::errs(), 2321e462fafSAndrzej Warzynski instance->getAllCookedSources()); 2334f21e6aeSAndrzej Warzynski return true; 2344f21e6aeSAndrzej Warzynski } 235*d1ea605eSPeter Klausler if (instance->getParsing().parseTree().has_value() && 236*d1ea605eSPeter Klausler !instance->getParsing().consumedWholeFile()) { 237*d1ea605eSPeter Klausler // Parsing failed without error. 238*d1ea605eSPeter Klausler const unsigned diagID = instance->getDiagnostics().getCustomDiagID( 239*d1ea605eSPeter Klausler clang::DiagnosticsEngine::Error, message); 240*d1ea605eSPeter Klausler instance->getDiagnostics().Report(diagID) << getCurrentFileOrBufferName(); 241*d1ea605eSPeter Klausler instance->getParsing().messages().Emit(llvm::errs(), 242*d1ea605eSPeter Klausler instance->getAllCookedSources()); 243*d1ea605eSPeter Klausler instance->getParsing().EmitMessage( 244*d1ea605eSPeter Klausler llvm::errs(), instance->getParsing().finalRestingPlace(), 245*d1ea605eSPeter Klausler "parser FAIL (final position)", "error: ", llvm::raw_ostream::RED); 246*d1ea605eSPeter Klausler return true; 247*d1ea605eSPeter Klausler } 2484f21e6aeSAndrzej Warzynski return false; 2494f21e6aeSAndrzej Warzynski } 2504f21e6aeSAndrzej Warzynski 2514f21e6aeSAndrzej Warzynski bool FrontendAction::reportFatalSemanticErrors() { 2521e462fafSAndrzej Warzynski auto &diags = instance->getDiagnostics(); 2531e462fafSAndrzej Warzynski auto &sema = instance->getSemantics(); 2544f21e6aeSAndrzej Warzynski 2551e462fafSAndrzej Warzynski if (instance->getSemantics().AnyFatalError()) { 2561e462fafSAndrzej Warzynski unsigned diagID = diags.getCustomDiagID(clang::DiagnosticsEngine::Error, 2571e462fafSAndrzej Warzynski "Semantic errors in %0"); 2581e462fafSAndrzej Warzynski diags.Report(diagID) << getCurrentFileOrBufferName(); 2591e462fafSAndrzej Warzynski sema.EmitMessages(instance->getSemaOutputStream()); 2604f21e6aeSAndrzej Warzynski 2614f21e6aeSAndrzej Warzynski return true; 2624f21e6aeSAndrzej Warzynski } 2634f21e6aeSAndrzej Warzynski 2644f21e6aeSAndrzej Warzynski return false; 2654f21e6aeSAndrzej Warzynski } 266