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->IsTopLevel()) { 35 return nullptr; 36 } 37 } 38 } 39 40 const Scope &GetTopLevelUnitContaining(const Scope &start) { 41 CHECK(!start.IsTopLevel()); 42 return DEREF(FindScopeContaining( 43 start, [](const Scope &scope) { return scope.parent().IsTopLevel(); })); 44 } 45 46 const Scope &GetTopLevelUnitContaining(const Symbol &symbol) { 47 return GetTopLevelUnitContaining(symbol.owner()); 48 } 49 50 const Scope *FindModuleContaining(const Scope &start) { 51 return FindScopeContaining( 52 start, [](const Scope &scope) { return scope.IsModule(); }); 53 } 54 55 const Scope *FindModuleFileContaining(const Scope &start) { 56 return FindScopeContaining( 57 start, [](const Scope &scope) { return scope.IsModuleFile(); }); 58 } 59 60 const Scope &GetProgramUnitContaining(const Scope &start) { 61 CHECK(!start.IsTopLevel()); 62 return DEREF(FindScopeContaining(start, [](const Scope &scope) { 63 switch (scope.kind()) { 64 case Scope::Kind::Module: 65 case Scope::Kind::MainProgram: 66 case Scope::Kind::Subprogram: 67 case Scope::Kind::BlockData: 68 return true; 69 default: 70 return false; 71 } 72 })); 73 } 74 75 const Scope &GetProgramUnitContaining(const Symbol &symbol) { 76 return GetProgramUnitContaining(symbol.owner()); 77 } 78 79 const Scope &GetProgramUnitOrBlockConstructContaining(const Scope &start) { 80 CHECK(!start.IsTopLevel()); 81 return DEREF(FindScopeContaining(start, [](const Scope &scope) { 82 switch (scope.kind()) { 83 case Scope::Kind::Module: 84 case Scope::Kind::MainProgram: 85 case Scope::Kind::Subprogram: 86 case Scope::Kind::BlockData: 87 case Scope::Kind::BlockConstruct: 88 return true; 89 default: 90 return false; 91 } 92 })); 93 } 94 95 const Scope &GetProgramUnitOrBlockConstructContaining(const Symbol &symbol) { 96 return GetProgramUnitOrBlockConstructContaining(symbol.owner()); 97 } 98 99 const Scope *FindPureProcedureContaining(const Scope &start) { 100 // N.B. We only need to examine the innermost containing program unit 101 // because an internal subprogram of a pure subprogram must also 102 // be pure (C1592). 103 if (start.IsTopLevel()) { 104 return nullptr; 105 } else { 106 const Scope &scope{GetProgramUnitContaining(start)}; 107 return IsPureProcedure(scope) ? &scope : nullptr; 108 } 109 } 110 111 const Scope *FindOpenACCConstructContaining(const Scope *scope) { 112 return scope ? FindScopeContaining(*scope, 113 [](const Scope &s) { 114 return s.kind() == Scope::Kind::OpenACCConstruct; 115 }) 116 : nullptr; 117 } 118 119 // 7.5.2.4 "same derived type" test -- rely on IsTkCompatibleWith() and its 120 // infrastructure to detect and handle comparisons on distinct (but "same") 121 // sequence/bind(C) derived types 122 static bool MightBeSameDerivedType( 123 const std::optional<evaluate::DynamicType> &lhsType, 124 const std::optional<evaluate::DynamicType> &rhsType) { 125 return lhsType && rhsType && lhsType->IsTkCompatibleWith(*rhsType); 126 } 127 128 Tristate IsDefinedAssignment( 129 const std::optional<evaluate::DynamicType> &lhsType, int lhsRank, 130 const std::optional<evaluate::DynamicType> &rhsType, int rhsRank) { 131 if (!lhsType || !rhsType) { 132 return Tristate::No; // error or rhs is untyped 133 } 134 if (lhsType->IsUnlimitedPolymorphic()) { 135 return Tristate::No; 136 } 137 if (rhsType->IsUnlimitedPolymorphic()) { 138 return Tristate::Maybe; 139 } 140 TypeCategory lhsCat{lhsType->category()}; 141 TypeCategory rhsCat{rhsType->category()}; 142 if (rhsRank > 0 && lhsRank != rhsRank) { 143 return Tristate::Yes; 144 } else if (lhsCat != TypeCategory::Derived) { 145 return ToTristate(lhsCat != rhsCat && 146 (!IsNumericTypeCategory(lhsCat) || !IsNumericTypeCategory(rhsCat))); 147 } else if (MightBeSameDerivedType(lhsType, rhsType)) { 148 return Tristate::Maybe; // TYPE(t) = TYPE(t) can be defined or intrinsic 149 } else { 150 return Tristate::Yes; 151 } 152 } 153 154 bool IsIntrinsicRelational(common::RelationalOperator opr, 155 const evaluate::DynamicType &type0, int rank0, 156 const evaluate::DynamicType &type1, int rank1) { 157 if (!evaluate::AreConformable(rank0, rank1)) { 158 return false; 159 } else { 160 auto cat0{type0.category()}; 161 auto cat1{type1.category()}; 162 if (IsNumericTypeCategory(cat0) && IsNumericTypeCategory(cat1)) { 163 // numeric types: EQ/NE always ok, others ok for non-complex 164 return opr == common::RelationalOperator::EQ || 165 opr == common::RelationalOperator::NE || 166 (cat0 != TypeCategory::Complex && cat1 != TypeCategory::Complex); 167 } else { 168 // not both numeric: only Character is ok 169 return cat0 == TypeCategory::Character && cat1 == TypeCategory::Character; 170 } 171 } 172 } 173 174 bool IsIntrinsicNumeric(const evaluate::DynamicType &type0) { 175 return IsNumericTypeCategory(type0.category()); 176 } 177 bool IsIntrinsicNumeric(const evaluate::DynamicType &type0, int rank0, 178 const evaluate::DynamicType &type1, int rank1) { 179 return evaluate::AreConformable(rank0, rank1) && 180 IsNumericTypeCategory(type0.category()) && 181 IsNumericTypeCategory(type1.category()); 182 } 183 184 bool IsIntrinsicLogical(const evaluate::DynamicType &type0) { 185 return type0.category() == TypeCategory::Logical; 186 } 187 bool IsIntrinsicLogical(const evaluate::DynamicType &type0, int rank0, 188 const evaluate::DynamicType &type1, int rank1) { 189 return evaluate::AreConformable(rank0, rank1) && 190 type0.category() == TypeCategory::Logical && 191 type1.category() == TypeCategory::Logical; 192 } 193 194 bool IsIntrinsicConcat(const evaluate::DynamicType &type0, int rank0, 195 const evaluate::DynamicType &type1, int rank1) { 196 return evaluate::AreConformable(rank0, rank1) && 197 type0.category() == TypeCategory::Character && 198 type1.category() == TypeCategory::Character && 199 type0.kind() == type1.kind(); 200 } 201 202 bool IsGenericDefinedOp(const Symbol &symbol) { 203 const Symbol &ultimate{symbol.GetUltimate()}; 204 if (const auto *generic{ultimate.detailsIf<GenericDetails>()}) { 205 return generic->kind().IsDefinedOperator(); 206 } else if (const auto *misc{ultimate.detailsIf<MiscDetails>()}) { 207 return misc->kind() == MiscDetails::Kind::TypeBoundDefinedOp; 208 } else { 209 return false; 210 } 211 } 212 213 bool IsDefinedOperator(SourceName name) { 214 const char *begin{name.begin()}; 215 const char *end{name.end()}; 216 return begin != end && begin[0] == '.' && end[-1] == '.'; 217 } 218 219 std::string MakeOpName(SourceName name) { 220 std::string result{name.ToString()}; 221 return IsDefinedOperator(name) ? "OPERATOR(" + result + ")" 222 : result.find("operator(", 0) == 0 ? parser::ToUpperCaseLetters(result) 223 : result; 224 } 225 226 bool IsCommonBlockContaining(const Symbol &block, const Symbol &object) { 227 const auto &objects{block.get<CommonBlockDetails>().objects()}; 228 return llvm::is_contained(objects, object); 229 } 230 231 bool IsUseAssociated(const Symbol &symbol, const Scope &scope) { 232 const Scope &owner{GetTopLevelUnitContaining(symbol.GetUltimate().owner())}; 233 return owner.kind() == Scope::Kind::Module && 234 owner != GetTopLevelUnitContaining(scope); 235 } 236 237 bool DoesScopeContain( 238 const Scope *maybeAncestor, const Scope &maybeDescendent) { 239 return maybeAncestor && !maybeDescendent.IsTopLevel() && 240 FindScopeContaining(maybeDescendent.parent(), 241 [&](const Scope &scope) { return &scope == maybeAncestor; }); 242 } 243 244 bool DoesScopeContain(const Scope *maybeAncestor, const Symbol &symbol) { 245 return DoesScopeContain(maybeAncestor, symbol.owner()); 246 } 247 248 static const Symbol &FollowHostAssoc(const Symbol &symbol) { 249 for (const Symbol *s{&symbol};;) { 250 const auto *details{s->detailsIf<HostAssocDetails>()}; 251 if (!details) { 252 return *s; 253 } 254 s = &details->symbol(); 255 } 256 } 257 258 bool IsHostAssociated(const Symbol &symbol, const Scope &scope) { 259 const Symbol &base{FollowHostAssoc(symbol)}; 260 return base.owner().IsTopLevel() || 261 DoesScopeContain(&GetProgramUnitOrBlockConstructContaining(base), 262 GetProgramUnitOrBlockConstructContaining(scope)); 263 } 264 265 bool IsHostAssociatedIntoSubprogram(const Symbol &symbol, const Scope &scope) { 266 const Symbol &base{FollowHostAssoc(symbol)}; 267 return base.owner().IsTopLevel() || 268 DoesScopeContain(&GetProgramUnitOrBlockConstructContaining(base), 269 GetProgramUnitContaining(scope)); 270 } 271 272 bool IsInStmtFunction(const Symbol &symbol) { 273 if (const Symbol * function{symbol.owner().symbol()}) { 274 return IsStmtFunction(*function); 275 } 276 return false; 277 } 278 279 bool IsStmtFunctionDummy(const Symbol &symbol) { 280 return IsDummy(symbol) && IsInStmtFunction(symbol); 281 } 282 283 bool IsStmtFunctionResult(const Symbol &symbol) { 284 return IsFunctionResult(symbol) && IsInStmtFunction(symbol); 285 } 286 287 bool IsPointerDummy(const Symbol &symbol) { 288 return IsPointer(symbol) && IsDummy(symbol); 289 } 290 291 bool IsBindCProcedure(const Symbol &original) { 292 const Symbol &symbol{original.GetUltimate()}; 293 if (const auto *procDetails{symbol.detailsIf<ProcEntityDetails>()}) { 294 if (procDetails->procInterface()) { 295 // procedure component with a BIND(C) interface 296 return IsBindCProcedure(*procDetails->procInterface()); 297 } 298 } 299 return symbol.attrs().test(Attr::BIND_C) && IsProcedure(symbol); 300 } 301 302 bool IsBindCProcedure(const Scope &scope) { 303 if (const Symbol * symbol{scope.GetSymbol()}) { 304 return IsBindCProcedure(*symbol); 305 } else { 306 return false; 307 } 308 } 309 310 static const Symbol *FindPointerComponent( 311 const Scope &scope, std::set<const Scope *> &visited) { 312 if (!scope.IsDerivedType()) { 313 return nullptr; 314 } 315 if (!visited.insert(&scope).second) { 316 return nullptr; 317 } 318 // If there's a top-level pointer component, return it for clearer error 319 // messaging. 320 for (const auto &pair : scope) { 321 const Symbol &symbol{*pair.second}; 322 if (IsPointer(symbol)) { 323 return &symbol; 324 } 325 } 326 for (const auto &pair : scope) { 327 const Symbol &symbol{*pair.second}; 328 if (const auto *details{symbol.detailsIf<ObjectEntityDetails>()}) { 329 if (const DeclTypeSpec * type{details->type()}) { 330 if (const DerivedTypeSpec * derived{type->AsDerived()}) { 331 if (const Scope * nested{derived->scope()}) { 332 if (const Symbol * 333 pointer{FindPointerComponent(*nested, visited)}) { 334 return pointer; 335 } 336 } 337 } 338 } 339 } 340 } 341 return nullptr; 342 } 343 344 const Symbol *FindPointerComponent(const Scope &scope) { 345 std::set<const Scope *> visited; 346 return FindPointerComponent(scope, visited); 347 } 348 349 const Symbol *FindPointerComponent(const DerivedTypeSpec &derived) { 350 if (const Scope * scope{derived.scope()}) { 351 return FindPointerComponent(*scope); 352 } else { 353 return nullptr; 354 } 355 } 356 357 const Symbol *FindPointerComponent(const DeclTypeSpec &type) { 358 if (const DerivedTypeSpec * derived{type.AsDerived()}) { 359 return FindPointerComponent(*derived); 360 } else { 361 return nullptr; 362 } 363 } 364 365 const Symbol *FindPointerComponent(const DeclTypeSpec *type) { 366 return type ? FindPointerComponent(*type) : nullptr; 367 } 368 369 const Symbol *FindPointerComponent(const Symbol &symbol) { 370 return IsPointer(symbol) ? &symbol : FindPointerComponent(symbol.GetType()); 371 } 372 373 // C1594 specifies several ways by which an object might be globally visible. 374 const Symbol *FindExternallyVisibleObject( 375 const Symbol &object, const Scope &scope, bool isPointerDefinition) { 376 // TODO: Storage association with any object for which this predicate holds, 377 // once EQUIVALENCE is supported. 378 const Symbol &ultimate{GetAssociationRoot(object)}; 379 if (IsDummy(ultimate)) { 380 if (IsIntentIn(ultimate)) { 381 return &ultimate; 382 } 383 if (!isPointerDefinition && IsPointer(ultimate) && 384 IsPureProcedure(ultimate.owner()) && IsFunction(ultimate.owner())) { 385 return &ultimate; 386 } 387 } else if (ultimate.owner().IsDerivedType()) { 388 return nullptr; 389 } else if (&GetProgramUnitContaining(ultimate) != 390 &GetProgramUnitContaining(scope)) { 391 return &object; 392 } else if (const Symbol * block{FindCommonBlockContaining(ultimate)}) { 393 return block; 394 } 395 return nullptr; 396 } 397 398 const Symbol &BypassGeneric(const Symbol &symbol) { 399 const Symbol &ultimate{symbol.GetUltimate()}; 400 if (const auto *generic{ultimate.detailsIf<GenericDetails>()}) { 401 if (const Symbol * specific{generic->specific()}) { 402 return *specific; 403 } 404 } 405 return symbol; 406 } 407 408 const Symbol &GetCrayPointer(const Symbol &crayPointee) { 409 const Symbol *found{nullptr}; 410 for (const auto &[pointee, pointer] : 411 crayPointee.GetUltimate().owner().crayPointers()) { 412 if (pointee == crayPointee.name()) { 413 found = &pointer.get(); 414 break; 415 } 416 } 417 return DEREF(found); 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( 437 bool crash, SemanticsContext *context, const T &x) { 438 if (crash && !(context && context->AnyFatalError())) { 439 std::string buf; 440 llvm::raw_string_ostream ss{buf}; 441 ss << "node has not been analyzed:\n"; 442 parser::DumpTree(ss, x); 443 common::die(buf.c_str()); 444 } 445 } 446 447 const SomeExpr *GetExprHelper::Get(const parser::Expr &x) { 448 CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x); 449 return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr; 450 } 451 const SomeExpr *GetExprHelper::Get(const parser::Variable &x) { 452 CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x); 453 return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr; 454 } 455 const SomeExpr *GetExprHelper::Get(const parser::DataStmtConstant &x) { 456 CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x); 457 return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr; 458 } 459 const SomeExpr *GetExprHelper::Get(const parser::AllocateObject &x) { 460 CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x); 461 return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr; 462 } 463 const SomeExpr *GetExprHelper::Get(const parser::PointerObject &x) { 464 CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x); 465 return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr; 466 } 467 468 const evaluate::Assignment *GetAssignment(const parser::AssignmentStmt &x) { 469 return x.typedAssignment ? common::GetPtrFromOptional(x.typedAssignment->v) 470 : nullptr; 471 } 472 const evaluate::Assignment *GetAssignment( 473 const parser::PointerAssignmentStmt &x) { 474 return x.typedAssignment ? common::GetPtrFromOptional(x.typedAssignment->v) 475 : nullptr; 476 } 477 478 const Symbol *FindInterface(const Symbol &symbol) { 479 return common::visit( 480 common::visitors{ 481 [](const ProcEntityDetails &details) { 482 const Symbol *interface{details.procInterface()}; 483 return interface ? FindInterface(*interface) : nullptr; 484 }, 485 [](const ProcBindingDetails &details) { 486 return FindInterface(details.symbol()); 487 }, 488 [&](const SubprogramDetails &) { return &symbol; }, 489 [](const UseDetails &details) { 490 return FindInterface(details.symbol()); 491 }, 492 [](const HostAssocDetails &details) { 493 return FindInterface(details.symbol()); 494 }, 495 [](const GenericDetails &details) { 496 return details.specific() ? FindInterface(*details.specific()) 497 : nullptr; 498 }, 499 [](const auto &) -> const Symbol * { return nullptr; }, 500 }, 501 symbol.details()); 502 } 503 504 const Symbol *FindSubprogram(const Symbol &symbol) { 505 return common::visit( 506 common::visitors{ 507 [&](const ProcEntityDetails &details) -> const Symbol * { 508 if (details.procInterface()) { 509 return FindSubprogram(*details.procInterface()); 510 } else { 511 return &symbol; 512 } 513 }, 514 [](const ProcBindingDetails &details) { 515 return FindSubprogram(details.symbol()); 516 }, 517 [&](const SubprogramDetails &) { return &symbol; }, 518 [](const UseDetails &details) { 519 return FindSubprogram(details.symbol()); 520 }, 521 [](const HostAssocDetails &details) { 522 return FindSubprogram(details.symbol()); 523 }, 524 [](const GenericDetails &details) { 525 return details.specific() ? FindSubprogram(*details.specific()) 526 : nullptr; 527 }, 528 [](const auto &) -> const Symbol * { return nullptr; }, 529 }, 530 symbol.details()); 531 } 532 533 const Symbol *FindOverriddenBinding( 534 const Symbol &symbol, bool &isInaccessibleDeferred) { 535 isInaccessibleDeferred = false; 536 if (symbol.has<ProcBindingDetails>()) { 537 if (const DeclTypeSpec * parentType{FindParentTypeSpec(symbol.owner())}) { 538 if (const DerivedTypeSpec * parentDerived{parentType->AsDerived()}) { 539 if (const Scope * parentScope{parentDerived->typeSymbol().scope()}) { 540 if (const Symbol * 541 overridden{parentScope->FindComponent(symbol.name())}) { 542 // 7.5.7.3 p1: only accessible bindings are overridden 543 if (!overridden->attrs().test(Attr::PRIVATE) || 544 FindModuleContaining(overridden->owner()) == 545 FindModuleContaining(symbol.owner())) { 546 return overridden; 547 } else if (overridden->attrs().test(Attr::DEFERRED)) { 548 isInaccessibleDeferred = true; 549 return overridden; 550 } 551 } 552 } 553 } 554 } 555 } 556 return nullptr; 557 } 558 559 const Symbol *FindGlobal(const Symbol &original) { 560 const Symbol &ultimate{original.GetUltimate()}; 561 if (ultimate.owner().IsGlobal()) { 562 return &ultimate; 563 } 564 bool isLocal{false}; 565 if (IsDummy(ultimate)) { 566 } else if (IsPointer(ultimate)) { 567 } else if (ultimate.has<ProcEntityDetails>()) { 568 isLocal = IsExternal(ultimate); 569 } else if (const auto *subp{ultimate.detailsIf<SubprogramDetails>()}) { 570 isLocal = subp->isInterface(); 571 } 572 if (isLocal) { 573 const std::string *bind{ultimate.GetBindName()}; 574 if (!bind || ultimate.name() == *bind) { 575 const Scope &globalScope{ultimate.owner().context().globalScope()}; 576 if (auto iter{globalScope.find(ultimate.name())}; 577 iter != globalScope.end()) { 578 const Symbol &global{*iter->second}; 579 const std::string *globalBind{global.GetBindName()}; 580 if (!globalBind || global.name() == *globalBind) { 581 return &global; 582 } 583 } 584 } 585 } 586 return nullptr; 587 } 588 589 const DeclTypeSpec *FindParentTypeSpec(const DerivedTypeSpec &derived) { 590 return FindParentTypeSpec(derived.typeSymbol()); 591 } 592 593 const DeclTypeSpec *FindParentTypeSpec(const DeclTypeSpec &decl) { 594 if (const DerivedTypeSpec * derived{decl.AsDerived()}) { 595 return FindParentTypeSpec(*derived); 596 } else { 597 return nullptr; 598 } 599 } 600 601 const DeclTypeSpec *FindParentTypeSpec(const Scope &scope) { 602 if (scope.kind() == Scope::Kind::DerivedType) { 603 if (const auto *symbol{scope.symbol()}) { 604 return FindParentTypeSpec(*symbol); 605 } 606 } 607 return nullptr; 608 } 609 610 const DeclTypeSpec *FindParentTypeSpec(const Symbol &symbol) { 611 if (const Scope * scope{symbol.scope()}) { 612 if (const auto *details{symbol.detailsIf<DerivedTypeDetails>()}) { 613 if (const Symbol * parent{details->GetParentComponent(*scope)}) { 614 return parent->GetType(); 615 } 616 } 617 } 618 return nullptr; 619 } 620 621 const EquivalenceSet *FindEquivalenceSet(const Symbol &symbol) { 622 const Symbol &ultimate{symbol.GetUltimate()}; 623 for (const EquivalenceSet &set : ultimate.owner().equivalenceSets()) { 624 for (const EquivalenceObject &object : set) { 625 if (object.symbol == ultimate) { 626 return &set; 627 } 628 } 629 } 630 return nullptr; 631 } 632 633 bool IsOrContainsEventOrLockComponent(const Symbol &original) { 634 const Symbol &symbol{ResolveAssociations(original)}; 635 if (const auto *details{symbol.detailsIf<ObjectEntityDetails>()}) { 636 if (const DeclTypeSpec * type{details->type()}) { 637 if (const DerivedTypeSpec * derived{type->AsDerived()}) { 638 return IsEventTypeOrLockType(derived) || 639 FindEventOrLockPotentialComponent(*derived); 640 } 641 } 642 } 643 return false; 644 } 645 646 // Check this symbol suitable as a type-bound procedure - C769 647 bool CanBeTypeBoundProc(const Symbol &symbol) { 648 if (IsDummy(symbol) || IsProcedurePointer(symbol)) { 649 return false; 650 } else if (symbol.has<SubprogramNameDetails>()) { 651 return symbol.owner().kind() == Scope::Kind::Module; 652 } else if (auto *details{symbol.detailsIf<SubprogramDetails>()}) { 653 if (details->isInterface()) { 654 return !symbol.attrs().test(Attr::ABSTRACT); 655 } else { 656 return symbol.owner().kind() == Scope::Kind::Module; 657 } 658 } else if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) { 659 return !symbol.attrs().test(Attr::INTRINSIC) && 660 proc->HasExplicitInterface(); 661 } else { 662 return false; 663 } 664 } 665 666 bool HasDeclarationInitializer(const Symbol &symbol) { 667 if (IsNamedConstant(symbol)) { 668 return false; 669 } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 670 return object->init().has_value(); 671 } else if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) { 672 return proc->init().has_value(); 673 } else { 674 return false; 675 } 676 } 677 678 bool IsInitialized(const Symbol &symbol, bool ignoreDataStatements, 679 bool ignoreAllocatable, bool ignorePointer) { 680 if (!ignoreAllocatable && IsAllocatable(symbol)) { 681 return true; 682 } else if (!ignoreDataStatements && symbol.test(Symbol::Flag::InDataStmt)) { 683 return true; 684 } else if (HasDeclarationInitializer(symbol)) { 685 return true; 686 } else if (IsPointer(symbol)) { 687 return !ignorePointer; 688 } else if (IsNamedConstant(symbol)) { 689 return false; 690 } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 691 if (!object->isDummy() && object->type()) { 692 if (const auto *derived{object->type()->AsDerived()}) { 693 return derived->HasDefaultInitialization( 694 ignoreAllocatable, ignorePointer); 695 } 696 } 697 } 698 return false; 699 } 700 701 bool IsDestructible(const Symbol &symbol, const Symbol *derivedTypeSymbol) { 702 if (IsAllocatable(symbol) || IsAutomatic(symbol)) { 703 return true; 704 } else if (IsNamedConstant(symbol) || IsFunctionResult(symbol) || 705 IsPointer(symbol)) { 706 return false; 707 } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 708 if (!object->isDummy() && object->type()) { 709 if (const auto *derived{object->type()->AsDerived()}) { 710 return &derived->typeSymbol() != derivedTypeSymbol && 711 derived->HasDestruction(); 712 } 713 } 714 } 715 return false; 716 } 717 718 bool HasIntrinsicTypeName(const Symbol &symbol) { 719 std::string name{symbol.name().ToString()}; 720 if (name == "doubleprecision") { 721 return true; 722 } else if (name == "derived") { 723 return false; 724 } else { 725 for (int i{0}; i != common::TypeCategory_enumSize; ++i) { 726 if (name == parser::ToLowerCaseLetters(EnumToString(TypeCategory{i}))) { 727 return true; 728 } 729 } 730 return false; 731 } 732 } 733 734 bool IsSeparateModuleProcedureInterface(const Symbol *symbol) { 735 if (symbol && symbol->attrs().test(Attr::MODULE)) { 736 if (auto *details{symbol->detailsIf<SubprogramDetails>()}) { 737 return details->isInterface(); 738 } 739 } 740 return false; 741 } 742 743 SymbolVector FinalsForDerivedTypeInstantiation(const DerivedTypeSpec &spec) { 744 SymbolVector result; 745 const Symbol &typeSymbol{spec.typeSymbol()}; 746 if (const auto *derived{typeSymbol.detailsIf<DerivedTypeDetails>()}) { 747 for (const auto &pair : derived->finals()) { 748 const Symbol &subr{*pair.second}; 749 // Errors in FINAL subroutines are caught in CheckFinal 750 // in check-declarations.cpp. 751 if (const auto *subprog{subr.detailsIf<SubprogramDetails>()}; 752 subprog && subprog->dummyArgs().size() == 1) { 753 if (const Symbol * arg{subprog->dummyArgs()[0]}) { 754 if (const DeclTypeSpec * type{arg->GetType()}) { 755 if (type->category() == DeclTypeSpec::TypeDerived && 756 evaluate::AreSameDerivedType(spec, type->derivedTypeSpec())) { 757 result.emplace_back(subr); 758 } 759 } 760 } 761 } 762 } 763 } 764 return result; 765 } 766 767 const Symbol *IsFinalizable(const Symbol &symbol, 768 std::set<const DerivedTypeSpec *> *inProgress, bool withImpureFinalizer) { 769 if (IsPointer(symbol) || evaluate::IsAssumedRank(symbol)) { 770 return nullptr; 771 } 772 if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 773 if (object->isDummy() && !IsIntentOut(symbol)) { 774 return nullptr; 775 } 776 const DeclTypeSpec *type{object->type()}; 777 if (const DerivedTypeSpec * typeSpec{type ? type->AsDerived() : nullptr}) { 778 return IsFinalizable( 779 *typeSpec, inProgress, withImpureFinalizer, symbol.Rank()); 780 } 781 } 782 return nullptr; 783 } 784 785 const Symbol *IsFinalizable(const DerivedTypeSpec &derived, 786 std::set<const DerivedTypeSpec *> *inProgress, bool withImpureFinalizer, 787 std::optional<int> rank) { 788 const Symbol *elemental{nullptr}; 789 for (auto ref : FinalsForDerivedTypeInstantiation(derived)) { 790 const Symbol *symbol{&ref->GetUltimate()}; 791 if (const auto *binding{symbol->detailsIf<ProcBindingDetails>()}) { 792 symbol = &binding->symbol(); 793 } 794 if (const auto *proc{symbol->detailsIf<ProcEntityDetails>()}) { 795 symbol = proc->procInterface(); 796 } 797 if (!symbol) { 798 } else if (IsElementalProcedure(*symbol)) { 799 elemental = symbol; 800 } else { 801 if (rank) { 802 if (const SubprogramDetails * 803 subp{symbol->detailsIf<SubprogramDetails>()}) { 804 if (const auto &args{subp->dummyArgs()}; !args.empty() && 805 args.at(0) && !evaluate::IsAssumedRank(*args.at(0)) && 806 args.at(0)->Rank() != *rank) { 807 continue; // not a finalizer for this rank 808 } 809 } 810 } 811 if (!withImpureFinalizer || !IsPureProcedure(*symbol)) { 812 return symbol; 813 } 814 // Found non-elemental pure finalizer of matching rank, but still 815 // need to check components for an impure finalizer. 816 elemental = nullptr; 817 break; 818 } 819 } 820 if (elemental && (!withImpureFinalizer || !IsPureProcedure(*elemental))) { 821 return elemental; 822 } 823 // Check components (including ancestors) 824 std::set<const DerivedTypeSpec *> basis; 825 if (inProgress) { 826 if (inProgress->find(&derived) != inProgress->end()) { 827 return nullptr; // don't loop on recursive type 828 } 829 } else { 830 inProgress = &basis; 831 } 832 auto iterator{inProgress->insert(&derived).first}; 833 const Symbol *result{nullptr}; 834 for (const Symbol &component : PotentialComponentIterator{derived}) { 835 result = IsFinalizable(component, inProgress, withImpureFinalizer); 836 if (result) { 837 break; 838 } 839 } 840 inProgress->erase(iterator); 841 return result; 842 } 843 844 static const Symbol *HasImpureFinal( 845 const DerivedTypeSpec &derived, std::optional<int> rank) { 846 return IsFinalizable(derived, nullptr, /*withImpureFinalizer=*/true, rank); 847 } 848 849 const Symbol *HasImpureFinal(const Symbol &original, std::optional<int> rank) { 850 const Symbol &symbol{ResolveAssociations(original)}; 851 if (symbol.has<ObjectEntityDetails>()) { 852 if (const DeclTypeSpec * symType{symbol.GetType()}) { 853 if (const DerivedTypeSpec * derived{symType->AsDerived()}) { 854 if (evaluate::IsAssumedRank(symbol)) { 855 // finalizable assumed-rank not allowed (C839) 856 return nullptr; 857 } else { 858 int actualRank{rank.value_or(symbol.Rank())}; 859 return HasImpureFinal(*derived, actualRank); 860 } 861 } 862 } 863 } 864 return nullptr; 865 } 866 867 bool MayRequireFinalization(const DerivedTypeSpec &derived) { 868 return IsFinalizable(derived) || 869 FindPolymorphicAllocatablePotentialComponent(derived); 870 } 871 872 bool HasAllocatableDirectComponent(const DerivedTypeSpec &derived) { 873 DirectComponentIterator directs{derived}; 874 return std::any_of(directs.begin(), directs.end(), IsAllocatable); 875 } 876 877 bool IsAssumedLengthCharacter(const Symbol &symbol) { 878 if (const DeclTypeSpec * type{symbol.GetType()}) { 879 return type->category() == DeclTypeSpec::Character && 880 type->characterTypeSpec().length().isAssumed(); 881 } else { 882 return false; 883 } 884 } 885 886 bool IsInBlankCommon(const Symbol &symbol) { 887 const Symbol *block{FindCommonBlockContaining(symbol)}; 888 return block && block->name().empty(); 889 } 890 891 // C722 and C723: For a function to be assumed length, it must be external and 892 // of CHARACTER type 893 bool IsExternal(const Symbol &symbol) { 894 return ClassifyProcedure(symbol) == ProcedureDefinitionClass::External; 895 } 896 897 // Most scopes have no EQUIVALENCE, and this function is a fast no-op for them. 898 std::list<std::list<SymbolRef>> GetStorageAssociations(const Scope &scope) { 899 UnorderedSymbolSet distinct; 900 for (const EquivalenceSet &set : scope.equivalenceSets()) { 901 for (const EquivalenceObject &object : set) { 902 distinct.emplace(object.symbol); 903 } 904 } 905 // This set is ordered by ascending offsets, with ties broken by greatest 906 // size. A multiset is used here because multiple symbols may have the 907 // same offset and size; the symbols in the set, however, are distinct. 908 std::multiset<SymbolRef, SymbolOffsetCompare> associated; 909 for (SymbolRef ref : distinct) { 910 associated.emplace(*ref); 911 } 912 std::list<std::list<SymbolRef>> result; 913 std::size_t limit{0}; 914 const Symbol *currentCommon{nullptr}; 915 for (const Symbol &symbol : associated) { 916 const Symbol *thisCommon{FindCommonBlockContaining(symbol)}; 917 if (result.empty() || symbol.offset() >= limit || 918 thisCommon != currentCommon) { 919 // Start a new group 920 result.emplace_back(std::list<SymbolRef>{}); 921 limit = 0; 922 currentCommon = thisCommon; 923 } 924 result.back().emplace_back(symbol); 925 limit = std::max(limit, symbol.offset() + symbol.size()); 926 } 927 return result; 928 } 929 930 bool IsModuleProcedure(const Symbol &symbol) { 931 return ClassifyProcedure(symbol) == ProcedureDefinitionClass::Module; 932 } 933 934 class ImageControlStmtHelper { 935 using ImageControlStmts = 936 std::variant<parser::ChangeTeamConstruct, parser::CriticalConstruct, 937 parser::EventPostStmt, parser::EventWaitStmt, parser::FormTeamStmt, 938 parser::LockStmt, parser::SyncAllStmt, parser::SyncImagesStmt, 939 parser::SyncMemoryStmt, parser::SyncTeamStmt, parser::UnlockStmt>; 940 941 public: 942 template <typename T> bool operator()(const T &) { 943 return common::HasMember<T, ImageControlStmts>; 944 } 945 template <typename T> bool operator()(const common::Indirection<T> &x) { 946 return (*this)(x.value()); 947 } 948 template <typename A> bool operator()(const parser::Statement<A> &x) { 949 return (*this)(x.statement); 950 } 951 bool operator()(const parser::AllocateStmt &stmt) { 952 const auto &allocationList{std::get<std::list<parser::Allocation>>(stmt.t)}; 953 for (const auto &allocation : allocationList) { 954 const auto &allocateObject{ 955 std::get<parser::AllocateObject>(allocation.t)}; 956 if (IsCoarrayObject(allocateObject)) { 957 return true; 958 } 959 } 960 return false; 961 } 962 bool operator()(const parser::DeallocateStmt &stmt) { 963 const auto &allocateObjectList{ 964 std::get<std::list<parser::AllocateObject>>(stmt.t)}; 965 for (const auto &allocateObject : allocateObjectList) { 966 if (IsCoarrayObject(allocateObject)) { 967 return true; 968 } 969 } 970 return false; 971 } 972 bool operator()(const parser::CallStmt &stmt) { 973 const auto &procedureDesignator{ 974 std::get<parser::ProcedureDesignator>(stmt.call.t)}; 975 if (auto *name{std::get_if<parser::Name>(&procedureDesignator.u)}) { 976 // TODO: also ensure that the procedure is, in fact, an intrinsic 977 if (name->source == "move_alloc") { 978 const auto &args{ 979 std::get<std::list<parser::ActualArgSpec>>(stmt.call.t)}; 980 if (!args.empty()) { 981 const parser::ActualArg &actualArg{ 982 std::get<parser::ActualArg>(args.front().t)}; 983 if (const auto *argExpr{ 984 std::get_if<common::Indirection<parser::Expr>>( 985 &actualArg.u)}) { 986 return HasCoarray(argExpr->value()); 987 } 988 } 989 } 990 } 991 return false; 992 } 993 bool operator()(const parser::StopStmt &stmt) { 994 // STOP is an image control statement; ERROR STOP is not 995 return std::get<parser::StopStmt::Kind>(stmt.t) == 996 parser::StopStmt::Kind::Stop; 997 } 998 bool operator()(const parser::IfStmt &stmt) { 999 return (*this)( 1000 std::get<parser::UnlabeledStatement<parser::ActionStmt>>(stmt.t) 1001 .statement); 1002 } 1003 bool operator()(const parser::ActionStmt &stmt) { 1004 return common::visit(*this, stmt.u); 1005 } 1006 1007 private: 1008 bool IsCoarrayObject(const parser::AllocateObject &allocateObject) { 1009 const parser::Name &name{GetLastName(allocateObject)}; 1010 return name.symbol && evaluate::IsCoarray(*name.symbol); 1011 } 1012 }; 1013 1014 bool IsImageControlStmt(const parser::ExecutableConstruct &construct) { 1015 return common::visit(ImageControlStmtHelper{}, construct.u); 1016 } 1017 1018 std::optional<parser::MessageFixedText> GetImageControlStmtCoarrayMsg( 1019 const parser::ExecutableConstruct &construct) { 1020 if (const auto *actionStmt{ 1021 std::get_if<parser::Statement<parser::ActionStmt>>(&construct.u)}) { 1022 return common::visit( 1023 common::visitors{ 1024 [](const common::Indirection<parser::AllocateStmt> &) 1025 -> std::optional<parser::MessageFixedText> { 1026 return "ALLOCATE of a coarray is an image control" 1027 " statement"_en_US; 1028 }, 1029 [](const common::Indirection<parser::DeallocateStmt> &) 1030 -> std::optional<parser::MessageFixedText> { 1031 return "DEALLOCATE of a coarray is an image control" 1032 " statement"_en_US; 1033 }, 1034 [](const common::Indirection<parser::CallStmt> &) 1035 -> std::optional<parser::MessageFixedText> { 1036 return "MOVE_ALLOC of a coarray is an image control" 1037 " statement "_en_US; 1038 }, 1039 [](const auto &) -> std::optional<parser::MessageFixedText> { 1040 return std::nullopt; 1041 }, 1042 }, 1043 actionStmt->statement.u); 1044 } 1045 return std::nullopt; 1046 } 1047 1048 parser::CharBlock GetImageControlStmtLocation( 1049 const parser::ExecutableConstruct &executableConstruct) { 1050 return common::visit( 1051 common::visitors{ 1052 [](const common::Indirection<parser::ChangeTeamConstruct> 1053 &construct) { 1054 return std::get<parser::Statement<parser::ChangeTeamStmt>>( 1055 construct.value().t) 1056 .source; 1057 }, 1058 [](const common::Indirection<parser::CriticalConstruct> &construct) { 1059 return std::get<parser::Statement<parser::CriticalStmt>>( 1060 construct.value().t) 1061 .source; 1062 }, 1063 [](const parser::Statement<parser::ActionStmt> &actionStmt) { 1064 return actionStmt.source; 1065 }, 1066 [](const auto &) { return parser::CharBlock{}; }, 1067 }, 1068 executableConstruct.u); 1069 } 1070 1071 bool HasCoarray(const parser::Expr &expression) { 1072 if (const auto *expr{GetExpr(nullptr, expression)}) { 1073 for (const Symbol &symbol : evaluate::CollectSymbols(*expr)) { 1074 if (evaluate::IsCoarray(symbol)) { 1075 return true; 1076 } 1077 } 1078 } 1079 return false; 1080 } 1081 1082 bool IsAssumedType(const Symbol &symbol) { 1083 if (const DeclTypeSpec * type{symbol.GetType()}) { 1084 return type->IsAssumedType(); 1085 } 1086 return false; 1087 } 1088 1089 bool IsPolymorphic(const Symbol &symbol) { 1090 if (const DeclTypeSpec * type{symbol.GetType()}) { 1091 return type->IsPolymorphic(); 1092 } 1093 return false; 1094 } 1095 1096 bool IsUnlimitedPolymorphic(const Symbol &symbol) { 1097 if (const DeclTypeSpec * type{symbol.GetType()}) { 1098 return type->IsUnlimitedPolymorphic(); 1099 } 1100 return false; 1101 } 1102 1103 bool IsPolymorphicAllocatable(const Symbol &symbol) { 1104 return IsAllocatable(symbol) && IsPolymorphic(symbol); 1105 } 1106 1107 const Scope *FindCUDADeviceContext(const Scope *scope) { 1108 return !scope ? nullptr : FindScopeContaining(*scope, [](const Scope &s) { 1109 return IsCUDADeviceContext(&s); 1110 }); 1111 } 1112 1113 std::optional<common::CUDADataAttr> GetCUDADataAttr(const Symbol *symbol) { 1114 const auto *object{ 1115 symbol ? symbol->detailsIf<ObjectEntityDetails>() : nullptr}; 1116 return object ? object->cudaDataAttr() : std::nullopt; 1117 } 1118 1119 std::optional<parser::MessageFormattedText> CheckAccessibleSymbol( 1120 const Scope &scope, const Symbol &symbol) { 1121 if (symbol.attrs().test(Attr::PRIVATE)) { 1122 if (FindModuleFileContaining(scope)) { 1123 // Don't enforce component accessibility checks in module files; 1124 // there may be forward-substituted named constants of derived type 1125 // whose structure constructors reference private components. 1126 } else if (const Scope * 1127 moduleScope{FindModuleContaining(symbol.owner())}) { 1128 if (!moduleScope->Contains(scope)) { 1129 return parser::MessageFormattedText{ 1130 "PRIVATE name '%s' is only accessible within module '%s'"_err_en_US, 1131 symbol.name(), moduleScope->GetName().value()}; 1132 } 1133 } 1134 } 1135 return std::nullopt; 1136 } 1137 1138 SymbolVector OrderParameterNames(const Symbol &typeSymbol) { 1139 SymbolVector result; 1140 if (const DerivedTypeSpec * spec{typeSymbol.GetParentTypeSpec()}) { 1141 result = OrderParameterNames(spec->typeSymbol()); 1142 } 1143 const auto ¶mNames{typeSymbol.get<DerivedTypeDetails>().paramNameOrder()}; 1144 result.insert(result.end(), paramNames.begin(), paramNames.end()); 1145 return result; 1146 } 1147 1148 SymbolVector OrderParameterDeclarations(const Symbol &typeSymbol) { 1149 SymbolVector result; 1150 if (const DerivedTypeSpec * spec{typeSymbol.GetParentTypeSpec()}) { 1151 result = OrderParameterDeclarations(spec->typeSymbol()); 1152 } 1153 const auto ¶mDecls{typeSymbol.get<DerivedTypeDetails>().paramDeclOrder()}; 1154 result.insert(result.end(), paramDecls.begin(), paramDecls.end()); 1155 return result; 1156 } 1157 1158 const DeclTypeSpec &FindOrInstantiateDerivedType( 1159 Scope &scope, DerivedTypeSpec &&spec, DeclTypeSpec::Category category) { 1160 spec.EvaluateParameters(scope.context()); 1161 if (const DeclTypeSpec * 1162 type{scope.FindInstantiatedDerivedType(spec, category)}) { 1163 return *type; 1164 } 1165 // Create a new instantiation of this parameterized derived type 1166 // for this particular distinct set of actual parameter values. 1167 DeclTypeSpec &type{scope.MakeDerivedType(category, std::move(spec))}; 1168 type.derivedTypeSpec().Instantiate(scope); 1169 return type; 1170 } 1171 1172 const Symbol *FindSeparateModuleSubprogramInterface(const Symbol *proc) { 1173 if (proc) { 1174 if (const auto *subprogram{proc->detailsIf<SubprogramDetails>()}) { 1175 if (const Symbol * iface{subprogram->moduleInterface()}) { 1176 return iface; 1177 } 1178 } 1179 } 1180 return nullptr; 1181 } 1182 1183 ProcedureDefinitionClass ClassifyProcedure(const Symbol &symbol) { // 15.2.2 1184 const Symbol &ultimate{symbol.GetUltimate()}; 1185 if (!IsProcedure(ultimate)) { 1186 return ProcedureDefinitionClass::None; 1187 } else if (ultimate.attrs().test(Attr::INTRINSIC)) { 1188 return ProcedureDefinitionClass::Intrinsic; 1189 } else if (IsDummy(ultimate)) { 1190 return ProcedureDefinitionClass::Dummy; 1191 } else if (IsProcedurePointer(symbol)) { 1192 return ProcedureDefinitionClass::Pointer; 1193 } else if (ultimate.attrs().test(Attr::EXTERNAL)) { 1194 return ProcedureDefinitionClass::External; 1195 } else if (const auto *nameDetails{ 1196 ultimate.detailsIf<SubprogramNameDetails>()}) { 1197 switch (nameDetails->kind()) { 1198 case SubprogramKind::Module: 1199 return ProcedureDefinitionClass::Module; 1200 case SubprogramKind::Internal: 1201 return ProcedureDefinitionClass::Internal; 1202 } 1203 } else if (const Symbol * subp{FindSubprogram(symbol)}) { 1204 if (const auto *subpDetails{subp->detailsIf<SubprogramDetails>()}) { 1205 if (subpDetails->stmtFunction()) { 1206 return ProcedureDefinitionClass::StatementFunction; 1207 } 1208 } 1209 switch (ultimate.owner().kind()) { 1210 case Scope::Kind::Global: 1211 case Scope::Kind::IntrinsicModules: 1212 return ProcedureDefinitionClass::External; 1213 case Scope::Kind::Module: 1214 return ProcedureDefinitionClass::Module; 1215 case Scope::Kind::MainProgram: 1216 case Scope::Kind::Subprogram: 1217 return ProcedureDefinitionClass::Internal; 1218 default: 1219 break; 1220 } 1221 } 1222 return ProcedureDefinitionClass::None; 1223 } 1224 1225 // ComponentIterator implementation 1226 1227 template <ComponentKind componentKind> 1228 typename ComponentIterator<componentKind>::const_iterator 1229 ComponentIterator<componentKind>::const_iterator::Create( 1230 const DerivedTypeSpec &derived) { 1231 const_iterator it{}; 1232 it.componentPath_.emplace_back(derived); 1233 it.Increment(); // cue up first relevant component, if any 1234 return it; 1235 } 1236 1237 template <ComponentKind componentKind> 1238 const DerivedTypeSpec * 1239 ComponentIterator<componentKind>::const_iterator::PlanComponentTraversal( 1240 const Symbol &component) const { 1241 if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) { 1242 if (const DeclTypeSpec * type{details->type()}) { 1243 if (const auto *derived{type->AsDerived()}) { 1244 bool traverse{false}; 1245 if constexpr (componentKind == ComponentKind::Ordered) { 1246 // Order Component (only visit parents) 1247 traverse = component.test(Symbol::Flag::ParentComp); 1248 } else if constexpr (componentKind == ComponentKind::Direct) { 1249 traverse = !IsAllocatableOrObjectPointer(&component); 1250 } else if constexpr (componentKind == ComponentKind::Ultimate) { 1251 traverse = !IsAllocatableOrObjectPointer(&component); 1252 } else if constexpr (componentKind == ComponentKind::Potential) { 1253 traverse = !IsPointer(component); 1254 } else if constexpr (componentKind == ComponentKind::Scope) { 1255 traverse = !IsAllocatableOrObjectPointer(&component); 1256 } else if constexpr (componentKind == 1257 ComponentKind::PotentialAndPointer) { 1258 traverse = !IsPointer(component); 1259 } 1260 if (traverse) { 1261 const Symbol &newTypeSymbol{derived->typeSymbol()}; 1262 // Avoid infinite loop if the type is already part of the types 1263 // being visited. It is possible to have "loops in type" because 1264 // C744 does not forbid to use not yet declared type for 1265 // ALLOCATABLE or POINTER components. 1266 for (const auto &node : componentPath_) { 1267 if (&newTypeSymbol == &node.GetTypeSymbol()) { 1268 return nullptr; 1269 } 1270 } 1271 return derived; 1272 } 1273 } 1274 } // intrinsic & unlimited polymorphic not traversable 1275 } 1276 return nullptr; 1277 } 1278 1279 template <ComponentKind componentKind> 1280 static bool StopAtComponentPre(const Symbol &component) { 1281 if constexpr (componentKind == ComponentKind::Ordered) { 1282 // Parent components need to be iterated upon after their 1283 // sub-components in structure constructor analysis. 1284 return !component.test(Symbol::Flag::ParentComp); 1285 } else if constexpr (componentKind == ComponentKind::Direct) { 1286 return true; 1287 } else if constexpr (componentKind == ComponentKind::Ultimate) { 1288 return component.has<ProcEntityDetails>() || 1289 IsAllocatableOrObjectPointer(&component) || 1290 (component.has<ObjectEntityDetails>() && 1291 component.get<ObjectEntityDetails>().type() && 1292 component.get<ObjectEntityDetails>().type()->AsIntrinsic()); 1293 } else if constexpr (componentKind == ComponentKind::Potential) { 1294 return !IsPointer(component); 1295 } else if constexpr (componentKind == ComponentKind::PotentialAndPointer) { 1296 return true; 1297 } else { 1298 DIE("unexpected ComponentKind"); 1299 } 1300 } 1301 1302 template <ComponentKind componentKind> 1303 static bool StopAtComponentPost(const Symbol &component) { 1304 return componentKind == ComponentKind::Ordered && 1305 component.test(Symbol::Flag::ParentComp); 1306 } 1307 1308 template <ComponentKind componentKind> 1309 void ComponentIterator<componentKind>::const_iterator::Increment() { 1310 while (!componentPath_.empty()) { 1311 ComponentPathNode &deepest{componentPath_.back()}; 1312 if (deepest.component()) { 1313 if (!deepest.descended()) { 1314 deepest.set_descended(true); 1315 if (const DerivedTypeSpec * 1316 derived{PlanComponentTraversal(*deepest.component())}) { 1317 componentPath_.emplace_back(*derived); 1318 continue; 1319 } 1320 } else if (!deepest.visited()) { 1321 deepest.set_visited(true); 1322 return; // this is the next component to visit, after descending 1323 } 1324 } 1325 auto &nameIterator{deepest.nameIterator()}; 1326 if (nameIterator == deepest.nameEnd()) { 1327 componentPath_.pop_back(); 1328 } else if constexpr (componentKind == ComponentKind::Scope) { 1329 deepest.set_component(*nameIterator++->second); 1330 deepest.set_descended(false); 1331 deepest.set_visited(true); 1332 return; // this is the next component to visit, before descending 1333 } else { 1334 const Scope &scope{deepest.GetScope()}; 1335 auto scopeIter{scope.find(*nameIterator++)}; 1336 if (scopeIter != scope.cend()) { 1337 const Symbol &component{*scopeIter->second}; 1338 deepest.set_component(component); 1339 deepest.set_descended(false); 1340 if (StopAtComponentPre<componentKind>(component)) { 1341 deepest.set_visited(true); 1342 return; // this is the next component to visit, before descending 1343 } else { 1344 deepest.set_visited(!StopAtComponentPost<componentKind>(component)); 1345 } 1346 } 1347 } 1348 } 1349 } 1350 1351 template <ComponentKind componentKind> 1352 std::string 1353 ComponentIterator<componentKind>::const_iterator::BuildResultDesignatorName() 1354 const { 1355 std::string designator; 1356 for (const auto &node : componentPath_) { 1357 designator += "%"s + DEREF(node.component()).name().ToString(); 1358 } 1359 return designator; 1360 } 1361 1362 template class ComponentIterator<ComponentKind::Ordered>; 1363 template class ComponentIterator<ComponentKind::Direct>; 1364 template class ComponentIterator<ComponentKind::Ultimate>; 1365 template class ComponentIterator<ComponentKind::Potential>; 1366 template class ComponentIterator<ComponentKind::Scope>; 1367 template class ComponentIterator<ComponentKind::PotentialAndPointer>; 1368 1369 UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent( 1370 const DerivedTypeSpec &derived) { 1371 UltimateComponentIterator ultimates{derived}; 1372 return std::find_if(ultimates.begin(), ultimates.end(), 1373 [](const Symbol &symbol) { return evaluate::IsCoarray(symbol); }); 1374 } 1375 1376 UltimateComponentIterator::const_iterator FindPointerUltimateComponent( 1377 const DerivedTypeSpec &derived) { 1378 UltimateComponentIterator ultimates{derived}; 1379 return std::find_if(ultimates.begin(), ultimates.end(), IsPointer); 1380 } 1381 1382 PotentialComponentIterator::const_iterator FindEventOrLockPotentialComponent( 1383 const DerivedTypeSpec &derived) { 1384 PotentialComponentIterator potentials{derived}; 1385 return std::find_if( 1386 potentials.begin(), potentials.end(), [](const Symbol &component) { 1387 if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) { 1388 const DeclTypeSpec *type{details->type()}; 1389 return type && IsEventTypeOrLockType(type->AsDerived()); 1390 } 1391 return false; 1392 }); 1393 } 1394 1395 UltimateComponentIterator::const_iterator FindAllocatableUltimateComponent( 1396 const DerivedTypeSpec &derived) { 1397 UltimateComponentIterator ultimates{derived}; 1398 return std::find_if(ultimates.begin(), ultimates.end(), IsAllocatable); 1399 } 1400 1401 DirectComponentIterator::const_iterator FindAllocatableOrPointerDirectComponent( 1402 const DerivedTypeSpec &derived) { 1403 DirectComponentIterator directs{derived}; 1404 return std::find_if(directs.begin(), directs.end(), IsAllocatableOrPointer); 1405 } 1406 1407 PotentialComponentIterator::const_iterator 1408 FindPolymorphicAllocatablePotentialComponent(const DerivedTypeSpec &derived) { 1409 PotentialComponentIterator potentials{derived}; 1410 return std::find_if( 1411 potentials.begin(), potentials.end(), IsPolymorphicAllocatable); 1412 } 1413 1414 const Symbol *FindUltimateComponent(const DerivedTypeSpec &derived, 1415 const std::function<bool(const Symbol &)> &predicate) { 1416 UltimateComponentIterator ultimates{derived}; 1417 if (auto it{std::find_if(ultimates.begin(), ultimates.end(), 1418 [&predicate](const Symbol &component) -> bool { 1419 return predicate(component); 1420 })}) { 1421 return &*it; 1422 } 1423 return nullptr; 1424 } 1425 1426 const Symbol *FindUltimateComponent(const Symbol &symbol, 1427 const std::function<bool(const Symbol &)> &predicate) { 1428 if (predicate(symbol)) { 1429 return &symbol; 1430 } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 1431 if (const auto *type{object->type()}) { 1432 if (const auto *derived{type->AsDerived()}) { 1433 return FindUltimateComponent(*derived, predicate); 1434 } 1435 } 1436 } 1437 return nullptr; 1438 } 1439 1440 const Symbol *FindImmediateComponent(const DerivedTypeSpec &type, 1441 const std::function<bool(const Symbol &)> &predicate) { 1442 if (const Scope * scope{type.scope()}) { 1443 const Symbol *parent{nullptr}; 1444 for (const auto &pair : *scope) { 1445 const Symbol *symbol{&*pair.second}; 1446 if (predicate(*symbol)) { 1447 return symbol; 1448 } 1449 if (symbol->test(Symbol::Flag::ParentComp)) { 1450 parent = symbol; 1451 } 1452 } 1453 if (parent) { 1454 if (const auto *object{parent->detailsIf<ObjectEntityDetails>()}) { 1455 if (const auto *type{object->type()}) { 1456 if (const auto *derived{type->AsDerived()}) { 1457 return FindImmediateComponent(*derived, predicate); 1458 } 1459 } 1460 } 1461 } 1462 } 1463 return nullptr; 1464 } 1465 1466 const Symbol *IsFunctionResultWithSameNameAsFunction(const Symbol &symbol) { 1467 if (IsFunctionResult(symbol)) { 1468 if (const Symbol * function{symbol.owner().symbol()}) { 1469 if (symbol.name() == function->name()) { 1470 return function; 1471 } 1472 } 1473 // Check ENTRY result symbols too 1474 const Scope &outer{symbol.owner().parent()}; 1475 auto iter{outer.find(symbol.name())}; 1476 if (iter != outer.end()) { 1477 const Symbol &outerSym{*iter->second}; 1478 if (const auto *subp{outerSym.detailsIf<SubprogramDetails>()}) { 1479 if (subp->entryScope() == &symbol.owner() && 1480 symbol.name() == outerSym.name()) { 1481 return &outerSym; 1482 } 1483 } 1484 } 1485 } 1486 return nullptr; 1487 } 1488 1489 void LabelEnforce::Post(const parser::GotoStmt &gotoStmt) { 1490 CheckLabelUse(gotoStmt.v); 1491 } 1492 void LabelEnforce::Post(const parser::ComputedGotoStmt &computedGotoStmt) { 1493 for (auto &i : std::get<std::list<parser::Label>>(computedGotoStmt.t)) { 1494 CheckLabelUse(i); 1495 } 1496 } 1497 1498 void LabelEnforce::Post(const parser::ArithmeticIfStmt &arithmeticIfStmt) { 1499 CheckLabelUse(std::get<1>(arithmeticIfStmt.t)); 1500 CheckLabelUse(std::get<2>(arithmeticIfStmt.t)); 1501 CheckLabelUse(std::get<3>(arithmeticIfStmt.t)); 1502 } 1503 1504 void LabelEnforce::Post(const parser::AssignStmt &assignStmt) { 1505 CheckLabelUse(std::get<parser::Label>(assignStmt.t)); 1506 } 1507 1508 void LabelEnforce::Post(const parser::AssignedGotoStmt &assignedGotoStmt) { 1509 for (auto &i : std::get<std::list<parser::Label>>(assignedGotoStmt.t)) { 1510 CheckLabelUse(i); 1511 } 1512 } 1513 1514 void LabelEnforce::Post(const parser::AltReturnSpec &altReturnSpec) { 1515 CheckLabelUse(altReturnSpec.v); 1516 } 1517 1518 void LabelEnforce::Post(const parser::ErrLabel &errLabel) { 1519 CheckLabelUse(errLabel.v); 1520 } 1521 void LabelEnforce::Post(const parser::EndLabel &endLabel) { 1522 CheckLabelUse(endLabel.v); 1523 } 1524 void LabelEnforce::Post(const parser::EorLabel &eorLabel) { 1525 CheckLabelUse(eorLabel.v); 1526 } 1527 1528 void LabelEnforce::CheckLabelUse(const parser::Label &labelUsed) { 1529 if (labels_.find(labelUsed) == labels_.end()) { 1530 SayWithConstruct(context_, currentStatementSourcePosition_, 1531 parser::MessageFormattedText{ 1532 "Control flow escapes from %s"_err_en_US, construct_}, 1533 constructSourcePosition_); 1534 } 1535 } 1536 1537 parser::MessageFormattedText LabelEnforce::GetEnclosingConstructMsg() { 1538 return {"Enclosing %s statement"_en_US, construct_}; 1539 } 1540 1541 void LabelEnforce::SayWithConstruct(SemanticsContext &context, 1542 parser::CharBlock stmtLocation, parser::MessageFormattedText &&message, 1543 parser::CharBlock constructLocation) { 1544 context.Say(stmtLocation, message) 1545 .Attach(constructLocation, GetEnclosingConstructMsg()); 1546 } 1547 1548 bool HasAlternateReturns(const Symbol &subprogram) { 1549 for (const auto *dummyArg : subprogram.get<SubprogramDetails>().dummyArgs()) { 1550 if (!dummyArg) { 1551 return true; 1552 } 1553 } 1554 return false; 1555 } 1556 1557 bool IsAutomaticallyDestroyed(const Symbol &symbol) { 1558 return symbol.has<ObjectEntityDetails>() && 1559 (symbol.owner().kind() == Scope::Kind::Subprogram || 1560 symbol.owner().kind() == Scope::Kind::BlockConstruct) && 1561 !IsNamedConstant(symbol) && (!IsDummy(symbol) || IsIntentOut(symbol)) && 1562 !IsPointer(symbol) && !IsSaved(symbol) && 1563 !FindCommonBlockContaining(symbol); 1564 } 1565 1566 const std::optional<parser::Name> &MaybeGetNodeName( 1567 const ConstructNode &construct) { 1568 return common::visit( 1569 common::visitors{ 1570 [&](const parser::BlockConstruct *blockConstruct) 1571 -> const std::optional<parser::Name> & { 1572 return std::get<0>(blockConstruct->t).statement.v; 1573 }, 1574 [&](const auto *a) -> const std::optional<parser::Name> & { 1575 return std::get<0>(std::get<0>(a->t).statement.t); 1576 }, 1577 }, 1578 construct); 1579 } 1580 1581 std::optional<ArraySpec> ToArraySpec( 1582 evaluate::FoldingContext &context, const evaluate::Shape &shape) { 1583 if (auto extents{evaluate::AsConstantExtents(context, shape)}) { 1584 ArraySpec result; 1585 for (const auto &extent : *extents) { 1586 result.emplace_back(ShapeSpec::MakeExplicit(Bound{extent})); 1587 } 1588 return {std::move(result)}; 1589 } else { 1590 return std::nullopt; 1591 } 1592 } 1593 1594 std::optional<ArraySpec> ToArraySpec(evaluate::FoldingContext &context, 1595 const std::optional<evaluate::Shape> &shape) { 1596 return shape ? ToArraySpec(context, *shape) : std::nullopt; 1597 } 1598 1599 static const DeclTypeSpec *GetDtvArgTypeSpec(const Symbol &proc) { 1600 if (const auto *subp{proc.detailsIf<SubprogramDetails>()}; 1601 subp && !subp->dummyArgs().empty()) { 1602 if (const auto *arg{subp->dummyArgs()[0]}) { 1603 return arg->GetType(); 1604 } 1605 } 1606 return nullptr; 1607 } 1608 1609 const DerivedTypeSpec *GetDtvArgDerivedType(const Symbol &proc) { 1610 if (const auto *type{GetDtvArgTypeSpec(proc)}) { 1611 return type->AsDerived(); 1612 } else { 1613 return nullptr; 1614 } 1615 } 1616 1617 bool HasDefinedIo(common::DefinedIo which, const DerivedTypeSpec &derived, 1618 const Scope *scope) { 1619 if (const Scope * dtScope{derived.scope()}) { 1620 for (const auto &pair : *dtScope) { 1621 const Symbol &symbol{*pair.second}; 1622 if (const auto *generic{symbol.detailsIf<GenericDetails>()}) { 1623 GenericKind kind{generic->kind()}; 1624 if (const auto *io{std::get_if<common::DefinedIo>(&kind.u)}) { 1625 if (*io == which) { 1626 return true; // type-bound GENERIC exists 1627 } 1628 } 1629 } 1630 } 1631 } 1632 if (scope) { 1633 SourceName name{GenericKind::AsFortran(which)}; 1634 evaluate::DynamicType dyDerived{derived}; 1635 for (; scope && !scope->IsGlobal(); scope = &scope->parent()) { 1636 auto iter{scope->find(name)}; 1637 if (iter != scope->end()) { 1638 const auto &generic{iter->second->GetUltimate().get<GenericDetails>()}; 1639 for (auto ref : generic.specificProcs()) { 1640 const Symbol &procSym{ref->GetUltimate()}; 1641 if (const DeclTypeSpec * dtSpec{GetDtvArgTypeSpec(procSym)}) { 1642 if (auto dyDummy{evaluate::DynamicType::From(*dtSpec)}) { 1643 if (dyDummy->IsTkCompatibleWith(dyDerived)) { 1644 return true; // GENERIC or INTERFACE not in type 1645 } 1646 } 1647 } 1648 } 1649 } 1650 } 1651 } 1652 return false; 1653 } 1654 1655 void WarnOnDeferredLengthCharacterScalar(SemanticsContext &context, 1656 const SomeExpr *expr, parser::CharBlock at, const char *what) { 1657 if (context.languageFeatures().ShouldWarn( 1658 common::UsageWarning::F202XAllocatableBreakingChange)) { 1659 if (const Symbol * 1660 symbol{evaluate::UnwrapWholeSymbolOrComponentDataRef(expr)}) { 1661 const Symbol &ultimate{ResolveAssociations(*symbol)}; 1662 if (const DeclTypeSpec * type{ultimate.GetType()}; type && 1663 type->category() == DeclTypeSpec::Category::Character && 1664 type->characterTypeSpec().length().isDeferred() && 1665 IsAllocatable(ultimate) && ultimate.Rank() == 0) { 1666 context.Say(at, 1667 "The deferred length allocatable character scalar variable '%s' may be reallocated to a different length under the new Fortran 202X standard semantics for %s"_port_en_US, 1668 symbol->name(), what); 1669 } 1670 } 1671 } 1672 } 1673 1674 bool CouldBeDataPointerValuedFunction(const Symbol *original) { 1675 if (original) { 1676 const Symbol &ultimate{original->GetUltimate()}; 1677 if (const Symbol * result{FindFunctionResult(ultimate)}) { 1678 return IsPointer(*result) && !IsProcedure(*result); 1679 } 1680 if (const auto *generic{ultimate.detailsIf<GenericDetails>()}) { 1681 for (const SymbolRef &ref : generic->specificProcs()) { 1682 if (CouldBeDataPointerValuedFunction(&*ref)) { 1683 return true; 1684 } 1685 } 1686 } 1687 } 1688 return false; 1689 } 1690 1691 std::string GetModuleOrSubmoduleName(const Symbol &symbol) { 1692 const auto &details{symbol.get<ModuleDetails>()}; 1693 std::string result{symbol.name().ToString()}; 1694 if (details.ancestor() && details.ancestor()->symbol()) { 1695 result = details.ancestor()->symbol()->name().ToString() + ':' + result; 1696 } 1697 return result; 1698 } 1699 1700 std::string GetCommonBlockObjectName(const Symbol &common, bool underscoring) { 1701 if (const std::string * bind{common.GetBindName()}) { 1702 return *bind; 1703 } 1704 if (common.name().empty()) { 1705 return Fortran::common::blankCommonObjectName; 1706 } 1707 return underscoring ? common.name().ToString() + "_"s 1708 : common.name().ToString(); 1709 } 1710 1711 bool HadUseError( 1712 SemanticsContext &context, SourceName at, const Symbol *symbol) { 1713 if (const auto *details{ 1714 symbol ? symbol->detailsIf<UseErrorDetails>() : nullptr}) { 1715 auto &msg{context.Say( 1716 at, "Reference to '%s' is ambiguous"_err_en_US, symbol->name())}; 1717 for (const auto &[location, module] : details->occurrences()) { 1718 msg.Attach(location, "'%s' was use-associated from module '%s'"_en_US, at, 1719 module->GetName().value()); 1720 } 1721 context.SetError(*symbol); 1722 return true; 1723 } else { 1724 return false; 1725 } 1726 } 1727 1728 } // namespace Fortran::semantics 1729