1 //===-- lib/Semantics/program-tree.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/Semantics/program-tree.h" 10 #include "flang/Common/idioms.h" 11 #include "flang/Parser/char-block.h" 12 #include "flang/Semantics/scope.h" 13 #include "flang/Semantics/semantics.h" 14 15 namespace Fortran::semantics { 16 17 static void GetEntryStmts( 18 ProgramTree &node, const parser::SpecificationPart &spec) { 19 const auto &implicitPart{std::get<parser::ImplicitPart>(spec.t)}; 20 for (const parser::ImplicitPartStmt &stmt : implicitPart.v) { 21 if (const auto *entryStmt{std::get_if< 22 parser::Statement<common::Indirection<parser::EntryStmt>>>( 23 &stmt.u)}) { 24 node.AddEntry(entryStmt->statement.value()); 25 } 26 } 27 for (const auto &decl : 28 std::get<std::list<parser::DeclarationConstruct>>(spec.t)) { 29 if (const auto *entryStmt{std::get_if< 30 parser::Statement<common::Indirection<parser::EntryStmt>>>( 31 &decl.u)}) { 32 node.AddEntry(entryStmt->statement.value()); 33 } 34 } 35 } 36 37 static void GetEntryStmts( 38 ProgramTree &node, const parser::ExecutionPart &exec) { 39 for (const auto &epConstruct : exec.v) { 40 if (const auto *entryStmt{std::get_if< 41 parser::Statement<common::Indirection<parser::EntryStmt>>>( 42 &epConstruct.u)}) { 43 node.AddEntry(entryStmt->statement.value()); 44 } 45 } 46 } 47 48 // Collects generics that define simple names that could include 49 // identically-named subprograms as specific procedures. 50 static void GetGenerics( 51 ProgramTree &node, const parser::SpecificationPart &spec) { 52 for (const auto &decl : 53 std::get<std::list<parser::DeclarationConstruct>>(spec.t)) { 54 if (const auto *spec{ 55 std::get_if<parser::SpecificationConstruct>(&decl.u)}) { 56 if (const auto *generic{std::get_if< 57 parser::Statement<common::Indirection<parser::GenericStmt>>>( 58 &spec->u)}) { 59 const parser::GenericStmt &genericStmt{generic->statement.value()}; 60 const auto &genericSpec{std::get<parser::GenericSpec>(genericStmt.t)}; 61 node.AddGeneric(genericSpec); 62 } else if (const auto *interface{ 63 std::get_if<common::Indirection<parser::InterfaceBlock>>( 64 &spec->u)}) { 65 const parser::InterfaceBlock &interfaceBlock{interface->value()}; 66 const parser::InterfaceStmt &interfaceStmt{ 67 std::get<parser::Statement<parser::InterfaceStmt>>(interfaceBlock.t) 68 .statement}; 69 const auto *genericSpec{ 70 std::get_if<std::optional<parser::GenericSpec>>(&interfaceStmt.u)}; 71 if (genericSpec && genericSpec->has_value()) { 72 node.AddGeneric(**genericSpec); 73 } 74 } 75 } 76 } 77 } 78 79 template <typename T> 80 static ProgramTree BuildSubprogramTree( 81 const parser::Name &name, SemanticsContext &context, const T &x) { 82 const auto &spec{std::get<parser::SpecificationPart>(x.t)}; 83 const auto &exec{std::get<parser::ExecutionPart>(x.t)}; 84 const auto &subps{ 85 std::get<std::optional<parser::InternalSubprogramPart>>(x.t)}; 86 ProgramTree node{name, spec, &exec}; 87 GetEntryStmts(node, spec); 88 GetEntryStmts(node, exec); 89 GetGenerics(node, spec); 90 if (subps) { 91 for (const auto &subp : 92 std::get<std::list<parser::InternalSubprogram>>(subps->t)) { 93 common::visit( 94 [&](const auto &y) { 95 if (auto child{ProgramTree::Build(y.value(), context)}) { 96 node.AddChild(std::move(*child)); 97 } 98 }, 99 subp.u); 100 } 101 } 102 return node; 103 } 104 105 static ProgramTree BuildSubprogramTree( 106 const parser::Name &name, SemanticsContext &, const parser::BlockData &x) { 107 const auto &spec{std::get<parser::SpecificationPart>(x.t)}; 108 return ProgramTree{name, spec}; 109 } 110 111 template <typename T> 112 static ProgramTree BuildModuleTree( 113 const parser::Name &name, SemanticsContext &context, const T &x) { 114 const auto &spec{std::get<parser::SpecificationPart>(x.t)}; 115 const auto &subps{std::get<std::optional<parser::ModuleSubprogramPart>>(x.t)}; 116 ProgramTree node{name, spec}; 117 GetGenerics(node, spec); 118 if (subps) { 119 for (const auto &subp : 120 std::get<std::list<parser::ModuleSubprogram>>(subps->t)) { 121 common::visit( 122 [&](const auto &y) { 123 if (auto child{ProgramTree::Build(y.value(), context)}) { 124 node.AddChild(std::move(*child)); 125 } 126 }, 127 subp.u); 128 } 129 } 130 return node; 131 } 132 133 ProgramTree &ProgramTree::Build( 134 const parser::ProgramUnit &x, SemanticsContext &context) { 135 return common::visit( 136 [&](const auto &y) -> ProgramTree & { 137 auto node{Build(y.value(), context)}; 138 CHECK(node.has_value()); 139 return context.SaveProgramTree(std::move(*node)); 140 }, 141 x.u); 142 } 143 144 std::optional<ProgramTree> ProgramTree::Build( 145 const parser::MainProgram &x, SemanticsContext &context) { 146 const auto &stmt{ 147 std::get<std::optional<parser::Statement<parser::ProgramStmt>>>(x.t)}; 148 const auto &end{std::get<parser::Statement<parser::EndProgramStmt>>(x.t)}; 149 static parser::Name emptyName; 150 auto result{stmt 151 ? BuildSubprogramTree(stmt->statement.v, context, x).set_stmt(*stmt) 152 : BuildSubprogramTree(emptyName, context, x)}; 153 return std::move(result.set_endStmt(end)); 154 } 155 156 std::optional<ProgramTree> ProgramTree::Build( 157 const parser::FunctionSubprogram &x, SemanticsContext &context) { 158 const auto &stmt{std::get<parser::Statement<parser::FunctionStmt>>(x.t)}; 159 const auto &end{std::get<parser::Statement<parser::EndFunctionStmt>>(x.t)}; 160 const auto &name{std::get<parser::Name>(stmt.statement.t)}; 161 const parser::LanguageBindingSpec *bindingSpec{}; 162 if (const auto &suffix{ 163 std::get<std::optional<parser::Suffix>>(stmt.statement.t)}) { 164 if (suffix->binding) { 165 bindingSpec = &*suffix->binding; 166 } 167 } 168 return BuildSubprogramTree(name, context, x) 169 .set_stmt(stmt) 170 .set_endStmt(end) 171 .set_bindingSpec(bindingSpec); 172 } 173 174 std::optional<ProgramTree> ProgramTree::Build( 175 const parser::SubroutineSubprogram &x, SemanticsContext &context) { 176 const auto &stmt{std::get<parser::Statement<parser::SubroutineStmt>>(x.t)}; 177 const auto &end{std::get<parser::Statement<parser::EndSubroutineStmt>>(x.t)}; 178 const auto &name{std::get<parser::Name>(stmt.statement.t)}; 179 const parser::LanguageBindingSpec *bindingSpec{}; 180 if (const auto &binding{std::get<std::optional<parser::LanguageBindingSpec>>( 181 stmt.statement.t)}) { 182 bindingSpec = &*binding; 183 } 184 return BuildSubprogramTree(name, context, x) 185 .set_stmt(stmt) 186 .set_endStmt(end) 187 .set_bindingSpec(bindingSpec); 188 } 189 190 std::optional<ProgramTree> ProgramTree::Build( 191 const parser::SeparateModuleSubprogram &x, SemanticsContext &context) { 192 const auto &stmt{std::get<parser::Statement<parser::MpSubprogramStmt>>(x.t)}; 193 const auto &end{ 194 std::get<parser::Statement<parser::EndMpSubprogramStmt>>(x.t)}; 195 const auto &name{stmt.statement.v}; 196 return BuildSubprogramTree(name, context, x).set_stmt(stmt).set_endStmt(end); 197 } 198 199 std::optional<ProgramTree> ProgramTree::Build( 200 const parser::Module &x, SemanticsContext &context) { 201 const auto &stmt{std::get<parser::Statement<parser::ModuleStmt>>(x.t)}; 202 const auto &end{std::get<parser::Statement<parser::EndModuleStmt>>(x.t)}; 203 const auto &name{stmt.statement.v}; 204 return BuildModuleTree(name, context, x).set_stmt(stmt).set_endStmt(end); 205 } 206 207 std::optional<ProgramTree> ProgramTree::Build( 208 const parser::Submodule &x, SemanticsContext &context) { 209 const auto &stmt{std::get<parser::Statement<parser::SubmoduleStmt>>(x.t)}; 210 const auto &end{std::get<parser::Statement<parser::EndSubmoduleStmt>>(x.t)}; 211 const auto &name{std::get<parser::Name>(stmt.statement.t)}; 212 return BuildModuleTree(name, context, x).set_stmt(stmt).set_endStmt(end); 213 } 214 215 std::optional<ProgramTree> ProgramTree::Build( 216 const parser::BlockData &x, SemanticsContext &context) { 217 const auto &stmt{std::get<parser::Statement<parser::BlockDataStmt>>(x.t)}; 218 const auto &end{std::get<parser::Statement<parser::EndBlockDataStmt>>(x.t)}; 219 static parser::Name emptyName; 220 auto result{stmt.statement.v 221 ? BuildSubprogramTree(*stmt.statement.v, context, x) 222 : BuildSubprogramTree(emptyName, context, x)}; 223 return std::move(result.set_stmt(stmt).set_endStmt(end)); 224 } 225 226 std::optional<ProgramTree> ProgramTree::Build( 227 const parser::CompilerDirective &x, SemanticsContext &context) { 228 if (context.ShouldWarn(common::UsageWarning::IgnoredDirective)) { 229 context.Say(x.source, "Compiler directive ignored here"_warn_en_US); 230 } 231 return std::nullopt; 232 } 233 234 std::optional<ProgramTree> ProgramTree::Build( 235 const parser::OpenACCRoutineConstruct &, SemanticsContext &) { 236 DIE("ProgramTree::Build() called for OpenACCRoutineConstruct"); 237 } 238 239 const parser::ParentIdentifier &ProgramTree::GetParentId() const { 240 const auto *stmt{ 241 std::get<const parser::Statement<parser::SubmoduleStmt> *>(stmt_)}; 242 return std::get<parser::ParentIdentifier>(stmt->statement.t); 243 } 244 245 bool ProgramTree::IsModule() const { 246 auto kind{GetKind()}; 247 return kind == Kind::Module || kind == Kind::Submodule; 248 } 249 250 Symbol::Flag ProgramTree::GetSubpFlag() const { 251 return GetKind() == Kind::Function ? Symbol::Flag::Function 252 : Symbol::Flag::Subroutine; 253 } 254 255 bool ProgramTree::HasModulePrefix() const { 256 if (std::holds_alternative< 257 const parser::Statement<parser::MpSubprogramStmt> *>(stmt_)) { 258 return true; // MODULE PROCEDURE foo 259 } 260 using ListType = std::list<parser::PrefixSpec>; 261 const auto *prefixes{common::visit( 262 common::visitors{ 263 [](const parser::Statement<parser::FunctionStmt> *x) { 264 return &std::get<ListType>(x->statement.t); 265 }, 266 [](const parser::Statement<parser::SubroutineStmt> *x) { 267 return &std::get<ListType>(x->statement.t); 268 }, 269 [](const auto *) -> const ListType * { return nullptr; }, 270 }, 271 stmt_)}; 272 if (prefixes) { 273 for (const auto &prefix : *prefixes) { 274 if (std::holds_alternative<parser::PrefixSpec::Module>(prefix.u)) { 275 return true; 276 } 277 } 278 } 279 return false; 280 } 281 282 ProgramTree::Kind ProgramTree::GetKind() const { 283 return common::visit( 284 common::visitors{ 285 [](const parser::Statement<parser::ProgramStmt> *) { 286 return Kind::Program; 287 }, 288 [](const parser::Statement<parser::FunctionStmt> *) { 289 return Kind::Function; 290 }, 291 [](const parser::Statement<parser::SubroutineStmt> *) { 292 return Kind::Subroutine; 293 }, 294 [](const parser::Statement<parser::MpSubprogramStmt> *) { 295 return Kind::MpSubprogram; 296 }, 297 [](const parser::Statement<parser::ModuleStmt> *) { 298 return Kind::Module; 299 }, 300 [](const parser::Statement<parser::SubmoduleStmt> *) { 301 return Kind::Submodule; 302 }, 303 [](const parser::Statement<parser::BlockDataStmt> *) { 304 return Kind::BlockData; 305 }, 306 }, 307 stmt_); 308 } 309 310 void ProgramTree::set_scope(Scope &scope) { 311 scope_ = &scope; 312 CHECK(endStmt_); 313 scope.AddSourceRange(*endStmt_); 314 } 315 316 void ProgramTree::AddChild(ProgramTree &&child) { 317 children_.emplace_back(std::move(child)); 318 } 319 320 void ProgramTree::AddEntry(const parser::EntryStmt &entryStmt) { 321 entryStmts_.emplace_back(entryStmt); 322 } 323 324 void ProgramTree::AddGeneric(const parser::GenericSpec &generic) { 325 genericSpecs_.emplace_back(generic); 326 } 327 328 } // namespace Fortran::semantics 329