1 //===-- lib/Semantics/tools.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/Parser/tools.h" 10 #include "flang/Common/Fortran.h" 11 #include "flang/Common/indirection.h" 12 #include "flang/Parser/dump-parse-tree.h" 13 #include "flang/Parser/message.h" 14 #include "flang/Parser/parse-tree.h" 15 #include "flang/Semantics/scope.h" 16 #include "flang/Semantics/semantics.h" 17 #include "flang/Semantics/symbol.h" 18 #include "flang/Semantics/tools.h" 19 #include "flang/Semantics/type.h" 20 #include "llvm/Support/raw_ostream.h" 21 #include <algorithm> 22 #include <set> 23 #include <variant> 24 25 namespace Fortran::semantics { 26 27 // Find this or containing scope that matches predicate 28 static const Scope *FindScopeContaining( 29 const Scope &start, std::function<bool(const Scope &)> predicate) { 30 for (const Scope *scope{&start};; scope = &scope->parent()) { 31 if (predicate(*scope)) { 32 return scope; 33 } 34 if (scope->IsGlobal()) { 35 return nullptr; 36 } 37 } 38 } 39 40 const Scope *FindModuleContaining(const Scope &start) { 41 return FindScopeContaining( 42 start, [](const Scope &scope) { return scope.IsModule(); }); 43 } 44 45 const Symbol *FindCommonBlockContaining(const Symbol &object) { 46 if (const auto *details{object.detailsIf<ObjectEntityDetails>()}) { 47 return details->commonBlock(); 48 } else { 49 return nullptr; 50 } 51 } 52 53 const Scope *FindProgramUnitContaining(const Scope &start) { 54 return FindScopeContaining(start, [](const Scope &scope) { 55 switch (scope.kind()) { 56 case Scope::Kind::Module: 57 case Scope::Kind::MainProgram: 58 case Scope::Kind::Subprogram: 59 case Scope::Kind::BlockData: 60 return true; 61 default: 62 return false; 63 } 64 }); 65 } 66 67 const Scope *FindProgramUnitContaining(const Symbol &symbol) { 68 return FindProgramUnitContaining(symbol.owner()); 69 } 70 71 const Scope *FindPureProcedureContaining(const Scope &start) { 72 // N.B. We only need to examine the innermost containing program unit 73 // because an internal subprogram of a pure subprogram must also 74 // be pure (C1592). 75 if (const Scope * scope{FindProgramUnitContaining(start)}) { 76 if (IsPureProcedure(*scope)) { 77 return scope; 78 } 79 } 80 return nullptr; 81 } 82 83 Tristate IsDefinedAssignment( 84 const std::optional<evaluate::DynamicType> &lhsType, int lhsRank, 85 const std::optional<evaluate::DynamicType> &rhsType, int rhsRank) { 86 if (!lhsType || !rhsType) { 87 return Tristate::No; // error or rhs is untyped 88 } 89 TypeCategory lhsCat{lhsType->category()}; 90 TypeCategory rhsCat{rhsType->category()}; 91 if (rhsRank > 0 && lhsRank != rhsRank) { 92 return Tristate::Yes; 93 } else if (lhsCat != TypeCategory::Derived) { 94 return ToTristate(lhsCat != rhsCat && 95 (!IsNumericTypeCategory(lhsCat) || !IsNumericTypeCategory(rhsCat))); 96 } else { 97 const auto *lhsDerived{evaluate::GetDerivedTypeSpec(lhsType)}; 98 const auto *rhsDerived{evaluate::GetDerivedTypeSpec(rhsType)}; 99 if (lhsDerived && rhsDerived && *lhsDerived == *rhsDerived) { 100 return Tristate::Maybe; // TYPE(t) = TYPE(t) can be defined or 101 // intrinsic 102 } else { 103 return Tristate::Yes; 104 } 105 } 106 } 107 108 bool IsIntrinsicRelational(common::RelationalOperator opr, 109 const evaluate::DynamicType &type0, int rank0, 110 const evaluate::DynamicType &type1, int rank1) { 111 if (!evaluate::AreConformable(rank0, rank1)) { 112 return false; 113 } else { 114 auto cat0{type0.category()}; 115 auto cat1{type1.category()}; 116 if (IsNumericTypeCategory(cat0) && IsNumericTypeCategory(cat1)) { 117 // numeric types: EQ/NE always ok, others ok for non-complex 118 return opr == common::RelationalOperator::EQ || 119 opr == common::RelationalOperator::NE || 120 (cat0 != TypeCategory::Complex && cat1 != TypeCategory::Complex); 121 } else { 122 // not both numeric: only Character is ok 123 return cat0 == TypeCategory::Character && cat1 == TypeCategory::Character; 124 } 125 } 126 } 127 128 bool IsIntrinsicNumeric(const evaluate::DynamicType &type0) { 129 return IsNumericTypeCategory(type0.category()); 130 } 131 bool IsIntrinsicNumeric(const evaluate::DynamicType &type0, int rank0, 132 const evaluate::DynamicType &type1, int rank1) { 133 return evaluate::AreConformable(rank0, rank1) && 134 IsNumericTypeCategory(type0.category()) && 135 IsNumericTypeCategory(type1.category()); 136 } 137 138 bool IsIntrinsicLogical(const evaluate::DynamicType &type0) { 139 return type0.category() == TypeCategory::Logical; 140 } 141 bool IsIntrinsicLogical(const evaluate::DynamicType &type0, int rank0, 142 const evaluate::DynamicType &type1, int rank1) { 143 return evaluate::AreConformable(rank0, rank1) && 144 type0.category() == TypeCategory::Logical && 145 type1.category() == TypeCategory::Logical; 146 } 147 148 bool IsIntrinsicConcat(const evaluate::DynamicType &type0, int rank0, 149 const evaluate::DynamicType &type1, int rank1) { 150 return evaluate::AreConformable(rank0, rank1) && 151 type0.category() == TypeCategory::Character && 152 type1.category() == TypeCategory::Character && 153 type0.kind() == type1.kind(); 154 } 155 156 bool IsGenericDefinedOp(const Symbol &symbol) { 157 const Symbol &ultimate{symbol.GetUltimate()}; 158 if (const auto *generic{ultimate.detailsIf<GenericDetails>()}) { 159 return generic->kind().IsDefinedOperator(); 160 } else if (const auto *misc{ultimate.detailsIf<MiscDetails>()}) { 161 return misc->kind() == MiscDetails::Kind::TypeBoundDefinedOp; 162 } else { 163 return false; 164 } 165 } 166 167 bool IsCommonBlockContaining(const Symbol &block, const Symbol &object) { 168 const auto &objects{block.get<CommonBlockDetails>().objects()}; 169 auto found{std::find(objects.begin(), objects.end(), object)}; 170 return found != objects.end(); 171 } 172 173 bool IsUseAssociated(const Symbol &symbol, const Scope &scope) { 174 const Scope *owner{FindProgramUnitContaining(symbol.GetUltimate().owner())}; 175 return owner && owner->kind() == Scope::Kind::Module && 176 owner != FindProgramUnitContaining(scope); 177 } 178 179 bool DoesScopeContain( 180 const Scope *maybeAncestor, const Scope &maybeDescendent) { 181 return maybeAncestor && !maybeDescendent.IsGlobal() && 182 FindScopeContaining(maybeDescendent.parent(), 183 [&](const Scope &scope) { return &scope == maybeAncestor; }); 184 } 185 186 bool DoesScopeContain(const Scope *maybeAncestor, const Symbol &symbol) { 187 return DoesScopeContain(maybeAncestor, symbol.owner()); 188 } 189 190 bool IsHostAssociated(const Symbol &symbol, const Scope &scope) { 191 const Scope *subprogram{FindProgramUnitContaining(scope)}; 192 return subprogram && 193 DoesScopeContain(FindProgramUnitContaining(symbol), *subprogram); 194 } 195 196 bool IsDummy(const Symbol &symbol) { 197 if (const auto *details{symbol.detailsIf<ObjectEntityDetails>()}) { 198 return details->isDummy(); 199 } else if (const auto *details{symbol.detailsIf<ProcEntityDetails>()}) { 200 return details->isDummy(); 201 } else { 202 return false; 203 } 204 } 205 206 bool IsStmtFunction(const Symbol &symbol) { 207 const auto *subprogram{symbol.detailsIf<SubprogramDetails>()}; 208 return subprogram && subprogram->stmtFunction(); 209 } 210 211 bool IsInStmtFunction(const Symbol &symbol) { 212 if (const Symbol * function{symbol.owner().symbol()}) { 213 return IsStmtFunction(*function); 214 } 215 return false; 216 } 217 218 bool IsStmtFunctionDummy(const Symbol &symbol) { 219 return IsDummy(symbol) && IsInStmtFunction(symbol); 220 } 221 222 bool IsStmtFunctionResult(const Symbol &symbol) { 223 return IsFunctionResult(symbol) && IsInStmtFunction(symbol); 224 } 225 226 bool IsPointerDummy(const Symbol &symbol) { 227 return IsPointer(symbol) && IsDummy(symbol); 228 } 229 230 // variable-name 231 bool IsVariableName(const Symbol &symbol) { 232 if (const Symbol * root{GetAssociationRoot(symbol)}) { 233 return root->has<ObjectEntityDetails>() && !IsNamedConstant(*root); 234 } else { 235 return false; 236 } 237 } 238 239 // proc-name 240 bool IsProcName(const Symbol &symbol) { 241 return symbol.GetUltimate().has<ProcEntityDetails>(); 242 } 243 244 bool IsFunction(const Symbol &symbol) { 245 return std::visit( 246 common::visitors{ 247 [](const SubprogramDetails &x) { return x.isFunction(); }, 248 [&](const SubprogramNameDetails &) { 249 return symbol.test(Symbol::Flag::Function); 250 }, 251 [](const ProcEntityDetails &x) { 252 const auto &ifc{x.interface()}; 253 return ifc.type() || (ifc.symbol() && IsFunction(*ifc.symbol())); 254 }, 255 [](const ProcBindingDetails &x) { return IsFunction(x.symbol()); }, 256 [](const UseDetails &x) { return IsFunction(x.symbol()); }, 257 [](const auto &) { return false; }, 258 }, 259 symbol.details()); 260 } 261 262 bool IsPureProcedure(const Symbol &symbol) { 263 if (const auto *procDetails{symbol.detailsIf<ProcEntityDetails>()}) { 264 if (const Symbol * procInterface{procDetails->interface().symbol()}) { 265 // procedure component with a pure interface 266 return IsPureProcedure(*procInterface); 267 } 268 } else if (const auto *details{symbol.detailsIf<ProcBindingDetails>()}) { 269 return IsPureProcedure(details->symbol()); 270 } else if (!IsProcedure(symbol)) { 271 return false; 272 } 273 if (IsStmtFunction(symbol)) { 274 // Section 15.7(1) states that a statement function is PURE if it does not 275 // reference an IMPURE procedure or a VOLATILE variable 276 const MaybeExpr &expr{symbol.get<SubprogramDetails>().stmtFunction()}; 277 if (expr) { 278 for (const Symbol &refSymbol : evaluate::CollectSymbols(*expr)) { 279 if (IsFunction(refSymbol) && !IsPureProcedure(refSymbol)) { 280 return false; 281 } 282 if (const Symbol * root{GetAssociationRoot(refSymbol)}) { 283 if (root->attrs().test(Attr::VOLATILE)) { 284 return false; 285 } 286 } 287 } 288 } 289 return true; // statement function was not found to be impure 290 } 291 return symbol.attrs().test(Attr::PURE) || 292 (symbol.attrs().test(Attr::ELEMENTAL) && 293 !symbol.attrs().test(Attr::IMPURE)); 294 } 295 296 bool IsPureProcedure(const Scope &scope) { 297 if (const Symbol * symbol{scope.GetSymbol()}) { 298 return IsPureProcedure(*symbol); 299 } else { 300 return false; 301 } 302 } 303 304 bool IsBindCProcedure(const Symbol &symbol) { 305 if (const auto *procDetails{symbol.detailsIf<ProcEntityDetails>()}) { 306 if (const Symbol * procInterface{procDetails->interface().symbol()}) { 307 // procedure component with a BIND(C) interface 308 return IsBindCProcedure(*procInterface); 309 } 310 } 311 return symbol.attrs().test(Attr::BIND_C) && IsProcedure(symbol); 312 } 313 314 bool IsBindCProcedure(const Scope &scope) { 315 if (const Symbol * symbol{scope.GetSymbol()}) { 316 return IsBindCProcedure(*symbol); 317 } else { 318 return false; 319 } 320 } 321 322 bool IsProcedure(const Symbol &symbol) { 323 return std::visit( 324 common::visitors{ 325 [](const SubprogramDetails &) { return true; }, 326 [](const SubprogramNameDetails &) { return true; }, 327 [](const ProcEntityDetails &) { return true; }, 328 [](const GenericDetails &) { return true; }, 329 [](const ProcBindingDetails &) { return true; }, 330 [](const UseDetails &x) { return IsProcedure(x.symbol()); }, 331 // TODO: FinalProcDetails? 332 [](const auto &) { return false; }, 333 }, 334 symbol.details()); 335 } 336 337 bool IsProcedurePointer(const Symbol &symbol) { 338 return symbol.has<ProcEntityDetails>() && IsPointer(symbol); 339 } 340 341 static const Symbol *FindPointerComponent( 342 const Scope &scope, std::set<const Scope *> &visited) { 343 if (!scope.IsDerivedType()) { 344 return nullptr; 345 } 346 if (!visited.insert(&scope).second) { 347 return nullptr; 348 } 349 // If there's a top-level pointer component, return it for clearer error 350 // messaging. 351 for (const auto &pair : scope) { 352 const Symbol &symbol{*pair.second}; 353 if (IsPointer(symbol)) { 354 return &symbol; 355 } 356 } 357 for (const auto &pair : scope) { 358 const Symbol &symbol{*pair.second}; 359 if (const auto *details{symbol.detailsIf<ObjectEntityDetails>()}) { 360 if (const DeclTypeSpec * type{details->type()}) { 361 if (const DerivedTypeSpec * derived{type->AsDerived()}) { 362 if (const Scope * nested{derived->scope()}) { 363 if (const Symbol * 364 pointer{FindPointerComponent(*nested, visited)}) { 365 return pointer; 366 } 367 } 368 } 369 } 370 } 371 } 372 return nullptr; 373 } 374 375 const Symbol *FindPointerComponent(const Scope &scope) { 376 std::set<const Scope *> visited; 377 return FindPointerComponent(scope, visited); 378 } 379 380 const Symbol *FindPointerComponent(const DerivedTypeSpec &derived) { 381 if (const Scope * scope{derived.scope()}) { 382 return FindPointerComponent(*scope); 383 } else { 384 return nullptr; 385 } 386 } 387 388 const Symbol *FindPointerComponent(const DeclTypeSpec &type) { 389 if (const DerivedTypeSpec * derived{type.AsDerived()}) { 390 return FindPointerComponent(*derived); 391 } else { 392 return nullptr; 393 } 394 } 395 396 const Symbol *FindPointerComponent(const DeclTypeSpec *type) { 397 return type ? FindPointerComponent(*type) : nullptr; 398 } 399 400 const Symbol *FindPointerComponent(const Symbol &symbol) { 401 return IsPointer(symbol) ? &symbol : FindPointerComponent(symbol.GetType()); 402 } 403 404 // C1594 specifies several ways by which an object might be globally visible. 405 const Symbol *FindExternallyVisibleObject( 406 const Symbol &object, const Scope &scope) { 407 // TODO: Storage association with any object for which this predicate holds, 408 // once EQUIVALENCE is supported. 409 if (IsUseAssociated(object, scope) || IsHostAssociated(object, scope) || 410 (IsPureProcedure(scope) && IsPointerDummy(object)) || 411 (IsIntentIn(object) && IsDummy(object))) { 412 return &object; 413 } else if (const Symbol * block{FindCommonBlockContaining(object)}) { 414 return block; 415 } else { 416 return nullptr; 417 } 418 } 419 420 bool ExprHasTypeCategory( 421 const SomeExpr &expr, const common::TypeCategory &type) { 422 auto dynamicType{expr.GetType()}; 423 return dynamicType && dynamicType->category() == type; 424 } 425 426 bool ExprTypeKindIsDefault( 427 const SomeExpr &expr, const SemanticsContext &context) { 428 auto dynamicType{expr.GetType()}; 429 return dynamicType && 430 dynamicType->category() != common::TypeCategory::Derived && 431 dynamicType->kind() == context.GetDefaultKind(dynamicType->category()); 432 } 433 434 // If an analyzed expr or assignment is missing, dump the node and die. 435 template <typename T> 436 static void CheckMissingAnalysis(bool absent, const T &x) { 437 if (absent) { 438 std::string buf; 439 llvm::raw_string_ostream ss{buf}; 440 ss << "node has not been analyzed:\n"; 441 parser::DumpTree(ss, x); 442 common::die(ss.str().c_str()); 443 } 444 } 445 446 const SomeExpr *GetExprHelper::Get(const parser::Expr &x) { 447 CheckMissingAnalysis(!x.typedExpr, x); 448 return common::GetPtrFromOptional(x.typedExpr->v); 449 } 450 const SomeExpr *GetExprHelper::Get(const parser::Variable &x) { 451 CheckMissingAnalysis(!x.typedExpr, x); 452 return common::GetPtrFromOptional(x.typedExpr->v); 453 } 454 455 const evaluate::Assignment *GetAssignment(const parser::AssignmentStmt &x) { 456 CheckMissingAnalysis(!x.typedAssignment, x); 457 return common::GetPtrFromOptional(x.typedAssignment->v); 458 } 459 const evaluate::Assignment *GetAssignment( 460 const parser::PointerAssignmentStmt &x) { 461 CheckMissingAnalysis(!x.typedAssignment, x); 462 return common::GetPtrFromOptional(x.typedAssignment->v); 463 } 464 465 const Symbol *FindInterface(const Symbol &symbol) { 466 return std::visit( 467 common::visitors{ 468 [](const ProcEntityDetails &details) { 469 return details.interface().symbol(); 470 }, 471 [](const ProcBindingDetails &details) { return &details.symbol(); }, 472 [](const auto &) -> const Symbol * { return nullptr; }, 473 }, 474 symbol.details()); 475 } 476 477 const Symbol *FindSubprogram(const Symbol &symbol) { 478 return std::visit( 479 common::visitors{ 480 [&](const ProcEntityDetails &details) -> const Symbol * { 481 if (const Symbol * interface{details.interface().symbol()}) { 482 return FindSubprogram(*interface); 483 } else { 484 return &symbol; 485 } 486 }, 487 [](const ProcBindingDetails &details) { 488 return FindSubprogram(details.symbol()); 489 }, 490 [&](const SubprogramDetails &) { return &symbol; }, 491 [](const UseDetails &details) { 492 return FindSubprogram(details.symbol()); 493 }, 494 [](const HostAssocDetails &details) { 495 return FindSubprogram(details.symbol()); 496 }, 497 [](const auto &) -> const Symbol * { return nullptr; }, 498 }, 499 symbol.details()); 500 } 501 502 const Symbol *FindFunctionResult(const Symbol &symbol) { 503 if (const Symbol * subp{FindSubprogram(symbol)}) { 504 if (const auto &subpDetails{subp->detailsIf<SubprogramDetails>()}) { 505 if (subpDetails->isFunction()) { 506 return &subpDetails->result(); 507 } 508 } 509 } 510 return nullptr; 511 } 512 513 const Symbol *FindOverriddenBinding(const Symbol &symbol) { 514 if (symbol.has<ProcBindingDetails>()) { 515 if (const DeclTypeSpec * parentType{FindParentTypeSpec(symbol.owner())}) { 516 if (const DerivedTypeSpec * parentDerived{parentType->AsDerived()}) { 517 if (const Scope * parentScope{parentDerived->typeSymbol().scope()}) { 518 return parentScope->FindComponent(symbol.name()); 519 } 520 } 521 } 522 } 523 return nullptr; 524 } 525 526 const DeclTypeSpec *FindParentTypeSpec(const DerivedTypeSpec &derived) { 527 return FindParentTypeSpec(derived.typeSymbol()); 528 } 529 530 const DeclTypeSpec *FindParentTypeSpec(const DeclTypeSpec &decl) { 531 if (const DerivedTypeSpec * derived{decl.AsDerived()}) { 532 return FindParentTypeSpec(*derived); 533 } else { 534 return nullptr; 535 } 536 } 537 538 const DeclTypeSpec *FindParentTypeSpec(const Scope &scope) { 539 if (scope.kind() == Scope::Kind::DerivedType) { 540 if (const auto *symbol{scope.symbol()}) { 541 return FindParentTypeSpec(*symbol); 542 } 543 } 544 return nullptr; 545 } 546 547 const DeclTypeSpec *FindParentTypeSpec(const Symbol &symbol) { 548 if (const Scope * scope{symbol.scope()}) { 549 if (const auto *details{symbol.detailsIf<DerivedTypeDetails>()}) { 550 if (const Symbol * parent{details->GetParentComponent(*scope)}) { 551 return parent->GetType(); 552 } 553 } 554 } 555 return nullptr; 556 } 557 558 // When a construct association maps to a variable, and that variable 559 // is not an array with a vector-valued subscript, return the base 560 // Symbol of that variable, else nullptr. Descends into other construct 561 // associations when one associations maps to another. 562 static const Symbol *GetAssociatedVariable(const AssocEntityDetails &details) { 563 if (const MaybeExpr & expr{details.expr()}) { 564 if (evaluate::IsVariable(*expr) && !evaluate::HasVectorSubscript(*expr)) { 565 if (const Symbol * varSymbol{evaluate::GetFirstSymbol(*expr)}) { 566 return GetAssociationRoot(*varSymbol); 567 } 568 } 569 } 570 return nullptr; 571 } 572 573 // Return the Symbol of the variable of a construct association, if it exists 574 // Return nullptr if the name is associated with an expression 575 const Symbol *GetAssociationRoot(const Symbol &symbol) { 576 const Symbol &ultimate{symbol.GetUltimate()}; 577 if (const auto *details{ultimate.detailsIf<AssocEntityDetails>()}) { 578 // We have a construct association 579 return GetAssociatedVariable(*details); 580 } else { 581 return &ultimate; 582 } 583 } 584 585 bool IsExtensibleType(const DerivedTypeSpec *derived) { 586 return derived && !IsIsoCType(derived) && 587 !derived->typeSymbol().attrs().test(Attr::BIND_C) && 588 !derived->typeSymbol().get<DerivedTypeDetails>().sequence(); 589 } 590 591 bool IsBuiltinDerivedType(const DerivedTypeSpec *derived, const char *name) { 592 if (!derived) { 593 return false; 594 } else { 595 const auto &symbol{derived->typeSymbol()}; 596 return symbol.owner().IsModule() && 597 symbol.owner().GetName().value() == "__fortran_builtins" && 598 symbol.name() == "__builtin_"s + name; 599 } 600 } 601 602 bool IsIsoCType(const DerivedTypeSpec *derived) { 603 return IsBuiltinDerivedType(derived, "c_ptr") || 604 IsBuiltinDerivedType(derived, "c_funptr"); 605 } 606 607 bool IsTeamType(const DerivedTypeSpec *derived) { 608 return IsBuiltinDerivedType(derived, "team_type"); 609 } 610 611 bool IsEventTypeOrLockType(const DerivedTypeSpec *derivedTypeSpec) { 612 return IsBuiltinDerivedType(derivedTypeSpec, "event_type") || 613 IsBuiltinDerivedType(derivedTypeSpec, "lock_type"); 614 } 615 616 bool IsOrContainsEventOrLockComponent(const Symbol &symbol) { 617 if (const Symbol * root{GetAssociationRoot(symbol)}) { 618 if (const auto *details{root->detailsIf<ObjectEntityDetails>()}) { 619 if (const DeclTypeSpec * type{details->type()}) { 620 if (const DerivedTypeSpec * derived{type->AsDerived()}) { 621 return IsEventTypeOrLockType(derived) || 622 FindEventOrLockPotentialComponent(*derived); 623 } 624 } 625 } 626 } 627 return false; 628 } 629 630 bool IsSaved(const Symbol &symbol) { 631 auto scopeKind{symbol.owner().kind()}; 632 if (scopeKind == Scope::Kind::Module || scopeKind == Scope::Kind::BlockData) { 633 return true; 634 } else if (scopeKind == Scope::Kind::DerivedType) { 635 return false; // this is a component 636 } else if (IsNamedConstant(symbol)) { 637 return false; 638 } else if (symbol.attrs().test(Attr::SAVE)) { 639 return true; 640 } else { 641 if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 642 if (object->init()) { 643 return true; 644 } 645 } else if (IsProcedurePointer(symbol)) { 646 if (symbol.get<ProcEntityDetails>().init()) { 647 return true; 648 } 649 } 650 if (const Symbol * block{FindCommonBlockContaining(symbol)}) { 651 if (block->attrs().test(Attr::SAVE)) { 652 return true; 653 } 654 } 655 return false; 656 } 657 } 658 659 // Check this symbol suitable as a type-bound procedure - C769 660 bool CanBeTypeBoundProc(const Symbol *symbol) { 661 if (!symbol || IsDummy(*symbol) || IsProcedurePointer(*symbol)) { 662 return false; 663 } else if (symbol->has<SubprogramNameDetails>()) { 664 return symbol->owner().kind() == Scope::Kind::Module; 665 } else if (auto *details{symbol->detailsIf<SubprogramDetails>()}) { 666 return symbol->owner().kind() == Scope::Kind::Module || 667 details->isInterface(); 668 } else if (const auto *proc{symbol->detailsIf<ProcEntityDetails>()}) { 669 return !symbol->attrs().test(Attr::INTRINSIC) && 670 proc->HasExplicitInterface(); 671 } else { 672 return false; 673 } 674 } 675 676 bool IsInitialized(const Symbol &symbol) { 677 if (symbol.test(Symbol::Flag::InDataStmt)) { 678 return true; 679 } else if (IsNamedConstant(symbol)) { 680 return false; 681 } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 682 if (IsAllocatable(symbol) || object->init()) { 683 return true; 684 } 685 if (!IsPointer(symbol) && object->type()) { 686 if (const auto *derived{object->type()->AsDerived()}) { 687 if (derived->HasDefaultInitialization()) { 688 return true; 689 } 690 } 691 } 692 } else if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) { 693 return proc->init().has_value(); 694 } 695 return false; 696 } 697 698 bool HasIntrinsicTypeName(const Symbol &symbol) { 699 std::string name{symbol.name().ToString()}; 700 if (name == "doubleprecision") { 701 return true; 702 } else if (name == "derived") { 703 return false; 704 } else { 705 for (int i{0}; i != common::TypeCategory_enumSize; ++i) { 706 if (name == parser::ToLowerCaseLetters(EnumToString(TypeCategory{i}))) { 707 return true; 708 } 709 } 710 return false; 711 } 712 } 713 714 bool IsSeparateModuleProcedureInterface(const Symbol *symbol) { 715 if (symbol && symbol->attrs().test(Attr::MODULE)) { 716 if (auto *details{symbol->detailsIf<SubprogramDetails>()}) { 717 return details->isInterface(); 718 } 719 } 720 return false; 721 } 722 723 bool IsFinalizable(const Symbol &symbol) { 724 if (const DeclTypeSpec * type{symbol.GetType()}) { 725 if (const DerivedTypeSpec * derived{type->AsDerived()}) { 726 return IsFinalizable(*derived); 727 } 728 } 729 return false; 730 } 731 732 bool IsFinalizable(const DerivedTypeSpec &derived) { 733 ScopeComponentIterator components{derived}; 734 return std::find_if(components.begin(), components.end(), 735 [](const Symbol &x) { return x.has<FinalProcDetails>(); }) != 736 components.end(); 737 } 738 739 // TODO The following function returns true for all types with FINAL procedures 740 // This is because we don't yet fill in the data for FinalProcDetails 741 bool HasImpureFinal(const DerivedTypeSpec &derived) { 742 ScopeComponentIterator components{derived}; 743 return std::find_if( 744 components.begin(), components.end(), [](const Symbol &x) { 745 return x.has<FinalProcDetails>() && !x.attrs().test(Attr::PURE); 746 }) != components.end(); 747 } 748 749 bool IsCoarray(const Symbol &symbol) { return symbol.Corank() > 0; } 750 751 bool IsAssumedLengthCharacter(const Symbol &symbol) { 752 if (const DeclTypeSpec * type{symbol.GetType()}) { 753 return type->category() == DeclTypeSpec::Character && 754 type->characterTypeSpec().length().isAssumed(); 755 } else { 756 return false; 757 } 758 } 759 760 // C722 and C723: For a function to be assumed length, it must be external and 761 // of CHARACTER type 762 bool IsExternal(const Symbol &symbol) { 763 return (symbol.has<SubprogramDetails>() && symbol.owner().IsGlobal()) || 764 symbol.attrs().test(Attr::EXTERNAL); 765 } 766 767 const Symbol *IsExternalInPureContext( 768 const Symbol &symbol, const Scope &scope) { 769 if (const auto *pureProc{FindPureProcedureContaining(scope)}) { 770 if (const Symbol * root{GetAssociationRoot(symbol)}) { 771 if (const Symbol * 772 visible{FindExternallyVisibleObject(*root, *pureProc)}) { 773 return visible; 774 } 775 } 776 } 777 return nullptr; 778 } 779 780 PotentialComponentIterator::const_iterator FindPolymorphicPotentialComponent( 781 const DerivedTypeSpec &derived) { 782 PotentialComponentIterator potentials{derived}; 783 return std::find_if( 784 potentials.begin(), potentials.end(), [](const Symbol &component) { 785 if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) { 786 const DeclTypeSpec *type{details->type()}; 787 return type && type->IsPolymorphic(); 788 } 789 return false; 790 }); 791 } 792 793 bool IsOrContainsPolymorphicComponent(const Symbol &symbol) { 794 if (const Symbol * root{GetAssociationRoot(symbol)}) { 795 if (const auto *details{root->detailsIf<ObjectEntityDetails>()}) { 796 if (const DeclTypeSpec * type{details->type()}) { 797 if (type->IsPolymorphic()) { 798 return true; 799 } 800 if (const DerivedTypeSpec * derived{type->AsDerived()}) { 801 return (bool)FindPolymorphicPotentialComponent(*derived); 802 } 803 } 804 } 805 } 806 return false; 807 } 808 809 bool InProtectedContext(const Symbol &symbol, const Scope ¤tScope) { 810 return IsProtected(symbol) && !IsHostAssociated(symbol, currentScope); 811 } 812 813 // C1101 and C1158 814 // TODO Need to check for a coindexed object (why? C1103?) 815 std::optional<parser::MessageFixedText> WhyNotModifiable( 816 const Symbol &symbol, const Scope &scope) { 817 const Symbol *root{GetAssociationRoot(symbol)}; 818 if (!root) { 819 return "'%s' is construct associated with an expression"_en_US; 820 } else if (InProtectedContext(*root, scope)) { 821 return "'%s' is protected in this scope"_en_US; 822 } else if (IsExternalInPureContext(*root, scope)) { 823 return "'%s' is externally visible and referenced in a pure" 824 " procedure"_en_US; 825 } else if (IsOrContainsEventOrLockComponent(*root)) { 826 return "'%s' is an entity with either an EVENT_TYPE or LOCK_TYPE"_en_US; 827 } else if (IsIntentIn(*root)) { 828 return "'%s' is an INTENT(IN) dummy argument"_en_US; 829 } else if (!IsVariableName(*root)) { 830 return "'%s' is not a variable"_en_US; 831 } else { 832 return std::nullopt; 833 } 834 } 835 836 std::optional<parser::Message> WhyNotModifiable(parser::CharBlock at, 837 const SomeExpr &expr, const Scope &scope, bool vectorSubscriptIsOk) { 838 if (!evaluate::IsVariable(expr)) { 839 return parser::Message{at, "Expression is not a variable"_en_US}; 840 } else if (auto dataRef{evaluate::ExtractDataRef(expr, true)}) { 841 if (!vectorSubscriptIsOk && evaluate::HasVectorSubscript(expr)) { 842 return parser::Message{at, "Variable has a vector subscript"_en_US}; 843 } 844 const Symbol &symbol{dataRef->GetFirstSymbol()}; 845 if (auto maybeWhy{WhyNotModifiable(symbol, scope)}) { 846 return parser::Message{symbol.name(), 847 parser::MessageFormattedText{std::move(*maybeWhy), symbol.name()}}; 848 } 849 } else { 850 // reference to function returning POINTER 851 } 852 return std::nullopt; 853 } 854 855 class ImageControlStmtHelper { 856 using ImageControlStmts = std::variant<parser::ChangeTeamConstruct, 857 parser::CriticalConstruct, parser::EventPostStmt, parser::EventWaitStmt, 858 parser::FormTeamStmt, parser::LockStmt, parser::StopStmt, 859 parser::SyncAllStmt, parser::SyncImagesStmt, parser::SyncMemoryStmt, 860 parser::SyncTeamStmt, parser::UnlockStmt>; 861 862 public: 863 template <typename T> bool operator()(const T &) { 864 return common::HasMember<T, ImageControlStmts>; 865 } 866 template <typename T> bool operator()(const common::Indirection<T> &x) { 867 return (*this)(x.value()); 868 } 869 bool operator()(const parser::AllocateStmt &stmt) { 870 const auto &allocationList{std::get<std::list<parser::Allocation>>(stmt.t)}; 871 for (const auto &allocation : allocationList) { 872 const auto &allocateObject{ 873 std::get<parser::AllocateObject>(allocation.t)}; 874 if (IsCoarrayObject(allocateObject)) { 875 return true; 876 } 877 } 878 return false; 879 } 880 bool operator()(const parser::DeallocateStmt &stmt) { 881 const auto &allocateObjectList{ 882 std::get<std::list<parser::AllocateObject>>(stmt.t)}; 883 for (const auto &allocateObject : allocateObjectList) { 884 if (IsCoarrayObject(allocateObject)) { 885 return true; 886 } 887 } 888 return false; 889 } 890 bool operator()(const parser::CallStmt &stmt) { 891 const auto &procedureDesignator{ 892 std::get<parser::ProcedureDesignator>(stmt.v.t)}; 893 if (auto *name{std::get_if<parser::Name>(&procedureDesignator.u)}) { 894 // TODO: also ensure that the procedure is, in fact, an intrinsic 895 if (name->source == "move_alloc") { 896 const auto &args{std::get<std::list<parser::ActualArgSpec>>(stmt.v.t)}; 897 if (!args.empty()) { 898 const parser::ActualArg &actualArg{ 899 std::get<parser::ActualArg>(args.front().t)}; 900 if (const auto *argExpr{ 901 std::get_if<common::Indirection<parser::Expr>>( 902 &actualArg.u)}) { 903 return HasCoarray(argExpr->value()); 904 } 905 } 906 } 907 } 908 return false; 909 } 910 bool operator()(const parser::Statement<parser::ActionStmt> &stmt) { 911 return std::visit(*this, stmt.statement.u); 912 } 913 914 private: 915 bool IsCoarrayObject(const parser::AllocateObject &allocateObject) { 916 const parser::Name &name{GetLastName(allocateObject)}; 917 return name.symbol && IsCoarray(*name.symbol); 918 } 919 }; 920 921 bool IsImageControlStmt(const parser::ExecutableConstruct &construct) { 922 return std::visit(ImageControlStmtHelper{}, construct.u); 923 } 924 925 std::optional<parser::MessageFixedText> GetImageControlStmtCoarrayMsg( 926 const parser::ExecutableConstruct &construct) { 927 if (const auto *actionStmt{ 928 std::get_if<parser::Statement<parser::ActionStmt>>(&construct.u)}) { 929 return std::visit( 930 common::visitors{ 931 [](const common::Indirection<parser::AllocateStmt> &) 932 -> std::optional<parser::MessageFixedText> { 933 return "ALLOCATE of a coarray is an image control" 934 " statement"_en_US; 935 }, 936 [](const common::Indirection<parser::DeallocateStmt> &) 937 -> std::optional<parser::MessageFixedText> { 938 return "DEALLOCATE of a coarray is an image control" 939 " statement"_en_US; 940 }, 941 [](const common::Indirection<parser::CallStmt> &) 942 -> std::optional<parser::MessageFixedText> { 943 return "MOVE_ALLOC of a coarray is an image control" 944 " statement "_en_US; 945 }, 946 [](const auto &) -> std::optional<parser::MessageFixedText> { 947 return std::nullopt; 948 }, 949 }, 950 actionStmt->statement.u); 951 } 952 return std::nullopt; 953 } 954 955 parser::CharBlock GetImageControlStmtLocation( 956 const parser::ExecutableConstruct &executableConstruct) { 957 return std::visit( 958 common::visitors{ 959 [](const common::Indirection<parser::ChangeTeamConstruct> 960 &construct) { 961 return std::get<parser::Statement<parser::ChangeTeamStmt>>( 962 construct.value().t) 963 .source; 964 }, 965 [](const common::Indirection<parser::CriticalConstruct> &construct) { 966 return std::get<parser::Statement<parser::CriticalStmt>>( 967 construct.value().t) 968 .source; 969 }, 970 [](const parser::Statement<parser::ActionStmt> &actionStmt) { 971 return actionStmt.source; 972 }, 973 [](const auto &) { return parser::CharBlock{}; }, 974 }, 975 executableConstruct.u); 976 } 977 978 bool HasCoarray(const parser::Expr &expression) { 979 if (const auto *expr{GetExpr(expression)}) { 980 for (const Symbol &symbol : evaluate::CollectSymbols(*expr)) { 981 if (const Symbol * root{GetAssociationRoot(symbol)}) { 982 if (IsCoarray(*root)) { 983 return true; 984 } 985 } 986 } 987 } 988 return false; 989 } 990 991 bool IsPolymorphic(const Symbol &symbol) { 992 if (const DeclTypeSpec * type{symbol.GetType()}) { 993 return type->IsPolymorphic(); 994 } 995 return false; 996 } 997 998 bool IsPolymorphicAllocatable(const Symbol &symbol) { 999 return IsAllocatable(symbol) && IsPolymorphic(symbol); 1000 } 1001 1002 std::optional<parser::MessageFormattedText> CheckAccessibleComponent( 1003 const Scope &scope, const Symbol &symbol) { 1004 CHECK(symbol.owner().IsDerivedType()); // symbol must be a component 1005 if (symbol.attrs().test(Attr::PRIVATE)) { 1006 if (const Scope * moduleScope{FindModuleContaining(symbol.owner())}) { 1007 if (!moduleScope->Contains(scope)) { 1008 return parser::MessageFormattedText{ 1009 "PRIVATE component '%s' is only accessible within module '%s'"_err_en_US, 1010 symbol.name(), moduleScope->GetName().value()}; 1011 } 1012 } 1013 } 1014 return std::nullopt; 1015 } 1016 1017 std::list<SourceName> OrderParameterNames(const Symbol &typeSymbol) { 1018 std::list<SourceName> result; 1019 if (const DerivedTypeSpec * spec{typeSymbol.GetParentTypeSpec()}) { 1020 result = OrderParameterNames(spec->typeSymbol()); 1021 } 1022 const auto ¶mNames{typeSymbol.get<DerivedTypeDetails>().paramNames()}; 1023 result.insert(result.end(), paramNames.begin(), paramNames.end()); 1024 return result; 1025 } 1026 1027 SymbolVector OrderParameterDeclarations(const Symbol &typeSymbol) { 1028 SymbolVector result; 1029 if (const DerivedTypeSpec * spec{typeSymbol.GetParentTypeSpec()}) { 1030 result = OrderParameterDeclarations(spec->typeSymbol()); 1031 } 1032 const auto ¶mDecls{typeSymbol.get<DerivedTypeDetails>().paramDecls()}; 1033 result.insert(result.end(), paramDecls.begin(), paramDecls.end()); 1034 return result; 1035 } 1036 1037 const DeclTypeSpec &FindOrInstantiateDerivedType(Scope &scope, 1038 DerivedTypeSpec &&spec, SemanticsContext &semanticsContext, 1039 DeclTypeSpec::Category category) { 1040 spec.CookParameters(semanticsContext.foldingContext()); 1041 spec.EvaluateParameters(semanticsContext.foldingContext()); 1042 if (const DeclTypeSpec * 1043 type{scope.FindInstantiatedDerivedType(spec, category)}) { 1044 return *type; 1045 } 1046 // Create a new instantiation of this parameterized derived type 1047 // for this particular distinct set of actual parameter values. 1048 DeclTypeSpec &type{scope.MakeDerivedType(category, std::move(spec))}; 1049 type.derivedTypeSpec().Instantiate(scope, semanticsContext); 1050 return type; 1051 } 1052 1053 const Symbol *FindSeparateModuleSubprogramInterface(const Symbol *proc) { 1054 if (proc) { 1055 if (const Symbol * submodule{proc->owner().symbol()}) { 1056 if (const auto *details{submodule->detailsIf<ModuleDetails>()}) { 1057 if (const Scope * ancestor{details->ancestor()}) { 1058 const Symbol *iface{ancestor->FindSymbol(proc->name())}; 1059 if (IsSeparateModuleProcedureInterface(iface)) { 1060 return iface; 1061 } 1062 } 1063 } 1064 } 1065 } 1066 return nullptr; 1067 } 1068 1069 // ComponentIterator implementation 1070 1071 template <ComponentKind componentKind> 1072 typename ComponentIterator<componentKind>::const_iterator 1073 ComponentIterator<componentKind>::const_iterator::Create( 1074 const DerivedTypeSpec &derived) { 1075 const_iterator it{}; 1076 it.componentPath_.emplace_back(derived); 1077 it.Increment(); // cue up first relevant component, if any 1078 return it; 1079 } 1080 1081 template <ComponentKind componentKind> 1082 const DerivedTypeSpec * 1083 ComponentIterator<componentKind>::const_iterator::PlanComponentTraversal( 1084 const Symbol &component) const { 1085 if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) { 1086 if (const DeclTypeSpec * type{details->type()}) { 1087 if (const auto *derived{type->AsDerived()}) { 1088 bool traverse{false}; 1089 if constexpr (componentKind == ComponentKind::Ordered) { 1090 // Order Component (only visit parents) 1091 traverse = component.test(Symbol::Flag::ParentComp); 1092 } else if constexpr (componentKind == ComponentKind::Direct) { 1093 traverse = !IsAllocatableOrPointer(component); 1094 } else if constexpr (componentKind == ComponentKind::Ultimate) { 1095 traverse = !IsAllocatableOrPointer(component); 1096 } else if constexpr (componentKind == ComponentKind::Potential) { 1097 traverse = !IsPointer(component); 1098 } else if constexpr (componentKind == ComponentKind::Scope) { 1099 traverse = !IsAllocatableOrPointer(component); 1100 } 1101 if (traverse) { 1102 const Symbol &newTypeSymbol{derived->typeSymbol()}; 1103 // Avoid infinite loop if the type is already part of the types 1104 // being visited. It is possible to have "loops in type" because 1105 // C744 does not forbid to use not yet declared type for 1106 // ALLOCATABLE or POINTER components. 1107 for (const auto &node : componentPath_) { 1108 if (&newTypeSymbol == &node.GetTypeSymbol()) { 1109 return nullptr; 1110 } 1111 } 1112 return derived; 1113 } 1114 } 1115 } // intrinsic & unlimited polymorphic not traversable 1116 } 1117 return nullptr; 1118 } 1119 1120 template <ComponentKind componentKind> 1121 static bool StopAtComponentPre(const Symbol &component) { 1122 if constexpr (componentKind == ComponentKind::Ordered) { 1123 // Parent components need to be iterated upon after their 1124 // sub-components in structure constructor analysis. 1125 return !component.test(Symbol::Flag::ParentComp); 1126 } else if constexpr (componentKind == ComponentKind::Direct) { 1127 return true; 1128 } else if constexpr (componentKind == ComponentKind::Ultimate) { 1129 return component.has<ProcEntityDetails>() || 1130 IsAllocatableOrPointer(component) || 1131 (component.get<ObjectEntityDetails>().type() && 1132 component.get<ObjectEntityDetails>().type()->AsIntrinsic()); 1133 } else if constexpr (componentKind == ComponentKind::Potential) { 1134 return !IsPointer(component); 1135 } 1136 } 1137 1138 template <ComponentKind componentKind> 1139 static bool StopAtComponentPost(const Symbol &component) { 1140 return componentKind == ComponentKind::Ordered && 1141 component.test(Symbol::Flag::ParentComp); 1142 } 1143 1144 template <ComponentKind componentKind> 1145 void ComponentIterator<componentKind>::const_iterator::Increment() { 1146 while (!componentPath_.empty()) { 1147 ComponentPathNode &deepest{componentPath_.back()}; 1148 if (deepest.component()) { 1149 if (!deepest.descended()) { 1150 deepest.set_descended(true); 1151 if (const DerivedTypeSpec * 1152 derived{PlanComponentTraversal(*deepest.component())}) { 1153 componentPath_.emplace_back(*derived); 1154 continue; 1155 } 1156 } else if (!deepest.visited()) { 1157 deepest.set_visited(true); 1158 return; // this is the next component to visit, after descending 1159 } 1160 } 1161 auto &nameIterator{deepest.nameIterator()}; 1162 if (nameIterator == deepest.nameEnd()) { 1163 componentPath_.pop_back(); 1164 } else if constexpr (componentKind == ComponentKind::Scope) { 1165 deepest.set_component(*nameIterator++->second); 1166 deepest.set_descended(false); 1167 deepest.set_visited(true); 1168 return; // this is the next component to visit, before descending 1169 } else { 1170 const Scope &scope{deepest.GetScope()}; 1171 auto scopeIter{scope.find(*nameIterator++)}; 1172 if (scopeIter != scope.cend()) { 1173 const Symbol &component{*scopeIter->second}; 1174 deepest.set_component(component); 1175 deepest.set_descended(false); 1176 if (StopAtComponentPre<componentKind>(component)) { 1177 deepest.set_visited(true); 1178 return; // this is the next component to visit, before descending 1179 } else { 1180 deepest.set_visited(!StopAtComponentPost<componentKind>(component)); 1181 } 1182 } 1183 } 1184 } 1185 } 1186 1187 template <ComponentKind componentKind> 1188 std::string 1189 ComponentIterator<componentKind>::const_iterator::BuildResultDesignatorName() 1190 const { 1191 std::string designator{""}; 1192 for (const auto &node : componentPath_) { 1193 designator += "%" + DEREF(node.component()).name().ToString(); 1194 } 1195 return designator; 1196 } 1197 1198 template class ComponentIterator<ComponentKind::Ordered>; 1199 template class ComponentIterator<ComponentKind::Direct>; 1200 template class ComponentIterator<ComponentKind::Ultimate>; 1201 template class ComponentIterator<ComponentKind::Potential>; 1202 template class ComponentIterator<ComponentKind::Scope>; 1203 1204 UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent( 1205 const DerivedTypeSpec &derived) { 1206 UltimateComponentIterator ultimates{derived}; 1207 return std::find_if(ultimates.begin(), ultimates.end(), IsCoarray); 1208 } 1209 1210 UltimateComponentIterator::const_iterator FindPointerUltimateComponent( 1211 const DerivedTypeSpec &derived) { 1212 UltimateComponentIterator ultimates{derived}; 1213 return std::find_if(ultimates.begin(), ultimates.end(), IsPointer); 1214 } 1215 1216 PotentialComponentIterator::const_iterator FindEventOrLockPotentialComponent( 1217 const DerivedTypeSpec &derived) { 1218 PotentialComponentIterator potentials{derived}; 1219 return std::find_if( 1220 potentials.begin(), potentials.end(), [](const Symbol &component) { 1221 if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) { 1222 const DeclTypeSpec *type{details->type()}; 1223 return type && IsEventTypeOrLockType(type->AsDerived()); 1224 } 1225 return false; 1226 }); 1227 } 1228 1229 UltimateComponentIterator::const_iterator FindAllocatableUltimateComponent( 1230 const DerivedTypeSpec &derived) { 1231 UltimateComponentIterator ultimates{derived}; 1232 return std::find_if(ultimates.begin(), ultimates.end(), IsAllocatable); 1233 } 1234 1235 UltimateComponentIterator::const_iterator 1236 FindPolymorphicAllocatableUltimateComponent(const DerivedTypeSpec &derived) { 1237 UltimateComponentIterator ultimates{derived}; 1238 return std::find_if( 1239 ultimates.begin(), ultimates.end(), IsPolymorphicAllocatable); 1240 } 1241 1242 UltimateComponentIterator::const_iterator 1243 FindPolymorphicAllocatableNonCoarrayUltimateComponent( 1244 const DerivedTypeSpec &derived) { 1245 UltimateComponentIterator ultimates{derived}; 1246 return std::find_if(ultimates.begin(), ultimates.end(), [](const Symbol &x) { 1247 return IsPolymorphicAllocatable(x) && !IsCoarray(x); 1248 }); 1249 } 1250 1251 const Symbol *FindUltimateComponent(const DerivedTypeSpec &derived, 1252 const std::function<bool(const Symbol &)> &predicate) { 1253 UltimateComponentIterator ultimates{derived}; 1254 if (auto it{std::find_if(ultimates.begin(), ultimates.end(), 1255 [&predicate](const Symbol &component) -> bool { 1256 return predicate(component); 1257 })}) { 1258 return &*it; 1259 } 1260 return nullptr; 1261 } 1262 1263 const Symbol *FindUltimateComponent(const Symbol &symbol, 1264 const std::function<bool(const Symbol &)> &predicate) { 1265 if (predicate(symbol)) { 1266 return &symbol; 1267 } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 1268 if (const auto *type{object->type()}) { 1269 if (const auto *derived{type->AsDerived()}) { 1270 return FindUltimateComponent(*derived, predicate); 1271 } 1272 } 1273 } 1274 return nullptr; 1275 } 1276 1277 const Symbol *FindImmediateComponent(const DerivedTypeSpec &type, 1278 const std::function<bool(const Symbol &)> &predicate) { 1279 if (const Scope * scope{type.scope()}) { 1280 const Symbol *parent{nullptr}; 1281 for (const auto &pair : *scope) { 1282 const Symbol *symbol{&*pair.second}; 1283 if (predicate(*symbol)) { 1284 return symbol; 1285 } 1286 if (symbol->test(Symbol::Flag::ParentComp)) { 1287 parent = symbol; 1288 } 1289 } 1290 if (parent) { 1291 if (const auto *object{parent->detailsIf<ObjectEntityDetails>()}) { 1292 if (const auto *type{object->type()}) { 1293 if (const auto *derived{type->AsDerived()}) { 1294 return FindImmediateComponent(*derived, predicate); 1295 } 1296 } 1297 } 1298 } 1299 } 1300 return nullptr; 1301 } 1302 1303 bool IsFunctionResult(const Symbol &symbol) { 1304 return (symbol.has<ObjectEntityDetails>() && 1305 symbol.get<ObjectEntityDetails>().isFuncResult()) || 1306 (symbol.has<ProcEntityDetails>() && 1307 symbol.get<ProcEntityDetails>().isFuncResult()); 1308 } 1309 1310 bool IsFunctionResultWithSameNameAsFunction(const Symbol &symbol) { 1311 if (IsFunctionResult(symbol)) { 1312 if (const Symbol * function{symbol.owner().symbol()}) { 1313 return symbol.name() == function->name(); 1314 } 1315 } 1316 return false; 1317 } 1318 1319 void LabelEnforce::Post(const parser::GotoStmt &gotoStmt) { 1320 checkLabelUse(gotoStmt.v); 1321 } 1322 void LabelEnforce::Post(const parser::ComputedGotoStmt &computedGotoStmt) { 1323 for (auto &i : std::get<std::list<parser::Label>>(computedGotoStmt.t)) { 1324 checkLabelUse(i); 1325 } 1326 } 1327 1328 void LabelEnforce::Post(const parser::ArithmeticIfStmt &arithmeticIfStmt) { 1329 checkLabelUse(std::get<1>(arithmeticIfStmt.t)); 1330 checkLabelUse(std::get<2>(arithmeticIfStmt.t)); 1331 checkLabelUse(std::get<3>(arithmeticIfStmt.t)); 1332 } 1333 1334 void LabelEnforce::Post(const parser::AssignStmt &assignStmt) { 1335 checkLabelUse(std::get<parser::Label>(assignStmt.t)); 1336 } 1337 1338 void LabelEnforce::Post(const parser::AssignedGotoStmt &assignedGotoStmt) { 1339 for (auto &i : std::get<std::list<parser::Label>>(assignedGotoStmt.t)) { 1340 checkLabelUse(i); 1341 } 1342 } 1343 1344 void LabelEnforce::Post(const parser::AltReturnSpec &altReturnSpec) { 1345 checkLabelUse(altReturnSpec.v); 1346 } 1347 1348 void LabelEnforce::Post(const parser::ErrLabel &errLabel) { 1349 checkLabelUse(errLabel.v); 1350 } 1351 void LabelEnforce::Post(const parser::EndLabel &endLabel) { 1352 checkLabelUse(endLabel.v); 1353 } 1354 void LabelEnforce::Post(const parser::EorLabel &eorLabel) { 1355 checkLabelUse(eorLabel.v); 1356 } 1357 1358 void LabelEnforce::checkLabelUse(const parser::Label &labelUsed) { 1359 if (labels_.find(labelUsed) == labels_.end()) { 1360 SayWithConstruct(context_, currentStatementSourcePosition_, 1361 parser::MessageFormattedText{ 1362 "Control flow escapes from %s"_err_en_US, construct_}, 1363 constructSourcePosition_); 1364 } 1365 } 1366 1367 parser::MessageFormattedText LabelEnforce::GetEnclosingConstructMsg() { 1368 return {"Enclosing %s statement"_en_US, construct_}; 1369 } 1370 1371 void LabelEnforce::SayWithConstruct(SemanticsContext &context, 1372 parser::CharBlock stmtLocation, parser::MessageFormattedText &&message, 1373 parser::CharBlock constructLocation) { 1374 context.Say(stmtLocation, message) 1375 .Attach(constructLocation, GetEnclosingConstructMsg()); 1376 } 1377 1378 } // namespace Fortran::semantics 1379