164ab3302SCarolineConcatto //===-- lib/Semantics/tools.cpp -------------------------------------------===// 264ab3302SCarolineConcatto // 364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information. 564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 664ab3302SCarolineConcatto // 764ab3302SCarolineConcatto //===----------------------------------------------------------------------===// 864ab3302SCarolineConcatto 964ab3302SCarolineConcatto #include "flang/Parser/tools.h" 1064ab3302SCarolineConcatto #include "flang/Common/Fortran.h" 1164ab3302SCarolineConcatto #include "flang/Common/indirection.h" 1264ab3302SCarolineConcatto #include "flang/Parser/dump-parse-tree.h" 1364ab3302SCarolineConcatto #include "flang/Parser/message.h" 1464ab3302SCarolineConcatto #include "flang/Parser/parse-tree.h" 1564ab3302SCarolineConcatto #include "flang/Semantics/scope.h" 1664ab3302SCarolineConcatto #include "flang/Semantics/semantics.h" 1764ab3302SCarolineConcatto #include "flang/Semantics/symbol.h" 1864ab3302SCarolineConcatto #include "flang/Semantics/tools.h" 1964ab3302SCarolineConcatto #include "flang/Semantics/type.h" 208670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h" 2164ab3302SCarolineConcatto #include <algorithm> 2264ab3302SCarolineConcatto #include <set> 2364ab3302SCarolineConcatto #include <variant> 2464ab3302SCarolineConcatto 2564ab3302SCarolineConcatto namespace Fortran::semantics { 2664ab3302SCarolineConcatto 2747452b96STim Keith // Find this or containing scope that matches predicate 2847452b96STim Keith static const Scope *FindScopeContaining( 2947452b96STim Keith const Scope &start, std::function<bool(const Scope &)> predicate) { 3047452b96STim Keith for (const Scope *scope{&start};; scope = &scope->parent()) { 3147452b96STim Keith if (predicate(*scope)) { 3247452b96STim Keith return scope; 3347452b96STim Keith } 3452a1346bSPeter Klausler if (scope->IsTopLevel()) { 3547452b96STim Keith return nullptr; 3647452b96STim Keith } 3747452b96STim Keith } 3847452b96STim Keith } 3947452b96STim Keith 401f525eceSTim Keith const Scope &GetTopLevelUnitContaining(const Scope &start) { 4152a1346bSPeter Klausler CHECK(!start.IsTopLevel()); 421f525eceSTim Keith return DEREF(FindScopeContaining( 4352a1346bSPeter Klausler start, [](const Scope &scope) { return scope.parent().IsTopLevel(); })); 441f525eceSTim Keith } 451f525eceSTim Keith 461f525eceSTim Keith const Scope &GetTopLevelUnitContaining(const Symbol &symbol) { 471f525eceSTim Keith return GetTopLevelUnitContaining(symbol.owner()); 481f525eceSTim Keith } 491f525eceSTim Keith 5047452b96STim Keith const Scope *FindModuleContaining(const Scope &start) { 5147452b96STim Keith return FindScopeContaining( 5247452b96STim Keith start, [](const Scope &scope) { return scope.IsModule(); }); 5347452b96STim Keith } 5447452b96STim Keith 559f0f54a6SPeter Klausler const Scope *FindModuleOrSubmoduleContaining(const Scope &start) { 569f0f54a6SPeter Klausler return FindScopeContaining(start, [](const Scope &scope) { 579f0f54a6SPeter Klausler return scope.IsModule() || scope.IsSubmodule(); 589f0f54a6SPeter Klausler }); 599f0f54a6SPeter Klausler } 609f0f54a6SPeter Klausler 611bd083b5Speter klausler const Scope *FindModuleFileContaining(const Scope &start) { 621bd083b5Speter klausler return FindScopeContaining( 631bd083b5Speter klausler start, [](const Scope &scope) { return scope.IsModuleFile(); }); 641bd083b5Speter klausler } 651bd083b5Speter klausler 661f525eceSTim Keith const Scope &GetProgramUnitContaining(const Scope &start) { 6752a1346bSPeter Klausler CHECK(!start.IsTopLevel()); 681f525eceSTim Keith return DEREF(FindScopeContaining(start, [](const Scope &scope) { 6947452b96STim Keith switch (scope.kind()) { 7064ab3302SCarolineConcatto case Scope::Kind::Module: 7164ab3302SCarolineConcatto case Scope::Kind::MainProgram: 7264ab3302SCarolineConcatto case Scope::Kind::Subprogram: 7384a099dfSpeter klausler case Scope::Kind::BlockData: 7484a099dfSpeter klausler return true; 7584a099dfSpeter klausler default: 7684a099dfSpeter klausler return false; 7764ab3302SCarolineConcatto } 781f525eceSTim Keith })); 7964ab3302SCarolineConcatto } 8064ab3302SCarolineConcatto 811f525eceSTim Keith const Scope &GetProgramUnitContaining(const Symbol &symbol) { 821f525eceSTim Keith return GetProgramUnitContaining(symbol.owner()); 8364ab3302SCarolineConcatto } 8464ab3302SCarolineConcatto 85a9782feaSPeter Klausler const Scope &GetProgramUnitOrBlockConstructContaining(const Scope &start) { 86a9782feaSPeter Klausler CHECK(!start.IsTopLevel()); 87a9782feaSPeter Klausler return DEREF(FindScopeContaining(start, [](const Scope &scope) { 88a9782feaSPeter Klausler switch (scope.kind()) { 89a9782feaSPeter Klausler case Scope::Kind::Module: 90a9782feaSPeter Klausler case Scope::Kind::MainProgram: 91a9782feaSPeter Klausler case Scope::Kind::Subprogram: 92a9782feaSPeter Klausler case Scope::Kind::BlockData: 93a9782feaSPeter Klausler case Scope::Kind::BlockConstruct: 94a9782feaSPeter Klausler return true; 95a9782feaSPeter Klausler default: 96a9782feaSPeter Klausler return false; 97a9782feaSPeter Klausler } 98a9782feaSPeter Klausler })); 99a9782feaSPeter Klausler } 100a9782feaSPeter Klausler 101a9782feaSPeter Klausler const Scope &GetProgramUnitOrBlockConstructContaining(const Symbol &symbol) { 102a9782feaSPeter Klausler return GetProgramUnitOrBlockConstructContaining(symbol.owner()); 103a9782feaSPeter Klausler } 104a9782feaSPeter Klausler 10564ab3302SCarolineConcatto const Scope *FindPureProcedureContaining(const Scope &start) { 10664ab3302SCarolineConcatto // N.B. We only need to examine the innermost containing program unit 10764ab3302SCarolineConcatto // because an internal subprogram of a pure subprogram must also 10864ab3302SCarolineConcatto // be pure (C1592). 10952a1346bSPeter Klausler if (start.IsTopLevel()) { 1101dff8637Speter klausler return nullptr; 1111dff8637Speter klausler } else { 1121f525eceSTim Keith const Scope &scope{GetProgramUnitContaining(start)}; 1131f525eceSTim Keith return IsPureProcedure(scope) ? &scope : nullptr; 11464ab3302SCarolineConcatto } 1151dff8637Speter klausler } 11664ab3302SCarolineConcatto 11789165e8bSPeter Klausler const Scope *FindOpenACCConstructContaining(const Scope *scope) { 11889165e8bSPeter Klausler return scope ? FindScopeContaining(*scope, 11989165e8bSPeter Klausler [](const Scope &s) { 12089165e8bSPeter Klausler return s.kind() == Scope::Kind::OpenACCConstruct; 12189165e8bSPeter Klausler }) 12289165e8bSPeter Klausler : nullptr; 12389165e8bSPeter Klausler } 12489165e8bSPeter Klausler 125f2dac557SPeter Klausler // 7.5.2.4 "same derived type" test -- rely on IsTkCompatibleWith() and its 126f2dac557SPeter Klausler // infrastructure to detect and handle comparisons on distinct (but "same") 127f2dac557SPeter Klausler // sequence/bind(C) derived types 128f2dac557SPeter Klausler static bool MightBeSameDerivedType( 129d667b96cSPeter Steinfeld const std::optional<evaluate::DynamicType> &lhsType, 130d667b96cSPeter Steinfeld const std::optional<evaluate::DynamicType> &rhsType) { 131eef76f98SPeter Klausler return lhsType && rhsType && lhsType->IsTkCompatibleWith(*rhsType); 132d667b96cSPeter Steinfeld } 133d667b96cSPeter Steinfeld 13464ab3302SCarolineConcatto Tristate IsDefinedAssignment( 13564ab3302SCarolineConcatto const std::optional<evaluate::DynamicType> &lhsType, int lhsRank, 13664ab3302SCarolineConcatto const std::optional<evaluate::DynamicType> &rhsType, int rhsRank) { 13764ab3302SCarolineConcatto if (!lhsType || !rhsType) { 13864ab3302SCarolineConcatto return Tristate::No; // error or rhs is untyped 13964ab3302SCarolineConcatto } 14048a8a3ebSPeter Klausler if (lhsType->IsUnlimitedPolymorphic()) { 1410363a164SPeter Klausler return Tristate::No; 1420363a164SPeter Klausler } 14348a8a3ebSPeter Klausler if (rhsType->IsUnlimitedPolymorphic()) { 14448a8a3ebSPeter Klausler return Tristate::Maybe; 14548a8a3ebSPeter Klausler } 14664ab3302SCarolineConcatto TypeCategory lhsCat{lhsType->category()}; 14764ab3302SCarolineConcatto TypeCategory rhsCat{rhsType->category()}; 14864ab3302SCarolineConcatto if (rhsRank > 0 && lhsRank != rhsRank) { 14964ab3302SCarolineConcatto return Tristate::Yes; 15064ab3302SCarolineConcatto } else if (lhsCat != TypeCategory::Derived) { 15164ab3302SCarolineConcatto return ToTristate(lhsCat != rhsCat && 152fc97d2e6SPeter Klausler (!IsNumericTypeCategory(lhsCat) || !IsNumericTypeCategory(rhsCat) || 153fc97d2e6SPeter Klausler lhsCat == TypeCategory::Unsigned || 154fc97d2e6SPeter Klausler rhsCat == TypeCategory::Unsigned)); 155f2dac557SPeter Klausler } else if (MightBeSameDerivedType(lhsType, rhsType)) { 156d667b96cSPeter Steinfeld return Tristate::Maybe; // TYPE(t) = TYPE(t) can be defined or intrinsic 15764ab3302SCarolineConcatto } else { 15864ab3302SCarolineConcatto return Tristate::Yes; 15964ab3302SCarolineConcatto } 16064ab3302SCarolineConcatto } 16164ab3302SCarolineConcatto 16264ab3302SCarolineConcatto bool IsIntrinsicRelational(common::RelationalOperator opr, 16364ab3302SCarolineConcatto const evaluate::DynamicType &type0, int rank0, 16464ab3302SCarolineConcatto const evaluate::DynamicType &type1, int rank1) { 16564ab3302SCarolineConcatto if (!evaluate::AreConformable(rank0, rank1)) { 16664ab3302SCarolineConcatto return false; 16764ab3302SCarolineConcatto } else { 16864ab3302SCarolineConcatto auto cat0{type0.category()}; 16964ab3302SCarolineConcatto auto cat1{type1.category()}; 170fc97d2e6SPeter Klausler if (cat0 == TypeCategory::Unsigned || cat1 == TypeCategory::Unsigned) { 171fc97d2e6SPeter Klausler return cat0 == cat1; 172fc97d2e6SPeter Klausler } else if (IsNumericTypeCategory(cat0) && IsNumericTypeCategory(cat1)) { 17364ab3302SCarolineConcatto // numeric types: EQ/NE always ok, others ok for non-complex 17464ab3302SCarolineConcatto return opr == common::RelationalOperator::EQ || 17564ab3302SCarolineConcatto opr == common::RelationalOperator::NE || 17664ab3302SCarolineConcatto (cat0 != TypeCategory::Complex && cat1 != TypeCategory::Complex); 17764ab3302SCarolineConcatto } else { 17864ab3302SCarolineConcatto // not both numeric: only Character is ok 17964ab3302SCarolineConcatto return cat0 == TypeCategory::Character && cat1 == TypeCategory::Character; 18064ab3302SCarolineConcatto } 18164ab3302SCarolineConcatto } 18264ab3302SCarolineConcatto } 18364ab3302SCarolineConcatto 18464ab3302SCarolineConcatto bool IsIntrinsicNumeric(const evaluate::DynamicType &type0) { 18564ab3302SCarolineConcatto return IsNumericTypeCategory(type0.category()); 18664ab3302SCarolineConcatto } 18764ab3302SCarolineConcatto bool IsIntrinsicNumeric(const evaluate::DynamicType &type0, int rank0, 18864ab3302SCarolineConcatto const evaluate::DynamicType &type1, int rank1) { 18964ab3302SCarolineConcatto return evaluate::AreConformable(rank0, rank1) && 19064ab3302SCarolineConcatto IsNumericTypeCategory(type0.category()) && 19164ab3302SCarolineConcatto IsNumericTypeCategory(type1.category()); 19264ab3302SCarolineConcatto } 19364ab3302SCarolineConcatto 19464ab3302SCarolineConcatto bool IsIntrinsicLogical(const evaluate::DynamicType &type0) { 19564ab3302SCarolineConcatto return type0.category() == TypeCategory::Logical; 19664ab3302SCarolineConcatto } 19764ab3302SCarolineConcatto bool IsIntrinsicLogical(const evaluate::DynamicType &type0, int rank0, 19864ab3302SCarolineConcatto const evaluate::DynamicType &type1, int rank1) { 19964ab3302SCarolineConcatto return evaluate::AreConformable(rank0, rank1) && 20064ab3302SCarolineConcatto type0.category() == TypeCategory::Logical && 20164ab3302SCarolineConcatto type1.category() == TypeCategory::Logical; 20264ab3302SCarolineConcatto } 20364ab3302SCarolineConcatto 20464ab3302SCarolineConcatto bool IsIntrinsicConcat(const evaluate::DynamicType &type0, int rank0, 20564ab3302SCarolineConcatto const evaluate::DynamicType &type1, int rank1) { 20664ab3302SCarolineConcatto return evaluate::AreConformable(rank0, rank1) && 20764ab3302SCarolineConcatto type0.category() == TypeCategory::Character && 20864ab3302SCarolineConcatto type1.category() == TypeCategory::Character && 20964ab3302SCarolineConcatto type0.kind() == type1.kind(); 21064ab3302SCarolineConcatto } 21164ab3302SCarolineConcatto 21264ab3302SCarolineConcatto bool IsGenericDefinedOp(const Symbol &symbol) { 21364ab3302SCarolineConcatto const Symbol &ultimate{symbol.GetUltimate()}; 21464ab3302SCarolineConcatto if (const auto *generic{ultimate.detailsIf<GenericDetails>()}) { 21564ab3302SCarolineConcatto return generic->kind().IsDefinedOperator(); 21664ab3302SCarolineConcatto } else if (const auto *misc{ultimate.detailsIf<MiscDetails>()}) { 21764ab3302SCarolineConcatto return misc->kind() == MiscDetails::Kind::TypeBoundDefinedOp; 21864ab3302SCarolineConcatto } else { 21964ab3302SCarolineConcatto return false; 22064ab3302SCarolineConcatto } 22164ab3302SCarolineConcatto } 22264ab3302SCarolineConcatto 22382edd428STim Keith bool IsDefinedOperator(SourceName name) { 22482edd428STim Keith const char *begin{name.begin()}; 22582edd428STim Keith const char *end{name.end()}; 22682edd428STim Keith return begin != end && begin[0] == '.' && end[-1] == '.'; 22782edd428STim Keith } 22882edd428STim Keith 22982edd428STim Keith std::string MakeOpName(SourceName name) { 23082edd428STim Keith std::string result{name.ToString()}; 23182edd428STim Keith return IsDefinedOperator(name) ? "OPERATOR(" + result + ")" 23282edd428STim Keith : result.find("operator(", 0) == 0 ? parser::ToUpperCaseLetters(result) 23382edd428STim Keith : result; 23482edd428STim Keith } 23582edd428STim Keith 23664ab3302SCarolineConcatto bool IsCommonBlockContaining(const Symbol &block, const Symbol &object) { 23764ab3302SCarolineConcatto const auto &objects{block.get<CommonBlockDetails>().objects()}; 23806b551c9SKazu Hirata return llvm::is_contained(objects, object); 23964ab3302SCarolineConcatto } 24064ab3302SCarolineConcatto 24164ab3302SCarolineConcatto bool IsUseAssociated(const Symbol &symbol, const Scope &scope) { 242573fc618SPeter Klausler const Scope &owner{GetTopLevelUnitContaining(symbol.GetUltimate().owner())}; 2431f525eceSTim Keith return owner.kind() == Scope::Kind::Module && 244573fc618SPeter Klausler owner != GetTopLevelUnitContaining(scope); 24564ab3302SCarolineConcatto } 24664ab3302SCarolineConcatto 24764ab3302SCarolineConcatto bool DoesScopeContain( 24864ab3302SCarolineConcatto const Scope *maybeAncestor, const Scope &maybeDescendent) { 24952a1346bSPeter Klausler return maybeAncestor && !maybeDescendent.IsTopLevel() && 25047452b96STim Keith FindScopeContaining(maybeDescendent.parent(), 25147452b96STim Keith [&](const Scope &scope) { return &scope == maybeAncestor; }); 25264ab3302SCarolineConcatto } 25364ab3302SCarolineConcatto 25464ab3302SCarolineConcatto bool DoesScopeContain(const Scope *maybeAncestor, const Symbol &symbol) { 25564ab3302SCarolineConcatto return DoesScopeContain(maybeAncestor, symbol.owner()); 25664ab3302SCarolineConcatto } 25764ab3302SCarolineConcatto 25838272f45STim Keith static const Symbol &FollowHostAssoc(const Symbol &symbol) { 25938272f45STim Keith for (const Symbol *s{&symbol};;) { 26038272f45STim Keith const auto *details{s->detailsIf<HostAssocDetails>()}; 26138272f45STim Keith if (!details) { 26238272f45STim Keith return *s; 26338272f45STim Keith } 26438272f45STim Keith s = &details->symbol(); 26538272f45STim Keith } 26638272f45STim Keith } 26738272f45STim Keith 26864ab3302SCarolineConcatto bool IsHostAssociated(const Symbol &symbol, const Scope &scope) { 269a51d92a4SPeter Klausler const Symbol &base{FollowHostAssoc(symbol)}; 270a51d92a4SPeter Klausler return base.owner().IsTopLevel() || 271a51d92a4SPeter Klausler DoesScopeContain(&GetProgramUnitOrBlockConstructContaining(base), 272a9782feaSPeter Klausler GetProgramUnitOrBlockConstructContaining(scope)); 27364ab3302SCarolineConcatto } 27464ab3302SCarolineConcatto 275e6373de5SPeter Klausler bool IsHostAssociatedIntoSubprogram(const Symbol &symbol, const Scope &scope) { 276a51d92a4SPeter Klausler const Symbol &base{FollowHostAssoc(symbol)}; 277a51d92a4SPeter Klausler return base.owner().IsTopLevel() || 278a51d92a4SPeter Klausler DoesScopeContain(&GetProgramUnitOrBlockConstructContaining(base), 279e6373de5SPeter Klausler GetProgramUnitContaining(scope)); 280e6373de5SPeter Klausler } 281e6373de5SPeter Klausler 282657aaf8bSPete Steinfeld bool IsInStmtFunction(const Symbol &symbol) { 283657aaf8bSPete Steinfeld if (const Symbol * function{symbol.owner().symbol()}) { 284657aaf8bSPete Steinfeld return IsStmtFunction(*function); 285657aaf8bSPete Steinfeld } 286657aaf8bSPete Steinfeld return false; 287657aaf8bSPete Steinfeld } 288657aaf8bSPete Steinfeld 289657aaf8bSPete Steinfeld bool IsStmtFunctionDummy(const Symbol &symbol) { 290657aaf8bSPete Steinfeld return IsDummy(symbol) && IsInStmtFunction(symbol); 291657aaf8bSPete Steinfeld } 292657aaf8bSPete Steinfeld 293657aaf8bSPete Steinfeld bool IsStmtFunctionResult(const Symbol &symbol) { 294657aaf8bSPete Steinfeld return IsFunctionResult(symbol) && IsInStmtFunction(symbol); 295657aaf8bSPete Steinfeld } 296657aaf8bSPete Steinfeld 29764ab3302SCarolineConcatto bool IsPointerDummy(const Symbol &symbol) { 29864ab3302SCarolineConcatto return IsPointer(symbol) && IsDummy(symbol); 29964ab3302SCarolineConcatto } 30064ab3302SCarolineConcatto 301d80a29a9SSlava Zakharin bool IsBindCProcedure(const Symbol &original) { 302d80a29a9SSlava Zakharin const Symbol &symbol{original.GetUltimate()}; 30364ab3302SCarolineConcatto if (const auto *procDetails{symbol.detailsIf<ProcEntityDetails>()}) { 304635656f4SPeter Klausler if (procDetails->procInterface()) { 30564ab3302SCarolineConcatto // procedure component with a BIND(C) interface 306635656f4SPeter Klausler return IsBindCProcedure(*procDetails->procInterface()); 30764ab3302SCarolineConcatto } 30864ab3302SCarolineConcatto } 30964ab3302SCarolineConcatto return symbol.attrs().test(Attr::BIND_C) && IsProcedure(symbol); 31064ab3302SCarolineConcatto } 31164ab3302SCarolineConcatto 31264ab3302SCarolineConcatto bool IsBindCProcedure(const Scope &scope) { 31364ab3302SCarolineConcatto if (const Symbol * symbol{scope.GetSymbol()}) { 31464ab3302SCarolineConcatto return IsBindCProcedure(*symbol); 31564ab3302SCarolineConcatto } else { 31664ab3302SCarolineConcatto return false; 31764ab3302SCarolineConcatto } 31864ab3302SCarolineConcatto } 31964ab3302SCarolineConcatto 32064ab3302SCarolineConcatto static const Symbol *FindPointerComponent( 32164ab3302SCarolineConcatto const Scope &scope, std::set<const Scope *> &visited) { 32264ab3302SCarolineConcatto if (!scope.IsDerivedType()) { 32364ab3302SCarolineConcatto return nullptr; 32464ab3302SCarolineConcatto } 32564ab3302SCarolineConcatto if (!visited.insert(&scope).second) { 32664ab3302SCarolineConcatto return nullptr; 32764ab3302SCarolineConcatto } 32864ab3302SCarolineConcatto // If there's a top-level pointer component, return it for clearer error 32964ab3302SCarolineConcatto // messaging. 33064ab3302SCarolineConcatto for (const auto &pair : scope) { 33164ab3302SCarolineConcatto const Symbol &symbol{*pair.second}; 33264ab3302SCarolineConcatto if (IsPointer(symbol)) { 33364ab3302SCarolineConcatto return &symbol; 33464ab3302SCarolineConcatto } 33564ab3302SCarolineConcatto } 33664ab3302SCarolineConcatto for (const auto &pair : scope) { 33764ab3302SCarolineConcatto const Symbol &symbol{*pair.second}; 33864ab3302SCarolineConcatto if (const auto *details{symbol.detailsIf<ObjectEntityDetails>()}) { 33964ab3302SCarolineConcatto if (const DeclTypeSpec * type{details->type()}) { 34064ab3302SCarolineConcatto if (const DerivedTypeSpec * derived{type->AsDerived()}) { 34164ab3302SCarolineConcatto if (const Scope * nested{derived->scope()}) { 34264ab3302SCarolineConcatto if (const Symbol * 34364ab3302SCarolineConcatto pointer{FindPointerComponent(*nested, visited)}) { 34464ab3302SCarolineConcatto return pointer; 34564ab3302SCarolineConcatto } 34664ab3302SCarolineConcatto } 34764ab3302SCarolineConcatto } 34864ab3302SCarolineConcatto } 34964ab3302SCarolineConcatto } 35064ab3302SCarolineConcatto } 35164ab3302SCarolineConcatto return nullptr; 35264ab3302SCarolineConcatto } 35364ab3302SCarolineConcatto 35464ab3302SCarolineConcatto const Symbol *FindPointerComponent(const Scope &scope) { 35564ab3302SCarolineConcatto std::set<const Scope *> visited; 35664ab3302SCarolineConcatto return FindPointerComponent(scope, visited); 35764ab3302SCarolineConcatto } 35864ab3302SCarolineConcatto 35964ab3302SCarolineConcatto const Symbol *FindPointerComponent(const DerivedTypeSpec &derived) { 36064ab3302SCarolineConcatto if (const Scope * scope{derived.scope()}) { 36164ab3302SCarolineConcatto return FindPointerComponent(*scope); 36264ab3302SCarolineConcatto } else { 36364ab3302SCarolineConcatto return nullptr; 36464ab3302SCarolineConcatto } 36564ab3302SCarolineConcatto } 36664ab3302SCarolineConcatto 36764ab3302SCarolineConcatto const Symbol *FindPointerComponent(const DeclTypeSpec &type) { 36864ab3302SCarolineConcatto if (const DerivedTypeSpec * derived{type.AsDerived()}) { 36964ab3302SCarolineConcatto return FindPointerComponent(*derived); 37064ab3302SCarolineConcatto } else { 37164ab3302SCarolineConcatto return nullptr; 37264ab3302SCarolineConcatto } 37364ab3302SCarolineConcatto } 37464ab3302SCarolineConcatto 37564ab3302SCarolineConcatto const Symbol *FindPointerComponent(const DeclTypeSpec *type) { 37664ab3302SCarolineConcatto return type ? FindPointerComponent(*type) : nullptr; 37764ab3302SCarolineConcatto } 37864ab3302SCarolineConcatto 37964ab3302SCarolineConcatto const Symbol *FindPointerComponent(const Symbol &symbol) { 38064ab3302SCarolineConcatto return IsPointer(symbol) ? &symbol : FindPointerComponent(symbol.GetType()); 38164ab3302SCarolineConcatto } 38264ab3302SCarolineConcatto 38364ab3302SCarolineConcatto // C1594 specifies several ways by which an object might be globally visible. 38464ab3302SCarolineConcatto const Symbol *FindExternallyVisibleObject( 385573fc618SPeter Klausler const Symbol &object, const Scope &scope, bool isPointerDefinition) { 38664ab3302SCarolineConcatto // TODO: Storage association with any object for which this predicate holds, 38764ab3302SCarolineConcatto // once EQUIVALENCE is supported. 3880996b590Speter klausler const Symbol &ultimate{GetAssociationRoot(object)}; 3890996b590Speter klausler if (IsDummy(ultimate)) { 3900996b590Speter klausler if (IsIntentIn(ultimate)) { 3910996b590Speter klausler return &ultimate; 39264ab3302SCarolineConcatto } 393573fc618SPeter Klausler if (!isPointerDefinition && IsPointer(ultimate) && 394573fc618SPeter Klausler IsPureProcedure(ultimate.owner()) && IsFunction(ultimate.owner())) { 3950996b590Speter klausler return &ultimate; 3960996b590Speter klausler } 397573fc618SPeter Klausler } else if (ultimate.owner().IsDerivedType()) { 398573fc618SPeter Klausler return nullptr; 3990996b590Speter klausler } else if (&GetProgramUnitContaining(ultimate) != 4000996b590Speter klausler &GetProgramUnitContaining(scope)) { 4010996b590Speter klausler return &object; 4020996b590Speter klausler } else if (const Symbol * block{FindCommonBlockContaining(ultimate)}) { 4030996b590Speter klausler return block; 4040996b590Speter klausler } 4050996b590Speter klausler return nullptr; 40664ab3302SCarolineConcatto } 40764ab3302SCarolineConcatto 4083cc5d4ffSpeter klausler const Symbol &BypassGeneric(const Symbol &symbol) { 4093cc5d4ffSpeter klausler const Symbol &ultimate{symbol.GetUltimate()}; 4103cc5d4ffSpeter klausler if (const auto *generic{ultimate.detailsIf<GenericDetails>()}) { 4113cc5d4ffSpeter klausler if (const Symbol * specific{generic->specific()}) { 4123cc5d4ffSpeter klausler return *specific; 4133cc5d4ffSpeter klausler } 4143cc5d4ffSpeter klausler } 4153cc5d4ffSpeter klausler return symbol; 4163cc5d4ffSpeter klausler } 4173cc5d4ffSpeter klausler 418de7a50fbSjeanPerier const Symbol &GetCrayPointer(const Symbol &crayPointee) { 419de7a50fbSjeanPerier const Symbol *found{nullptr}; 420de7a50fbSjeanPerier for (const auto &[pointee, pointer] : 421de7a50fbSjeanPerier crayPointee.GetUltimate().owner().crayPointers()) { 422de7a50fbSjeanPerier if (pointee == crayPointee.name()) { 423de7a50fbSjeanPerier found = &pointer.get(); 424de7a50fbSjeanPerier break; 425de7a50fbSjeanPerier } 426de7a50fbSjeanPerier } 427de7a50fbSjeanPerier return DEREF(found); 428de7a50fbSjeanPerier } 429de7a50fbSjeanPerier 43064ab3302SCarolineConcatto bool ExprHasTypeCategory( 43164ab3302SCarolineConcatto const SomeExpr &expr, const common::TypeCategory &type) { 43264ab3302SCarolineConcatto auto dynamicType{expr.GetType()}; 43364ab3302SCarolineConcatto return dynamicType && dynamicType->category() == type; 43464ab3302SCarolineConcatto } 43564ab3302SCarolineConcatto 43664ab3302SCarolineConcatto bool ExprTypeKindIsDefault( 43764ab3302SCarolineConcatto const SomeExpr &expr, const SemanticsContext &context) { 43864ab3302SCarolineConcatto auto dynamicType{expr.GetType()}; 43964ab3302SCarolineConcatto return dynamicType && 44064ab3302SCarolineConcatto dynamicType->category() != common::TypeCategory::Derived && 44164ab3302SCarolineConcatto dynamicType->kind() == context.GetDefaultKind(dynamicType->category()); 44264ab3302SCarolineConcatto } 44364ab3302SCarolineConcatto 44464ab3302SCarolineConcatto // If an analyzed expr or assignment is missing, dump the node and die. 44584a099dfSpeter klausler template <typename T> 4467e225423SPeter Klausler static void CheckMissingAnalysis( 4477e225423SPeter Klausler bool crash, SemanticsContext *context, const T &x) { 4487e225423SPeter Klausler if (crash && !(context && context->AnyFatalError())) { 4498670e499SCaroline Concatto std::string buf; 4508670e499SCaroline Concatto llvm::raw_string_ostream ss{buf}; 45164ab3302SCarolineConcatto ss << "node has not been analyzed:\n"; 45264ab3302SCarolineConcatto parser::DumpTree(ss, x); 453d5dd7d23SYoungsuk Kim common::die(buf.c_str()); 45464ab3302SCarolineConcatto } 45564ab3302SCarolineConcatto } 45664ab3302SCarolineConcatto 45792d27b96SJean Perier const SomeExpr *GetExprHelper::Get(const parser::Expr &x) { 4587e225423SPeter Klausler CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x); 4597e225423SPeter Klausler return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr; 46092d27b96SJean Perier } 46164ab3302SCarolineConcatto const SomeExpr *GetExprHelper::Get(const parser::Variable &x) { 4627e225423SPeter Klausler CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x); 4637e225423SPeter Klausler return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr; 46464ab3302SCarolineConcatto } 4654171f80dSpeter klausler const SomeExpr *GetExprHelper::Get(const parser::DataStmtConstant &x) { 4667e225423SPeter Klausler CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x); 4677e225423SPeter Klausler return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr; 46892d27b96SJean Perier } 46992d27b96SJean Perier const SomeExpr *GetExprHelper::Get(const parser::AllocateObject &x) { 4707e225423SPeter Klausler CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x); 4717e225423SPeter Klausler return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr; 47292d27b96SJean Perier } 47392d27b96SJean Perier const SomeExpr *GetExprHelper::Get(const parser::PointerObject &x) { 4747e225423SPeter Klausler CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x); 4757e225423SPeter Klausler return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr; 4764171f80dSpeter klausler } 47764ab3302SCarolineConcatto 47864ab3302SCarolineConcatto const evaluate::Assignment *GetAssignment(const parser::AssignmentStmt &x) { 4797e225423SPeter Klausler return x.typedAssignment ? common::GetPtrFromOptional(x.typedAssignment->v) 4807e225423SPeter Klausler : nullptr; 48164ab3302SCarolineConcatto } 48264ab3302SCarolineConcatto const evaluate::Assignment *GetAssignment( 48364ab3302SCarolineConcatto const parser::PointerAssignmentStmt &x) { 4847e225423SPeter Klausler return x.typedAssignment ? common::GetPtrFromOptional(x.typedAssignment->v) 4857e225423SPeter Klausler : nullptr; 48664ab3302SCarolineConcatto } 48764ab3302SCarolineConcatto 48864ab3302SCarolineConcatto const Symbol *FindInterface(const Symbol &symbol) { 489cd03e96fSPeter Klausler return common::visit( 49064ab3302SCarolineConcatto common::visitors{ 49164ab3302SCarolineConcatto [](const ProcEntityDetails &details) { 49283ca78deSPeter Klausler const Symbol *interface{details.procInterface()}; 49346c49e66SPeter Klausler return interface ? FindInterface(*interface) : nullptr; 49464ab3302SCarolineConcatto }, 49546c49e66SPeter Klausler [](const ProcBindingDetails &details) { 49646c49e66SPeter Klausler return FindInterface(details.symbol()); 49746c49e66SPeter Klausler }, 49846c49e66SPeter Klausler [&](const SubprogramDetails &) { return &symbol; }, 49946c49e66SPeter Klausler [](const UseDetails &details) { 50046c49e66SPeter Klausler return FindInterface(details.symbol()); 50146c49e66SPeter Klausler }, 50246c49e66SPeter Klausler [](const HostAssocDetails &details) { 50346c49e66SPeter Klausler return FindInterface(details.symbol()); 50446c49e66SPeter Klausler }, 50546c49e66SPeter Klausler [](const GenericDetails &details) { 50646c49e66SPeter Klausler return details.specific() ? FindInterface(*details.specific()) 50746c49e66SPeter Klausler : nullptr; 50846c49e66SPeter Klausler }, 50964ab3302SCarolineConcatto [](const auto &) -> const Symbol * { return nullptr; }, 51064ab3302SCarolineConcatto }, 51164ab3302SCarolineConcatto symbol.details()); 51264ab3302SCarolineConcatto } 51364ab3302SCarolineConcatto 51464ab3302SCarolineConcatto const Symbol *FindSubprogram(const Symbol &symbol) { 515cd03e96fSPeter Klausler return common::visit( 51664ab3302SCarolineConcatto common::visitors{ 51764ab3302SCarolineConcatto [&](const ProcEntityDetails &details) -> const Symbol * { 518635656f4SPeter Klausler if (details.procInterface()) { 519635656f4SPeter Klausler return FindSubprogram(*details.procInterface()); 52064ab3302SCarolineConcatto } else { 52164ab3302SCarolineConcatto return &symbol; 52264ab3302SCarolineConcatto } 52364ab3302SCarolineConcatto }, 52464ab3302SCarolineConcatto [](const ProcBindingDetails &details) { 52564ab3302SCarolineConcatto return FindSubprogram(details.symbol()); 52664ab3302SCarolineConcatto }, 52764ab3302SCarolineConcatto [&](const SubprogramDetails &) { return &symbol; }, 52864ab3302SCarolineConcatto [](const UseDetails &details) { 52964ab3302SCarolineConcatto return FindSubprogram(details.symbol()); 53064ab3302SCarolineConcatto }, 53164ab3302SCarolineConcatto [](const HostAssocDetails &details) { 53264ab3302SCarolineConcatto return FindSubprogram(details.symbol()); 53364ab3302SCarolineConcatto }, 53446c49e66SPeter Klausler [](const GenericDetails &details) { 53546c49e66SPeter Klausler return details.specific() ? FindSubprogram(*details.specific()) 53646c49e66SPeter Klausler : nullptr; 53746c49e66SPeter Klausler }, 53864ab3302SCarolineConcatto [](const auto &) -> const Symbol * { return nullptr; }, 53964ab3302SCarolineConcatto }, 54064ab3302SCarolineConcatto symbol.details()); 54164ab3302SCarolineConcatto } 54264ab3302SCarolineConcatto 543f4fc959cSPeter Klausler const Symbol *FindOverriddenBinding( 544f4fc959cSPeter Klausler const Symbol &symbol, bool &isInaccessibleDeferred) { 545f4fc959cSPeter Klausler isInaccessibleDeferred = false; 54664ab3302SCarolineConcatto if (symbol.has<ProcBindingDetails>()) { 54764ab3302SCarolineConcatto if (const DeclTypeSpec * parentType{FindParentTypeSpec(symbol.owner())}) { 54864ab3302SCarolineConcatto if (const DerivedTypeSpec * parentDerived{parentType->AsDerived()}) { 54964ab3302SCarolineConcatto if (const Scope * parentScope{parentDerived->typeSymbol().scope()}) { 5507f7bbc73SPeter Klausler if (const Symbol * 5517f7bbc73SPeter Klausler overridden{parentScope->FindComponent(symbol.name())}) { 5527f7bbc73SPeter Klausler // 7.5.7.3 p1: only accessible bindings are overridden 553ecf264d3SPeter Klausler if (IsAccessible(*overridden, symbol.owner())) { 554f4fc959cSPeter Klausler return overridden; 555f4fc959cSPeter Klausler } else if (overridden->attrs().test(Attr::DEFERRED)) { 556f4fc959cSPeter Klausler isInaccessibleDeferred = true; 5577f7bbc73SPeter Klausler return overridden; 5587f7bbc73SPeter Klausler } 5597f7bbc73SPeter Klausler } 56064ab3302SCarolineConcatto } 56164ab3302SCarolineConcatto } 56264ab3302SCarolineConcatto } 56364ab3302SCarolineConcatto } 56464ab3302SCarolineConcatto return nullptr; 56564ab3302SCarolineConcatto } 56664ab3302SCarolineConcatto 5670d588347SPeter Klausler const Symbol *FindGlobal(const Symbol &original) { 5680d588347SPeter Klausler const Symbol &ultimate{original.GetUltimate()}; 5690d588347SPeter Klausler if (ultimate.owner().IsGlobal()) { 5700d588347SPeter Klausler return &ultimate; 5710d588347SPeter Klausler } 5720d588347SPeter Klausler bool isLocal{false}; 5730d588347SPeter Klausler if (IsDummy(ultimate)) { 5740d588347SPeter Klausler } else if (IsPointer(ultimate)) { 5750d588347SPeter Klausler } else if (ultimate.has<ProcEntityDetails>()) { 5760d588347SPeter Klausler isLocal = IsExternal(ultimate); 5770d588347SPeter Klausler } else if (const auto *subp{ultimate.detailsIf<SubprogramDetails>()}) { 5780d588347SPeter Klausler isLocal = subp->isInterface(); 5790d588347SPeter Klausler } 5800d588347SPeter Klausler if (isLocal) { 5810d588347SPeter Klausler const std::string *bind{ultimate.GetBindName()}; 5820d588347SPeter Klausler if (!bind || ultimate.name() == *bind) { 5830d588347SPeter Klausler const Scope &globalScope{ultimate.owner().context().globalScope()}; 5840d588347SPeter Klausler if (auto iter{globalScope.find(ultimate.name())}; 5850d588347SPeter Klausler iter != globalScope.end()) { 5860d588347SPeter Klausler const Symbol &global{*iter->second}; 5870d588347SPeter Klausler const std::string *globalBind{global.GetBindName()}; 5880d588347SPeter Klausler if (!globalBind || global.name() == *globalBind) { 5890d588347SPeter Klausler return &global; 5900d588347SPeter Klausler } 5910d588347SPeter Klausler } 5920d588347SPeter Klausler } 5930d588347SPeter Klausler } 5940d588347SPeter Klausler return nullptr; 5950d588347SPeter Klausler } 5960d588347SPeter Klausler 59764ab3302SCarolineConcatto const DeclTypeSpec *FindParentTypeSpec(const DerivedTypeSpec &derived) { 59864ab3302SCarolineConcatto return FindParentTypeSpec(derived.typeSymbol()); 59964ab3302SCarolineConcatto } 60064ab3302SCarolineConcatto 60164ab3302SCarolineConcatto const DeclTypeSpec *FindParentTypeSpec(const DeclTypeSpec &decl) { 60264ab3302SCarolineConcatto if (const DerivedTypeSpec * derived{decl.AsDerived()}) { 60364ab3302SCarolineConcatto return FindParentTypeSpec(*derived); 60464ab3302SCarolineConcatto } else { 60564ab3302SCarolineConcatto return nullptr; 60664ab3302SCarolineConcatto } 60764ab3302SCarolineConcatto } 60864ab3302SCarolineConcatto 60964ab3302SCarolineConcatto const DeclTypeSpec *FindParentTypeSpec(const Scope &scope) { 61064ab3302SCarolineConcatto if (scope.kind() == Scope::Kind::DerivedType) { 61164ab3302SCarolineConcatto if (const auto *symbol{scope.symbol()}) { 61264ab3302SCarolineConcatto return FindParentTypeSpec(*symbol); 61364ab3302SCarolineConcatto } 61464ab3302SCarolineConcatto } 61564ab3302SCarolineConcatto return nullptr; 61664ab3302SCarolineConcatto } 61764ab3302SCarolineConcatto 61864ab3302SCarolineConcatto const DeclTypeSpec *FindParentTypeSpec(const Symbol &symbol) { 61964ab3302SCarolineConcatto if (const Scope * scope{symbol.scope()}) { 62064ab3302SCarolineConcatto if (const auto *details{symbol.detailsIf<DerivedTypeDetails>()}) { 62164ab3302SCarolineConcatto if (const Symbol * parent{details->GetParentComponent(*scope)}) { 62264ab3302SCarolineConcatto return parent->GetType(); 62364ab3302SCarolineConcatto } 62464ab3302SCarolineConcatto } 62564ab3302SCarolineConcatto } 62664ab3302SCarolineConcatto return nullptr; 62764ab3302SCarolineConcatto } 62864ab3302SCarolineConcatto 629d60a0220Speter klausler const EquivalenceSet *FindEquivalenceSet(const Symbol &symbol) { 630d60a0220Speter klausler const Symbol &ultimate{symbol.GetUltimate()}; 631d60a0220Speter klausler for (const EquivalenceSet &set : ultimate.owner().equivalenceSets()) { 632d60a0220Speter klausler for (const EquivalenceObject &object : set) { 633d60a0220Speter klausler if (object.symbol == ultimate) { 634d60a0220Speter klausler return &set; 635d60a0220Speter klausler } 636d60a0220Speter klausler } 637d60a0220Speter klausler } 638d60a0220Speter klausler return nullptr; 639d60a0220Speter klausler } 640d60a0220Speter klausler 641a50bb84eSpeter klausler bool IsOrContainsEventOrLockComponent(const Symbol &original) { 642a50bb84eSpeter klausler const Symbol &symbol{ResolveAssociations(original)}; 643a50bb84eSpeter klausler if (const auto *details{symbol.detailsIf<ObjectEntityDetails>()}) { 64464ab3302SCarolineConcatto if (const DeclTypeSpec * type{details->type()}) { 64564ab3302SCarolineConcatto if (const DerivedTypeSpec * derived{type->AsDerived()}) { 64664ab3302SCarolineConcatto return IsEventTypeOrLockType(derived) || 64764ab3302SCarolineConcatto FindEventOrLockPotentialComponent(*derived); 64864ab3302SCarolineConcatto } 64964ab3302SCarolineConcatto } 65064ab3302SCarolineConcatto } 65164ab3302SCarolineConcatto return false; 65264ab3302SCarolineConcatto } 65364ab3302SCarolineConcatto 65464ab3302SCarolineConcatto // Check this symbol suitable as a type-bound procedure - C769 65517f32bddSPeter Klausler bool CanBeTypeBoundProc(const Symbol &symbol) { 65617f32bddSPeter Klausler if (IsDummy(symbol) || IsProcedurePointer(symbol)) { 65764ab3302SCarolineConcatto return false; 65817f32bddSPeter Klausler } else if (symbol.has<SubprogramNameDetails>()) { 65917f32bddSPeter Klausler return symbol.owner().kind() == Scope::Kind::Module; 66017f32bddSPeter Klausler } else if (auto *details{symbol.detailsIf<SubprogramDetails>()}) { 66117f32bddSPeter Klausler if (details->isInterface()) { 66217f32bddSPeter Klausler return !symbol.attrs().test(Attr::ABSTRACT); 66317f32bddSPeter Klausler } else { 66417f32bddSPeter Klausler return symbol.owner().kind() == Scope::Kind::Module; 66517f32bddSPeter Klausler } 66617f32bddSPeter Klausler } else if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) { 66717f32bddSPeter Klausler return !symbol.attrs().test(Attr::INTRINSIC) && 66864ab3302SCarolineConcatto proc->HasExplicitInterface(); 66964ab3302SCarolineConcatto } else { 67064ab3302SCarolineConcatto return false; 67164ab3302SCarolineConcatto } 67264ab3302SCarolineConcatto } 67364ab3302SCarolineConcatto 674d60a0220Speter klausler bool HasDeclarationInitializer(const Symbol &symbol) { 675d60a0220Speter klausler if (IsNamedConstant(symbol)) { 67664ab3302SCarolineConcatto return false; 67764ab3302SCarolineConcatto } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 678a50bb84eSpeter klausler return object->init().has_value(); 67964ab3302SCarolineConcatto } else if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) { 68064ab3302SCarolineConcatto return proc->init().has_value(); 681d60a0220Speter klausler } else { 68264ab3302SCarolineConcatto return false; 68364ab3302SCarolineConcatto } 684d60a0220Speter klausler } 68564ab3302SCarolineConcatto 68627cf6ba1SPeter Klausler bool IsInitialized(const Symbol &symbol, bool ignoreDataStatements, 68727cf6ba1SPeter Klausler bool ignoreAllocatable, bool ignorePointer) { 688c4f67ea1SPeter Klausler if (!ignoreAllocatable && IsAllocatable(symbol)) { 689c4f67ea1SPeter Klausler return true; 690c4f67ea1SPeter Klausler } else if (!ignoreDataStatements && symbol.test(Symbol::Flag::InDataStmt)) { 691c4f67ea1SPeter Klausler return true; 692c4f67ea1SPeter Klausler } else if (HasDeclarationInitializer(symbol)) { 693a50bb84eSpeter klausler return true; 69427cf6ba1SPeter Klausler } else if (IsPointer(symbol)) { 69527cf6ba1SPeter Klausler return !ignorePointer; 69633c27f28SPeter Klausler } else if (IsNamedConstant(symbol)) { 697a50bb84eSpeter klausler return false; 698a50bb84eSpeter klausler } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 69970cbedcdSPeter Klausler if ((!object->isDummy() || IsIntentOut(symbol)) && object->type()) { 700d60a0220Speter klausler if (const auto *derived{object->type()->AsDerived()}) { 70127cf6ba1SPeter Klausler return derived->HasDefaultInitialization( 70227cf6ba1SPeter Klausler ignoreAllocatable, ignorePointer); 703d60a0220Speter klausler } 704a50bb84eSpeter klausler } 705a50bb84eSpeter klausler } 706a50bb84eSpeter klausler return false; 707a50bb84eSpeter klausler } 708a50bb84eSpeter klausler 709a48e4168Speter klausler bool IsDestructible(const Symbol &symbol, const Symbol *derivedTypeSymbol) { 710a48e4168Speter klausler if (IsAllocatable(symbol) || IsAutomatic(symbol)) { 711a48e4168Speter klausler return true; 712a48e4168Speter klausler } else if (IsNamedConstant(symbol) || IsFunctionResult(symbol) || 713a48e4168Speter klausler IsPointer(symbol)) { 714a48e4168Speter klausler return false; 715a48e4168Speter klausler } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 71670cbedcdSPeter Klausler if ((!object->isDummy() || IsIntentOut(symbol)) && object->type()) { 717a48e4168Speter klausler if (const auto *derived{object->type()->AsDerived()}) { 718a48e4168Speter klausler return &derived->typeSymbol() != derivedTypeSymbol && 719a48e4168Speter klausler derived->HasDestruction(); 720a48e4168Speter klausler } 721a48e4168Speter klausler } 722a48e4168Speter klausler } 723a48e4168Speter klausler return false; 724a48e4168Speter klausler } 725a48e4168Speter klausler 726e17e7173SPete Steinfeld bool HasIntrinsicTypeName(const Symbol &symbol) { 727e17e7173SPete Steinfeld std::string name{symbol.name().ToString()}; 728e17e7173SPete Steinfeld if (name == "doubleprecision") { 729e17e7173SPete Steinfeld return true; 730e17e7173SPete Steinfeld } else if (name == "derived") { 731e17e7173SPete Steinfeld return false; 732e17e7173SPete Steinfeld } else { 733e17e7173SPete Steinfeld for (int i{0}; i != common::TypeCategory_enumSize; ++i) { 734e17e7173SPete Steinfeld if (name == parser::ToLowerCaseLetters(EnumToString(TypeCategory{i}))) { 735e17e7173SPete Steinfeld return true; 736e17e7173SPete Steinfeld } 737e17e7173SPete Steinfeld } 738e17e7173SPete Steinfeld return false; 739e17e7173SPete Steinfeld } 740e17e7173SPete Steinfeld } 741e17e7173SPete Steinfeld 742c42f6314Speter klausler bool IsSeparateModuleProcedureInterface(const Symbol *symbol) { 743c42f6314Speter klausler if (symbol && symbol->attrs().test(Attr::MODULE)) { 744c42f6314Speter klausler if (auto *details{symbol->detailsIf<SubprogramDetails>()}) { 745c42f6314Speter klausler return details->isInterface(); 746c42f6314Speter klausler } 747c42f6314Speter klausler } 748c42f6314Speter klausler return false; 749c42f6314Speter klausler } 750c42f6314Speter klausler 751d84faa42SPeter Klausler SymbolVector FinalsForDerivedTypeInstantiation(const DerivedTypeSpec &spec) { 752d84faa42SPeter Klausler SymbolVector result; 753d84faa42SPeter Klausler const Symbol &typeSymbol{spec.typeSymbol()}; 754d84faa42SPeter Klausler if (const auto *derived{typeSymbol.detailsIf<DerivedTypeDetails>()}) { 755d84faa42SPeter Klausler for (const auto &pair : derived->finals()) { 756d84faa42SPeter Klausler const Symbol &subr{*pair.second}; 757d84faa42SPeter Klausler // Errors in FINAL subroutines are caught in CheckFinal 758d84faa42SPeter Klausler // in check-declarations.cpp. 759d84faa42SPeter Klausler if (const auto *subprog{subr.detailsIf<SubprogramDetails>()}; 760d84faa42SPeter Klausler subprog && subprog->dummyArgs().size() == 1) { 761d84faa42SPeter Klausler if (const Symbol * arg{subprog->dummyArgs()[0]}) { 762d84faa42SPeter Klausler if (const DeclTypeSpec * type{arg->GetType()}) { 763d84faa42SPeter Klausler if (type->category() == DeclTypeSpec::TypeDerived && 764d84faa42SPeter Klausler evaluate::AreSameDerivedType(spec, type->derivedTypeSpec())) { 765d84faa42SPeter Klausler result.emplace_back(subr); 766d84faa42SPeter Klausler } 767d84faa42SPeter Klausler } 768d84faa42SPeter Klausler } 769d84faa42SPeter Klausler } 770d84faa42SPeter Klausler } 771d84faa42SPeter Klausler } 772d84faa42SPeter Klausler return result; 773d84faa42SPeter Klausler } 774d84faa42SPeter Klausler 775e9a8ab00SPeter Klausler const Symbol *IsFinalizable(const Symbol &symbol, 776e9a8ab00SPeter Klausler std::set<const DerivedTypeSpec *> *inProgress, bool withImpureFinalizer) { 777e9a8ab00SPeter Klausler if (IsPointer(symbol) || evaluate::IsAssumedRank(symbol)) { 778e9a8ab00SPeter Klausler return nullptr; 77964ab3302SCarolineConcatto } 7804fede8bcSpeter klausler if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 7814fede8bcSpeter klausler if (object->isDummy() && !IsIntentOut(symbol)) { 782e9a8ab00SPeter Klausler return nullptr; 7834fede8bcSpeter klausler } 7844fede8bcSpeter klausler const DeclTypeSpec *type{object->type()}; 785e9a8ab00SPeter Klausler if (const DerivedTypeSpec * typeSpec{type ? type->AsDerived() : nullptr}) { 786e9a8ab00SPeter Klausler return IsFinalizable( 787e9a8ab00SPeter Klausler *typeSpec, inProgress, withImpureFinalizer, symbol.Rank()); 78864ab3302SCarolineConcatto } 789e9a8ab00SPeter Klausler } 790e9a8ab00SPeter Klausler return nullptr; 79164ab3302SCarolineConcatto } 79264ab3302SCarolineConcatto 793e9a8ab00SPeter Klausler const Symbol *IsFinalizable(const DerivedTypeSpec &derived, 794e9a8ab00SPeter Klausler std::set<const DerivedTypeSpec *> *inProgress, bool withImpureFinalizer, 795e9a8ab00SPeter Klausler std::optional<int> rank) { 796e9a8ab00SPeter Klausler const Symbol *elemental{nullptr}; 797e9a8ab00SPeter Klausler for (auto ref : FinalsForDerivedTypeInstantiation(derived)) { 798e9a8ab00SPeter Klausler const Symbol *symbol{&ref->GetUltimate()}; 799e9a8ab00SPeter Klausler if (const auto *binding{symbol->detailsIf<ProcBindingDetails>()}) { 800e9a8ab00SPeter Klausler symbol = &binding->symbol(); 80137b2e2b0Speter klausler } 802e9a8ab00SPeter Klausler if (const auto *proc{symbol->detailsIf<ProcEntityDetails>()}) { 803e9a8ab00SPeter Klausler symbol = proc->procInterface(); 804e9a8ab00SPeter Klausler } 805e9a8ab00SPeter Klausler if (!symbol) { 806e9a8ab00SPeter Klausler } else if (IsElementalProcedure(*symbol)) { 807e9a8ab00SPeter Klausler elemental = symbol; 808e9a8ab00SPeter Klausler } else { 809e9a8ab00SPeter Klausler if (rank) { 810e9a8ab00SPeter Klausler if (const SubprogramDetails * 811e9a8ab00SPeter Klausler subp{symbol->detailsIf<SubprogramDetails>()}) { 812e9a8ab00SPeter Klausler if (const auto &args{subp->dummyArgs()}; !args.empty() && 813e9a8ab00SPeter Klausler args.at(0) && !evaluate::IsAssumedRank(*args.at(0)) && 814e9a8ab00SPeter Klausler args.at(0)->Rank() != *rank) { 815e9a8ab00SPeter Klausler continue; // not a finalizer for this rank 816e9a8ab00SPeter Klausler } 817e9a8ab00SPeter Klausler } 818e9a8ab00SPeter Klausler } 819e9a8ab00SPeter Klausler if (!withImpureFinalizer || !IsPureProcedure(*symbol)) { 820e9a8ab00SPeter Klausler return symbol; 821e9a8ab00SPeter Klausler } 822e9a8ab00SPeter Klausler // Found non-elemental pure finalizer of matching rank, but still 823e9a8ab00SPeter Klausler // need to check components for an impure finalizer. 824e9a8ab00SPeter Klausler elemental = nullptr; 825e9a8ab00SPeter Klausler break; 826e9a8ab00SPeter Klausler } 827e9a8ab00SPeter Klausler } 828e9a8ab00SPeter Klausler if (elemental && (!withImpureFinalizer || !IsPureProcedure(*elemental))) { 829e9a8ab00SPeter Klausler return elemental; 830e9a8ab00SPeter Klausler } 831e9a8ab00SPeter Klausler // Check components (including ancestors) 83265f52904Speter klausler std::set<const DerivedTypeSpec *> basis; 83365f52904Speter klausler if (inProgress) { 83465f52904Speter klausler if (inProgress->find(&derived) != inProgress->end()) { 835e9a8ab00SPeter Klausler return nullptr; // don't loop on recursive type 83665f52904Speter klausler } 83765f52904Speter klausler } else { 83865f52904Speter klausler inProgress = &basis; 83965f52904Speter klausler } 84065f52904Speter klausler auto iterator{inProgress->insert(&derived).first}; 841e9a8ab00SPeter Klausler const Symbol *result{nullptr}; 842e9a8ab00SPeter Klausler for (const Symbol &component : PotentialComponentIterator{derived}) { 843e9a8ab00SPeter Klausler result = IsFinalizable(component, inProgress, withImpureFinalizer); 844e9a8ab00SPeter Klausler if (result) { 845e9a8ab00SPeter Klausler break; 846e9a8ab00SPeter Klausler } 847e9a8ab00SPeter Klausler } 84865f52904Speter klausler inProgress->erase(iterator); 84965f52904Speter klausler return result; 85064ab3302SCarolineConcatto } 85164ab3302SCarolineConcatto 852e9a8ab00SPeter Klausler static const Symbol *HasImpureFinal( 853e9a8ab00SPeter Klausler const DerivedTypeSpec &derived, std::optional<int> rank) { 854e9a8ab00SPeter Klausler return IsFinalizable(derived, nullptr, /*withImpureFinalizer=*/true, rank); 855e9a8ab00SPeter Klausler } 856e9a8ab00SPeter Klausler 8570c21377aSKelvin Li const Symbol *HasImpureFinal(const Symbol &original, std::optional<int> rank) { 858e9a8ab00SPeter Klausler const Symbol &symbol{ResolveAssociations(original)}; 859e9a8ab00SPeter Klausler if (symbol.has<ObjectEntityDetails>()) { 860e9a8ab00SPeter Klausler if (const DeclTypeSpec * symType{symbol.GetType()}) { 861e9a8ab00SPeter Klausler if (const DerivedTypeSpec * derived{symType->AsDerived()}) { 8620c21377aSKelvin Li if (evaluate::IsAssumedRank(symbol)) { 863e9a8ab00SPeter Klausler // finalizable assumed-rank not allowed (C839) 8640c21377aSKelvin Li return nullptr; 8650c21377aSKelvin Li } else { 8660c21377aSKelvin Li int actualRank{rank.value_or(symbol.Rank())}; 8670c21377aSKelvin Li return HasImpureFinal(*derived, actualRank); 8680c21377aSKelvin Li } 86937b2e2b0Speter klausler } 87064ab3302SCarolineConcatto } 871e9a8ab00SPeter Klausler } 872e9a8ab00SPeter Klausler return nullptr; 873d84faa42SPeter Klausler } 87464ab3302SCarolineConcatto 875710503fcSjeanPerier bool MayRequireFinalization(const DerivedTypeSpec &derived) { 876710503fcSjeanPerier return IsFinalizable(derived) || 87725822dc3SPeter Klausler FindPolymorphicAllocatablePotentialComponent(derived); 878710503fcSjeanPerier } 879710503fcSjeanPerier 880be66a2f6SSlava Zakharin bool HasAllocatableDirectComponent(const DerivedTypeSpec &derived) { 881be66a2f6SSlava Zakharin DirectComponentIterator directs{derived}; 882be66a2f6SSlava Zakharin return std::any_of(directs.begin(), directs.end(), IsAllocatable); 883be66a2f6SSlava Zakharin } 884be66a2f6SSlava Zakharin 88564ab3302SCarolineConcatto bool IsAssumedLengthCharacter(const Symbol &symbol) { 88664ab3302SCarolineConcatto if (const DeclTypeSpec * type{symbol.GetType()}) { 88764ab3302SCarolineConcatto return type->category() == DeclTypeSpec::Character && 88864ab3302SCarolineConcatto type->characterTypeSpec().length().isAssumed(); 88964ab3302SCarolineConcatto } else { 89064ab3302SCarolineConcatto return false; 89164ab3302SCarolineConcatto } 89264ab3302SCarolineConcatto } 89364ab3302SCarolineConcatto 89470f1b4b4SAnchu Rajendran bool IsInBlankCommon(const Symbol &symbol) { 8954171f80dSpeter klausler const Symbol *block{FindCommonBlockContaining(symbol)}; 8964171f80dSpeter klausler return block && block->name().empty(); 89770f1b4b4SAnchu Rajendran } 89870f1b4b4SAnchu Rajendran 899657aaf8bSPete Steinfeld // C722 and C723: For a function to be assumed length, it must be external and 900657aaf8bSPete Steinfeld // of CHARACTER type 901c42f6314Speter klausler bool IsExternal(const Symbol &symbol) { 90237b2e2b0Speter klausler return ClassifyProcedure(symbol) == ProcedureDefinitionClass::External; 90364ab3302SCarolineConcatto } 90464ab3302SCarolineConcatto 905d60a0220Speter klausler // Most scopes have no EQUIVALENCE, and this function is a fast no-op for them. 906d60a0220Speter klausler std::list<std::list<SymbolRef>> GetStorageAssociations(const Scope &scope) { 907d60a0220Speter klausler UnorderedSymbolSet distinct; 908d60a0220Speter klausler for (const EquivalenceSet &set : scope.equivalenceSets()) { 909d60a0220Speter klausler for (const EquivalenceObject &object : set) { 910d60a0220Speter klausler distinct.emplace(object.symbol); 911d60a0220Speter klausler } 912d60a0220Speter klausler } 913d60a0220Speter klausler // This set is ordered by ascending offsets, with ties broken by greatest 914d60a0220Speter klausler // size. A multiset is used here because multiple symbols may have the 915d60a0220Speter klausler // same offset and size; the symbols in the set, however, are distinct. 916d60a0220Speter klausler std::multiset<SymbolRef, SymbolOffsetCompare> associated; 917d60a0220Speter klausler for (SymbolRef ref : distinct) { 918d60a0220Speter klausler associated.emplace(*ref); 919d60a0220Speter klausler } 920d60a0220Speter klausler std::list<std::list<SymbolRef>> result; 921d60a0220Speter klausler std::size_t limit{0}; 922d60a0220Speter klausler const Symbol *currentCommon{nullptr}; 923d60a0220Speter klausler for (const Symbol &symbol : associated) { 924d60a0220Speter klausler const Symbol *thisCommon{FindCommonBlockContaining(symbol)}; 925d60a0220Speter klausler if (result.empty() || symbol.offset() >= limit || 926d60a0220Speter klausler thisCommon != currentCommon) { 927d60a0220Speter klausler // Start a new group 928d60a0220Speter klausler result.emplace_back(std::list<SymbolRef>{}); 929d60a0220Speter klausler limit = 0; 930d60a0220Speter klausler currentCommon = thisCommon; 931d60a0220Speter klausler } 932d60a0220Speter klausler result.back().emplace_back(symbol); 933d60a0220Speter klausler limit = std::max(limit, symbol.offset() + symbol.size()); 934d60a0220Speter klausler } 935d60a0220Speter klausler return result; 936d60a0220Speter klausler } 937d60a0220Speter klausler 93837b2e2b0Speter klausler bool IsModuleProcedure(const Symbol &symbol) { 93937b2e2b0Speter klausler return ClassifyProcedure(symbol) == ProcedureDefinitionClass::Module; 94037b2e2b0Speter klausler } 94164ab3302SCarolineConcatto 94264ab3302SCarolineConcatto class ImageControlStmtHelper { 943eb6cd7feSPeter Klausler using ImageControlStmts = 944eb6cd7feSPeter Klausler std::variant<parser::ChangeTeamConstruct, parser::CriticalConstruct, 945eb6cd7feSPeter Klausler parser::EventPostStmt, parser::EventWaitStmt, parser::FormTeamStmt, 946eb6cd7feSPeter Klausler parser::LockStmt, parser::SyncAllStmt, parser::SyncImagesStmt, 947eb6cd7feSPeter Klausler parser::SyncMemoryStmt, parser::SyncTeamStmt, parser::UnlockStmt>; 94864ab3302SCarolineConcatto 94964ab3302SCarolineConcatto public: 95064ab3302SCarolineConcatto template <typename T> bool operator()(const T &) { 95164ab3302SCarolineConcatto return common::HasMember<T, ImageControlStmts>; 95264ab3302SCarolineConcatto } 95364ab3302SCarolineConcatto template <typename T> bool operator()(const common::Indirection<T> &x) { 95464ab3302SCarolineConcatto return (*this)(x.value()); 95564ab3302SCarolineConcatto } 9561b56f273SPeter Klausler template <typename A> bool operator()(const parser::Statement<A> &x) { 9571b56f273SPeter Klausler return (*this)(x.statement); 9581b56f273SPeter Klausler } 95964ab3302SCarolineConcatto bool operator()(const parser::AllocateStmt &stmt) { 96064ab3302SCarolineConcatto const auto &allocationList{std::get<std::list<parser::Allocation>>(stmt.t)}; 96164ab3302SCarolineConcatto for (const auto &allocation : allocationList) { 96264ab3302SCarolineConcatto const auto &allocateObject{ 96364ab3302SCarolineConcatto std::get<parser::AllocateObject>(allocation.t)}; 96464ab3302SCarolineConcatto if (IsCoarrayObject(allocateObject)) { 96564ab3302SCarolineConcatto return true; 96664ab3302SCarolineConcatto } 96764ab3302SCarolineConcatto } 96864ab3302SCarolineConcatto return false; 96964ab3302SCarolineConcatto } 97064ab3302SCarolineConcatto bool operator()(const parser::DeallocateStmt &stmt) { 97164ab3302SCarolineConcatto const auto &allocateObjectList{ 97264ab3302SCarolineConcatto std::get<std::list<parser::AllocateObject>>(stmt.t)}; 97364ab3302SCarolineConcatto for (const auto &allocateObject : allocateObjectList) { 97464ab3302SCarolineConcatto if (IsCoarrayObject(allocateObject)) { 97564ab3302SCarolineConcatto return true; 97664ab3302SCarolineConcatto } 97764ab3302SCarolineConcatto } 97864ab3302SCarolineConcatto return false; 97964ab3302SCarolineConcatto } 98064ab3302SCarolineConcatto bool operator()(const parser::CallStmt &stmt) { 98164ab3302SCarolineConcatto const auto &procedureDesignator{ 9824ad72793SPeter Klausler std::get<parser::ProcedureDesignator>(stmt.call.t)}; 98364ab3302SCarolineConcatto if (auto *name{std::get_if<parser::Name>(&procedureDesignator.u)}) { 98464ab3302SCarolineConcatto // TODO: also ensure that the procedure is, in fact, an intrinsic 98564ab3302SCarolineConcatto if (name->source == "move_alloc") { 9864ad72793SPeter Klausler const auto &args{ 9874ad72793SPeter Klausler std::get<std::list<parser::ActualArgSpec>>(stmt.call.t)}; 98864ab3302SCarolineConcatto if (!args.empty()) { 98964ab3302SCarolineConcatto const parser::ActualArg &actualArg{ 99064ab3302SCarolineConcatto std::get<parser::ActualArg>(args.front().t)}; 99164ab3302SCarolineConcatto if (const auto *argExpr{ 99264ab3302SCarolineConcatto std::get_if<common::Indirection<parser::Expr>>( 99364ab3302SCarolineConcatto &actualArg.u)}) { 99464ab3302SCarolineConcatto return HasCoarray(argExpr->value()); 99564ab3302SCarolineConcatto } 99664ab3302SCarolineConcatto } 99764ab3302SCarolineConcatto } 99864ab3302SCarolineConcatto } 99964ab3302SCarolineConcatto return false; 100064ab3302SCarolineConcatto } 1001eb6cd7feSPeter Klausler bool operator()(const parser::StopStmt &stmt) { 1002eb6cd7feSPeter Klausler // STOP is an image control statement; ERROR STOP is not 1003eb6cd7feSPeter Klausler return std::get<parser::StopStmt::Kind>(stmt.t) == 1004eb6cd7feSPeter Klausler parser::StopStmt::Kind::Stop; 1005eb6cd7feSPeter Klausler } 10061b56f273SPeter Klausler bool operator()(const parser::IfStmt &stmt) { 10071b56f273SPeter Klausler return (*this)( 10081b56f273SPeter Klausler std::get<parser::UnlabeledStatement<parser::ActionStmt>>(stmt.t) 10091b56f273SPeter Klausler .statement); 10101b56f273SPeter Klausler } 10111b56f273SPeter Klausler bool operator()(const parser::ActionStmt &stmt) { 10121b56f273SPeter Klausler return common::visit(*this, stmt.u); 101364ab3302SCarolineConcatto } 101464ab3302SCarolineConcatto 101564ab3302SCarolineConcatto private: 101664ab3302SCarolineConcatto bool IsCoarrayObject(const parser::AllocateObject &allocateObject) { 101764ab3302SCarolineConcatto const parser::Name &name{GetLastName(allocateObject)}; 10181ee6f7adSPeter Klausler return name.symbol && evaluate::IsCoarray(*name.symbol); 101964ab3302SCarolineConcatto } 102064ab3302SCarolineConcatto }; 102164ab3302SCarolineConcatto 102264ab3302SCarolineConcatto bool IsImageControlStmt(const parser::ExecutableConstruct &construct) { 1023cd03e96fSPeter Klausler return common::visit(ImageControlStmtHelper{}, construct.u); 102464ab3302SCarolineConcatto } 102564ab3302SCarolineConcatto 102664ab3302SCarolineConcatto std::optional<parser::MessageFixedText> GetImageControlStmtCoarrayMsg( 102764ab3302SCarolineConcatto const parser::ExecutableConstruct &construct) { 102864ab3302SCarolineConcatto if (const auto *actionStmt{ 102964ab3302SCarolineConcatto std::get_if<parser::Statement<parser::ActionStmt>>(&construct.u)}) { 1030cd03e96fSPeter Klausler return common::visit( 103164ab3302SCarolineConcatto common::visitors{ 103264ab3302SCarolineConcatto [](const common::Indirection<parser::AllocateStmt> &) 103364ab3302SCarolineConcatto -> std::optional<parser::MessageFixedText> { 103464ab3302SCarolineConcatto return "ALLOCATE of a coarray is an image control" 103564ab3302SCarolineConcatto " statement"_en_US; 103664ab3302SCarolineConcatto }, 103764ab3302SCarolineConcatto [](const common::Indirection<parser::DeallocateStmt> &) 103864ab3302SCarolineConcatto -> std::optional<parser::MessageFixedText> { 103964ab3302SCarolineConcatto return "DEALLOCATE of a coarray is an image control" 104064ab3302SCarolineConcatto " statement"_en_US; 104164ab3302SCarolineConcatto }, 104264ab3302SCarolineConcatto [](const common::Indirection<parser::CallStmt> &) 104364ab3302SCarolineConcatto -> std::optional<parser::MessageFixedText> { 104464ab3302SCarolineConcatto return "MOVE_ALLOC of a coarray is an image control" 104564ab3302SCarolineConcatto " statement "_en_US; 104664ab3302SCarolineConcatto }, 104764ab3302SCarolineConcatto [](const auto &) -> std::optional<parser::MessageFixedText> { 104864ab3302SCarolineConcatto return std::nullopt; 104964ab3302SCarolineConcatto }, 105064ab3302SCarolineConcatto }, 105164ab3302SCarolineConcatto actionStmt->statement.u); 105264ab3302SCarolineConcatto } 105364ab3302SCarolineConcatto return std::nullopt; 105464ab3302SCarolineConcatto } 105564ab3302SCarolineConcatto 105664ab3302SCarolineConcatto parser::CharBlock GetImageControlStmtLocation( 105764ab3302SCarolineConcatto const parser::ExecutableConstruct &executableConstruct) { 1058cd03e96fSPeter Klausler return common::visit( 105964ab3302SCarolineConcatto common::visitors{ 106064ab3302SCarolineConcatto [](const common::Indirection<parser::ChangeTeamConstruct> 106164ab3302SCarolineConcatto &construct) { 106264ab3302SCarolineConcatto return std::get<parser::Statement<parser::ChangeTeamStmt>>( 106364ab3302SCarolineConcatto construct.value().t) 106464ab3302SCarolineConcatto .source; 106564ab3302SCarolineConcatto }, 106664ab3302SCarolineConcatto [](const common::Indirection<parser::CriticalConstruct> &construct) { 106764ab3302SCarolineConcatto return std::get<parser::Statement<parser::CriticalStmt>>( 106864ab3302SCarolineConcatto construct.value().t) 106964ab3302SCarolineConcatto .source; 107064ab3302SCarolineConcatto }, 107164ab3302SCarolineConcatto [](const parser::Statement<parser::ActionStmt> &actionStmt) { 107264ab3302SCarolineConcatto return actionStmt.source; 107364ab3302SCarolineConcatto }, 107464ab3302SCarolineConcatto [](const auto &) { return parser::CharBlock{}; }, 107564ab3302SCarolineConcatto }, 107664ab3302SCarolineConcatto executableConstruct.u); 107764ab3302SCarolineConcatto } 107864ab3302SCarolineConcatto 107964ab3302SCarolineConcatto bool HasCoarray(const parser::Expr &expression) { 10807e225423SPeter Klausler if (const auto *expr{GetExpr(nullptr, expression)}) { 108164ab3302SCarolineConcatto for (const Symbol &symbol : evaluate::CollectSymbols(*expr)) { 10821ee6f7adSPeter Klausler if (evaluate::IsCoarray(symbol)) { 108364ab3302SCarolineConcatto return true; 108464ab3302SCarolineConcatto } 108564ab3302SCarolineConcatto } 108664ab3302SCarolineConcatto } 108764ab3302SCarolineConcatto return false; 108864ab3302SCarolineConcatto } 108964ab3302SCarolineConcatto 10903eef2c2bSValentin Clement bool IsAssumedType(const Symbol &symbol) { 10913eef2c2bSValentin Clement if (const DeclTypeSpec * type{symbol.GetType()}) { 10923eef2c2bSValentin Clement return type->IsAssumedType(); 10933eef2c2bSValentin Clement } 10943eef2c2bSValentin Clement return false; 10953eef2c2bSValentin Clement } 10963eef2c2bSValentin Clement 109764ab3302SCarolineConcatto bool IsPolymorphic(const Symbol &symbol) { 109864ab3302SCarolineConcatto if (const DeclTypeSpec * type{symbol.GetType()}) { 109964ab3302SCarolineConcatto return type->IsPolymorphic(); 110064ab3302SCarolineConcatto } 110164ab3302SCarolineConcatto return false; 110264ab3302SCarolineConcatto } 110364ab3302SCarolineConcatto 110497492fd1SValentin Clement bool IsUnlimitedPolymorphic(const Symbol &symbol) { 110597492fd1SValentin Clement if (const DeclTypeSpec * type{symbol.GetType()}) { 110697492fd1SValentin Clement return type->IsUnlimitedPolymorphic(); 110797492fd1SValentin Clement } 110897492fd1SValentin Clement return false; 110997492fd1SValentin Clement } 111097492fd1SValentin Clement 111164ab3302SCarolineConcatto bool IsPolymorphicAllocatable(const Symbol &symbol) { 111264ab3302SCarolineConcatto return IsAllocatable(symbol) && IsPolymorphic(symbol); 111364ab3302SCarolineConcatto } 111464ab3302SCarolineConcatto 111527f71807SPeter Klausler const Scope *FindCUDADeviceContext(const Scope *scope) { 111627f71807SPeter Klausler return !scope ? nullptr : FindScopeContaining(*scope, [](const Scope &s) { 111727f71807SPeter Klausler return IsCUDADeviceContext(&s); 111827f71807SPeter Klausler }); 111927f71807SPeter Klausler } 112027f71807SPeter Klausler 112127f71807SPeter Klausler std::optional<common::CUDADataAttr> GetCUDADataAttr(const Symbol *symbol) { 112227f71807SPeter Klausler const auto *object{ 112327f71807SPeter Klausler symbol ? symbol->detailsIf<ObjectEntityDetails>() : nullptr}; 112427f71807SPeter Klausler return object ? object->cudaDataAttr() : std::nullopt; 112527f71807SPeter Klausler } 112627f71807SPeter Klausler 1127ecf264d3SPeter Klausler bool IsAccessible(const Symbol &original, const Scope &scope) { 1128ecf264d3SPeter Klausler const Symbol &ultimate{original.GetUltimate()}; 1129ecf264d3SPeter Klausler if (ultimate.attrs().test(Attr::PRIVATE)) { 1130ecf264d3SPeter Klausler const Scope *module{FindModuleContaining(ultimate.owner())}; 1131ecf264d3SPeter Klausler return !module || module->Contains(scope); 1132ecf264d3SPeter Klausler } else { 1133ecf264d3SPeter Klausler return true; 1134ecf264d3SPeter Klausler } 1135ecf264d3SPeter Klausler } 1136ecf264d3SPeter Klausler 1137d7a1351bSPeter Klausler std::optional<parser::MessageFormattedText> CheckAccessibleSymbol( 113847452b96STim Keith const Scope &scope, const Symbol &symbol) { 1139ecf264d3SPeter Klausler if (IsAccessible(symbol, scope)) { 1140ecf264d3SPeter Klausler return std::nullopt; 1141ecf264d3SPeter Klausler } else if (FindModuleFileContaining(scope)) { 11421bd083b5Speter klausler // Don't enforce component accessibility checks in module files; 11431bd083b5Speter klausler // there may be forward-substituted named constants of derived type 11441bd083b5Speter klausler // whose structure constructors reference private components. 1145ecf264d3SPeter Klausler return std::nullopt; 1146ecf264d3SPeter Klausler } else { 114747452b96STim Keith return parser::MessageFormattedText{ 1148d7a1351bSPeter Klausler "PRIVATE name '%s' is only accessible within module '%s'"_err_en_US, 1149ecf264d3SPeter Klausler symbol.name(), 1150ecf264d3SPeter Klausler DEREF(FindModuleContaining(symbol.owner())).GetName().value()}; 115147452b96STim Keith } 115247452b96STim Keith } 115347452b96STim Keith 1154539a6b50SPeter Klausler SymbolVector OrderParameterNames(const Symbol &typeSymbol) { 1155539a6b50SPeter Klausler SymbolVector result; 115664ab3302SCarolineConcatto if (const DerivedTypeSpec * spec{typeSymbol.GetParentTypeSpec()}) { 115764ab3302SCarolineConcatto result = OrderParameterNames(spec->typeSymbol()); 115864ab3302SCarolineConcatto } 1159539a6b50SPeter Klausler const auto ¶mNames{typeSymbol.get<DerivedTypeDetails>().paramNameOrder()}; 116064ab3302SCarolineConcatto result.insert(result.end(), paramNames.begin(), paramNames.end()); 116164ab3302SCarolineConcatto return result; 116264ab3302SCarolineConcatto } 116364ab3302SCarolineConcatto 116464ab3302SCarolineConcatto SymbolVector OrderParameterDeclarations(const Symbol &typeSymbol) { 116564ab3302SCarolineConcatto SymbolVector result; 116664ab3302SCarolineConcatto if (const DerivedTypeSpec * spec{typeSymbol.GetParentTypeSpec()}) { 116764ab3302SCarolineConcatto result = OrderParameterDeclarations(spec->typeSymbol()); 116864ab3302SCarolineConcatto } 1169539a6b50SPeter Klausler const auto ¶mDecls{typeSymbol.get<DerivedTypeDetails>().paramDeclOrder()}; 117064ab3302SCarolineConcatto result.insert(result.end(), paramDecls.begin(), paramDecls.end()); 117164ab3302SCarolineConcatto return result; 117264ab3302SCarolineConcatto } 117364ab3302SCarolineConcatto 11745091671cSpeter klausler const DeclTypeSpec &FindOrInstantiateDerivedType( 11755091671cSpeter klausler Scope &scope, DerivedTypeSpec &&spec, DeclTypeSpec::Category category) { 11765091671cSpeter klausler spec.EvaluateParameters(scope.context()); 117764ab3302SCarolineConcatto if (const DeclTypeSpec * 117864ab3302SCarolineConcatto type{scope.FindInstantiatedDerivedType(spec, category)}) { 117964ab3302SCarolineConcatto return *type; 118064ab3302SCarolineConcatto } 118164ab3302SCarolineConcatto // Create a new instantiation of this parameterized derived type 118264ab3302SCarolineConcatto // for this particular distinct set of actual parameter values. 118364ab3302SCarolineConcatto DeclTypeSpec &type{scope.MakeDerivedType(category, std::move(spec))}; 11845091671cSpeter klausler type.derivedTypeSpec().Instantiate(scope); 118564ab3302SCarolineConcatto return type; 118664ab3302SCarolineConcatto } 118764ab3302SCarolineConcatto 1188c42f6314Speter klausler const Symbol *FindSeparateModuleSubprogramInterface(const Symbol *proc) { 1189c42f6314Speter klausler if (proc) { 119039686557SPeter Klausler if (const auto *subprogram{proc->detailsIf<SubprogramDetails>()}) { 119139686557SPeter Klausler if (const Symbol * iface{subprogram->moduleInterface()}) { 1192c42f6314Speter klausler return iface; 1193c42f6314Speter klausler } 1194c42f6314Speter klausler } 1195c42f6314Speter klausler } 1196c42f6314Speter klausler return nullptr; 1197c42f6314Speter klausler } 1198c42f6314Speter klausler 119937b2e2b0Speter klausler ProcedureDefinitionClass ClassifyProcedure(const Symbol &symbol) { // 15.2.2 120037b2e2b0Speter klausler const Symbol &ultimate{symbol.GetUltimate()}; 1201cfd474e0SPeter Klausler if (!IsProcedure(ultimate)) { 1202cfd474e0SPeter Klausler return ProcedureDefinitionClass::None; 1203cfd474e0SPeter Klausler } else if (ultimate.attrs().test(Attr::INTRINSIC)) { 120437b2e2b0Speter klausler return ProcedureDefinitionClass::Intrinsic; 12053077d614SPeter Klausler } else if (IsDummy(ultimate)) { 12063077d614SPeter Klausler return ProcedureDefinitionClass::Dummy; 12073077d614SPeter Klausler } else if (IsProcedurePointer(symbol)) { 12083077d614SPeter Klausler return ProcedureDefinitionClass::Pointer; 120937b2e2b0Speter klausler } else if (ultimate.attrs().test(Attr::EXTERNAL)) { 121037b2e2b0Speter klausler return ProcedureDefinitionClass::External; 12113b7b7fa7SPeter Klausler } else if (const auto *nameDetails{ 12123b7b7fa7SPeter Klausler ultimate.detailsIf<SubprogramNameDetails>()}) { 12133b7b7fa7SPeter Klausler switch (nameDetails->kind()) { 12143b7b7fa7SPeter Klausler case SubprogramKind::Module: 12153b7b7fa7SPeter Klausler return ProcedureDefinitionClass::Module; 12163b7b7fa7SPeter Klausler case SubprogramKind::Internal: 12173b7b7fa7SPeter Klausler return ProcedureDefinitionClass::Internal; 12183b7b7fa7SPeter Klausler } 121937b2e2b0Speter klausler } else if (const Symbol * subp{FindSubprogram(symbol)}) { 122037b2e2b0Speter klausler if (const auto *subpDetails{subp->detailsIf<SubprogramDetails>()}) { 122137b2e2b0Speter klausler if (subpDetails->stmtFunction()) { 122237b2e2b0Speter klausler return ProcedureDefinitionClass::StatementFunction; 122337b2e2b0Speter klausler } 122437b2e2b0Speter klausler } 122537b2e2b0Speter klausler switch (ultimate.owner().kind()) { 122637b2e2b0Speter klausler case Scope::Kind::Global: 122752a1346bSPeter Klausler case Scope::Kind::IntrinsicModules: 122837b2e2b0Speter klausler return ProcedureDefinitionClass::External; 122937b2e2b0Speter klausler case Scope::Kind::Module: 123037b2e2b0Speter klausler return ProcedureDefinitionClass::Module; 123137b2e2b0Speter klausler case Scope::Kind::MainProgram: 123237b2e2b0Speter klausler case Scope::Kind::Subprogram: 123337b2e2b0Speter klausler return ProcedureDefinitionClass::Internal; 123437b2e2b0Speter klausler default: 123537b2e2b0Speter klausler break; 123637b2e2b0Speter klausler } 123737b2e2b0Speter klausler } 123837b2e2b0Speter klausler return ProcedureDefinitionClass::None; 123937b2e2b0Speter klausler } 124037b2e2b0Speter klausler 124164ab3302SCarolineConcatto // ComponentIterator implementation 124264ab3302SCarolineConcatto 124364ab3302SCarolineConcatto template <ComponentKind componentKind> 124464ab3302SCarolineConcatto typename ComponentIterator<componentKind>::const_iterator 124564ab3302SCarolineConcatto ComponentIterator<componentKind>::const_iterator::Create( 124664ab3302SCarolineConcatto const DerivedTypeSpec &derived) { 124764ab3302SCarolineConcatto const_iterator it{}; 124864ab3302SCarolineConcatto it.componentPath_.emplace_back(derived); 124964ab3302SCarolineConcatto it.Increment(); // cue up first relevant component, if any 125064ab3302SCarolineConcatto return it; 125164ab3302SCarolineConcatto } 125264ab3302SCarolineConcatto 125364ab3302SCarolineConcatto template <ComponentKind componentKind> 125464ab3302SCarolineConcatto const DerivedTypeSpec * 125564ab3302SCarolineConcatto ComponentIterator<componentKind>::const_iterator::PlanComponentTraversal( 125664ab3302SCarolineConcatto const Symbol &component) const { 125764ab3302SCarolineConcatto if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) { 125864ab3302SCarolineConcatto if (const DeclTypeSpec * type{details->type()}) { 125964ab3302SCarolineConcatto if (const auto *derived{type->AsDerived()}) { 126064ab3302SCarolineConcatto bool traverse{false}; 126164ab3302SCarolineConcatto if constexpr (componentKind == ComponentKind::Ordered) { 126264ab3302SCarolineConcatto // Order Component (only visit parents) 126364ab3302SCarolineConcatto traverse = component.test(Symbol::Flag::ParentComp); 126464ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Direct) { 1265031b4e5eSPeter Klausler traverse = !IsAllocatableOrObjectPointer(&component); 126664ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Ultimate) { 1267031b4e5eSPeter Klausler traverse = !IsAllocatableOrObjectPointer(&component); 126864ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Potential) { 126964ab3302SCarolineConcatto traverse = !IsPointer(component); 127064ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Scope) { 1271031b4e5eSPeter Klausler traverse = !IsAllocatableOrObjectPointer(&component); 1272962863d9SPeter Klausler } else if constexpr (componentKind == 1273962863d9SPeter Klausler ComponentKind::PotentialAndPointer) { 1274962863d9SPeter Klausler traverse = !IsPointer(component); 127564ab3302SCarolineConcatto } 127664ab3302SCarolineConcatto if (traverse) { 127764ab3302SCarolineConcatto const Symbol &newTypeSymbol{derived->typeSymbol()}; 127864ab3302SCarolineConcatto // Avoid infinite loop if the type is already part of the types 127964ab3302SCarolineConcatto // being visited. It is possible to have "loops in type" because 128064ab3302SCarolineConcatto // C744 does not forbid to use not yet declared type for 128164ab3302SCarolineConcatto // ALLOCATABLE or POINTER components. 128264ab3302SCarolineConcatto for (const auto &node : componentPath_) { 128364ab3302SCarolineConcatto if (&newTypeSymbol == &node.GetTypeSymbol()) { 128464ab3302SCarolineConcatto return nullptr; 128564ab3302SCarolineConcatto } 128664ab3302SCarolineConcatto } 128764ab3302SCarolineConcatto return derived; 128864ab3302SCarolineConcatto } 128964ab3302SCarolineConcatto } 129064ab3302SCarolineConcatto } // intrinsic & unlimited polymorphic not traversable 129164ab3302SCarolineConcatto } 129264ab3302SCarolineConcatto return nullptr; 129364ab3302SCarolineConcatto } 129464ab3302SCarolineConcatto 129564ab3302SCarolineConcatto template <ComponentKind componentKind> 129664ab3302SCarolineConcatto static bool StopAtComponentPre(const Symbol &component) { 129764ab3302SCarolineConcatto if constexpr (componentKind == ComponentKind::Ordered) { 129864ab3302SCarolineConcatto // Parent components need to be iterated upon after their 129964ab3302SCarolineConcatto // sub-components in structure constructor analysis. 130064ab3302SCarolineConcatto return !component.test(Symbol::Flag::ParentComp); 130164ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Direct) { 130264ab3302SCarolineConcatto return true; 130364ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Ultimate) { 130464ab3302SCarolineConcatto return component.has<ProcEntityDetails>() || 1305031b4e5eSPeter Klausler IsAllocatableOrObjectPointer(&component) || 1306710503fcSjeanPerier (component.has<ObjectEntityDetails>() && 1307710503fcSjeanPerier component.get<ObjectEntityDetails>().type() && 130864ab3302SCarolineConcatto component.get<ObjectEntityDetails>().type()->AsIntrinsic()); 130964ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Potential) { 131064ab3302SCarolineConcatto return !IsPointer(component); 1311962863d9SPeter Klausler } else if constexpr (componentKind == ComponentKind::PotentialAndPointer) { 1312962863d9SPeter Klausler return true; 1313f92f7752SPeter Klausler } else { 1314f92f7752SPeter Klausler DIE("unexpected ComponentKind"); 131564ab3302SCarolineConcatto } 131664ab3302SCarolineConcatto } 131764ab3302SCarolineConcatto 131864ab3302SCarolineConcatto template <ComponentKind componentKind> 131964ab3302SCarolineConcatto static bool StopAtComponentPost(const Symbol &component) { 132064ab3302SCarolineConcatto return componentKind == ComponentKind::Ordered && 132164ab3302SCarolineConcatto component.test(Symbol::Flag::ParentComp); 132264ab3302SCarolineConcatto } 132364ab3302SCarolineConcatto 132464ab3302SCarolineConcatto template <ComponentKind componentKind> 132564ab3302SCarolineConcatto void ComponentIterator<componentKind>::const_iterator::Increment() { 132664ab3302SCarolineConcatto while (!componentPath_.empty()) { 132764ab3302SCarolineConcatto ComponentPathNode &deepest{componentPath_.back()}; 132864ab3302SCarolineConcatto if (deepest.component()) { 132964ab3302SCarolineConcatto if (!deepest.descended()) { 133064ab3302SCarolineConcatto deepest.set_descended(true); 133164ab3302SCarolineConcatto if (const DerivedTypeSpec * 133264ab3302SCarolineConcatto derived{PlanComponentTraversal(*deepest.component())}) { 133364ab3302SCarolineConcatto componentPath_.emplace_back(*derived); 133464ab3302SCarolineConcatto continue; 133564ab3302SCarolineConcatto } 133664ab3302SCarolineConcatto } else if (!deepest.visited()) { 133764ab3302SCarolineConcatto deepest.set_visited(true); 133864ab3302SCarolineConcatto return; // this is the next component to visit, after descending 133964ab3302SCarolineConcatto } 134064ab3302SCarolineConcatto } 134164ab3302SCarolineConcatto auto &nameIterator{deepest.nameIterator()}; 134264ab3302SCarolineConcatto if (nameIterator == deepest.nameEnd()) { 134364ab3302SCarolineConcatto componentPath_.pop_back(); 134464ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Scope) { 134564ab3302SCarolineConcatto deepest.set_component(*nameIterator++->second); 134664ab3302SCarolineConcatto deepest.set_descended(false); 134764ab3302SCarolineConcatto deepest.set_visited(true); 134864ab3302SCarolineConcatto return; // this is the next component to visit, before descending 134964ab3302SCarolineConcatto } else { 135064ab3302SCarolineConcatto const Scope &scope{deepest.GetScope()}; 135164ab3302SCarolineConcatto auto scopeIter{scope.find(*nameIterator++)}; 135264ab3302SCarolineConcatto if (scopeIter != scope.cend()) { 135364ab3302SCarolineConcatto const Symbol &component{*scopeIter->second}; 135464ab3302SCarolineConcatto deepest.set_component(component); 135564ab3302SCarolineConcatto deepest.set_descended(false); 135664ab3302SCarolineConcatto if (StopAtComponentPre<componentKind>(component)) { 135764ab3302SCarolineConcatto deepest.set_visited(true); 135864ab3302SCarolineConcatto return; // this is the next component to visit, before descending 135964ab3302SCarolineConcatto } else { 136064ab3302SCarolineConcatto deepest.set_visited(!StopAtComponentPost<componentKind>(component)); 136164ab3302SCarolineConcatto } 136264ab3302SCarolineConcatto } 136364ab3302SCarolineConcatto } 136464ab3302SCarolineConcatto } 136564ab3302SCarolineConcatto } 136664ab3302SCarolineConcatto 136764ab3302SCarolineConcatto template <ComponentKind componentKind> 1368*2625510eSPeter Klausler SymbolVector 1369*2625510eSPeter Klausler ComponentIterator<componentKind>::const_iterator::GetComponentPath() const { 1370*2625510eSPeter Klausler SymbolVector result; 1371*2625510eSPeter Klausler for (const auto &node : componentPath_) { 1372*2625510eSPeter Klausler result.push_back(DEREF(node.component())); 1373*2625510eSPeter Klausler } 1374*2625510eSPeter Klausler return result; 1375*2625510eSPeter Klausler } 1376*2625510eSPeter Klausler 1377*2625510eSPeter Klausler template <ComponentKind componentKind> 137864ab3302SCarolineConcatto std::string 137964ab3302SCarolineConcatto ComponentIterator<componentKind>::const_iterator::BuildResultDesignatorName() 138064ab3302SCarolineConcatto const { 1381a8c294d6SKazu Hirata std::string designator; 1382*2625510eSPeter Klausler for (const Symbol &component : GetComponentPath()) { 1383*2625510eSPeter Klausler designator += "%"s + component.name().ToString(); 138464ab3302SCarolineConcatto } 138564ab3302SCarolineConcatto return designator; 138664ab3302SCarolineConcatto } 138764ab3302SCarolineConcatto 138864ab3302SCarolineConcatto template class ComponentIterator<ComponentKind::Ordered>; 138964ab3302SCarolineConcatto template class ComponentIterator<ComponentKind::Direct>; 139064ab3302SCarolineConcatto template class ComponentIterator<ComponentKind::Ultimate>; 139164ab3302SCarolineConcatto template class ComponentIterator<ComponentKind::Potential>; 139264ab3302SCarolineConcatto template class ComponentIterator<ComponentKind::Scope>; 1393962863d9SPeter Klausler template class ComponentIterator<ComponentKind::PotentialAndPointer>; 139464ab3302SCarolineConcatto 139564ab3302SCarolineConcatto UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent( 139664ab3302SCarolineConcatto const DerivedTypeSpec &derived) { 139764ab3302SCarolineConcatto UltimateComponentIterator ultimates{derived}; 13981ee6f7adSPeter Klausler return std::find_if(ultimates.begin(), ultimates.end(), 13991ee6f7adSPeter Klausler [](const Symbol &symbol) { return evaluate::IsCoarray(symbol); }); 140064ab3302SCarolineConcatto } 140164ab3302SCarolineConcatto 140264ab3302SCarolineConcatto UltimateComponentIterator::const_iterator FindPointerUltimateComponent( 140364ab3302SCarolineConcatto const DerivedTypeSpec &derived) { 140464ab3302SCarolineConcatto UltimateComponentIterator ultimates{derived}; 140564ab3302SCarolineConcatto return std::find_if(ultimates.begin(), ultimates.end(), IsPointer); 140664ab3302SCarolineConcatto } 140764ab3302SCarolineConcatto 140864ab3302SCarolineConcatto PotentialComponentIterator::const_iterator FindEventOrLockPotentialComponent( 1409*2625510eSPeter Klausler const DerivedTypeSpec &derived, bool ignoreCoarrays) { 141064ab3302SCarolineConcatto PotentialComponentIterator potentials{derived}; 1411*2625510eSPeter Klausler auto iter{potentials.begin()}; 1412*2625510eSPeter Klausler for (auto end{potentials.end()}; iter != end; ++iter) { 1413*2625510eSPeter Klausler const Symbol &component{*iter}; 1414*2625510eSPeter Klausler if (const auto *object{component.detailsIf<ObjectEntityDetails>()}) { 1415*2625510eSPeter Klausler if (const DeclTypeSpec * type{object->type()}) { 1416*2625510eSPeter Klausler if (IsEventTypeOrLockType(type->AsDerived())) { 1417*2625510eSPeter Klausler if (!ignoreCoarrays) { 1418*2625510eSPeter Klausler break; // found one 141964ab3302SCarolineConcatto } 1420*2625510eSPeter Klausler auto path{iter.GetComponentPath()}; 1421*2625510eSPeter Klausler path.pop_back(); 1422*2625510eSPeter Klausler if (std::find_if(path.begin(), path.end(), [](const Symbol &sym) { 1423*2625510eSPeter Klausler return evaluate::IsCoarray(sym); 1424*2625510eSPeter Klausler }) == path.end()) { 1425*2625510eSPeter Klausler break; // found one not in a coarray 1426*2625510eSPeter Klausler } 1427*2625510eSPeter Klausler } 1428*2625510eSPeter Klausler } 1429*2625510eSPeter Klausler } 1430*2625510eSPeter Klausler } 1431*2625510eSPeter Klausler return iter; 143264ab3302SCarolineConcatto } 143364ab3302SCarolineConcatto 143464ab3302SCarolineConcatto UltimateComponentIterator::const_iterator FindAllocatableUltimateComponent( 143564ab3302SCarolineConcatto const DerivedTypeSpec &derived) { 143664ab3302SCarolineConcatto UltimateComponentIterator ultimates{derived}; 143764ab3302SCarolineConcatto return std::find_if(ultimates.begin(), ultimates.end(), IsAllocatable); 143864ab3302SCarolineConcatto } 143964ab3302SCarolineConcatto 144019d86426SPeter Klausler DirectComponentIterator::const_iterator FindAllocatableOrPointerDirectComponent( 144119d86426SPeter Klausler const DerivedTypeSpec &derived) { 144219d86426SPeter Klausler DirectComponentIterator directs{derived}; 144319d86426SPeter Klausler return std::find_if(directs.begin(), directs.end(), IsAllocatableOrPointer); 144419d86426SPeter Klausler } 144519d86426SPeter Klausler 144625822dc3SPeter Klausler PotentialComponentIterator::const_iterator 144725822dc3SPeter Klausler FindPolymorphicAllocatablePotentialComponent(const DerivedTypeSpec &derived) { 144825822dc3SPeter Klausler PotentialComponentIterator potentials{derived}; 144964ab3302SCarolineConcatto return std::find_if( 145025822dc3SPeter Klausler potentials.begin(), potentials.end(), IsPolymorphicAllocatable); 145164ab3302SCarolineConcatto } 145264ab3302SCarolineConcatto 145364ab3302SCarolineConcatto const Symbol *FindUltimateComponent(const DerivedTypeSpec &derived, 145464ab3302SCarolineConcatto const std::function<bool(const Symbol &)> &predicate) { 145564ab3302SCarolineConcatto UltimateComponentIterator ultimates{derived}; 145664ab3302SCarolineConcatto if (auto it{std::find_if(ultimates.begin(), ultimates.end(), 145764ab3302SCarolineConcatto [&predicate](const Symbol &component) -> bool { 145864ab3302SCarolineConcatto return predicate(component); 145964ab3302SCarolineConcatto })}) { 146064ab3302SCarolineConcatto return &*it; 146164ab3302SCarolineConcatto } 146264ab3302SCarolineConcatto return nullptr; 146364ab3302SCarolineConcatto } 146464ab3302SCarolineConcatto 146564ab3302SCarolineConcatto const Symbol *FindUltimateComponent(const Symbol &symbol, 146664ab3302SCarolineConcatto const std::function<bool(const Symbol &)> &predicate) { 146764ab3302SCarolineConcatto if (predicate(symbol)) { 146864ab3302SCarolineConcatto return &symbol; 146964ab3302SCarolineConcatto } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 147064ab3302SCarolineConcatto if (const auto *type{object->type()}) { 147164ab3302SCarolineConcatto if (const auto *derived{type->AsDerived()}) { 147264ab3302SCarolineConcatto return FindUltimateComponent(*derived, predicate); 147364ab3302SCarolineConcatto } 147464ab3302SCarolineConcatto } 147564ab3302SCarolineConcatto } 147664ab3302SCarolineConcatto return nullptr; 147764ab3302SCarolineConcatto } 147864ab3302SCarolineConcatto 147964ab3302SCarolineConcatto const Symbol *FindImmediateComponent(const DerivedTypeSpec &type, 148064ab3302SCarolineConcatto const std::function<bool(const Symbol &)> &predicate) { 148164ab3302SCarolineConcatto if (const Scope * scope{type.scope()}) { 148264ab3302SCarolineConcatto const Symbol *parent{nullptr}; 148364ab3302SCarolineConcatto for (const auto &pair : *scope) { 148464ab3302SCarolineConcatto const Symbol *symbol{&*pair.second}; 148564ab3302SCarolineConcatto if (predicate(*symbol)) { 148664ab3302SCarolineConcatto return symbol; 148764ab3302SCarolineConcatto } 148864ab3302SCarolineConcatto if (symbol->test(Symbol::Flag::ParentComp)) { 148964ab3302SCarolineConcatto parent = symbol; 149064ab3302SCarolineConcatto } 149164ab3302SCarolineConcatto } 149264ab3302SCarolineConcatto if (parent) { 149364ab3302SCarolineConcatto if (const auto *object{parent->detailsIf<ObjectEntityDetails>()}) { 149464ab3302SCarolineConcatto if (const auto *type{object->type()}) { 149564ab3302SCarolineConcatto if (const auto *derived{type->AsDerived()}) { 149664ab3302SCarolineConcatto return FindImmediateComponent(*derived, predicate); 149764ab3302SCarolineConcatto } 149864ab3302SCarolineConcatto } 149964ab3302SCarolineConcatto } 150064ab3302SCarolineConcatto } 150164ab3302SCarolineConcatto } 150264ab3302SCarolineConcatto return nullptr; 150364ab3302SCarolineConcatto } 150464ab3302SCarolineConcatto 1505a5679615SPeter Klausler const Symbol *IsFunctionResultWithSameNameAsFunction(const Symbol &symbol) { 150664ab3302SCarolineConcatto if (IsFunctionResult(symbol)) { 150764ab3302SCarolineConcatto if (const Symbol * function{symbol.owner().symbol()}) { 1508a5679615SPeter Klausler if (symbol.name() == function->name()) { 1509a5679615SPeter Klausler return function; 151064ab3302SCarolineConcatto } 151164ab3302SCarolineConcatto } 15127f680b26SPeter Klausler // Check ENTRY result symbols too 15137f680b26SPeter Klausler const Scope &outer{symbol.owner().parent()}; 15147f680b26SPeter Klausler auto iter{outer.find(symbol.name())}; 15157f680b26SPeter Klausler if (iter != outer.end()) { 15167f680b26SPeter Klausler const Symbol &outerSym{*iter->second}; 15177f680b26SPeter Klausler if (const auto *subp{outerSym.detailsIf<SubprogramDetails>()}) { 15187f680b26SPeter Klausler if (subp->entryScope() == &symbol.owner() && 15197f680b26SPeter Klausler symbol.name() == outerSym.name()) { 15207f680b26SPeter Klausler return &outerSym; 15217f680b26SPeter Klausler } 15227f680b26SPeter Klausler } 15237f680b26SPeter Klausler } 1524a5679615SPeter Klausler } 1525a5679615SPeter Klausler return nullptr; 152664ab3302SCarolineConcatto } 152764ab3302SCarolineConcatto 152864ab3302SCarolineConcatto void LabelEnforce::Post(const parser::GotoStmt &gotoStmt) { 1529505f6da1SPeter Klausler CheckLabelUse(gotoStmt.v); 153064ab3302SCarolineConcatto } 153164ab3302SCarolineConcatto void LabelEnforce::Post(const parser::ComputedGotoStmt &computedGotoStmt) { 153264ab3302SCarolineConcatto for (auto &i : std::get<std::list<parser::Label>>(computedGotoStmt.t)) { 1533505f6da1SPeter Klausler CheckLabelUse(i); 153464ab3302SCarolineConcatto } 153564ab3302SCarolineConcatto } 153664ab3302SCarolineConcatto 153764ab3302SCarolineConcatto void LabelEnforce::Post(const parser::ArithmeticIfStmt &arithmeticIfStmt) { 1538505f6da1SPeter Klausler CheckLabelUse(std::get<1>(arithmeticIfStmt.t)); 1539505f6da1SPeter Klausler CheckLabelUse(std::get<2>(arithmeticIfStmt.t)); 1540505f6da1SPeter Klausler CheckLabelUse(std::get<3>(arithmeticIfStmt.t)); 154164ab3302SCarolineConcatto } 154264ab3302SCarolineConcatto 154364ab3302SCarolineConcatto void LabelEnforce::Post(const parser::AssignStmt &assignStmt) { 1544505f6da1SPeter Klausler CheckLabelUse(std::get<parser::Label>(assignStmt.t)); 154564ab3302SCarolineConcatto } 154664ab3302SCarolineConcatto 154764ab3302SCarolineConcatto void LabelEnforce::Post(const parser::AssignedGotoStmt &assignedGotoStmt) { 154864ab3302SCarolineConcatto for (auto &i : std::get<std::list<parser::Label>>(assignedGotoStmt.t)) { 1549505f6da1SPeter Klausler CheckLabelUse(i); 155064ab3302SCarolineConcatto } 155164ab3302SCarolineConcatto } 155264ab3302SCarolineConcatto 155364ab3302SCarolineConcatto void LabelEnforce::Post(const parser::AltReturnSpec &altReturnSpec) { 1554505f6da1SPeter Klausler CheckLabelUse(altReturnSpec.v); 155564ab3302SCarolineConcatto } 155664ab3302SCarolineConcatto 155764ab3302SCarolineConcatto void LabelEnforce::Post(const parser::ErrLabel &errLabel) { 1558505f6da1SPeter Klausler CheckLabelUse(errLabel.v); 155964ab3302SCarolineConcatto } 156064ab3302SCarolineConcatto void LabelEnforce::Post(const parser::EndLabel &endLabel) { 1561505f6da1SPeter Klausler CheckLabelUse(endLabel.v); 156264ab3302SCarolineConcatto } 156364ab3302SCarolineConcatto void LabelEnforce::Post(const parser::EorLabel &eorLabel) { 1564505f6da1SPeter Klausler CheckLabelUse(eorLabel.v); 156564ab3302SCarolineConcatto } 156664ab3302SCarolineConcatto 1567505f6da1SPeter Klausler void LabelEnforce::CheckLabelUse(const parser::Label &labelUsed) { 156864ab3302SCarolineConcatto if (labels_.find(labelUsed) == labels_.end()) { 156964ab3302SCarolineConcatto SayWithConstruct(context_, currentStatementSourcePosition_, 157064ab3302SCarolineConcatto parser::MessageFormattedText{ 157164ab3302SCarolineConcatto "Control flow escapes from %s"_err_en_US, construct_}, 157264ab3302SCarolineConcatto constructSourcePosition_); 157364ab3302SCarolineConcatto } 157464ab3302SCarolineConcatto } 157564ab3302SCarolineConcatto 157664ab3302SCarolineConcatto parser::MessageFormattedText LabelEnforce::GetEnclosingConstructMsg() { 157764ab3302SCarolineConcatto return {"Enclosing %s statement"_en_US, construct_}; 157864ab3302SCarolineConcatto } 157964ab3302SCarolineConcatto 158064ab3302SCarolineConcatto void LabelEnforce::SayWithConstruct(SemanticsContext &context, 158164ab3302SCarolineConcatto parser::CharBlock stmtLocation, parser::MessageFormattedText &&message, 158264ab3302SCarolineConcatto parser::CharBlock constructLocation) { 158364ab3302SCarolineConcatto context.Say(stmtLocation, message) 158464ab3302SCarolineConcatto .Attach(constructLocation, GetEnclosingConstructMsg()); 158564ab3302SCarolineConcatto } 15868d0c3c05SPete Steinfeld 158705756e69STim Keith bool HasAlternateReturns(const Symbol &subprogram) { 158805756e69STim Keith for (const auto *dummyArg : subprogram.get<SubprogramDetails>().dummyArgs()) { 158905756e69STim Keith if (!dummyArg) { 159005756e69STim Keith return true; 159105756e69STim Keith } 159205756e69STim Keith } 159305756e69STim Keith return false; 159405756e69STim Keith } 159505756e69STim Keith 1596e9a8ab00SPeter Klausler bool IsAutomaticallyDestroyed(const Symbol &symbol) { 1597e9a8ab00SPeter Klausler return symbol.has<ObjectEntityDetails>() && 1598e9a8ab00SPeter Klausler (symbol.owner().kind() == Scope::Kind::Subprogram || 1599e9a8ab00SPeter Klausler symbol.owner().kind() == Scope::Kind::BlockConstruct) && 1600143be4eaSPeter Klausler !IsNamedConstant(symbol) && (!IsDummy(symbol) || IsIntentOut(symbol)) && 1601143be4eaSPeter Klausler !IsPointer(symbol) && !IsSaved(symbol) && 1602143be4eaSPeter Klausler !FindCommonBlockContaining(symbol); 1603e9a8ab00SPeter Klausler } 1604e9a8ab00SPeter Klausler 16054a51691aSsameeran joshi const std::optional<parser::Name> &MaybeGetNodeName( 16064a51691aSsameeran joshi const ConstructNode &construct) { 1607cd03e96fSPeter Klausler return common::visit( 16084a51691aSsameeran joshi common::visitors{ 16094a51691aSsameeran joshi [&](const parser::BlockConstruct *blockConstruct) 16104a51691aSsameeran joshi -> const std::optional<parser::Name> & { 16114a51691aSsameeran joshi return std::get<0>(blockConstruct->t).statement.v; 16124a51691aSsameeran joshi }, 16134a51691aSsameeran joshi [&](const auto *a) -> const std::optional<parser::Name> & { 16144a51691aSsameeran joshi return std::get<0>(std::get<0>(a->t).statement.t); 16154a51691aSsameeran joshi }, 16164a51691aSsameeran joshi }, 16174a51691aSsameeran joshi construct); 16184a51691aSsameeran joshi } 16194a51691aSsameeran joshi 1620ebe74d95Speter klausler std::optional<ArraySpec> ToArraySpec( 1621ebe74d95Speter klausler evaluate::FoldingContext &context, const evaluate::Shape &shape) { 162296963554SPeter Klausler if (auto extents{evaluate::AsConstantExtents(context, shape)}; 162396963554SPeter Klausler extents && !evaluate::HasNegativeExtent(*extents)) { 1624ebe74d95Speter klausler ArraySpec result; 1625ebe74d95Speter klausler for (const auto &extent : *extents) { 1626ebe74d95Speter klausler result.emplace_back(ShapeSpec::MakeExplicit(Bound{extent})); 1627ebe74d95Speter klausler } 1628ebe74d95Speter klausler return {std::move(result)}; 1629ebe74d95Speter klausler } else { 1630ebe74d95Speter klausler return std::nullopt; 1631ebe74d95Speter klausler } 1632ebe74d95Speter klausler } 1633ebe74d95Speter klausler 1634ebe74d95Speter klausler std::optional<ArraySpec> ToArraySpec(evaluate::FoldingContext &context, 1635ebe74d95Speter klausler const std::optional<evaluate::Shape> &shape) { 1636ebe74d95Speter klausler return shape ? ToArraySpec(context, *shape) : std::nullopt; 1637ebe74d95Speter klausler } 1638ebe74d95Speter klausler 163909b00ab4SPeter Klausler static const DeclTypeSpec *GetDtvArgTypeSpec(const Symbol &proc) { 164009b00ab4SPeter Klausler if (const auto *subp{proc.detailsIf<SubprogramDetails>()}; 164109b00ab4SPeter Klausler subp && !subp->dummyArgs().empty()) { 164209b00ab4SPeter Klausler if (const auto *arg{subp->dummyArgs()[0]}) { 164309b00ab4SPeter Klausler return arg->GetType(); 164409b00ab4SPeter Klausler } 164509b00ab4SPeter Klausler } 164609b00ab4SPeter Klausler return nullptr; 164709b00ab4SPeter Klausler } 164809b00ab4SPeter Klausler 164909b00ab4SPeter Klausler const DerivedTypeSpec *GetDtvArgDerivedType(const Symbol &proc) { 165009b00ab4SPeter Klausler if (const auto *type{GetDtvArgTypeSpec(proc)}) { 165109b00ab4SPeter Klausler return type->AsDerived(); 165209b00ab4SPeter Klausler } else { 165309b00ab4SPeter Klausler return nullptr; 165409b00ab4SPeter Klausler } 165509b00ab4SPeter Klausler } 165609b00ab4SPeter Klausler 16577cf1608bSPeter Klausler bool HasDefinedIo(common::DefinedIo which, const DerivedTypeSpec &derived, 165819d86426SPeter Klausler const Scope *scope) { 165919d86426SPeter Klausler if (const Scope * dtScope{derived.scope()}) { 166019d86426SPeter Klausler for (const auto &pair : *dtScope) { 166119d86426SPeter Klausler const Symbol &symbol{*pair.second}; 166219d86426SPeter Klausler if (const auto *generic{symbol.detailsIf<GenericDetails>()}) { 166319d86426SPeter Klausler GenericKind kind{generic->kind()}; 16647cf1608bSPeter Klausler if (const auto *io{std::get_if<common::DefinedIo>(&kind.u)}) { 166519d86426SPeter Klausler if (*io == which) { 166619d86426SPeter Klausler return true; // type-bound GENERIC exists 166719d86426SPeter Klausler } 166819d86426SPeter Klausler } 166919d86426SPeter Klausler } 167019d86426SPeter Klausler } 167119d86426SPeter Klausler } 167219d86426SPeter Klausler if (scope) { 167319d86426SPeter Klausler SourceName name{GenericKind::AsFortran(which)}; 167419d86426SPeter Klausler evaluate::DynamicType dyDerived{derived}; 167519d86426SPeter Klausler for (; scope && !scope->IsGlobal(); scope = &scope->parent()) { 167619d86426SPeter Klausler auto iter{scope->find(name)}; 167719d86426SPeter Klausler if (iter != scope->end()) { 167819d86426SPeter Klausler const auto &generic{iter->second->GetUltimate().get<GenericDetails>()}; 167919d86426SPeter Klausler for (auto ref : generic.specificProcs()) { 168019d86426SPeter Klausler const Symbol &procSym{ref->GetUltimate()}; 168109b00ab4SPeter Klausler if (const DeclTypeSpec * dtSpec{GetDtvArgTypeSpec(procSym)}) { 168219d86426SPeter Klausler if (auto dyDummy{evaluate::DynamicType::From(*dtSpec)}) { 168319d86426SPeter Klausler if (dyDummy->IsTkCompatibleWith(dyDerived)) { 168419d86426SPeter Klausler return true; // GENERIC or INTERFACE not in type 168519d86426SPeter Klausler } 168619d86426SPeter Klausler } 168719d86426SPeter Klausler } 168819d86426SPeter Klausler } 168919d86426SPeter Klausler } 169019d86426SPeter Klausler } 169119d86426SPeter Klausler } 169249016d53SPeter Klausler // Check for inherited defined I/O 169349016d53SPeter Klausler const auto *parentType{derived.typeSymbol().GetParentTypeSpec()}; 169449016d53SPeter Klausler return parentType && HasDefinedIo(which, *parentType, scope); 169519d86426SPeter Klausler } 169619d86426SPeter Klausler 16972f22656dSPeter Klausler template <typename E> 16982f22656dSPeter Klausler std::forward_list<std::string> GetOperatorNames( 16992f22656dSPeter Klausler const SemanticsContext &context, E opr) { 17002f22656dSPeter Klausler std::forward_list<std::string> result; 17012f22656dSPeter Klausler for (const char *name : context.languageFeatures().GetNames(opr)) { 17022f22656dSPeter Klausler result.emplace_front("operator("s + name + ')'); 17032f22656dSPeter Klausler } 17042f22656dSPeter Klausler return result; 17052f22656dSPeter Klausler } 17062f22656dSPeter Klausler 17072f22656dSPeter Klausler std::forward_list<std::string> GetAllNames( 17082f22656dSPeter Klausler const SemanticsContext &context, const SourceName &name) { 17092f22656dSPeter Klausler std::string str{name.ToString()}; 17102f22656dSPeter Klausler if (!name.empty() && name.end()[-1] == ')' && 17112f22656dSPeter Klausler name.ToString().rfind("operator(", 0) == 0) { 17122f22656dSPeter Klausler for (int i{0}; i != common::LogicalOperator_enumSize; ++i) { 17132f22656dSPeter Klausler auto names{GetOperatorNames(context, common::LogicalOperator{i})}; 17142f22656dSPeter Klausler if (llvm::is_contained(names, str)) { 17152f22656dSPeter Klausler return names; 17162f22656dSPeter Klausler } 17172f22656dSPeter Klausler } 17182f22656dSPeter Klausler for (int i{0}; i != common::RelationalOperator_enumSize; ++i) { 17192f22656dSPeter Klausler auto names{GetOperatorNames(context, common::RelationalOperator{i})}; 17202f22656dSPeter Klausler if (llvm::is_contained(names, str)) { 17212f22656dSPeter Klausler return names; 17222f22656dSPeter Klausler } 17232f22656dSPeter Klausler } 17242f22656dSPeter Klausler } 17252f22656dSPeter Klausler return {str}; 17262f22656dSPeter Klausler } 17272f22656dSPeter Klausler 17287871deb8SPeter Klausler void WarnOnDeferredLengthCharacterScalar(SemanticsContext &context, 17297871deb8SPeter Klausler const SomeExpr *expr, parser::CharBlock at, const char *what) { 17307871deb8SPeter Klausler if (context.languageFeatures().ShouldWarn( 17317871deb8SPeter Klausler common::UsageWarning::F202XAllocatableBreakingChange)) { 17327871deb8SPeter Klausler if (const Symbol * 17337871deb8SPeter Klausler symbol{evaluate::UnwrapWholeSymbolOrComponentDataRef(expr)}) { 17347871deb8SPeter Klausler const Symbol &ultimate{ResolveAssociations(*symbol)}; 17357871deb8SPeter Klausler if (const DeclTypeSpec * type{ultimate.GetType()}; type && 17367871deb8SPeter Klausler type->category() == DeclTypeSpec::Category::Character && 17377871deb8SPeter Klausler type->characterTypeSpec().length().isDeferred() && 17387871deb8SPeter Klausler IsAllocatable(ultimate) && ultimate.Rank() == 0) { 17397871deb8SPeter Klausler context.Say(at, 17407871deb8SPeter Klausler "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, 17417871deb8SPeter Klausler symbol->name(), what); 17427871deb8SPeter Klausler } 17437871deb8SPeter Klausler } 17447871deb8SPeter Klausler } 17457871deb8SPeter Klausler } 17467871deb8SPeter Klausler 17478b290482SPeter Klausler bool CouldBeDataPointerValuedFunction(const Symbol *original) { 17488b290482SPeter Klausler if (original) { 17498b290482SPeter Klausler const Symbol &ultimate{original->GetUltimate()}; 17508b290482SPeter Klausler if (const Symbol * result{FindFunctionResult(ultimate)}) { 17518b290482SPeter Klausler return IsPointer(*result) && !IsProcedure(*result); 17528b290482SPeter Klausler } 17538b290482SPeter Klausler if (const auto *generic{ultimate.detailsIf<GenericDetails>()}) { 17548b290482SPeter Klausler for (const SymbolRef &ref : generic->specificProcs()) { 17558b290482SPeter Klausler if (CouldBeDataPointerValuedFunction(&*ref)) { 17568b290482SPeter Klausler return true; 17578b290482SPeter Klausler } 17588b290482SPeter Klausler } 17598b290482SPeter Klausler } 17608b290482SPeter Klausler } 17618b290482SPeter Klausler return false; 17628b290482SPeter Klausler } 17638b290482SPeter Klausler 176477e965efSPeter Klausler std::string GetModuleOrSubmoduleName(const Symbol &symbol) { 176577e965efSPeter Klausler const auto &details{symbol.get<ModuleDetails>()}; 176677e965efSPeter Klausler std::string result{symbol.name().ToString()}; 176777e965efSPeter Klausler if (details.ancestor() && details.ancestor()->symbol()) { 176877e965efSPeter Klausler result = details.ancestor()->symbol()->name().ToString() + ':' + result; 176977e965efSPeter Klausler } 177077e965efSPeter Klausler return result; 177177e965efSPeter Klausler } 177277e965efSPeter Klausler 17736ffea74fSjeanPerier std::string GetCommonBlockObjectName(const Symbol &common, bool underscoring) { 17746ffea74fSjeanPerier if (const std::string * bind{common.GetBindName()}) { 17756ffea74fSjeanPerier return *bind; 17766ffea74fSjeanPerier } 17776ffea74fSjeanPerier if (common.name().empty()) { 17786ffea74fSjeanPerier return Fortran::common::blankCommonObjectName; 17796ffea74fSjeanPerier } 17806ffea74fSjeanPerier return underscoring ? common.name().ToString() + "_"s 17816ffea74fSjeanPerier : common.name().ToString(); 17826ffea74fSjeanPerier } 17836ffea74fSjeanPerier 17842b7a928dSPeter Klausler bool HadUseError( 17852b7a928dSPeter Klausler SemanticsContext &context, SourceName at, const Symbol *symbol) { 17862b7a928dSPeter Klausler if (const auto *details{ 17872b7a928dSPeter Klausler symbol ? symbol->detailsIf<UseErrorDetails>() : nullptr}) { 17882b7a928dSPeter Klausler auto &msg{context.Say( 17892b7a928dSPeter Klausler at, "Reference to '%s' is ambiguous"_err_en_US, symbol->name())}; 1790038b42baSPeter Klausler for (const auto &[location, sym] : details->occurrences()) { 1791038b42baSPeter Klausler const Symbol &ultimate{sym->GetUltimate()}; 1792038b42baSPeter Klausler auto &attachment{ 1793038b42baSPeter Klausler msg.Attach(location, "'%s' was use-associated from module '%s'"_en_US, 1794038b42baSPeter Klausler at, sym->owner().GetName().value())}; 1795038b42baSPeter Klausler if (&*sym != &ultimate) { 1796038b42baSPeter Klausler // For incompatible definitions where one comes from a hermetic 1797038b42baSPeter Klausler // module file's incorporated dependences and the other from another 1798038b42baSPeter Klausler // module of the same name. 1799038b42baSPeter Klausler attachment.Attach(ultimate.name(), 1800038b42baSPeter Klausler "ultimately from '%s' in module '%s'"_en_US, ultimate.name(), 1801038b42baSPeter Klausler ultimate.owner().GetName().value()); 1802038b42baSPeter Klausler } 18032b7a928dSPeter Klausler } 18042b7a928dSPeter Klausler context.SetError(*symbol); 18052b7a928dSPeter Klausler return true; 18062b7a928dSPeter Klausler } else { 18072b7a928dSPeter Klausler return false; 18082b7a928dSPeter Klausler } 18092b7a928dSPeter Klausler } 18102b7a928dSPeter Klausler 181184a099dfSpeter klausler } // namespace Fortran::semantics 1812