164ab3302SCarolineConcatto //===-- lib/Semantics/rewrite-parse-tree.cpp ------------------------------===// 264ab3302SCarolineConcatto // 364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information. 564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 664ab3302SCarolineConcatto // 764ab3302SCarolineConcatto //===----------------------------------------------------------------------===// 864ab3302SCarolineConcatto 964ab3302SCarolineConcatto #include "rewrite-parse-tree.h" 10b49f846fSSergio Afonso #include "rewrite-directives.h" 1164ab3302SCarolineConcatto #include "flang/Common/indirection.h" 1264ab3302SCarolineConcatto #include "flang/Parser/parse-tree-visitor.h" 1364ab3302SCarolineConcatto #include "flang/Parser/parse-tree.h" 1464ab3302SCarolineConcatto #include "flang/Parser/tools.h" 1564ab3302SCarolineConcatto #include "flang/Semantics/scope.h" 1664ab3302SCarolineConcatto #include "flang/Semantics/semantics.h" 1764ab3302SCarolineConcatto #include "flang/Semantics/symbol.h" 1864ab3302SCarolineConcatto #include "flang/Semantics/tools.h" 1964ab3302SCarolineConcatto #include <list> 2064ab3302SCarolineConcatto 2164ab3302SCarolineConcatto namespace Fortran::semantics { 2264ab3302SCarolineConcatto 2364ab3302SCarolineConcatto using namespace parser::literals; 2464ab3302SCarolineConcatto 25149d3e43SPeter Klausler /// Convert misidentified statement functions to array element assignments 26149d3e43SPeter Klausler /// or pointer-valued function result assignments. 274171f80dSpeter klausler /// Convert misidentified format expressions to namelist group names. 284171f80dSpeter klausler /// Convert misidentified character variables in I/O units to integer 2964ab3302SCarolineConcatto /// unit number expressions. 304171f80dSpeter klausler /// Convert misidentified named constants in data statement values to 314171f80dSpeter klausler /// initial data targets 3264ab3302SCarolineConcatto class RewriteMutator { 3364ab3302SCarolineConcatto public: 3464ab3302SCarolineConcatto RewriteMutator(SemanticsContext &context) 35a70ffe78SPeter Klausler : context_{context}, errorOnUnresolvedName_{!context.AnyFatalError()}, 3664ab3302SCarolineConcatto messages_{context.messages()} {} 3764ab3302SCarolineConcatto 3864ab3302SCarolineConcatto // Default action for a parse tree node is to visit children. 3964ab3302SCarolineConcatto template <typename T> bool Pre(T &) { return true; } 4064ab3302SCarolineConcatto template <typename T> void Post(T &) {} 4164ab3302SCarolineConcatto 4264ab3302SCarolineConcatto void Post(parser::Name &); 43*fbbd8b07SPeter Klausler bool Pre(parser::MainProgram &); 44*fbbd8b07SPeter Klausler bool Pre(parser::FunctionSubprogram &); 45*fbbd8b07SPeter Klausler bool Pre(parser::SubroutineSubprogram &); 46*fbbd8b07SPeter Klausler bool Pre(parser::SeparateModuleSubprogram &); 47*fbbd8b07SPeter Klausler bool Pre(parser::BlockConstruct &); 48a70ffe78SPeter Klausler bool Pre(parser::ActionStmt &); 4964ab3302SCarolineConcatto void Post(parser::ReadStmt &); 5064ab3302SCarolineConcatto void Post(parser::WriteStmt &); 5164ab3302SCarolineConcatto 5264ab3302SCarolineConcatto // Name resolution yet implemented: 534171f80dSpeter klausler // TODO: Can some/all of these now be enabled? 5464ab3302SCarolineConcatto bool Pre(parser::EquivalenceStmt &) { return false; } 5564ab3302SCarolineConcatto bool Pre(parser::Keyword &) { return false; } 5664ab3302SCarolineConcatto bool Pre(parser::EntryStmt &) { return false; } 5764ab3302SCarolineConcatto bool Pre(parser::CompilerDirective &) { return false; } 5864ab3302SCarolineConcatto 5964ab3302SCarolineConcatto // Don't bother resolving names in end statements. 6064ab3302SCarolineConcatto bool Pre(parser::EndBlockDataStmt &) { return false; } 6164ab3302SCarolineConcatto bool Pre(parser::EndFunctionStmt &) { return false; } 6264ab3302SCarolineConcatto bool Pre(parser::EndInterfaceStmt &) { return false; } 6364ab3302SCarolineConcatto bool Pre(parser::EndModuleStmt &) { return false; } 6464ab3302SCarolineConcatto bool Pre(parser::EndMpSubprogramStmt &) { return false; } 6564ab3302SCarolineConcatto bool Pre(parser::EndProgramStmt &) { return false; } 6664ab3302SCarolineConcatto bool Pre(parser::EndSubmoduleStmt &) { return false; } 6764ab3302SCarolineConcatto bool Pre(parser::EndSubroutineStmt &) { return false; } 6864ab3302SCarolineConcatto bool Pre(parser::EndTypeStmt &) { return false; } 6964ab3302SCarolineConcatto 7064ab3302SCarolineConcatto private: 71*fbbd8b07SPeter Klausler void FixMisparsedStmtFuncs(parser::SpecificationPart &, parser::Block &); 72*fbbd8b07SPeter Klausler 73a70ffe78SPeter Klausler SemanticsContext &context_; 7464ab3302SCarolineConcatto bool errorOnUnresolvedName_{true}; 7564ab3302SCarolineConcatto parser::Messages &messages_; 7664ab3302SCarolineConcatto }; 7764ab3302SCarolineConcatto 7864ab3302SCarolineConcatto // Check that name has been resolved to a symbol 7964ab3302SCarolineConcatto void RewriteMutator::Post(parser::Name &name) { 8064ab3302SCarolineConcatto if (!name.symbol && errorOnUnresolvedName_) { 8164ab3302SCarolineConcatto messages_.Say(name.source, "Internal: no symbol found for '%s'"_err_en_US, 8264ab3302SCarolineConcatto name.source); 8364ab3302SCarolineConcatto } 8464ab3302SCarolineConcatto } 8564ab3302SCarolineConcatto 86f472c099SPeter Klausler static bool ReturnsDataPointer(const Symbol &symbol) { 87f472c099SPeter Klausler if (const Symbol * funcRes{FindFunctionResult(symbol)}) { 88f472c099SPeter Klausler return IsPointer(*funcRes) && !IsProcedure(*funcRes); 89f472c099SPeter Klausler } else if (const auto *generic{symbol.detailsIf<GenericDetails>()}) { 90f472c099SPeter Klausler for (auto ref : generic->specificProcs()) { 91f472c099SPeter Klausler if (ReturnsDataPointer(*ref)) { 92f472c099SPeter Klausler return true; 93f472c099SPeter Klausler } 94f472c099SPeter Klausler } 95f472c099SPeter Klausler } 96f472c099SPeter Klausler return false; 97f472c099SPeter Klausler } 98f472c099SPeter Klausler 99*fbbd8b07SPeter Klausler // Finds misparsed statement functions in a specification part, rewrites 100*fbbd8b07SPeter Klausler // them into array element assignment statements, and moves them into the 101*fbbd8b07SPeter Klausler // beginning of the corresponding (execution part's) block. 102*fbbd8b07SPeter Klausler void RewriteMutator::FixMisparsedStmtFuncs( 103*fbbd8b07SPeter Klausler parser::SpecificationPart &specPart, parser::Block &block) { 104*fbbd8b07SPeter Klausler auto &list{std::get<std::list<parser::DeclarationConstruct>>(specPart.t)}; 105*fbbd8b07SPeter Klausler auto origFirst{block.begin()}; // insert each elem before origFirst 10664ab3302SCarolineConcatto for (auto it{list.begin()}; it != list.end();) { 107*fbbd8b07SPeter Klausler bool convert{false}; 108*fbbd8b07SPeter Klausler if (auto *stmt{std::get_if< 109*fbbd8b07SPeter Klausler parser::Statement<common::Indirection<parser::StmtFunctionStmt>>>( 110*fbbd8b07SPeter Klausler &it->u)}) { 111149d3e43SPeter Klausler if (const Symbol * 112149d3e43SPeter Klausler symbol{std::get<parser::Name>(stmt->statement.value().t).symbol}) { 113f472c099SPeter Klausler const Symbol &ultimate{symbol->GetUltimate()}; 114*fbbd8b07SPeter Klausler convert = 115f472c099SPeter Klausler ultimate.has<ObjectEntityDetails>() || ReturnsDataPointer(ultimate); 116*fbbd8b07SPeter Klausler if (convert) { 117*fbbd8b07SPeter Klausler auto newStmt{stmt->statement.value().ConvertToAssignment()}; 118*fbbd8b07SPeter Klausler newStmt.source = stmt->source; 119*fbbd8b07SPeter Klausler block.insert(origFirst, 120*fbbd8b07SPeter Klausler parser::ExecutionPartConstruct{ 121*fbbd8b07SPeter Klausler parser::ExecutableConstruct{std::move(newStmt)}}); 122149d3e43SPeter Klausler } 123149d3e43SPeter Klausler } 124149d3e43SPeter Klausler } 125*fbbd8b07SPeter Klausler if (convert) { 12664ab3302SCarolineConcatto it = list.erase(it); 127149d3e43SPeter Klausler } else { 12864ab3302SCarolineConcatto ++it; 12964ab3302SCarolineConcatto } 13064ab3302SCarolineConcatto } 131149d3e43SPeter Klausler } 13264ab3302SCarolineConcatto 133*fbbd8b07SPeter Klausler bool RewriteMutator::Pre(parser::MainProgram &program) { 134*fbbd8b07SPeter Klausler FixMisparsedStmtFuncs(std::get<parser::SpecificationPart>(program.t), 135*fbbd8b07SPeter Klausler std::get<parser::ExecutionPart>(program.t).v); 136*fbbd8b07SPeter Klausler return true; 13764ab3302SCarolineConcatto } 138*fbbd8b07SPeter Klausler 139*fbbd8b07SPeter Klausler bool RewriteMutator::Pre(parser::FunctionSubprogram &func) { 140*fbbd8b07SPeter Klausler FixMisparsedStmtFuncs(std::get<parser::SpecificationPart>(func.t), 141*fbbd8b07SPeter Klausler std::get<parser::ExecutionPart>(func.t).v); 142*fbbd8b07SPeter Klausler return true; 143*fbbd8b07SPeter Klausler } 144*fbbd8b07SPeter Klausler 145*fbbd8b07SPeter Klausler bool RewriteMutator::Pre(parser::SubroutineSubprogram &subr) { 146*fbbd8b07SPeter Klausler FixMisparsedStmtFuncs(std::get<parser::SpecificationPart>(subr.t), 147*fbbd8b07SPeter Klausler std::get<parser::ExecutionPart>(subr.t).v); 148*fbbd8b07SPeter Klausler return true; 149*fbbd8b07SPeter Klausler } 150*fbbd8b07SPeter Klausler 151*fbbd8b07SPeter Klausler bool RewriteMutator::Pre(parser::SeparateModuleSubprogram &subp) { 152*fbbd8b07SPeter Klausler FixMisparsedStmtFuncs(std::get<parser::SpecificationPart>(subp.t), 153*fbbd8b07SPeter Klausler std::get<parser::ExecutionPart>(subp.t).v); 154*fbbd8b07SPeter Klausler return true; 155*fbbd8b07SPeter Klausler } 156*fbbd8b07SPeter Klausler 157*fbbd8b07SPeter Klausler bool RewriteMutator::Pre(parser::BlockConstruct &block) { 158*fbbd8b07SPeter Klausler FixMisparsedStmtFuncs(std::get<parser::BlockSpecificationPart>(block.t).v, 159*fbbd8b07SPeter Klausler std::get<parser::Block>(block.t)); 16064ab3302SCarolineConcatto return true; 16164ab3302SCarolineConcatto } 16264ab3302SCarolineConcatto 163a70ffe78SPeter Klausler // Rewrite PRINT NML -> WRITE(*,NML=NML) 164a70ffe78SPeter Klausler bool RewriteMutator::Pre(parser::ActionStmt &x) { 165a70ffe78SPeter Klausler if (auto *print{std::get_if<common::Indirection<parser::PrintStmt>>(&x.u)}; 166a70ffe78SPeter Klausler print && 167a70ffe78SPeter Klausler std::get<std::list<parser::OutputItem>>(print->value().t).empty()) { 168a70ffe78SPeter Klausler auto &format{std::get<parser::Format>(print->value().t)}; 169a70ffe78SPeter Klausler if (std::holds_alternative<parser::Expr>(format.u)) { 170a70ffe78SPeter Klausler if (auto *name{parser::Unwrap<parser::Name>(format)}; name && 171a70ffe78SPeter Klausler name->symbol && name->symbol->GetUltimate().has<NamelistDetails>() && 172a70ffe78SPeter Klausler context_.IsEnabled(common::LanguageFeature::PrintNamelist)) { 173a70ffe78SPeter Klausler context_.Warn(common::LanguageFeature::PrintNamelist, name->source, 174a70ffe78SPeter Klausler "nonstandard: namelist in PRINT statement"_port_en_US); 175a70ffe78SPeter Klausler std::list<parser::IoControlSpec> controls; 176a70ffe78SPeter Klausler controls.emplace_back(std::move(*name)); 177a70ffe78SPeter Klausler x.u = common::Indirection<parser::WriteStmt>::Make( 178a70ffe78SPeter Klausler parser::IoUnit{parser::Star{}}, std::optional<parser::Format>{}, 179a70ffe78SPeter Klausler std::move(controls), std::list<parser::OutputItem>{}); 180a70ffe78SPeter Klausler } 181a70ffe78SPeter Klausler } 182a70ffe78SPeter Klausler } 183a70ffe78SPeter Klausler return true; 184a70ffe78SPeter Klausler } 185a70ffe78SPeter Klausler 18664ab3302SCarolineConcatto // When a namelist group name appears (without NML=) in a READ or WRITE 18764ab3302SCarolineConcatto // statement in such a way that it can be misparsed as a format expression, 18864ab3302SCarolineConcatto // rewrite the I/O statement's parse tree node as if the namelist group 18964ab3302SCarolineConcatto // name had appeared with NML=. 19064ab3302SCarolineConcatto template <typename READ_OR_WRITE> 19164ab3302SCarolineConcatto void FixMisparsedUntaggedNamelistName(READ_OR_WRITE &x) { 19264ab3302SCarolineConcatto if (x.iounit && x.format && 193455ed8deSpeter klausler std::holds_alternative<parser::Expr>(x.format->u)) { 19464ab3302SCarolineConcatto if (const parser::Name * name{parser::Unwrap<parser::Name>(x.format)}) { 19564ab3302SCarolineConcatto if (name->symbol && name->symbol->GetUltimate().has<NamelistDetails>()) { 19664ab3302SCarolineConcatto x.controls.emplace_front(parser::IoControlSpec{std::move(*name)}); 19764ab3302SCarolineConcatto x.format.reset(); 19864ab3302SCarolineConcatto } 19964ab3302SCarolineConcatto } 20064ab3302SCarolineConcatto } 20164ab3302SCarolineConcatto } 20264ab3302SCarolineConcatto 2034acd8f7fSpeter klausler // READ(CVAR) [, ...] will be misparsed as UNIT=CVAR; correct 2044acd8f7fSpeter klausler // it to READ CVAR [,...] with CVAR as a format rather than as 2054acd8f7fSpeter klausler // an internal I/O unit for unformatted I/O, which Fortran does 2064acd8f7fSpeter klausler // not support. 20764ab3302SCarolineConcatto void RewriteMutator::Post(parser::ReadStmt &x) { 2084acd8f7fSpeter klausler if (x.iounit && !x.format && x.controls.empty()) { 2094acd8f7fSpeter klausler if (auto *var{std::get_if<parser::Variable>(&x.iounit->u)}) { 2104acd8f7fSpeter klausler const parser::Name &last{parser::GetLastName(*var)}; 2114acd8f7fSpeter klausler DeclTypeSpec *type{last.symbol ? last.symbol->GetType() : nullptr}; 2124acd8f7fSpeter klausler if (type && type->category() == DeclTypeSpec::Character) { 213cd03e96fSPeter Klausler x.format = common::visit( 2144acd8f7fSpeter klausler [](auto &&indirection) { 2154acd8f7fSpeter klausler return parser::Expr{std::move(indirection)}; 2164acd8f7fSpeter klausler }, 2174acd8f7fSpeter klausler std::move(var->u)); 2184acd8f7fSpeter klausler x.iounit.reset(); 2194acd8f7fSpeter klausler } 2204acd8f7fSpeter klausler } 2214acd8f7fSpeter klausler } 22264ab3302SCarolineConcatto FixMisparsedUntaggedNamelistName(x); 22364ab3302SCarolineConcatto } 22464ab3302SCarolineConcatto 22564ab3302SCarolineConcatto void RewriteMutator::Post(parser::WriteStmt &x) { 22664ab3302SCarolineConcatto FixMisparsedUntaggedNamelistName(x); 22764ab3302SCarolineConcatto } 22864ab3302SCarolineConcatto 22964ab3302SCarolineConcatto bool RewriteParseTree(SemanticsContext &context, parser::Program &program) { 23064ab3302SCarolineConcatto RewriteMutator mutator{context}; 23164ab3302SCarolineConcatto parser::Walk(program, mutator); 232b49f846fSSergio Afonso return !context.AnyFatalError() && RewriteOmpParts(context, program); 23364ab3302SCarolineConcatto } 23464ab3302SCarolineConcatto 2351f879005STim Keith } // namespace Fortran::semantics 236