xref: /llvm-project/flang/lib/Semantics/rewrite-parse-tree.cpp (revision fbbd8b0741586794721639715d1d974db56f83ac)
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