1 //===-- include/flang/Semantics/tools.h -------------------------*- C++ -*-===// 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 #ifndef FORTRAN_SEMANTICS_TOOLS_H_ 10 #define FORTRAN_SEMANTICS_TOOLS_H_ 11 12 // Simple predicates and look-up functions that are best defined 13 // canonically for use in semantic checking. 14 15 #include "flang/Common/Fortran.h" 16 #include "flang/Common/visit.h" 17 #include "flang/Evaluate/expression.h" 18 #include "flang/Evaluate/shape.h" 19 #include "flang/Evaluate/type.h" 20 #include "flang/Evaluate/variable.h" 21 #include "flang/Parser/message.h" 22 #include "flang/Parser/parse-tree.h" 23 #include "flang/Semantics/attr.h" 24 #include "flang/Semantics/expression.h" 25 #include "flang/Semantics/semantics.h" 26 #include <functional> 27 28 namespace Fortran::semantics { 29 30 class DeclTypeSpec; 31 class DerivedTypeSpec; 32 class Scope; 33 class Symbol; 34 35 // Note: Here ProgramUnit includes internal subprograms while TopLevelUnit 36 // does not. "program-unit" in the Fortran standard matches TopLevelUnit. 37 const Scope &GetTopLevelUnitContaining(const Scope &); 38 const Scope &GetTopLevelUnitContaining(const Symbol &); 39 const Scope &GetProgramUnitContaining(const Scope &); 40 const Scope &GetProgramUnitContaining(const Symbol &); 41 const Scope &GetProgramUnitOrBlockConstructContaining(const Scope &); 42 const Scope &GetProgramUnitOrBlockConstructContaining(const Symbol &); 43 44 const Scope *FindModuleContaining(const Scope &); 45 const Scope *FindModuleOrSubmoduleContaining(const Scope &); 46 const Scope *FindModuleFileContaining(const Scope &); 47 const Scope *FindPureProcedureContaining(const Scope &); 48 const Scope *FindOpenACCConstructContaining(const Scope *); 49 50 const Symbol *FindPointerComponent(const Scope &); 51 const Symbol *FindPointerComponent(const DerivedTypeSpec &); 52 const Symbol *FindPointerComponent(const DeclTypeSpec &); 53 const Symbol *FindPointerComponent(const Symbol &); 54 const Symbol *FindInterface(const Symbol &); 55 const Symbol *FindSubprogram(const Symbol &); 56 const Symbol *FindOverriddenBinding( 57 const Symbol &, bool &isInaccessibleDeferred); 58 const Symbol *FindGlobal(const Symbol &); 59 60 const DeclTypeSpec *FindParentTypeSpec(const DerivedTypeSpec &); 61 const DeclTypeSpec *FindParentTypeSpec(const DeclTypeSpec &); 62 const DeclTypeSpec *FindParentTypeSpec(const Scope &); 63 const DeclTypeSpec *FindParentTypeSpec(const Symbol &); 64 65 const EquivalenceSet *FindEquivalenceSet(const Symbol &); 66 67 enum class Tristate { No, Yes, Maybe }; 68 inline Tristate ToTristate(bool x) { return x ? Tristate::Yes : Tristate::No; } 69 70 // Is this a user-defined assignment? If both sides are the same derived type 71 // (and the ranks are okay) the answer is Maybe. 72 Tristate IsDefinedAssignment( 73 const std::optional<evaluate::DynamicType> &lhsType, int lhsRank, 74 const std::optional<evaluate::DynamicType> &rhsType, int rhsRank); 75 // Test for intrinsic unary and binary operators based on types and ranks 76 bool IsIntrinsicRelational(common::RelationalOperator, 77 const evaluate::DynamicType &, int, const evaluate::DynamicType &, int); 78 bool IsIntrinsicNumeric(const evaluate::DynamicType &); 79 bool IsIntrinsicNumeric( 80 const evaluate::DynamicType &, int, const evaluate::DynamicType &, int); 81 bool IsIntrinsicLogical(const evaluate::DynamicType &); 82 bool IsIntrinsicLogical( 83 const evaluate::DynamicType &, int, const evaluate::DynamicType &, int); 84 bool IsIntrinsicConcat( 85 const evaluate::DynamicType &, int, const evaluate::DynamicType &, int); 86 87 bool IsGenericDefinedOp(const Symbol &); 88 bool IsDefinedOperator(SourceName); 89 std::string MakeOpName(SourceName); 90 bool IsCommonBlockContaining(const Symbol &, const Symbol &); 91 92 // Returns true if maybeAncestor exists and is a proper ancestor of a 93 // descendent scope (or symbol owner). Will be false, unlike Scope::Contains(), 94 // if maybeAncestor *is* the descendent. 95 bool DoesScopeContain(const Scope *maybeAncestor, const Scope &maybeDescendent); 96 bool DoesScopeContain(const Scope *, const Symbol &); 97 98 bool IsUseAssociated(const Symbol &, const Scope &); 99 bool IsHostAssociated(const Symbol &, const Scope &); 100 bool IsHostAssociatedIntoSubprogram(const Symbol &, const Scope &); 101 inline bool IsStmtFunction(const Symbol &symbol) { 102 const auto *subprogram{symbol.detailsIf<SubprogramDetails>()}; 103 return subprogram && subprogram->stmtFunction(); 104 } 105 bool IsInStmtFunction(const Symbol &); 106 bool IsStmtFunctionDummy(const Symbol &); 107 bool IsStmtFunctionResult(const Symbol &); 108 bool IsPointerDummy(const Symbol &); 109 bool IsBindCProcedure(const Symbol &); 110 bool IsBindCProcedure(const Scope &); 111 // Returns a pointer to the function's symbol when true, else null 112 const Symbol *IsFunctionResultWithSameNameAsFunction(const Symbol &); 113 bool IsOrContainsEventOrLockComponent(const Symbol &); 114 bool CanBeTypeBoundProc(const Symbol &); 115 // Does a non-PARAMETER symbol have explicit initialization with =value or 116 // =>target in its declaration (but not in a DATA statement)? (Being 117 // ALLOCATABLE or having a derived type with default component initialization 118 // doesn't count; it must be a variable initialization that implies the SAVE 119 // attribute, or a derived type component default value.) 120 bool HasDeclarationInitializer(const Symbol &); 121 // Is the symbol explicitly or implicitly initialized in any way? 122 bool IsInitialized(const Symbol &, bool ignoreDATAstatements = false, 123 bool ignoreAllocatable = false, bool ignorePointer = true); 124 // Is the symbol a component subject to deallocation or finalization? 125 bool IsDestructible(const Symbol &, const Symbol *derivedType = nullptr); 126 bool HasIntrinsicTypeName(const Symbol &); 127 bool IsSeparateModuleProcedureInterface(const Symbol *); 128 bool HasAlternateReturns(const Symbol &); 129 bool IsAutomaticallyDestroyed(const Symbol &); 130 131 // Return an ultimate component of type that matches predicate, or nullptr. 132 const Symbol *FindUltimateComponent(const DerivedTypeSpec &type, 133 const std::function<bool(const Symbol &)> &predicate); 134 const Symbol *FindUltimateComponent( 135 const Symbol &symbol, const std::function<bool(const Symbol &)> &predicate); 136 137 // Returns an immediate component of type that matches predicate, or nullptr. 138 // An immediate component of a type is one declared for that type or is an 139 // immediate component of the type that it extends. 140 const Symbol *FindImmediateComponent( 141 const DerivedTypeSpec &, const std::function<bool(const Symbol &)> &); 142 143 inline bool IsPointer(const Symbol &symbol) { 144 return symbol.attrs().test(Attr::POINTER); 145 } 146 inline bool IsAllocatable(const Symbol &symbol) { 147 return symbol.attrs().test(Attr::ALLOCATABLE); 148 } 149 inline bool IsValue(const Symbol &symbol) { 150 return symbol.attrs().test(Attr::VALUE); 151 } 152 // IsAllocatableOrObjectPointer() may be the better choice 153 inline bool IsAllocatableOrPointer(const Symbol &symbol) { 154 return IsPointer(symbol) || IsAllocatable(symbol); 155 } 156 inline bool IsNamedConstant(const Symbol &symbol) { 157 return symbol.attrs().test(Attr::PARAMETER); 158 } 159 inline bool IsOptional(const Symbol &symbol) { 160 return symbol.attrs().test(Attr::OPTIONAL); 161 } 162 inline bool IsIntentIn(const Symbol &symbol) { 163 return symbol.attrs().test(Attr::INTENT_IN); 164 } 165 inline bool IsIntentInOut(const Symbol &symbol) { 166 return symbol.attrs().test(Attr::INTENT_INOUT); 167 } 168 inline bool IsIntentOut(const Symbol &symbol) { 169 return symbol.attrs().test(Attr::INTENT_OUT); 170 } 171 inline bool IsProtected(const Symbol &symbol) { 172 return symbol.attrs().test(Attr::PROTECTED); 173 } 174 inline bool IsImpliedDoIndex(const Symbol &symbol) { 175 return symbol.owner().kind() == Scope::Kind::ImpliedDos; 176 } 177 SymbolVector FinalsForDerivedTypeInstantiation(const DerivedTypeSpec &); 178 // Returns a non-null pointer to a FINAL procedure, if any. 179 const Symbol *IsFinalizable(const Symbol &, 180 std::set<const DerivedTypeSpec *> * = nullptr, 181 bool withImpureFinalizer = false); 182 const Symbol *IsFinalizable(const DerivedTypeSpec &, 183 std::set<const DerivedTypeSpec *> * = nullptr, 184 bool withImpureFinalizer = false, std::optional<int> rank = std::nullopt); 185 const Symbol *HasImpureFinal( 186 const Symbol &, std::optional<int> rank = std::nullopt); 187 // Is this type finalizable or does it contain any polymorphic allocatable 188 // ultimate components? 189 bool MayRequireFinalization(const DerivedTypeSpec &derived); 190 // Does this type have an allocatable direct component? 191 bool HasAllocatableDirectComponent(const DerivedTypeSpec &derived); 192 193 bool IsInBlankCommon(const Symbol &); 194 bool IsAssumedLengthCharacter(const Symbol &); 195 bool IsExternal(const Symbol &); 196 bool IsModuleProcedure(const Symbol &); 197 bool HasCoarray(const parser::Expr &); 198 bool IsAssumedType(const Symbol &); 199 bool IsPolymorphic(const Symbol &); 200 bool IsUnlimitedPolymorphic(const Symbol &); 201 bool IsPolymorphicAllocatable(const Symbol &); 202 203 inline bool IsCUDADeviceContext(const Scope *scope) { 204 if (scope) { 205 if (const Symbol * symbol{scope->symbol()}) { 206 if (const auto *subp{symbol->detailsIf<SubprogramDetails>()}) { 207 if (auto attrs{subp->cudaSubprogramAttrs()}) { 208 return *attrs != common::CUDASubprogramAttrs::Host; 209 } 210 } 211 } 212 } 213 return false; 214 } 215 216 inline bool HasCUDAAttr(const Symbol &sym) { 217 if (const auto *details{sym.GetUltimate().detailsIf<ObjectEntityDetails>()}) { 218 if (details->cudaDataAttr()) { 219 return true; 220 } 221 } 222 return false; 223 } 224 225 inline bool NeedCUDAAlloc(const Symbol &sym) { 226 if (IsDummy(sym)) { 227 return false; 228 } 229 if (const auto *details{sym.GetUltimate().detailsIf<ObjectEntityDetails>()}) { 230 if (details->cudaDataAttr() && 231 (*details->cudaDataAttr() == common::CUDADataAttr::Device || 232 *details->cudaDataAttr() == common::CUDADataAttr::Managed || 233 *details->cudaDataAttr() == common::CUDADataAttr::Unified || 234 *details->cudaDataAttr() == common::CUDADataAttr::Pinned)) { 235 return true; 236 } 237 } 238 return false; 239 } 240 241 const Scope *FindCUDADeviceContext(const Scope *); 242 std::optional<common::CUDADataAttr> GetCUDADataAttr(const Symbol *); 243 244 bool IsAccessible(const Symbol &, const Scope &); 245 246 // Return an error if a symbol is not accessible from a scope 247 std::optional<parser::MessageFormattedText> CheckAccessibleSymbol( 248 const Scope &, const Symbol &); 249 250 // Analysis of image control statements 251 bool IsImageControlStmt(const parser::ExecutableConstruct &); 252 // Get the location of the image control statement in this ExecutableConstruct 253 parser::CharBlock GetImageControlStmtLocation( 254 const parser::ExecutableConstruct &); 255 // Image control statements that reference coarrays need an extra message 256 // to clarify why they're image control statements. This function returns 257 // std::nullopt for ExecutableConstructs that do not require an extra message. 258 std::optional<parser::MessageFixedText> GetImageControlStmtCoarrayMsg( 259 const parser::ExecutableConstruct &); 260 261 // Returns the complete list of derived type parameter symbols in 262 // the order in which their declarations appear in the derived type 263 // definitions (parents first). 264 SymbolVector OrderParameterDeclarations(const Symbol &); 265 // Returns the complete list of derived type parameter names in the 266 // order defined by 7.5.3.2. 267 SymbolVector OrderParameterNames(const Symbol &); 268 269 // Return an existing or new derived type instance 270 const DeclTypeSpec &FindOrInstantiateDerivedType(Scope &, DerivedTypeSpec &&, 271 DeclTypeSpec::Category = DeclTypeSpec::TypeDerived); 272 273 // When a subprogram defined in a submodule defines a separate module 274 // procedure whose interface is defined in an ancestor (sub)module, 275 // returns a pointer to that interface, else null. 276 const Symbol *FindSeparateModuleSubprogramInterface(const Symbol *); 277 278 // Determines whether an object might be visible outside a 279 // pure function (C1594); returns a non-null Symbol pointer for 280 // diagnostic purposes if so. 281 const Symbol *FindExternallyVisibleObject( 282 const Symbol &, const Scope &, bool isPointerDefinition); 283 284 template <typename A> 285 const Symbol *FindExternallyVisibleObject(const A &, const Scope &) { 286 return nullptr; // default base case 287 } 288 289 template <typename T> 290 const Symbol *FindExternallyVisibleObject( 291 const evaluate::Designator<T> &designator, const Scope &scope) { 292 if (const Symbol * symbol{designator.GetBaseObject().symbol()}) { 293 return FindExternallyVisibleObject(*symbol, scope, false); 294 } else if (std::holds_alternative<evaluate::CoarrayRef>(designator.u)) { 295 // Coindexed values are visible even if their image-local objects are not. 296 return designator.GetBaseObject().symbol(); 297 } else { 298 return nullptr; 299 } 300 } 301 302 template <typename T> 303 const Symbol *FindExternallyVisibleObject( 304 const evaluate::Expr<T> &expr, const Scope &scope) { 305 return common::visit( 306 [&](const auto &x) { return FindExternallyVisibleObject(x, scope); }, 307 expr.u); 308 } 309 310 // Applies GetUltimate(), then if the symbol is a generic procedure shadowing a 311 // specific procedure of the same name, return it instead. 312 const Symbol &BypassGeneric(const Symbol &); 313 314 // Given a cray pointee symbol, returns the related cray pointer symbol. 315 const Symbol &GetCrayPointer(const Symbol &crayPointee); 316 317 using SomeExpr = evaluate::Expr<evaluate::SomeType>; 318 319 bool ExprHasTypeCategory( 320 const SomeExpr &expr, const common::TypeCategory &type); 321 bool ExprTypeKindIsDefault( 322 const SomeExpr &expr, const SemanticsContext &context); 323 324 class GetExprHelper { 325 public: 326 explicit GetExprHelper(SemanticsContext *context) : context_{context} {} 327 GetExprHelper() : crashIfNoExpr_{true} {} 328 329 // Specializations for parse tree nodes that have a typedExpr member. 330 const SomeExpr *Get(const parser::Expr &); 331 const SomeExpr *Get(const parser::Variable &); 332 const SomeExpr *Get(const parser::DataStmtConstant &); 333 const SomeExpr *Get(const parser::AllocateObject &); 334 const SomeExpr *Get(const parser::PointerObject &); 335 336 template <typename T> const SomeExpr *Get(const common::Indirection<T> &x) { 337 return Get(x.value()); 338 } 339 template <typename T> const SomeExpr *Get(const std::optional<T> &x) { 340 return x ? Get(*x) : nullptr; 341 } 342 template <typename T> const SomeExpr *Get(const T &x) { 343 static_assert( 344 !parser::HasTypedExpr<T>::value, "explicit Get overload must be added"); 345 if constexpr (ConstraintTrait<T>) { 346 return Get(x.thing); 347 } else if constexpr (WrapperTrait<T>) { 348 return Get(x.v); 349 } else { 350 return nullptr; 351 } 352 } 353 354 private: 355 SemanticsContext *context_{nullptr}; 356 const bool crashIfNoExpr_{false}; 357 }; 358 359 // If a SemanticsContext is passed, even if null, it is possible for a null 360 // pointer to be returned in the event of an expression that had fatal errors. 361 // Use these first two forms in semantics checks for best error recovery. 362 // If a SemanticsContext is not passed, a missing expression will 363 // cause a crash. 364 template <typename T> 365 const SomeExpr *GetExpr(SemanticsContext *context, const T &x) { 366 return GetExprHelper{context}.Get(x); 367 } 368 template <typename T> 369 const SomeExpr *GetExpr(SemanticsContext &context, const T &x) { 370 return GetExprHelper{&context}.Get(x); 371 } 372 template <typename T> const SomeExpr *GetExpr(const T &x) { 373 return GetExprHelper{}.Get(x); 374 } 375 376 const evaluate::Assignment *GetAssignment(const parser::AssignmentStmt &); 377 const evaluate::Assignment *GetAssignment( 378 const parser::PointerAssignmentStmt &); 379 380 template <typename T> std::optional<std::int64_t> GetIntValue(const T &x) { 381 if (const auto *expr{GetExpr(nullptr, x)}) { 382 return evaluate::ToInt64(*expr); 383 } else { 384 return std::nullopt; 385 } 386 } 387 388 template <typename T> bool IsZero(const T &expr) { 389 auto value{GetIntValue(expr)}; 390 return value && *value == 0; 391 } 392 393 // 15.2.2 394 enum class ProcedureDefinitionClass { 395 None, 396 Intrinsic, 397 External, 398 Internal, 399 Module, 400 Dummy, 401 Pointer, 402 StatementFunction 403 }; 404 405 ProcedureDefinitionClass ClassifyProcedure(const Symbol &); 406 407 // Returns a list of storage associations due to EQUIVALENCE in a 408 // scope; each storage association is a list of symbol references 409 // in ascending order of scope offset. Note that the scope may have 410 // more EquivalenceSets than this function's result has storage 411 // associations; these are closures over equivalences. 412 std::list<std::list<SymbolRef>> GetStorageAssociations(const Scope &); 413 414 // Derived type component iterator that provides a C++ LegacyForwardIterator 415 // iterator over the Ordered, Direct, Ultimate or Potential components of a 416 // DerivedTypeSpec. These iterators can be used with STL algorithms 417 // accepting LegacyForwardIterator. 418 // The kind of component is a template argument of the iterator factory 419 // ComponentIterator. 420 // 421 // - Ordered components are the components from the component order defined 422 // in 7.5.4.7, except that the parent component IS added between the parent 423 // component order and the components in order of declaration. 424 // This "deviation" is important for structure-constructor analysis. 425 // For this kind of iterator, the component tree is recursively visited in the 426 // following order: 427 // - first, the Ordered components of the parent type (if relevant) 428 // - then, the parent component (if relevant, different from 7.5.4.7!) 429 // - then, the components in declaration order (without visiting subcomponents) 430 // 431 // - Ultimate, Direct and Potential components are as defined in 7.5.1. 432 // - Ultimate components of a derived type are the closure of its components 433 // of intrinsic type, its ALLOCATABLE or POINTER components, and the 434 // ultimate components of its non-ALLOCATABLE non-POINTER derived type 435 // components. (No ultimate component has a derived type unless it is 436 // ALLOCATABLE or POINTER.) 437 // - Direct components of a derived type are all of its components, and all 438 // of the direct components of its non-ALLOCATABLE non-POINTER derived type 439 // components. (Direct components are always present.) 440 // - Potential subobject components of a derived type are the closure of 441 // its non-POINTER components and the potential subobject components of 442 // its non-POINTER derived type components. (The lifetime of each 443 // potential subobject component is that of the entire instance.) 444 // - PotentialAndPointer subobject components of a derived type are the 445 // closure of its components (including POINTERs) and the 446 // PotentialAndPointer subobject components of its non-POINTER derived type 447 // components. 448 // 449 // type t1 ultimate components: x, a, p 450 // real x direct components: x, a, p 451 // real, allocatable :: a potential components: x, a 452 // real, pointer :: p potential & pointers: x, a, p 453 // end type 454 // type t2 ultimate components: y, c%x, c%a, c%p, b 455 // real y direct components: y, c, c%x, c%a, c%p, b 456 // type(t1) :: c potential components: y, c, c%x, c%a, b, b%x, b%a 457 // type(t1), allocatable :: b potential & pointers: potentials + c%p + b%p 458 // end type 459 // 460 // Parent and procedure components are considered against these definitions. 461 // For this kind of iterator, the component tree is recursively visited in the 462 // following order: 463 // - the parent component first (if relevant) 464 // - then, the components of the parent type (if relevant) 465 // + visiting the component and then, if it is derived type data component, 466 // visiting the subcomponents before visiting the next 467 // component in declaration order. 468 // - then, components in declaration order, similarly to components of parent 469 // type. 470 // Here, the parent component is visited first so that search for a component 471 // verifying a property will never descend into a component that already 472 // verifies the property (this helps giving clearer feedback). 473 // 474 // ComponentIterator::const_iterator remain valid during the whole lifetime of 475 // the DerivedTypeSpec passed by reference to the ComponentIterator factory. 476 // Their validity is independent of the ComponentIterator factory lifetime. 477 // 478 // For safety and simplicity, the iterators are read only and can only be 479 // incremented. This could be changed if desired. 480 // 481 // Note that iterators are made in such a way that one can easily test and build 482 // info message in the following way: 483 // ComponentIterator<ComponentKind::...> comp{derived} 484 // if (auto it{std::find_if(comp.begin(), comp.end(), predicate)}) { 485 // msg = it.BuildResultDesignatorName() + " verifies predicates"; 486 // const Symbol *component{*it}; 487 // .... 488 // } 489 490 ENUM_CLASS(ComponentKind, Ordered, Direct, Ultimate, Potential, Scope, 491 PotentialAndPointer) 492 493 template <ComponentKind componentKind> class ComponentIterator { 494 public: 495 ComponentIterator(const DerivedTypeSpec &derived) : derived_{derived} {} 496 class const_iterator { 497 public: 498 using iterator_category = std::forward_iterator_tag; 499 using value_type = SymbolRef; 500 using difference_type = void; 501 using pointer = const Symbol *; 502 using reference = const Symbol &; 503 504 static const_iterator Create(const DerivedTypeSpec &); 505 506 const_iterator &operator++() { 507 Increment(); 508 return *this; 509 } 510 const_iterator operator++(int) { 511 const_iterator tmp(*this); 512 Increment(); 513 return tmp; 514 } 515 reference operator*() const { 516 CHECK(!componentPath_.empty()); 517 return DEREF(componentPath_.back().component()); 518 } 519 pointer operator->() const { return &**this; } 520 521 bool operator==(const const_iterator &other) const { 522 return componentPath_ == other.componentPath_; 523 } 524 bool operator!=(const const_iterator &other) const { 525 return !(*this == other); 526 } 527 528 // bool() operator indicates if the iterator can be dereferenced without 529 // having to check against an end() iterator. 530 explicit operator bool() const { return !componentPath_.empty(); } 531 532 // Returns the current sequence of components, including parent components. 533 SymbolVector GetComponentPath() const; 534 535 // Builds a designator name of the referenced component for messages. 536 // The designator helps when the component referred to by the iterator 537 // may be "buried" into other components. This gives the full 538 // path inside the iterated derived type: e.g "%a%b%c%ultimate" 539 // when it->name() only gives "ultimate". Parent components are 540 // part of the path for clarity, even though they could be 541 // skipped. 542 std::string BuildResultDesignatorName() const; 543 544 private: 545 using name_iterator = 546 std::conditional_t<componentKind == ComponentKind::Scope, 547 typename Scope::const_iterator, 548 typename std::list<SourceName>::const_iterator>; 549 550 class ComponentPathNode { 551 public: 552 explicit ComponentPathNode(const DerivedTypeSpec &derived) 553 : derived_{derived} { 554 if constexpr (componentKind == ComponentKind::Scope) { 555 const Scope &scope{DEREF(derived.GetScope())}; 556 nameIterator_ = scope.cbegin(); 557 nameEnd_ = scope.cend(); 558 } else { 559 const std::list<SourceName> &nameList{ 560 derived.typeSymbol().get<DerivedTypeDetails>().componentNames()}; 561 nameIterator_ = nameList.cbegin(); 562 nameEnd_ = nameList.cend(); 563 } 564 } 565 const Symbol *component() const { return component_; } 566 void set_component(const Symbol &component) { component_ = &component; } 567 bool visited() const { return visited_; } 568 void set_visited(bool yes) { visited_ = yes; } 569 bool descended() const { return descended_; } 570 void set_descended(bool yes) { descended_ = yes; } 571 name_iterator &nameIterator() { return nameIterator_; } 572 name_iterator nameEnd() { return nameEnd_; } 573 const Symbol &GetTypeSymbol() const { return derived_->typeSymbol(); } 574 const Scope &GetScope() const { 575 return derived_->scope() ? *derived_->scope() 576 : DEREF(GetTypeSymbol().scope()); 577 } 578 bool operator==(const ComponentPathNode &that) const { 579 return &*derived_ == &*that.derived_ && 580 nameIterator_ == that.nameIterator_ && 581 component_ == that.component_; 582 } 583 584 private: 585 common::Reference<const DerivedTypeSpec> derived_; 586 name_iterator nameEnd_; 587 name_iterator nameIterator_; 588 const Symbol *component_{nullptr}; // until Increment() 589 bool visited_{false}; 590 bool descended_{false}; 591 }; 592 593 const DerivedTypeSpec *PlanComponentTraversal( 594 const Symbol &component) const; 595 // Advances to the next relevant symbol, if any. Afterwards, the 596 // iterator will either be at its end or contain no null component(). 597 void Increment(); 598 599 std::vector<ComponentPathNode> componentPath_; 600 }; 601 602 const_iterator begin() { return cbegin(); } 603 const_iterator end() { return cend(); } 604 const_iterator cbegin() { return const_iterator::Create(derived_); } 605 const_iterator cend() { return const_iterator{}; } 606 607 private: 608 const DerivedTypeSpec &derived_; 609 }; 610 611 extern template class ComponentIterator<ComponentKind::Ordered>; 612 extern template class ComponentIterator<ComponentKind::Direct>; 613 extern template class ComponentIterator<ComponentKind::Ultimate>; 614 extern template class ComponentIterator<ComponentKind::Potential>; 615 extern template class ComponentIterator<ComponentKind::Scope>; 616 extern template class ComponentIterator<ComponentKind::PotentialAndPointer>; 617 using OrderedComponentIterator = ComponentIterator<ComponentKind::Ordered>; 618 using DirectComponentIterator = ComponentIterator<ComponentKind::Direct>; 619 using UltimateComponentIterator = ComponentIterator<ComponentKind::Ultimate>; 620 using PotentialComponentIterator = ComponentIterator<ComponentKind::Potential>; 621 using ScopeComponentIterator = ComponentIterator<ComponentKind::Scope>; 622 using PotentialAndPointerComponentIterator = 623 ComponentIterator<ComponentKind::PotentialAndPointer>; 624 625 // Common component searches, the iterator returned is referring to the first 626 // component, according to the order defined for the related ComponentIterator, 627 // that verifies the property from the name. 628 // If no component verifies the property, an end iterator (casting to false) 629 // is returned. Otherwise, the returned iterator casts to true and can be 630 // dereferenced. 631 PotentialComponentIterator::const_iterator FindEventOrLockPotentialComponent( 632 const DerivedTypeSpec &, bool ignoreCoarrays = false); 633 UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent( 634 const DerivedTypeSpec &); 635 UltimateComponentIterator::const_iterator FindPointerUltimateComponent( 636 const DerivedTypeSpec &); 637 UltimateComponentIterator::const_iterator FindAllocatableUltimateComponent( 638 const DerivedTypeSpec &); 639 DirectComponentIterator::const_iterator FindAllocatableOrPointerDirectComponent( 640 const DerivedTypeSpec &); 641 PotentialComponentIterator::const_iterator 642 FindPolymorphicAllocatablePotentialComponent(const DerivedTypeSpec &); 643 644 // The LabelEnforce class (given a set of labels) provides an error message if 645 // there is a branch to a label which is not in the given set. 646 class LabelEnforce { 647 public: 648 LabelEnforce(SemanticsContext &context, std::set<parser::Label> &&labels, 649 parser::CharBlock constructSourcePosition, const char *construct) 650 : context_{context}, labels_{labels}, 651 constructSourcePosition_{constructSourcePosition}, construct_{ 652 construct} {} 653 template <typename T> bool Pre(const T &) { return true; } 654 template <typename T> bool Pre(const parser::Statement<T> &statement) { 655 currentStatementSourcePosition_ = statement.source; 656 return true; 657 } 658 659 template <typename T> void Post(const T &) {} 660 661 void Post(const parser::GotoStmt &gotoStmt); 662 void Post(const parser::ComputedGotoStmt &computedGotoStmt); 663 void Post(const parser::ArithmeticIfStmt &arithmeticIfStmt); 664 void Post(const parser::AssignStmt &assignStmt); 665 void Post(const parser::AssignedGotoStmt &assignedGotoStmt); 666 void Post(const parser::AltReturnSpec &altReturnSpec); 667 void Post(const parser::ErrLabel &errLabel); 668 void Post(const parser::EndLabel &endLabel); 669 void Post(const parser::EorLabel &eorLabel); 670 void CheckLabelUse(const parser::Label &labelUsed); 671 672 private: 673 SemanticsContext &context_; 674 std::set<parser::Label> labels_; 675 parser::CharBlock currentStatementSourcePosition_{nullptr}; 676 parser::CharBlock constructSourcePosition_{nullptr}; 677 const char *construct_{nullptr}; 678 679 parser::MessageFormattedText GetEnclosingConstructMsg(); 680 void SayWithConstruct(SemanticsContext &context, 681 parser::CharBlock stmtLocation, parser::MessageFormattedText &&message, 682 parser::CharBlock constructLocation); 683 }; 684 // Return the (possibly null) name of the ConstructNode 685 const std::optional<parser::Name> &MaybeGetNodeName( 686 const ConstructNode &construct); 687 688 // Convert evaluate::GetShape() result into an ArraySpec 689 std::optional<ArraySpec> ToArraySpec( 690 evaluate::FoldingContext &, const evaluate::Shape &); 691 std::optional<ArraySpec> ToArraySpec( 692 evaluate::FoldingContext &, const std::optional<evaluate::Shape> &); 693 694 // Searches a derived type and a scope for a particular defined I/O procedure. 695 bool HasDefinedIo( 696 common::DefinedIo, const DerivedTypeSpec &, const Scope * = nullptr); 697 698 // Some intrinsic operators have more than one name (e.g. `operator(.eq.)` and 699 // `operator(==)`). GetAllNames() returns them all, including symbolName. 700 std::forward_list<std::string> GetAllNames( 701 const SemanticsContext &, const SourceName &); 702 703 // Determines the derived type of a procedure's initial "dtv" dummy argument, 704 // assuming that the procedure is a specific procedure of a defined I/O 705 // generic interface, 706 const DerivedTypeSpec *GetDtvArgDerivedType(const Symbol &); 707 708 // If "expr" exists and is a designator for a deferred length 709 // character allocatable whose semantics might change under Fortran 202X, 710 // emit a portability warning. 711 void WarnOnDeferredLengthCharacterScalar(SemanticsContext &, const SomeExpr *, 712 parser::CharBlock at, const char *what); 713 714 inline const parser::Name *getDesignatorNameIfDataRef( 715 const parser::Designator &designator) { 716 const auto *dataRef{std::get_if<parser::DataRef>(&designator.u)}; 717 return dataRef ? std::get_if<parser::Name>(&dataRef->u) : nullptr; 718 } 719 720 bool CouldBeDataPointerValuedFunction(const Symbol *); 721 722 template <typename R, typename T> 723 std::optional<R> GetConstExpr(SemanticsContext &semanticsContext, const T &x) { 724 using DefaultCharConstantType = evaluate::Ascii; 725 if (const auto *expr{GetExpr(semanticsContext, x)}) { 726 const auto foldExpr{evaluate::Fold( 727 semanticsContext.foldingContext(), common::Clone(*expr))}; 728 if constexpr (std::is_same_v<R, std::string>) { 729 return evaluate::GetScalarConstantValue<DefaultCharConstantType>( 730 foldExpr); 731 } 732 } 733 return std::nullopt; 734 } 735 736 // Returns "m" for a module, "m:sm" for a submodule. 737 std::string GetModuleOrSubmoduleName(const Symbol &); 738 739 // Return the assembly name emitted for a common block. 740 std::string GetCommonBlockObjectName(const Symbol &, bool underscoring); 741 742 // Check for ambiguous USE associations 743 bool HadUseError(SemanticsContext &, SourceName at, const Symbol *); 744 745 /// Checks if the assignment statement has a single variable on the RHS. 746 inline bool checkForSingleVariableOnRHS( 747 const Fortran::parser::AssignmentStmt &assignmentStmt) { 748 const Fortran::parser::Expr &expr{ 749 std::get<Fortran::parser::Expr>(assignmentStmt.t)}; 750 const Fortran::common::Indirection<Fortran::parser::Designator> *designator = 751 std::get_if<Fortran::common::Indirection<Fortran::parser::Designator>>( 752 &expr.u); 753 return designator != nullptr; 754 } 755 756 /// Checks if the symbol on the LHS of the assignment statement is present in 757 /// the RHS expression. 758 inline bool checkForSymbolMatch( 759 const Fortran::parser::AssignmentStmt &assignmentStmt) { 760 const auto &var{std::get<Fortran::parser::Variable>(assignmentStmt.t)}; 761 const auto &expr{std::get<Fortran::parser::Expr>(assignmentStmt.t)}; 762 const auto *e{Fortran::semantics::GetExpr(expr)}; 763 const auto *v{Fortran::semantics::GetExpr(var)}; 764 auto varSyms{Fortran::evaluate::GetSymbolVector(*v)}; 765 const Fortran::semantics::Symbol &varSymbol{*varSyms.front()}; 766 for (const Fortran::semantics::Symbol &symbol : 767 Fortran::evaluate::GetSymbolVector(*e)) { 768 if (varSymbol == symbol) { 769 return true; 770 } 771 } 772 return false; 773 } 774 } // namespace Fortran::semantics 775 #endif // FORTRAN_SEMANTICS_TOOLS_H_ 776