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"
1064ab3302SCarolineConcatto #include "flang/Common/indirection.h"
1164ab3302SCarolineConcatto #include "flang/Parser/parse-tree-visitor.h"
1264ab3302SCarolineConcatto #include "flang/Parser/parse-tree.h"
1364ab3302SCarolineConcatto #include "flang/Parser/tools.h"
1464ab3302SCarolineConcatto #include "flang/Semantics/scope.h"
1564ab3302SCarolineConcatto #include "flang/Semantics/semantics.h"
1664ab3302SCarolineConcatto #include "flang/Semantics/symbol.h"
1764ab3302SCarolineConcatto #include "flang/Semantics/tools.h"
1864ab3302SCarolineConcatto #include <list>
1964ab3302SCarolineConcatto 
2064ab3302SCarolineConcatto namespace Fortran::semantics {
2164ab3302SCarolineConcatto 
2264ab3302SCarolineConcatto using namespace parser::literals;
2364ab3302SCarolineConcatto 
24149d3e43SPeter Klausler /// Convert misidentified statement functions to array element assignments
25149d3e43SPeter Klausler /// or pointer-valued function result assignments.
264171f80dSpeter klausler /// Convert misidentified format expressions to namelist group names.
274171f80dSpeter klausler /// Convert misidentified character variables in I/O units to integer
2864ab3302SCarolineConcatto /// unit number expressions.
294171f80dSpeter klausler /// Convert misidentified named constants in data statement values to
304171f80dSpeter klausler /// initial data targets
3164ab3302SCarolineConcatto class RewriteMutator {
3264ab3302SCarolineConcatto public:
RewriteMutator(SemanticsContext & context)3364ab3302SCarolineConcatto   RewriteMutator(SemanticsContext &context)
3464ab3302SCarolineConcatto       : errorOnUnresolvedName_{!context.AnyFatalError()},
3564ab3302SCarolineConcatto         messages_{context.messages()} {}
3664ab3302SCarolineConcatto 
3764ab3302SCarolineConcatto   // Default action for a parse tree node is to visit children.
Pre(T &)3864ab3302SCarolineConcatto   template <typename T> bool Pre(T &) { return true; }
Post(T &)3964ab3302SCarolineConcatto   template <typename T> void Post(T &) {}
4064ab3302SCarolineConcatto 
4164ab3302SCarolineConcatto   void Post(parser::Name &);
4264ab3302SCarolineConcatto   void Post(parser::SpecificationPart &);
4364ab3302SCarolineConcatto   bool Pre(parser::ExecutionPart &);
4464ab3302SCarolineConcatto   void Post(parser::IoUnit &);
4564ab3302SCarolineConcatto   void Post(parser::ReadStmt &);
4664ab3302SCarolineConcatto   void Post(parser::WriteStmt &);
4764ab3302SCarolineConcatto 
4864ab3302SCarolineConcatto   // Name resolution yet implemented:
494171f80dSpeter klausler   // TODO: Can some/all of these now be enabled?
Pre(parser::EquivalenceStmt &)5064ab3302SCarolineConcatto   bool Pre(parser::EquivalenceStmt &) { return false; }
Pre(parser::Keyword &)5164ab3302SCarolineConcatto   bool Pre(parser::Keyword &) { return false; }
Pre(parser::EntryStmt &)5264ab3302SCarolineConcatto   bool Pre(parser::EntryStmt &) { return false; }
Pre(parser::CompilerDirective &)5364ab3302SCarolineConcatto   bool Pre(parser::CompilerDirective &) { return false; }
5464ab3302SCarolineConcatto 
5564ab3302SCarolineConcatto   // Don't bother resolving names in end statements.
Pre(parser::EndBlockDataStmt &)5664ab3302SCarolineConcatto   bool Pre(parser::EndBlockDataStmt &) { return false; }
Pre(parser::EndFunctionStmt &)5764ab3302SCarolineConcatto   bool Pre(parser::EndFunctionStmt &) { return false; }
Pre(parser::EndInterfaceStmt &)5864ab3302SCarolineConcatto   bool Pre(parser::EndInterfaceStmt &) { return false; }
Pre(parser::EndModuleStmt &)5964ab3302SCarolineConcatto   bool Pre(parser::EndModuleStmt &) { return false; }
Pre(parser::EndMpSubprogramStmt &)6064ab3302SCarolineConcatto   bool Pre(parser::EndMpSubprogramStmt &) { return false; }
Pre(parser::EndProgramStmt &)6164ab3302SCarolineConcatto   bool Pre(parser::EndProgramStmt &) { return false; }
Pre(parser::EndSubmoduleStmt &)6264ab3302SCarolineConcatto   bool Pre(parser::EndSubmoduleStmt &) { return false; }
Pre(parser::EndSubroutineStmt &)6364ab3302SCarolineConcatto   bool Pre(parser::EndSubroutineStmt &) { return false; }
Pre(parser::EndTypeStmt &)6464ab3302SCarolineConcatto   bool Pre(parser::EndTypeStmt &) { return false; }
6564ab3302SCarolineConcatto 
6664ab3302SCarolineConcatto private:
6764ab3302SCarolineConcatto   using stmtFuncType =
6864ab3302SCarolineConcatto       parser::Statement<common::Indirection<parser::StmtFunctionStmt>>;
6964ab3302SCarolineConcatto   bool errorOnUnresolvedName_{true};
7064ab3302SCarolineConcatto   parser::Messages &messages_;
7164ab3302SCarolineConcatto   std::list<stmtFuncType> stmtFuncsToConvert_;
7264ab3302SCarolineConcatto };
7364ab3302SCarolineConcatto 
7464ab3302SCarolineConcatto // Check that name has been resolved to a symbol
Post(parser::Name & name)7564ab3302SCarolineConcatto void RewriteMutator::Post(parser::Name &name) {
7664ab3302SCarolineConcatto   if (!name.symbol && errorOnUnresolvedName_) {
7764ab3302SCarolineConcatto     messages_.Say(name.source, "Internal: no symbol found for '%s'"_err_en_US,
7864ab3302SCarolineConcatto         name.source);
7964ab3302SCarolineConcatto   }
8064ab3302SCarolineConcatto }
8164ab3302SCarolineConcatto 
ReturnsDataPointer(const Symbol & symbol)82*f472c099SPeter Klausler static bool ReturnsDataPointer(const Symbol &symbol) {
83*f472c099SPeter Klausler   if (const Symbol * funcRes{FindFunctionResult(symbol)}) {
84*f472c099SPeter Klausler     return IsPointer(*funcRes) && !IsProcedure(*funcRes);
85*f472c099SPeter Klausler   } else if (const auto *generic{symbol.detailsIf<GenericDetails>()}) {
86*f472c099SPeter Klausler     for (auto ref : generic->specificProcs()) {
87*f472c099SPeter Klausler       if (ReturnsDataPointer(*ref)) {
88*f472c099SPeter Klausler         return true;
89*f472c099SPeter Klausler       }
90*f472c099SPeter Klausler     }
91*f472c099SPeter Klausler   }
92*f472c099SPeter Klausler   return false;
93*f472c099SPeter Klausler }
94*f472c099SPeter Klausler 
9564ab3302SCarolineConcatto // Find mis-parsed statement functions and move to stmtFuncsToConvert_ list.
Post(parser::SpecificationPart & x)9664ab3302SCarolineConcatto void RewriteMutator::Post(parser::SpecificationPart &x) {
9764ab3302SCarolineConcatto   auto &list{std::get<std::list<parser::DeclarationConstruct>>(x.t)};
9864ab3302SCarolineConcatto   for (auto it{list.begin()}; it != list.end();) {
99149d3e43SPeter Klausler     bool isAssignment{false};
100149d3e43SPeter Klausler     if (auto *stmt{std::get_if<stmtFuncType>(&it->u)}) {
101149d3e43SPeter Klausler       if (const Symbol *
102149d3e43SPeter Klausler           symbol{std::get<parser::Name>(stmt->statement.value().t).symbol}) {
103*f472c099SPeter Klausler         const Symbol &ultimate{symbol->GetUltimate()};
104*f472c099SPeter Klausler         isAssignment =
105*f472c099SPeter Klausler             ultimate.has<ObjectEntityDetails>() || ReturnsDataPointer(ultimate);
106149d3e43SPeter Klausler         if (isAssignment) {
107149d3e43SPeter Klausler           stmtFuncsToConvert_.emplace_back(std::move(*stmt));
108149d3e43SPeter Klausler         }
109149d3e43SPeter Klausler       }
110149d3e43SPeter Klausler     }
111149d3e43SPeter Klausler     if (isAssignment) {
11264ab3302SCarolineConcatto       it = list.erase(it);
113149d3e43SPeter Klausler     } else {
11464ab3302SCarolineConcatto       ++it;
11564ab3302SCarolineConcatto     }
11664ab3302SCarolineConcatto   }
117149d3e43SPeter Klausler }
11864ab3302SCarolineConcatto 
11964ab3302SCarolineConcatto // Insert converted assignments at start of ExecutionPart.
Pre(parser::ExecutionPart & x)12064ab3302SCarolineConcatto bool RewriteMutator::Pre(parser::ExecutionPart &x) {
12164ab3302SCarolineConcatto   auto origFirst{x.v.begin()}; // insert each elem before origFirst
12264ab3302SCarolineConcatto   for (stmtFuncType &sf : stmtFuncsToConvert_) {
12364ab3302SCarolineConcatto     auto stmt{sf.statement.value().ConvertToAssignment()};
12464ab3302SCarolineConcatto     stmt.source = sf.source;
12564ab3302SCarolineConcatto     x.v.insert(origFirst,
12664ab3302SCarolineConcatto         parser::ExecutionPartConstruct{
12764ab3302SCarolineConcatto             parser::ExecutableConstruct{std::move(stmt)}});
12864ab3302SCarolineConcatto   }
12964ab3302SCarolineConcatto   stmtFuncsToConvert_.clear();
13064ab3302SCarolineConcatto   return true;
13164ab3302SCarolineConcatto }
13264ab3302SCarolineConcatto 
13304a14798Speter klausler // Convert a syntactically ambiguous io-unit internal-file-variable to a
13404a14798Speter klausler // file-unit-number.
Post(parser::IoUnit & x)13564ab3302SCarolineConcatto void RewriteMutator::Post(parser::IoUnit &x) {
13664ab3302SCarolineConcatto   if (auto *var{std::get_if<parser::Variable>(&x.u)}) {
13764ab3302SCarolineConcatto     const parser::Name &last{parser::GetLastName(*var)};
13864ab3302SCarolineConcatto     DeclTypeSpec *type{last.symbol ? last.symbol->GetType() : nullptr};
13964ab3302SCarolineConcatto     if (!type || type->category() != DeclTypeSpec::Character) {
14064ab3302SCarolineConcatto       // If the Variable is not known to be character (any kind), transform
14164ab3302SCarolineConcatto       // the I/O unit in situ to a FileUnitNumber so that automatic expression
14264ab3302SCarolineConcatto       // constraint checking will be applied.
14304a14798Speter klausler       auto source{var->GetSource()};
144cd03e96fSPeter Klausler       auto expr{common::visit(
14564ab3302SCarolineConcatto           [](auto &&indirection) {
14664ab3302SCarolineConcatto             return parser::Expr{std::move(indirection)};
14764ab3302SCarolineConcatto           },
14864ab3302SCarolineConcatto           std::move(var->u))};
14904a14798Speter klausler       expr.source = source;
15064ab3302SCarolineConcatto       x.u = parser::FileUnitNumber{
15164ab3302SCarolineConcatto           parser::ScalarIntExpr{parser::IntExpr{std::move(expr)}}};
15264ab3302SCarolineConcatto     }
15364ab3302SCarolineConcatto   }
15464ab3302SCarolineConcatto }
15564ab3302SCarolineConcatto 
15664ab3302SCarolineConcatto // When a namelist group name appears (without NML=) in a READ or WRITE
15764ab3302SCarolineConcatto // statement in such a way that it can be misparsed as a format expression,
15864ab3302SCarolineConcatto // rewrite the I/O statement's parse tree node as if the namelist group
15964ab3302SCarolineConcatto // name had appeared with NML=.
16064ab3302SCarolineConcatto template <typename READ_OR_WRITE>
FixMisparsedUntaggedNamelistName(READ_OR_WRITE & x)16164ab3302SCarolineConcatto void FixMisparsedUntaggedNamelistName(READ_OR_WRITE &x) {
16264ab3302SCarolineConcatto   if (x.iounit && x.format &&
163455ed8deSpeter klausler       std::holds_alternative<parser::Expr>(x.format->u)) {
16464ab3302SCarolineConcatto     if (const parser::Name * name{parser::Unwrap<parser::Name>(x.format)}) {
16564ab3302SCarolineConcatto       if (name->symbol && name->symbol->GetUltimate().has<NamelistDetails>()) {
16664ab3302SCarolineConcatto         x.controls.emplace_front(parser::IoControlSpec{std::move(*name)});
16764ab3302SCarolineConcatto         x.format.reset();
16864ab3302SCarolineConcatto       }
16964ab3302SCarolineConcatto     }
17064ab3302SCarolineConcatto   }
17164ab3302SCarolineConcatto }
17264ab3302SCarolineConcatto 
1734acd8f7fSpeter klausler // READ(CVAR) [, ...] will be misparsed as UNIT=CVAR; correct
1744acd8f7fSpeter klausler // it to READ CVAR [,...] with CVAR as a format rather than as
1754acd8f7fSpeter klausler // an internal I/O unit for unformatted I/O, which Fortran does
1764acd8f7fSpeter klausler // not support.
Post(parser::ReadStmt & x)17764ab3302SCarolineConcatto void RewriteMutator::Post(parser::ReadStmt &x) {
1784acd8f7fSpeter klausler   if (x.iounit && !x.format && x.controls.empty()) {
1794acd8f7fSpeter klausler     if (auto *var{std::get_if<parser::Variable>(&x.iounit->u)}) {
1804acd8f7fSpeter klausler       const parser::Name &last{parser::GetLastName(*var)};
1814acd8f7fSpeter klausler       DeclTypeSpec *type{last.symbol ? last.symbol->GetType() : nullptr};
1824acd8f7fSpeter klausler       if (type && type->category() == DeclTypeSpec::Character) {
183cd03e96fSPeter Klausler         x.format = common::visit(
1844acd8f7fSpeter klausler             [](auto &&indirection) {
1854acd8f7fSpeter klausler               return parser::Expr{std::move(indirection)};
1864acd8f7fSpeter klausler             },
1874acd8f7fSpeter klausler             std::move(var->u));
1884acd8f7fSpeter klausler         x.iounit.reset();
1894acd8f7fSpeter klausler       }
1904acd8f7fSpeter klausler     }
1914acd8f7fSpeter klausler   }
19264ab3302SCarolineConcatto   FixMisparsedUntaggedNamelistName(x);
19364ab3302SCarolineConcatto }
19464ab3302SCarolineConcatto 
Post(parser::WriteStmt & x)19564ab3302SCarolineConcatto void RewriteMutator::Post(parser::WriteStmt &x) {
19664ab3302SCarolineConcatto   FixMisparsedUntaggedNamelistName(x);
19764ab3302SCarolineConcatto }
19864ab3302SCarolineConcatto 
RewriteParseTree(SemanticsContext & context,parser::Program & program)19964ab3302SCarolineConcatto bool RewriteParseTree(SemanticsContext &context, parser::Program &program) {
20064ab3302SCarolineConcatto   RewriteMutator mutator{context};
20164ab3302SCarolineConcatto   parser::Walk(program, mutator);
20264ab3302SCarolineConcatto   return !context.AnyFatalError();
20364ab3302SCarolineConcatto }
20464ab3302SCarolineConcatto 
2051f879005STim Keith } // namespace Fortran::semantics
206