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