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" 2064ab3302SCarolineConcatto #include <algorithm> 2164ab3302SCarolineConcatto #include <set> 2264ab3302SCarolineConcatto #include <sstream> 2364ab3302SCarolineConcatto #include <variant> 2464ab3302SCarolineConcatto 2564ab3302SCarolineConcatto namespace Fortran::semantics { 2664ab3302SCarolineConcatto 2764ab3302SCarolineConcatto const Symbol *FindCommonBlockContaining(const Symbol &object) { 2864ab3302SCarolineConcatto if (const auto *details{object.detailsIf<ObjectEntityDetails>()}) { 2964ab3302SCarolineConcatto return details->commonBlock(); 3064ab3302SCarolineConcatto } else { 3164ab3302SCarolineConcatto return nullptr; 3264ab3302SCarolineConcatto } 3364ab3302SCarolineConcatto } 3464ab3302SCarolineConcatto 3564ab3302SCarolineConcatto const Scope *FindProgramUnitContaining(const Scope &start) { 3664ab3302SCarolineConcatto const Scope *scope{&start}; 3764ab3302SCarolineConcatto while (scope) { 3864ab3302SCarolineConcatto switch (scope->kind()) { 3964ab3302SCarolineConcatto case Scope::Kind::Module: 4064ab3302SCarolineConcatto case Scope::Kind::MainProgram: 4164ab3302SCarolineConcatto case Scope::Kind::Subprogram: 4264ab3302SCarolineConcatto case Scope::Kind::BlockData: return scope; 4364ab3302SCarolineConcatto case Scope::Kind::Global: return nullptr; 4464ab3302SCarolineConcatto case Scope::Kind::DerivedType: 4564ab3302SCarolineConcatto case Scope::Kind::Block: 4664ab3302SCarolineConcatto case Scope::Kind::Forall: 4764ab3302SCarolineConcatto case Scope::Kind::ImpliedDos: scope = &scope->parent(); 4864ab3302SCarolineConcatto } 4964ab3302SCarolineConcatto } 5064ab3302SCarolineConcatto return nullptr; 5164ab3302SCarolineConcatto } 5264ab3302SCarolineConcatto 5364ab3302SCarolineConcatto const Scope *FindProgramUnitContaining(const Symbol &symbol) { 5464ab3302SCarolineConcatto return FindProgramUnitContaining(symbol.owner()); 5564ab3302SCarolineConcatto } 5664ab3302SCarolineConcatto 5764ab3302SCarolineConcatto const Scope *FindPureProcedureContaining(const Scope &start) { 5864ab3302SCarolineConcatto // N.B. We only need to examine the innermost containing program unit 5964ab3302SCarolineConcatto // because an internal subprogram of a pure subprogram must also 6064ab3302SCarolineConcatto // be pure (C1592). 6164ab3302SCarolineConcatto if (const Scope * scope{FindProgramUnitContaining(start)}) { 6264ab3302SCarolineConcatto if (IsPureProcedure(*scope)) { 6364ab3302SCarolineConcatto return scope; 6464ab3302SCarolineConcatto } 6564ab3302SCarolineConcatto } 6664ab3302SCarolineConcatto return nullptr; 6764ab3302SCarolineConcatto } 6864ab3302SCarolineConcatto 6964ab3302SCarolineConcatto Tristate IsDefinedAssignment( 7064ab3302SCarolineConcatto const std::optional<evaluate::DynamicType> &lhsType, int lhsRank, 7164ab3302SCarolineConcatto const std::optional<evaluate::DynamicType> &rhsType, int rhsRank) { 7264ab3302SCarolineConcatto if (!lhsType || !rhsType) { 7364ab3302SCarolineConcatto return Tristate::No; // error or rhs is untyped 7464ab3302SCarolineConcatto } 7564ab3302SCarolineConcatto TypeCategory lhsCat{lhsType->category()}; 7664ab3302SCarolineConcatto TypeCategory rhsCat{rhsType->category()}; 7764ab3302SCarolineConcatto if (rhsRank > 0 && lhsRank != rhsRank) { 7864ab3302SCarolineConcatto return Tristate::Yes; 7964ab3302SCarolineConcatto } else if (lhsCat != TypeCategory::Derived) { 8064ab3302SCarolineConcatto return ToTristate(lhsCat != rhsCat && 8164ab3302SCarolineConcatto (!IsNumericTypeCategory(lhsCat) || !IsNumericTypeCategory(rhsCat))); 8264ab3302SCarolineConcatto } else { 8364ab3302SCarolineConcatto const auto *lhsDerived{evaluate::GetDerivedTypeSpec(lhsType)}; 8464ab3302SCarolineConcatto const auto *rhsDerived{evaluate::GetDerivedTypeSpec(rhsType)}; 8564ab3302SCarolineConcatto if (lhsDerived && rhsDerived && *lhsDerived == *rhsDerived) { 8664ab3302SCarolineConcatto return Tristate::Maybe; // TYPE(t) = TYPE(t) can be defined or 8764ab3302SCarolineConcatto // intrinsic 8864ab3302SCarolineConcatto } else { 8964ab3302SCarolineConcatto return Tristate::Yes; 9064ab3302SCarolineConcatto } 9164ab3302SCarolineConcatto } 9264ab3302SCarolineConcatto } 9364ab3302SCarolineConcatto 9464ab3302SCarolineConcatto bool IsIntrinsicRelational(common::RelationalOperator opr, 9564ab3302SCarolineConcatto const evaluate::DynamicType &type0, int rank0, 9664ab3302SCarolineConcatto const evaluate::DynamicType &type1, int rank1) { 9764ab3302SCarolineConcatto if (!evaluate::AreConformable(rank0, rank1)) { 9864ab3302SCarolineConcatto return false; 9964ab3302SCarolineConcatto } else { 10064ab3302SCarolineConcatto auto cat0{type0.category()}; 10164ab3302SCarolineConcatto auto cat1{type1.category()}; 10264ab3302SCarolineConcatto if (IsNumericTypeCategory(cat0) && IsNumericTypeCategory(cat1)) { 10364ab3302SCarolineConcatto // numeric types: EQ/NE always ok, others ok for non-complex 10464ab3302SCarolineConcatto return opr == common::RelationalOperator::EQ || 10564ab3302SCarolineConcatto opr == common::RelationalOperator::NE || 10664ab3302SCarolineConcatto (cat0 != TypeCategory::Complex && cat1 != TypeCategory::Complex); 10764ab3302SCarolineConcatto } else { 10864ab3302SCarolineConcatto // not both numeric: only Character is ok 10964ab3302SCarolineConcatto return cat0 == TypeCategory::Character && cat1 == TypeCategory::Character; 11064ab3302SCarolineConcatto } 11164ab3302SCarolineConcatto } 11264ab3302SCarolineConcatto } 11364ab3302SCarolineConcatto 11464ab3302SCarolineConcatto bool IsIntrinsicNumeric(const evaluate::DynamicType &type0) { 11564ab3302SCarolineConcatto return IsNumericTypeCategory(type0.category()); 11664ab3302SCarolineConcatto } 11764ab3302SCarolineConcatto bool IsIntrinsicNumeric(const evaluate::DynamicType &type0, int rank0, 11864ab3302SCarolineConcatto const evaluate::DynamicType &type1, int rank1) { 11964ab3302SCarolineConcatto return evaluate::AreConformable(rank0, rank1) && 12064ab3302SCarolineConcatto IsNumericTypeCategory(type0.category()) && 12164ab3302SCarolineConcatto IsNumericTypeCategory(type1.category()); 12264ab3302SCarolineConcatto } 12364ab3302SCarolineConcatto 12464ab3302SCarolineConcatto bool IsIntrinsicLogical(const evaluate::DynamicType &type0) { 12564ab3302SCarolineConcatto return type0.category() == TypeCategory::Logical; 12664ab3302SCarolineConcatto } 12764ab3302SCarolineConcatto bool IsIntrinsicLogical(const evaluate::DynamicType &type0, int rank0, 12864ab3302SCarolineConcatto const evaluate::DynamicType &type1, int rank1) { 12964ab3302SCarolineConcatto return evaluate::AreConformable(rank0, rank1) && 13064ab3302SCarolineConcatto type0.category() == TypeCategory::Logical && 13164ab3302SCarolineConcatto type1.category() == TypeCategory::Logical; 13264ab3302SCarolineConcatto } 13364ab3302SCarolineConcatto 13464ab3302SCarolineConcatto bool IsIntrinsicConcat(const evaluate::DynamicType &type0, int rank0, 13564ab3302SCarolineConcatto const evaluate::DynamicType &type1, int rank1) { 13664ab3302SCarolineConcatto return evaluate::AreConformable(rank0, rank1) && 13764ab3302SCarolineConcatto type0.category() == TypeCategory::Character && 13864ab3302SCarolineConcatto type1.category() == TypeCategory::Character && 13964ab3302SCarolineConcatto type0.kind() == type1.kind(); 14064ab3302SCarolineConcatto } 14164ab3302SCarolineConcatto 14264ab3302SCarolineConcatto bool IsGenericDefinedOp(const Symbol &symbol) { 14364ab3302SCarolineConcatto const Symbol &ultimate{symbol.GetUltimate()}; 14464ab3302SCarolineConcatto if (const auto *generic{ultimate.detailsIf<GenericDetails>()}) { 14564ab3302SCarolineConcatto return generic->kind().IsDefinedOperator(); 14664ab3302SCarolineConcatto } else if (const auto *misc{ultimate.detailsIf<MiscDetails>()}) { 14764ab3302SCarolineConcatto return misc->kind() == MiscDetails::Kind::TypeBoundDefinedOp; 14864ab3302SCarolineConcatto } else { 14964ab3302SCarolineConcatto return false; 15064ab3302SCarolineConcatto } 15164ab3302SCarolineConcatto } 15264ab3302SCarolineConcatto 15364ab3302SCarolineConcatto bool IsCommonBlockContaining(const Symbol &block, const Symbol &object) { 15464ab3302SCarolineConcatto const auto &objects{block.get<CommonBlockDetails>().objects()}; 15564ab3302SCarolineConcatto auto found{std::find(objects.begin(), objects.end(), object)}; 15664ab3302SCarolineConcatto return found != objects.end(); 15764ab3302SCarolineConcatto } 15864ab3302SCarolineConcatto 15964ab3302SCarolineConcatto bool IsUseAssociated(const Symbol &symbol, const Scope &scope) { 16064ab3302SCarolineConcatto const Scope *owner{FindProgramUnitContaining(symbol.GetUltimate().owner())}; 16164ab3302SCarolineConcatto return owner && owner->kind() == Scope::Kind::Module && 16264ab3302SCarolineConcatto owner != FindProgramUnitContaining(scope); 16364ab3302SCarolineConcatto } 16464ab3302SCarolineConcatto 16564ab3302SCarolineConcatto bool DoesScopeContain( 16664ab3302SCarolineConcatto const Scope *maybeAncestor, const Scope &maybeDescendent) { 16764ab3302SCarolineConcatto if (maybeAncestor) { 16864ab3302SCarolineConcatto const Scope *scope{&maybeDescendent}; 16964ab3302SCarolineConcatto while (!scope->IsGlobal()) { 17064ab3302SCarolineConcatto scope = &scope->parent(); 17164ab3302SCarolineConcatto if (scope == maybeAncestor) { 17264ab3302SCarolineConcatto return true; 17364ab3302SCarolineConcatto } 17464ab3302SCarolineConcatto } 17564ab3302SCarolineConcatto } 17664ab3302SCarolineConcatto return false; 17764ab3302SCarolineConcatto } 17864ab3302SCarolineConcatto 17964ab3302SCarolineConcatto bool DoesScopeContain(const Scope *maybeAncestor, const Symbol &symbol) { 18064ab3302SCarolineConcatto return DoesScopeContain(maybeAncestor, symbol.owner()); 18164ab3302SCarolineConcatto } 18264ab3302SCarolineConcatto 18364ab3302SCarolineConcatto bool IsHostAssociated(const Symbol &symbol, const Scope &scope) { 18464ab3302SCarolineConcatto const Scope *subprogram{FindProgramUnitContaining(scope)}; 18564ab3302SCarolineConcatto return subprogram && 18664ab3302SCarolineConcatto DoesScopeContain(FindProgramUnitContaining(symbol), *subprogram); 18764ab3302SCarolineConcatto } 18864ab3302SCarolineConcatto 18964ab3302SCarolineConcatto bool IsDummy(const Symbol &symbol) { 19064ab3302SCarolineConcatto if (const auto *details{symbol.detailsIf<ObjectEntityDetails>()}) { 19164ab3302SCarolineConcatto return details->isDummy(); 19264ab3302SCarolineConcatto } else if (const auto *details{symbol.detailsIf<ProcEntityDetails>()}) { 19364ab3302SCarolineConcatto return details->isDummy(); 19464ab3302SCarolineConcatto } else { 19564ab3302SCarolineConcatto return false; 19664ab3302SCarolineConcatto } 19764ab3302SCarolineConcatto } 19864ab3302SCarolineConcatto 199*657aaf8bSPete Steinfeld bool IsStmtFunction(const Symbol &symbol) { 200*657aaf8bSPete Steinfeld const auto *subprogram{symbol.detailsIf<SubprogramDetails>()}; 201*657aaf8bSPete Steinfeld if (subprogram && subprogram->stmtFunction()) { 202*657aaf8bSPete Steinfeld return true; 203*657aaf8bSPete Steinfeld } 204*657aaf8bSPete Steinfeld return false; 205*657aaf8bSPete Steinfeld } 206*657aaf8bSPete Steinfeld 207*657aaf8bSPete Steinfeld bool IsInStmtFunction(const Symbol &symbol) { 208*657aaf8bSPete Steinfeld if (const Symbol * function{symbol.owner().symbol()}) { 209*657aaf8bSPete Steinfeld return IsStmtFunction(*function); 210*657aaf8bSPete Steinfeld } 211*657aaf8bSPete Steinfeld return false; 212*657aaf8bSPete Steinfeld } 213*657aaf8bSPete Steinfeld 214*657aaf8bSPete Steinfeld bool IsStmtFunctionDummy(const Symbol &symbol) { 215*657aaf8bSPete Steinfeld return IsDummy(symbol) && IsInStmtFunction(symbol); 216*657aaf8bSPete Steinfeld } 217*657aaf8bSPete Steinfeld 218*657aaf8bSPete Steinfeld bool IsStmtFunctionResult(const Symbol &symbol) { 219*657aaf8bSPete Steinfeld return IsFunctionResult(symbol) && IsInStmtFunction(symbol); 220*657aaf8bSPete Steinfeld } 221*657aaf8bSPete Steinfeld 22264ab3302SCarolineConcatto bool IsPointerDummy(const Symbol &symbol) { 22364ab3302SCarolineConcatto return IsPointer(symbol) && IsDummy(symbol); 22464ab3302SCarolineConcatto } 22564ab3302SCarolineConcatto 22664ab3302SCarolineConcatto // variable-name 22764ab3302SCarolineConcatto bool IsVariableName(const Symbol &symbol) { 22864ab3302SCarolineConcatto if (const Symbol * root{GetAssociationRoot(symbol)}) { 22964ab3302SCarolineConcatto return root->has<ObjectEntityDetails>() && !IsNamedConstant(*root); 23064ab3302SCarolineConcatto } else { 23164ab3302SCarolineConcatto return false; 23264ab3302SCarolineConcatto } 23364ab3302SCarolineConcatto } 23464ab3302SCarolineConcatto 23564ab3302SCarolineConcatto // proc-name 23664ab3302SCarolineConcatto bool IsProcName(const Symbol &symbol) { 23764ab3302SCarolineConcatto return symbol.GetUltimate().has<ProcEntityDetails>(); 23864ab3302SCarolineConcatto } 23964ab3302SCarolineConcatto 24064ab3302SCarolineConcatto bool IsFunction(const Symbol &symbol) { 24164ab3302SCarolineConcatto return std::visit( 24264ab3302SCarolineConcatto common::visitors{ 24364ab3302SCarolineConcatto [](const SubprogramDetails &x) { return x.isFunction(); }, 24464ab3302SCarolineConcatto [&](const SubprogramNameDetails &) { 24564ab3302SCarolineConcatto return symbol.test(Symbol::Flag::Function); 24664ab3302SCarolineConcatto }, 24764ab3302SCarolineConcatto [](const ProcEntityDetails &x) { 24864ab3302SCarolineConcatto const auto &ifc{x.interface()}; 24964ab3302SCarolineConcatto return ifc.type() || (ifc.symbol() && IsFunction(*ifc.symbol())); 25064ab3302SCarolineConcatto }, 25164ab3302SCarolineConcatto [](const ProcBindingDetails &x) { return IsFunction(x.symbol()); }, 25264ab3302SCarolineConcatto [](const UseDetails &x) { return IsFunction(x.symbol()); }, 25364ab3302SCarolineConcatto [](const auto &) { return false; }, 25464ab3302SCarolineConcatto }, 25564ab3302SCarolineConcatto symbol.details()); 25664ab3302SCarolineConcatto } 25764ab3302SCarolineConcatto 25864ab3302SCarolineConcatto bool IsPureProcedure(const Symbol &symbol) { 25964ab3302SCarolineConcatto if (const auto *procDetails{symbol.detailsIf<ProcEntityDetails>()}) { 26064ab3302SCarolineConcatto if (const Symbol * procInterface{procDetails->interface().symbol()}) { 26164ab3302SCarolineConcatto // procedure component with a pure interface 26264ab3302SCarolineConcatto return IsPureProcedure(*procInterface); 26364ab3302SCarolineConcatto } 26464ab3302SCarolineConcatto } else if (const auto *details{symbol.detailsIf<ProcBindingDetails>()}) { 26564ab3302SCarolineConcatto return IsPureProcedure(details->symbol()); 26664ab3302SCarolineConcatto } else if (!IsProcedure(symbol)) { 26764ab3302SCarolineConcatto return false; 26864ab3302SCarolineConcatto } 26964ab3302SCarolineConcatto return symbol.attrs().test(Attr::PURE) || 27064ab3302SCarolineConcatto (symbol.attrs().test(Attr::ELEMENTAL) && 27164ab3302SCarolineConcatto !symbol.attrs().test(Attr::IMPURE)); 27264ab3302SCarolineConcatto } 27364ab3302SCarolineConcatto 27464ab3302SCarolineConcatto bool IsPureProcedure(const Scope &scope) { 27564ab3302SCarolineConcatto if (const Symbol * symbol{scope.GetSymbol()}) { 27664ab3302SCarolineConcatto return IsPureProcedure(*symbol); 27764ab3302SCarolineConcatto } else { 27864ab3302SCarolineConcatto return false; 27964ab3302SCarolineConcatto } 28064ab3302SCarolineConcatto } 28164ab3302SCarolineConcatto 28264ab3302SCarolineConcatto bool IsBindCProcedure(const Symbol &symbol) { 28364ab3302SCarolineConcatto if (const auto *procDetails{symbol.detailsIf<ProcEntityDetails>()}) { 28464ab3302SCarolineConcatto if (const Symbol * procInterface{procDetails->interface().symbol()}) { 28564ab3302SCarolineConcatto // procedure component with a BIND(C) interface 28664ab3302SCarolineConcatto return IsBindCProcedure(*procInterface); 28764ab3302SCarolineConcatto } 28864ab3302SCarolineConcatto } 28964ab3302SCarolineConcatto return symbol.attrs().test(Attr::BIND_C) && IsProcedure(symbol); 29064ab3302SCarolineConcatto } 29164ab3302SCarolineConcatto 29264ab3302SCarolineConcatto bool IsBindCProcedure(const Scope &scope) { 29364ab3302SCarolineConcatto if (const Symbol * symbol{scope.GetSymbol()}) { 29464ab3302SCarolineConcatto return IsBindCProcedure(*symbol); 29564ab3302SCarolineConcatto } else { 29664ab3302SCarolineConcatto return false; 29764ab3302SCarolineConcatto } 29864ab3302SCarolineConcatto } 29964ab3302SCarolineConcatto 30064ab3302SCarolineConcatto bool IsProcedure(const Symbol &symbol) { 30164ab3302SCarolineConcatto return std::visit( 30264ab3302SCarolineConcatto common::visitors{ 30364ab3302SCarolineConcatto [](const SubprogramDetails &) { return true; }, 30464ab3302SCarolineConcatto [](const SubprogramNameDetails &) { return true; }, 30564ab3302SCarolineConcatto [](const ProcEntityDetails &) { return true; }, 30664ab3302SCarolineConcatto [](const GenericDetails &) { return true; }, 30764ab3302SCarolineConcatto [](const ProcBindingDetails &) { return true; }, 30864ab3302SCarolineConcatto [](const UseDetails &x) { return IsProcedure(x.symbol()); }, 30964ab3302SCarolineConcatto // TODO: FinalProcDetails? 31064ab3302SCarolineConcatto [](const auto &) { return false; }, 31164ab3302SCarolineConcatto }, 31264ab3302SCarolineConcatto symbol.details()); 31364ab3302SCarolineConcatto } 31464ab3302SCarolineConcatto 31564ab3302SCarolineConcatto bool IsProcedurePointer(const Symbol &symbol) { 31664ab3302SCarolineConcatto return symbol.has<ProcEntityDetails>() && IsPointer(symbol); 31764ab3302SCarolineConcatto } 31864ab3302SCarolineConcatto 31964ab3302SCarolineConcatto static const Symbol *FindPointerComponent( 32064ab3302SCarolineConcatto const Scope &scope, std::set<const Scope *> &visited) { 32164ab3302SCarolineConcatto if (!scope.IsDerivedType()) { 32264ab3302SCarolineConcatto return nullptr; 32364ab3302SCarolineConcatto } 32464ab3302SCarolineConcatto if (!visited.insert(&scope).second) { 32564ab3302SCarolineConcatto return nullptr; 32664ab3302SCarolineConcatto } 32764ab3302SCarolineConcatto // If there's a top-level pointer component, return it for clearer error 32864ab3302SCarolineConcatto // messaging. 32964ab3302SCarolineConcatto for (const auto &pair : scope) { 33064ab3302SCarolineConcatto const Symbol &symbol{*pair.second}; 33164ab3302SCarolineConcatto if (IsPointer(symbol)) { 33264ab3302SCarolineConcatto return &symbol; 33364ab3302SCarolineConcatto } 33464ab3302SCarolineConcatto } 33564ab3302SCarolineConcatto for (const auto &pair : scope) { 33664ab3302SCarolineConcatto const Symbol &symbol{*pair.second}; 33764ab3302SCarolineConcatto if (const auto *details{symbol.detailsIf<ObjectEntityDetails>()}) { 33864ab3302SCarolineConcatto if (const DeclTypeSpec * type{details->type()}) { 33964ab3302SCarolineConcatto if (const DerivedTypeSpec * derived{type->AsDerived()}) { 34064ab3302SCarolineConcatto if (const Scope * nested{derived->scope()}) { 34164ab3302SCarolineConcatto if (const Symbol * 34264ab3302SCarolineConcatto pointer{FindPointerComponent(*nested, visited)}) { 34364ab3302SCarolineConcatto return pointer; 34464ab3302SCarolineConcatto } 34564ab3302SCarolineConcatto } 34664ab3302SCarolineConcatto } 34764ab3302SCarolineConcatto } 34864ab3302SCarolineConcatto } 34964ab3302SCarolineConcatto } 35064ab3302SCarolineConcatto return nullptr; 35164ab3302SCarolineConcatto } 35264ab3302SCarolineConcatto 35364ab3302SCarolineConcatto const Symbol *FindPointerComponent(const Scope &scope) { 35464ab3302SCarolineConcatto std::set<const Scope *> visited; 35564ab3302SCarolineConcatto return FindPointerComponent(scope, visited); 35664ab3302SCarolineConcatto } 35764ab3302SCarolineConcatto 35864ab3302SCarolineConcatto const Symbol *FindPointerComponent(const DerivedTypeSpec &derived) { 35964ab3302SCarolineConcatto if (const Scope * scope{derived.scope()}) { 36064ab3302SCarolineConcatto return FindPointerComponent(*scope); 36164ab3302SCarolineConcatto } else { 36264ab3302SCarolineConcatto return nullptr; 36364ab3302SCarolineConcatto } 36464ab3302SCarolineConcatto } 36564ab3302SCarolineConcatto 36664ab3302SCarolineConcatto const Symbol *FindPointerComponent(const DeclTypeSpec &type) { 36764ab3302SCarolineConcatto if (const DerivedTypeSpec * derived{type.AsDerived()}) { 36864ab3302SCarolineConcatto return FindPointerComponent(*derived); 36964ab3302SCarolineConcatto } else { 37064ab3302SCarolineConcatto return nullptr; 37164ab3302SCarolineConcatto } 37264ab3302SCarolineConcatto } 37364ab3302SCarolineConcatto 37464ab3302SCarolineConcatto const Symbol *FindPointerComponent(const DeclTypeSpec *type) { 37564ab3302SCarolineConcatto return type ? FindPointerComponent(*type) : nullptr; 37664ab3302SCarolineConcatto } 37764ab3302SCarolineConcatto 37864ab3302SCarolineConcatto const Symbol *FindPointerComponent(const Symbol &symbol) { 37964ab3302SCarolineConcatto return IsPointer(symbol) ? &symbol : FindPointerComponent(symbol.GetType()); 38064ab3302SCarolineConcatto } 38164ab3302SCarolineConcatto 38264ab3302SCarolineConcatto // C1594 specifies several ways by which an object might be globally visible. 38364ab3302SCarolineConcatto const Symbol *FindExternallyVisibleObject( 38464ab3302SCarolineConcatto const Symbol &object, const Scope &scope) { 38564ab3302SCarolineConcatto // TODO: Storage association with any object for which this predicate holds, 38664ab3302SCarolineConcatto // once EQUIVALENCE is supported. 38764ab3302SCarolineConcatto if (IsUseAssociated(object, scope) || IsHostAssociated(object, scope) || 38864ab3302SCarolineConcatto (IsPureProcedure(scope) && IsPointerDummy(object)) || 38964ab3302SCarolineConcatto (IsIntentIn(object) && IsDummy(object))) { 39064ab3302SCarolineConcatto return &object; 39164ab3302SCarolineConcatto } else if (const Symbol * block{FindCommonBlockContaining(object)}) { 39264ab3302SCarolineConcatto return block; 39364ab3302SCarolineConcatto } else { 39464ab3302SCarolineConcatto return nullptr; 39564ab3302SCarolineConcatto } 39664ab3302SCarolineConcatto } 39764ab3302SCarolineConcatto 39864ab3302SCarolineConcatto bool ExprHasTypeCategory( 39964ab3302SCarolineConcatto const SomeExpr &expr, const common::TypeCategory &type) { 40064ab3302SCarolineConcatto auto dynamicType{expr.GetType()}; 40164ab3302SCarolineConcatto return dynamicType && dynamicType->category() == type; 40264ab3302SCarolineConcatto } 40364ab3302SCarolineConcatto 40464ab3302SCarolineConcatto bool ExprTypeKindIsDefault( 40564ab3302SCarolineConcatto const SomeExpr &expr, const SemanticsContext &context) { 40664ab3302SCarolineConcatto auto dynamicType{expr.GetType()}; 40764ab3302SCarolineConcatto return dynamicType && 40864ab3302SCarolineConcatto dynamicType->category() != common::TypeCategory::Derived && 40964ab3302SCarolineConcatto dynamicType->kind() == context.GetDefaultKind(dynamicType->category()); 41064ab3302SCarolineConcatto } 41164ab3302SCarolineConcatto 41264ab3302SCarolineConcatto // If an analyzed expr or assignment is missing, dump the node and die. 41364ab3302SCarolineConcatto template<typename T> static void CheckMissingAnalysis(bool absent, const T &x) { 41464ab3302SCarolineConcatto if (absent) { 41564ab3302SCarolineConcatto std::ostringstream ss; 41664ab3302SCarolineConcatto ss << "node has not been analyzed:\n"; 41764ab3302SCarolineConcatto parser::DumpTree(ss, x); 41864ab3302SCarolineConcatto common::die(ss.str().c_str()); 41964ab3302SCarolineConcatto } 42064ab3302SCarolineConcatto } 42164ab3302SCarolineConcatto 42264ab3302SCarolineConcatto const SomeExpr *GetExprHelper::Get(const parser::Expr &x) { 42364ab3302SCarolineConcatto CheckMissingAnalysis(!x.typedExpr, x); 42464ab3302SCarolineConcatto return common::GetPtrFromOptional(x.typedExpr->v); 42564ab3302SCarolineConcatto } 42664ab3302SCarolineConcatto const SomeExpr *GetExprHelper::Get(const parser::Variable &x) { 42764ab3302SCarolineConcatto CheckMissingAnalysis(!x.typedExpr, x); 42864ab3302SCarolineConcatto return common::GetPtrFromOptional(x.typedExpr->v); 42964ab3302SCarolineConcatto } 43064ab3302SCarolineConcatto 43164ab3302SCarolineConcatto const evaluate::Assignment *GetAssignment(const parser::AssignmentStmt &x) { 43264ab3302SCarolineConcatto CheckMissingAnalysis(!x.typedAssignment, x); 43364ab3302SCarolineConcatto return common::GetPtrFromOptional(x.typedAssignment->v); 43464ab3302SCarolineConcatto } 43564ab3302SCarolineConcatto const evaluate::Assignment *GetAssignment( 43664ab3302SCarolineConcatto const parser::PointerAssignmentStmt &x) { 43764ab3302SCarolineConcatto CheckMissingAnalysis(!x.typedAssignment, x); 43864ab3302SCarolineConcatto return common::GetPtrFromOptional(x.typedAssignment->v); 43964ab3302SCarolineConcatto } 44064ab3302SCarolineConcatto 44164ab3302SCarolineConcatto const Symbol *FindInterface(const Symbol &symbol) { 44264ab3302SCarolineConcatto return std::visit( 44364ab3302SCarolineConcatto common::visitors{ 44464ab3302SCarolineConcatto [](const ProcEntityDetails &details) { 44564ab3302SCarolineConcatto return details.interface().symbol(); 44664ab3302SCarolineConcatto }, 44764ab3302SCarolineConcatto [](const ProcBindingDetails &details) { return &details.symbol(); }, 44864ab3302SCarolineConcatto [](const auto &) -> const Symbol * { return nullptr; }, 44964ab3302SCarolineConcatto }, 45064ab3302SCarolineConcatto symbol.details()); 45164ab3302SCarolineConcatto } 45264ab3302SCarolineConcatto 45364ab3302SCarolineConcatto const Symbol *FindSubprogram(const Symbol &symbol) { 45464ab3302SCarolineConcatto return std::visit( 45564ab3302SCarolineConcatto common::visitors{ 45664ab3302SCarolineConcatto [&](const ProcEntityDetails &details) -> const Symbol * { 45764ab3302SCarolineConcatto if (const Symbol * interface{details.interface().symbol()}) { 45864ab3302SCarolineConcatto return FindSubprogram(*interface); 45964ab3302SCarolineConcatto } else { 46064ab3302SCarolineConcatto return &symbol; 46164ab3302SCarolineConcatto } 46264ab3302SCarolineConcatto }, 46364ab3302SCarolineConcatto [](const ProcBindingDetails &details) { 46464ab3302SCarolineConcatto return FindSubprogram(details.symbol()); 46564ab3302SCarolineConcatto }, 46664ab3302SCarolineConcatto [&](const SubprogramDetails &) { return &symbol; }, 46764ab3302SCarolineConcatto [](const UseDetails &details) { 46864ab3302SCarolineConcatto return FindSubprogram(details.symbol()); 46964ab3302SCarolineConcatto }, 47064ab3302SCarolineConcatto [](const HostAssocDetails &details) { 47164ab3302SCarolineConcatto return FindSubprogram(details.symbol()); 47264ab3302SCarolineConcatto }, 47364ab3302SCarolineConcatto [](const auto &) -> const Symbol * { return nullptr; }, 47464ab3302SCarolineConcatto }, 47564ab3302SCarolineConcatto symbol.details()); 47664ab3302SCarolineConcatto } 47764ab3302SCarolineConcatto 47864ab3302SCarolineConcatto const Symbol *FindFunctionResult(const Symbol &symbol) { 47964ab3302SCarolineConcatto if (const Symbol * subp{FindSubprogram(symbol)}) { 48064ab3302SCarolineConcatto if (const auto &subpDetails{subp->detailsIf<SubprogramDetails>()}) { 48164ab3302SCarolineConcatto if (subpDetails->isFunction()) { 48264ab3302SCarolineConcatto return &subpDetails->result(); 48364ab3302SCarolineConcatto } 48464ab3302SCarolineConcatto } 48564ab3302SCarolineConcatto } 48664ab3302SCarolineConcatto return nullptr; 48764ab3302SCarolineConcatto } 48864ab3302SCarolineConcatto 48964ab3302SCarolineConcatto const Symbol *FindOverriddenBinding(const Symbol &symbol) { 49064ab3302SCarolineConcatto if (symbol.has<ProcBindingDetails>()) { 49164ab3302SCarolineConcatto if (const DeclTypeSpec * parentType{FindParentTypeSpec(symbol.owner())}) { 49264ab3302SCarolineConcatto if (const DerivedTypeSpec * parentDerived{parentType->AsDerived()}) { 49364ab3302SCarolineConcatto if (const Scope * parentScope{parentDerived->typeSymbol().scope()}) { 49464ab3302SCarolineConcatto return parentScope->FindComponent(symbol.name()); 49564ab3302SCarolineConcatto } 49664ab3302SCarolineConcatto } 49764ab3302SCarolineConcatto } 49864ab3302SCarolineConcatto } 49964ab3302SCarolineConcatto return nullptr; 50064ab3302SCarolineConcatto } 50164ab3302SCarolineConcatto 50264ab3302SCarolineConcatto const DeclTypeSpec *FindParentTypeSpec(const DerivedTypeSpec &derived) { 50364ab3302SCarolineConcatto return FindParentTypeSpec(derived.typeSymbol()); 50464ab3302SCarolineConcatto } 50564ab3302SCarolineConcatto 50664ab3302SCarolineConcatto const DeclTypeSpec *FindParentTypeSpec(const DeclTypeSpec &decl) { 50764ab3302SCarolineConcatto if (const DerivedTypeSpec * derived{decl.AsDerived()}) { 50864ab3302SCarolineConcatto return FindParentTypeSpec(*derived); 50964ab3302SCarolineConcatto } else { 51064ab3302SCarolineConcatto return nullptr; 51164ab3302SCarolineConcatto } 51264ab3302SCarolineConcatto } 51364ab3302SCarolineConcatto 51464ab3302SCarolineConcatto const DeclTypeSpec *FindParentTypeSpec(const Scope &scope) { 51564ab3302SCarolineConcatto if (scope.kind() == Scope::Kind::DerivedType) { 51664ab3302SCarolineConcatto if (const auto *symbol{scope.symbol()}) { 51764ab3302SCarolineConcatto return FindParentTypeSpec(*symbol); 51864ab3302SCarolineConcatto } 51964ab3302SCarolineConcatto } 52064ab3302SCarolineConcatto return nullptr; 52164ab3302SCarolineConcatto } 52264ab3302SCarolineConcatto 52364ab3302SCarolineConcatto const DeclTypeSpec *FindParentTypeSpec(const Symbol &symbol) { 52464ab3302SCarolineConcatto if (const Scope * scope{symbol.scope()}) { 52564ab3302SCarolineConcatto if (const auto *details{symbol.detailsIf<DerivedTypeDetails>()}) { 52664ab3302SCarolineConcatto if (const Symbol * parent{details->GetParentComponent(*scope)}) { 52764ab3302SCarolineConcatto return parent->GetType(); 52864ab3302SCarolineConcatto } 52964ab3302SCarolineConcatto } 53064ab3302SCarolineConcatto } 53164ab3302SCarolineConcatto return nullptr; 53264ab3302SCarolineConcatto } 53364ab3302SCarolineConcatto 53464ab3302SCarolineConcatto // When a construct association maps to a variable, and that variable 53564ab3302SCarolineConcatto // is not an array with a vector-valued subscript, return the base 53664ab3302SCarolineConcatto // Symbol of that variable, else nullptr. Descends into other construct 53764ab3302SCarolineConcatto // associations when one associations maps to another. 53864ab3302SCarolineConcatto static const Symbol *GetAssociatedVariable(const AssocEntityDetails &details) { 53964ab3302SCarolineConcatto if (const MaybeExpr & expr{details.expr()}) { 54064ab3302SCarolineConcatto if (evaluate::IsVariable(*expr) && !evaluate::HasVectorSubscript(*expr)) { 54164ab3302SCarolineConcatto if (const Symbol * varSymbol{evaluate::GetFirstSymbol(*expr)}) { 54264ab3302SCarolineConcatto return GetAssociationRoot(*varSymbol); 54364ab3302SCarolineConcatto } 54464ab3302SCarolineConcatto } 54564ab3302SCarolineConcatto } 54664ab3302SCarolineConcatto return nullptr; 54764ab3302SCarolineConcatto } 54864ab3302SCarolineConcatto 54964ab3302SCarolineConcatto // Return the Symbol of the variable of a construct association, if it exists 55064ab3302SCarolineConcatto // Return nullptr if the name is associated with an expression 55164ab3302SCarolineConcatto const Symbol *GetAssociationRoot(const Symbol &symbol) { 55264ab3302SCarolineConcatto const Symbol &ultimate{symbol.GetUltimate()}; 55364ab3302SCarolineConcatto if (const auto *details{ultimate.detailsIf<AssocEntityDetails>()}) { 55464ab3302SCarolineConcatto // We have a construct association 55564ab3302SCarolineConcatto return GetAssociatedVariable(*details); 55664ab3302SCarolineConcatto } else { 55764ab3302SCarolineConcatto return &ultimate; 55864ab3302SCarolineConcatto } 55964ab3302SCarolineConcatto } 56064ab3302SCarolineConcatto 56164ab3302SCarolineConcatto bool IsExtensibleType(const DerivedTypeSpec *derived) { 56264ab3302SCarolineConcatto return derived && !IsIsoCType(derived) && 56364ab3302SCarolineConcatto !derived->typeSymbol().attrs().test(Attr::BIND_C) && 56464ab3302SCarolineConcatto !derived->typeSymbol().get<DerivedTypeDetails>().sequence(); 56564ab3302SCarolineConcatto } 56664ab3302SCarolineConcatto 56764ab3302SCarolineConcatto bool IsBuiltinDerivedType(const DerivedTypeSpec *derived, const char *name) { 56864ab3302SCarolineConcatto if (!derived) { 56964ab3302SCarolineConcatto return false; 57064ab3302SCarolineConcatto } else { 57164ab3302SCarolineConcatto const auto &symbol{derived->typeSymbol()}; 57264ab3302SCarolineConcatto return symbol.owner().IsModule() && 57364ab3302SCarolineConcatto symbol.owner().GetName().value() == "__fortran_builtins" && 57464ab3302SCarolineConcatto symbol.name() == "__builtin_"s + name; 57564ab3302SCarolineConcatto } 57664ab3302SCarolineConcatto } 57764ab3302SCarolineConcatto 57864ab3302SCarolineConcatto bool IsIsoCType(const DerivedTypeSpec *derived) { 57964ab3302SCarolineConcatto return IsBuiltinDerivedType(derived, "c_ptr") || 58064ab3302SCarolineConcatto IsBuiltinDerivedType(derived, "c_funptr"); 58164ab3302SCarolineConcatto } 58264ab3302SCarolineConcatto 58364ab3302SCarolineConcatto bool IsTeamType(const DerivedTypeSpec *derived) { 58464ab3302SCarolineConcatto return IsBuiltinDerivedType(derived, "team_type"); 58564ab3302SCarolineConcatto } 58664ab3302SCarolineConcatto 58764ab3302SCarolineConcatto bool IsEventTypeOrLockType(const DerivedTypeSpec *derivedTypeSpec) { 58864ab3302SCarolineConcatto return IsBuiltinDerivedType(derivedTypeSpec, "event_type") || 58964ab3302SCarolineConcatto IsBuiltinDerivedType(derivedTypeSpec, "lock_type"); 59064ab3302SCarolineConcatto } 59164ab3302SCarolineConcatto 59264ab3302SCarolineConcatto bool IsOrContainsEventOrLockComponent(const Symbol &symbol) { 59364ab3302SCarolineConcatto if (const Symbol * root{GetAssociationRoot(symbol)}) { 59464ab3302SCarolineConcatto if (const auto *details{root->detailsIf<ObjectEntityDetails>()}) { 59564ab3302SCarolineConcatto if (const DeclTypeSpec * type{details->type()}) { 59664ab3302SCarolineConcatto if (const DerivedTypeSpec * derived{type->AsDerived()}) { 59764ab3302SCarolineConcatto return IsEventTypeOrLockType(derived) || 59864ab3302SCarolineConcatto FindEventOrLockPotentialComponent(*derived); 59964ab3302SCarolineConcatto } 60064ab3302SCarolineConcatto } 60164ab3302SCarolineConcatto } 60264ab3302SCarolineConcatto } 60364ab3302SCarolineConcatto return false; 60464ab3302SCarolineConcatto } 60564ab3302SCarolineConcatto 60664ab3302SCarolineConcatto bool IsSaved(const Symbol &symbol) { 60764ab3302SCarolineConcatto auto scopeKind{symbol.owner().kind()}; 60864ab3302SCarolineConcatto if (scopeKind == Scope::Kind::MainProgram || 60964ab3302SCarolineConcatto scopeKind == Scope::Kind::Module) { 61064ab3302SCarolineConcatto return true; 61164ab3302SCarolineConcatto } else if (scopeKind == Scope::Kind::DerivedType) { 61264ab3302SCarolineConcatto return false; // this is a component 61364ab3302SCarolineConcatto } else if (IsNamedConstant(symbol)) { 61464ab3302SCarolineConcatto return false; 61564ab3302SCarolineConcatto } else if (symbol.attrs().test(Attr::SAVE)) { 61664ab3302SCarolineConcatto return true; 61764ab3302SCarolineConcatto } else { 61864ab3302SCarolineConcatto if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 61964ab3302SCarolineConcatto if (object->init()) { 62064ab3302SCarolineConcatto return true; 62164ab3302SCarolineConcatto } 62264ab3302SCarolineConcatto } else if (IsProcedurePointer(symbol)) { 62364ab3302SCarolineConcatto if (symbol.get<ProcEntityDetails>().init()) { 62464ab3302SCarolineConcatto return true; 62564ab3302SCarolineConcatto } 62664ab3302SCarolineConcatto } 62764ab3302SCarolineConcatto if (const Symbol * block{FindCommonBlockContaining(symbol)}) { 62864ab3302SCarolineConcatto if (block->attrs().test(Attr::SAVE)) { 62964ab3302SCarolineConcatto return true; 63064ab3302SCarolineConcatto } 63164ab3302SCarolineConcatto } 63264ab3302SCarolineConcatto return false; 63364ab3302SCarolineConcatto } 63464ab3302SCarolineConcatto } 63564ab3302SCarolineConcatto 63664ab3302SCarolineConcatto // Check this symbol suitable as a type-bound procedure - C769 63764ab3302SCarolineConcatto bool CanBeTypeBoundProc(const Symbol *symbol) { 63864ab3302SCarolineConcatto if (!symbol || IsDummy(*symbol) || IsProcedurePointer(*symbol)) { 63964ab3302SCarolineConcatto return false; 64064ab3302SCarolineConcatto } else if (symbol->has<SubprogramNameDetails>()) { 64164ab3302SCarolineConcatto return symbol->owner().kind() == Scope::Kind::Module; 64264ab3302SCarolineConcatto } else if (auto *details{symbol->detailsIf<SubprogramDetails>()}) { 64364ab3302SCarolineConcatto return symbol->owner().kind() == Scope::Kind::Module || 64464ab3302SCarolineConcatto details->isInterface(); 64564ab3302SCarolineConcatto } else if (const auto *proc{symbol->detailsIf<ProcEntityDetails>()}) { 64664ab3302SCarolineConcatto return !symbol->attrs().test(Attr::INTRINSIC) && 64764ab3302SCarolineConcatto proc->HasExplicitInterface(); 64864ab3302SCarolineConcatto } else { 64964ab3302SCarolineConcatto return false; 65064ab3302SCarolineConcatto } 65164ab3302SCarolineConcatto } 65264ab3302SCarolineConcatto 65364ab3302SCarolineConcatto bool IsInitialized(const Symbol &symbol) { 65464ab3302SCarolineConcatto if (symbol.test(Symbol::Flag::InDataStmt)) { 65564ab3302SCarolineConcatto return true; 65664ab3302SCarolineConcatto } else if (IsNamedConstant(symbol)) { 65764ab3302SCarolineConcatto return false; 65864ab3302SCarolineConcatto } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 65964ab3302SCarolineConcatto if (IsAllocatable(symbol) || object->init()) { 66064ab3302SCarolineConcatto return true; 66164ab3302SCarolineConcatto } 66264ab3302SCarolineConcatto if (!IsPointer(symbol) && object->type()) { 66364ab3302SCarolineConcatto if (const auto *derived{object->type()->AsDerived()}) { 66464ab3302SCarolineConcatto if (derived->HasDefaultInitialization()) { 66564ab3302SCarolineConcatto return true; 66664ab3302SCarolineConcatto } 66764ab3302SCarolineConcatto } 66864ab3302SCarolineConcatto } 66964ab3302SCarolineConcatto } else if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) { 67064ab3302SCarolineConcatto return proc->init().has_value(); 67164ab3302SCarolineConcatto } 67264ab3302SCarolineConcatto return false; 67364ab3302SCarolineConcatto } 67464ab3302SCarolineConcatto 67564ab3302SCarolineConcatto bool IsFinalizable(const Symbol &symbol) { 67664ab3302SCarolineConcatto if (const DeclTypeSpec * type{symbol.GetType()}) { 67764ab3302SCarolineConcatto if (const DerivedTypeSpec * derived{type->AsDerived()}) { 67864ab3302SCarolineConcatto return IsFinalizable(*derived); 67964ab3302SCarolineConcatto } 68064ab3302SCarolineConcatto } 68164ab3302SCarolineConcatto return false; 68264ab3302SCarolineConcatto } 68364ab3302SCarolineConcatto 68464ab3302SCarolineConcatto bool IsFinalizable(const DerivedTypeSpec &derived) { 68564ab3302SCarolineConcatto ScopeComponentIterator components{derived}; 68664ab3302SCarolineConcatto return std::find_if(components.begin(), components.end(), 68764ab3302SCarolineConcatto [](const Symbol &x) { return x.has<FinalProcDetails>(); }) != 68864ab3302SCarolineConcatto components.end(); 68964ab3302SCarolineConcatto } 69064ab3302SCarolineConcatto 69164ab3302SCarolineConcatto // TODO The following function returns true for all types with FINAL procedures 69264ab3302SCarolineConcatto // This is because we don't yet fill in the data for FinalProcDetails 69364ab3302SCarolineConcatto bool HasImpureFinal(const DerivedTypeSpec &derived) { 69464ab3302SCarolineConcatto ScopeComponentIterator components{derived}; 69564ab3302SCarolineConcatto return std::find_if( 69664ab3302SCarolineConcatto components.begin(), components.end(), [](const Symbol &x) { 69764ab3302SCarolineConcatto return x.has<FinalProcDetails>() && !x.attrs().test(Attr::PURE); 69864ab3302SCarolineConcatto }) != components.end(); 69964ab3302SCarolineConcatto } 70064ab3302SCarolineConcatto 70164ab3302SCarolineConcatto bool IsCoarray(const Symbol &symbol) { return symbol.Corank() > 0; } 70264ab3302SCarolineConcatto 70364ab3302SCarolineConcatto bool IsAssumedLengthCharacter(const Symbol &symbol) { 70464ab3302SCarolineConcatto if (const DeclTypeSpec * type{symbol.GetType()}) { 70564ab3302SCarolineConcatto return type->category() == DeclTypeSpec::Character && 70664ab3302SCarolineConcatto type->characterTypeSpec().length().isAssumed(); 70764ab3302SCarolineConcatto } else { 70864ab3302SCarolineConcatto return false; 70964ab3302SCarolineConcatto } 71064ab3302SCarolineConcatto } 71164ab3302SCarolineConcatto 712*657aaf8bSPete Steinfeld // C722 and C723: For a function to be assumed length, it must be external and 713*657aaf8bSPete Steinfeld // of CHARACTER type 714*657aaf8bSPete Steinfeld bool IsAssumedLengthExternalCharacterFunction(const Symbol &symbol) { 715*657aaf8bSPete Steinfeld return IsAssumedLengthCharacter(symbol) && 716*657aaf8bSPete Steinfeld ((symbol.has<SubprogramDetails>() && symbol.owner().IsGlobal()) || 717*657aaf8bSPete Steinfeld (symbol.test(Symbol::Flag::Function) && 718*657aaf8bSPete Steinfeld symbol.attrs().test(Attr::EXTERNAL))); 71964ab3302SCarolineConcatto } 72064ab3302SCarolineConcatto 72164ab3302SCarolineConcatto const Symbol *IsExternalInPureContext( 72264ab3302SCarolineConcatto const Symbol &symbol, const Scope &scope) { 72364ab3302SCarolineConcatto if (const auto *pureProc{semantics::FindPureProcedureContaining(scope)}) { 72464ab3302SCarolineConcatto if (const Symbol * root{GetAssociationRoot(symbol)}) { 72564ab3302SCarolineConcatto if (const Symbol * 72664ab3302SCarolineConcatto visible{FindExternallyVisibleObject(*root, *pureProc)}) { 72764ab3302SCarolineConcatto return visible; 72864ab3302SCarolineConcatto } 72964ab3302SCarolineConcatto } 73064ab3302SCarolineConcatto } 73164ab3302SCarolineConcatto return nullptr; 73264ab3302SCarolineConcatto } 73364ab3302SCarolineConcatto 73464ab3302SCarolineConcatto PotentialComponentIterator::const_iterator FindPolymorphicPotentialComponent( 73564ab3302SCarolineConcatto const DerivedTypeSpec &derived) { 73664ab3302SCarolineConcatto PotentialComponentIterator potentials{derived}; 73764ab3302SCarolineConcatto return std::find_if( 73864ab3302SCarolineConcatto potentials.begin(), potentials.end(), [](const Symbol &component) { 73964ab3302SCarolineConcatto if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) { 74064ab3302SCarolineConcatto const DeclTypeSpec *type{details->type()}; 74164ab3302SCarolineConcatto return type && type->IsPolymorphic(); 74264ab3302SCarolineConcatto } 74364ab3302SCarolineConcatto return false; 74464ab3302SCarolineConcatto }); 74564ab3302SCarolineConcatto } 74664ab3302SCarolineConcatto 74764ab3302SCarolineConcatto bool IsOrContainsPolymorphicComponent(const Symbol &symbol) { 74864ab3302SCarolineConcatto if (const Symbol * root{GetAssociationRoot(symbol)}) { 74964ab3302SCarolineConcatto if (const auto *details{root->detailsIf<ObjectEntityDetails>()}) { 75064ab3302SCarolineConcatto if (const DeclTypeSpec * type{details->type()}) { 75164ab3302SCarolineConcatto if (type->IsPolymorphic()) { 75264ab3302SCarolineConcatto return true; 75364ab3302SCarolineConcatto } 75464ab3302SCarolineConcatto if (const DerivedTypeSpec * derived{type->AsDerived()}) { 75564ab3302SCarolineConcatto return (bool)FindPolymorphicPotentialComponent(*derived); 75664ab3302SCarolineConcatto } 75764ab3302SCarolineConcatto } 75864ab3302SCarolineConcatto } 75964ab3302SCarolineConcatto } 76064ab3302SCarolineConcatto return false; 76164ab3302SCarolineConcatto } 76264ab3302SCarolineConcatto 76364ab3302SCarolineConcatto bool InProtectedContext(const Symbol &symbol, const Scope ¤tScope) { 76464ab3302SCarolineConcatto return IsProtected(symbol) && !IsHostAssociated(symbol, currentScope); 76564ab3302SCarolineConcatto } 76664ab3302SCarolineConcatto 76764ab3302SCarolineConcatto // C1101 and C1158 76864ab3302SCarolineConcatto // TODO Need to check for a coindexed object (why? C1103?) 76964ab3302SCarolineConcatto std::optional<parser::MessageFixedText> WhyNotModifiable( 77064ab3302SCarolineConcatto const Symbol &symbol, const Scope &scope) { 77164ab3302SCarolineConcatto const Symbol *root{GetAssociationRoot(symbol)}; 77264ab3302SCarolineConcatto if (!root) { 77364ab3302SCarolineConcatto return "'%s' is construct associated with an expression"_en_US; 77464ab3302SCarolineConcatto } else if (InProtectedContext(*root, scope)) { 77564ab3302SCarolineConcatto return "'%s' is protected in this scope"_en_US; 77664ab3302SCarolineConcatto } else if (IsExternalInPureContext(*root, scope)) { 77764ab3302SCarolineConcatto return "'%s' is externally visible and referenced in a pure" 77864ab3302SCarolineConcatto " procedure"_en_US; 77964ab3302SCarolineConcatto } else if (IsOrContainsEventOrLockComponent(*root)) { 78064ab3302SCarolineConcatto return "'%s' is an entity with either an EVENT_TYPE or LOCK_TYPE"_en_US; 78164ab3302SCarolineConcatto } else if (IsIntentIn(*root)) { 78264ab3302SCarolineConcatto return "'%s' is an INTENT(IN) dummy argument"_en_US; 78364ab3302SCarolineConcatto } else if (!IsVariableName(*root)) { 78464ab3302SCarolineConcatto return "'%s' is not a variable"_en_US; 78564ab3302SCarolineConcatto } else { 78664ab3302SCarolineConcatto return std::nullopt; 78764ab3302SCarolineConcatto } 78864ab3302SCarolineConcatto } 78964ab3302SCarolineConcatto 79064ab3302SCarolineConcatto std::unique_ptr<parser::Message> WhyNotModifiable(parser::CharBlock at, 79164ab3302SCarolineConcatto const SomeExpr &expr, const Scope &scope, bool vectorSubscriptIsOk) { 79264ab3302SCarolineConcatto if (evaluate::IsVariable(expr)) { 79364ab3302SCarolineConcatto if (auto dataRef{evaluate::ExtractDataRef(expr)}) { 79464ab3302SCarolineConcatto if (!vectorSubscriptIsOk && evaluate::HasVectorSubscript(expr)) { 79564ab3302SCarolineConcatto return std::make_unique<parser::Message>( 79664ab3302SCarolineConcatto at, "variable has a vector subscript"_en_US); 79764ab3302SCarolineConcatto } else { 79864ab3302SCarolineConcatto const Symbol &symbol{dataRef->GetFirstSymbol()}; 79964ab3302SCarolineConcatto if (auto maybeWhy{WhyNotModifiable(symbol, scope)}) { 80064ab3302SCarolineConcatto return std::make_unique<parser::Message>(symbol.name(), 80164ab3302SCarolineConcatto parser::MessageFormattedText{ 80264ab3302SCarolineConcatto std::move(*maybeWhy), symbol.name()}); 80364ab3302SCarolineConcatto } 80464ab3302SCarolineConcatto } 80564ab3302SCarolineConcatto } else { 80664ab3302SCarolineConcatto // reference to function returning POINTER 80764ab3302SCarolineConcatto } 80864ab3302SCarolineConcatto } else { 80964ab3302SCarolineConcatto return std::make_unique<parser::Message>( 81064ab3302SCarolineConcatto at, "expression is not a variable"_en_US); 81164ab3302SCarolineConcatto } 81264ab3302SCarolineConcatto return {}; 81364ab3302SCarolineConcatto } 81464ab3302SCarolineConcatto 81564ab3302SCarolineConcatto class ImageControlStmtHelper { 81664ab3302SCarolineConcatto using ImageControlStmts = std::variant<parser::ChangeTeamConstruct, 81764ab3302SCarolineConcatto parser::CriticalConstruct, parser::EventPostStmt, parser::EventWaitStmt, 81864ab3302SCarolineConcatto parser::FormTeamStmt, parser::LockStmt, parser::StopStmt, 81964ab3302SCarolineConcatto parser::SyncAllStmt, parser::SyncImagesStmt, parser::SyncMemoryStmt, 82064ab3302SCarolineConcatto parser::SyncTeamStmt, parser::UnlockStmt>; 82164ab3302SCarolineConcatto 82264ab3302SCarolineConcatto public: 82364ab3302SCarolineConcatto template<typename T> bool operator()(const T &) { 82464ab3302SCarolineConcatto return common::HasMember<T, ImageControlStmts>; 82564ab3302SCarolineConcatto } 82664ab3302SCarolineConcatto template<typename T> bool operator()(const common::Indirection<T> &x) { 82764ab3302SCarolineConcatto return (*this)(x.value()); 82864ab3302SCarolineConcatto } 82964ab3302SCarolineConcatto bool operator()(const parser::AllocateStmt &stmt) { 83064ab3302SCarolineConcatto const auto &allocationList{std::get<std::list<parser::Allocation>>(stmt.t)}; 83164ab3302SCarolineConcatto for (const auto &allocation : allocationList) { 83264ab3302SCarolineConcatto const auto &allocateObject{ 83364ab3302SCarolineConcatto std::get<parser::AllocateObject>(allocation.t)}; 83464ab3302SCarolineConcatto if (IsCoarrayObject(allocateObject)) { 83564ab3302SCarolineConcatto return true; 83664ab3302SCarolineConcatto } 83764ab3302SCarolineConcatto } 83864ab3302SCarolineConcatto return false; 83964ab3302SCarolineConcatto } 84064ab3302SCarolineConcatto bool operator()(const parser::DeallocateStmt &stmt) { 84164ab3302SCarolineConcatto const auto &allocateObjectList{ 84264ab3302SCarolineConcatto std::get<std::list<parser::AllocateObject>>(stmt.t)}; 84364ab3302SCarolineConcatto for (const auto &allocateObject : allocateObjectList) { 84464ab3302SCarolineConcatto if (IsCoarrayObject(allocateObject)) { 84564ab3302SCarolineConcatto return true; 84664ab3302SCarolineConcatto } 84764ab3302SCarolineConcatto } 84864ab3302SCarolineConcatto return false; 84964ab3302SCarolineConcatto } 85064ab3302SCarolineConcatto bool operator()(const parser::CallStmt &stmt) { 85164ab3302SCarolineConcatto const auto &procedureDesignator{ 85264ab3302SCarolineConcatto std::get<parser::ProcedureDesignator>(stmt.v.t)}; 85364ab3302SCarolineConcatto if (auto *name{std::get_if<parser::Name>(&procedureDesignator.u)}) { 85464ab3302SCarolineConcatto // TODO: also ensure that the procedure is, in fact, an intrinsic 85564ab3302SCarolineConcatto if (name->source == "move_alloc") { 85664ab3302SCarolineConcatto const auto &args{std::get<std::list<parser::ActualArgSpec>>(stmt.v.t)}; 85764ab3302SCarolineConcatto if (!args.empty()) { 85864ab3302SCarolineConcatto const parser::ActualArg &actualArg{ 85964ab3302SCarolineConcatto std::get<parser::ActualArg>(args.front().t)}; 86064ab3302SCarolineConcatto if (const auto *argExpr{ 86164ab3302SCarolineConcatto std::get_if<common::Indirection<parser::Expr>>( 86264ab3302SCarolineConcatto &actualArg.u)}) { 86364ab3302SCarolineConcatto return HasCoarray(argExpr->value()); 86464ab3302SCarolineConcatto } 86564ab3302SCarolineConcatto } 86664ab3302SCarolineConcatto } 86764ab3302SCarolineConcatto } 86864ab3302SCarolineConcatto return false; 86964ab3302SCarolineConcatto } 87064ab3302SCarolineConcatto bool operator()(const parser::Statement<parser::ActionStmt> &stmt) { 87164ab3302SCarolineConcatto return std::visit(*this, stmt.statement.u); 87264ab3302SCarolineConcatto } 87364ab3302SCarolineConcatto 87464ab3302SCarolineConcatto private: 87564ab3302SCarolineConcatto bool IsCoarrayObject(const parser::AllocateObject &allocateObject) { 87664ab3302SCarolineConcatto const parser::Name &name{GetLastName(allocateObject)}; 87764ab3302SCarolineConcatto return name.symbol && IsCoarray(*name.symbol); 87864ab3302SCarolineConcatto } 87964ab3302SCarolineConcatto }; 88064ab3302SCarolineConcatto 88164ab3302SCarolineConcatto bool IsImageControlStmt(const parser::ExecutableConstruct &construct) { 88264ab3302SCarolineConcatto return std::visit(ImageControlStmtHelper{}, construct.u); 88364ab3302SCarolineConcatto } 88464ab3302SCarolineConcatto 88564ab3302SCarolineConcatto std::optional<parser::MessageFixedText> GetImageControlStmtCoarrayMsg( 88664ab3302SCarolineConcatto const parser::ExecutableConstruct &construct) { 88764ab3302SCarolineConcatto if (const auto *actionStmt{ 88864ab3302SCarolineConcatto std::get_if<parser::Statement<parser::ActionStmt>>(&construct.u)}) { 88964ab3302SCarolineConcatto return std::visit( 89064ab3302SCarolineConcatto common::visitors{ 89164ab3302SCarolineConcatto [](const common::Indirection<parser::AllocateStmt> &) 89264ab3302SCarolineConcatto -> std::optional<parser::MessageFixedText> { 89364ab3302SCarolineConcatto return "ALLOCATE of a coarray is an image control" 89464ab3302SCarolineConcatto " statement"_en_US; 89564ab3302SCarolineConcatto }, 89664ab3302SCarolineConcatto [](const common::Indirection<parser::DeallocateStmt> &) 89764ab3302SCarolineConcatto -> std::optional<parser::MessageFixedText> { 89864ab3302SCarolineConcatto return "DEALLOCATE of a coarray is an image control" 89964ab3302SCarolineConcatto " statement"_en_US; 90064ab3302SCarolineConcatto }, 90164ab3302SCarolineConcatto [](const common::Indirection<parser::CallStmt> &) 90264ab3302SCarolineConcatto -> std::optional<parser::MessageFixedText> { 90364ab3302SCarolineConcatto return "MOVE_ALLOC of a coarray is an image control" 90464ab3302SCarolineConcatto " statement "_en_US; 90564ab3302SCarolineConcatto }, 90664ab3302SCarolineConcatto [](const auto &) -> std::optional<parser::MessageFixedText> { 90764ab3302SCarolineConcatto return std::nullopt; 90864ab3302SCarolineConcatto }, 90964ab3302SCarolineConcatto }, 91064ab3302SCarolineConcatto actionStmt->statement.u); 91164ab3302SCarolineConcatto } 91264ab3302SCarolineConcatto return std::nullopt; 91364ab3302SCarolineConcatto } 91464ab3302SCarolineConcatto 91564ab3302SCarolineConcatto parser::CharBlock GetImageControlStmtLocation( 91664ab3302SCarolineConcatto const parser::ExecutableConstruct &executableConstruct) { 91764ab3302SCarolineConcatto return std::visit( 91864ab3302SCarolineConcatto common::visitors{ 91964ab3302SCarolineConcatto [](const common::Indirection<parser::ChangeTeamConstruct> 92064ab3302SCarolineConcatto &construct) { 92164ab3302SCarolineConcatto return std::get<parser::Statement<parser::ChangeTeamStmt>>( 92264ab3302SCarolineConcatto construct.value().t) 92364ab3302SCarolineConcatto .source; 92464ab3302SCarolineConcatto }, 92564ab3302SCarolineConcatto [](const common::Indirection<parser::CriticalConstruct> &construct) { 92664ab3302SCarolineConcatto return std::get<parser::Statement<parser::CriticalStmt>>( 92764ab3302SCarolineConcatto construct.value().t) 92864ab3302SCarolineConcatto .source; 92964ab3302SCarolineConcatto }, 93064ab3302SCarolineConcatto [](const parser::Statement<parser::ActionStmt> &actionStmt) { 93164ab3302SCarolineConcatto return actionStmt.source; 93264ab3302SCarolineConcatto }, 93364ab3302SCarolineConcatto [](const auto &) { return parser::CharBlock{}; }, 93464ab3302SCarolineConcatto }, 93564ab3302SCarolineConcatto executableConstruct.u); 93664ab3302SCarolineConcatto } 93764ab3302SCarolineConcatto 93864ab3302SCarolineConcatto bool HasCoarray(const parser::Expr &expression) { 93964ab3302SCarolineConcatto if (const auto *expr{GetExpr(expression)}) { 94064ab3302SCarolineConcatto for (const Symbol &symbol : evaluate::CollectSymbols(*expr)) { 94164ab3302SCarolineConcatto if (const Symbol * root{GetAssociationRoot(symbol)}) { 94264ab3302SCarolineConcatto if (IsCoarray(*root)) { 94364ab3302SCarolineConcatto return true; 94464ab3302SCarolineConcatto } 94564ab3302SCarolineConcatto } 94664ab3302SCarolineConcatto } 94764ab3302SCarolineConcatto } 94864ab3302SCarolineConcatto return false; 94964ab3302SCarolineConcatto } 95064ab3302SCarolineConcatto 95164ab3302SCarolineConcatto bool IsPolymorphic(const Symbol &symbol) { 95264ab3302SCarolineConcatto if (const DeclTypeSpec * type{symbol.GetType()}) { 95364ab3302SCarolineConcatto return type->IsPolymorphic(); 95464ab3302SCarolineConcatto } 95564ab3302SCarolineConcatto return false; 95664ab3302SCarolineConcatto } 95764ab3302SCarolineConcatto 95864ab3302SCarolineConcatto bool IsPolymorphicAllocatable(const Symbol &symbol) { 95964ab3302SCarolineConcatto return IsAllocatable(symbol) && IsPolymorphic(symbol); 96064ab3302SCarolineConcatto } 96164ab3302SCarolineConcatto 96264ab3302SCarolineConcatto std::list<SourceName> OrderParameterNames(const Symbol &typeSymbol) { 96364ab3302SCarolineConcatto std::list<SourceName> result; 96464ab3302SCarolineConcatto if (const DerivedTypeSpec * spec{typeSymbol.GetParentTypeSpec()}) { 96564ab3302SCarolineConcatto result = OrderParameterNames(spec->typeSymbol()); 96664ab3302SCarolineConcatto } 96764ab3302SCarolineConcatto const auto ¶mNames{typeSymbol.get<DerivedTypeDetails>().paramNames()}; 96864ab3302SCarolineConcatto result.insert(result.end(), paramNames.begin(), paramNames.end()); 96964ab3302SCarolineConcatto return result; 97064ab3302SCarolineConcatto } 97164ab3302SCarolineConcatto 97264ab3302SCarolineConcatto SymbolVector OrderParameterDeclarations(const Symbol &typeSymbol) { 97364ab3302SCarolineConcatto SymbolVector result; 97464ab3302SCarolineConcatto if (const DerivedTypeSpec * spec{typeSymbol.GetParentTypeSpec()}) { 97564ab3302SCarolineConcatto result = OrderParameterDeclarations(spec->typeSymbol()); 97664ab3302SCarolineConcatto } 97764ab3302SCarolineConcatto const auto ¶mDecls{typeSymbol.get<DerivedTypeDetails>().paramDecls()}; 97864ab3302SCarolineConcatto result.insert(result.end(), paramDecls.begin(), paramDecls.end()); 97964ab3302SCarolineConcatto return result; 98064ab3302SCarolineConcatto } 98164ab3302SCarolineConcatto 98264ab3302SCarolineConcatto const DeclTypeSpec &FindOrInstantiateDerivedType(Scope &scope, 98364ab3302SCarolineConcatto DerivedTypeSpec &&spec, SemanticsContext &semanticsContext, 98464ab3302SCarolineConcatto DeclTypeSpec::Category category) { 98564ab3302SCarolineConcatto spec.CookParameters(semanticsContext.foldingContext()); 98664ab3302SCarolineConcatto spec.EvaluateParameters(semanticsContext.foldingContext()); 98764ab3302SCarolineConcatto if (const DeclTypeSpec * 98864ab3302SCarolineConcatto type{scope.FindInstantiatedDerivedType(spec, category)}) { 98964ab3302SCarolineConcatto return *type; 99064ab3302SCarolineConcatto } 99164ab3302SCarolineConcatto // Create a new instantiation of this parameterized derived type 99264ab3302SCarolineConcatto // for this particular distinct set of actual parameter values. 99364ab3302SCarolineConcatto DeclTypeSpec &type{scope.MakeDerivedType(category, std::move(spec))}; 99464ab3302SCarolineConcatto type.derivedTypeSpec().Instantiate(scope, semanticsContext); 99564ab3302SCarolineConcatto return type; 99664ab3302SCarolineConcatto } 99764ab3302SCarolineConcatto 99864ab3302SCarolineConcatto // ComponentIterator implementation 99964ab3302SCarolineConcatto 100064ab3302SCarolineConcatto template<ComponentKind componentKind> 100164ab3302SCarolineConcatto typename ComponentIterator<componentKind>::const_iterator 100264ab3302SCarolineConcatto ComponentIterator<componentKind>::const_iterator::Create( 100364ab3302SCarolineConcatto const DerivedTypeSpec &derived) { 100464ab3302SCarolineConcatto const_iterator it{}; 100564ab3302SCarolineConcatto it.componentPath_.emplace_back(derived); 100664ab3302SCarolineConcatto it.Increment(); // cue up first relevant component, if any 100764ab3302SCarolineConcatto return it; 100864ab3302SCarolineConcatto } 100964ab3302SCarolineConcatto 101064ab3302SCarolineConcatto template<ComponentKind componentKind> 101164ab3302SCarolineConcatto const DerivedTypeSpec * 101264ab3302SCarolineConcatto ComponentIterator<componentKind>::const_iterator::PlanComponentTraversal( 101364ab3302SCarolineConcatto const Symbol &component) const { 101464ab3302SCarolineConcatto if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) { 101564ab3302SCarolineConcatto if (const DeclTypeSpec * type{details->type()}) { 101664ab3302SCarolineConcatto if (const auto *derived{type->AsDerived()}) { 101764ab3302SCarolineConcatto bool traverse{false}; 101864ab3302SCarolineConcatto if constexpr (componentKind == ComponentKind::Ordered) { 101964ab3302SCarolineConcatto // Order Component (only visit parents) 102064ab3302SCarolineConcatto traverse = component.test(Symbol::Flag::ParentComp); 102164ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Direct) { 102264ab3302SCarolineConcatto traverse = !IsAllocatableOrPointer(component); 102364ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Ultimate) { 102464ab3302SCarolineConcatto traverse = !IsAllocatableOrPointer(component); 102564ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Potential) { 102664ab3302SCarolineConcatto traverse = !IsPointer(component); 102764ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Scope) { 102864ab3302SCarolineConcatto traverse = !IsAllocatableOrPointer(component); 102964ab3302SCarolineConcatto } 103064ab3302SCarolineConcatto if (traverse) { 103164ab3302SCarolineConcatto const Symbol &newTypeSymbol{derived->typeSymbol()}; 103264ab3302SCarolineConcatto // Avoid infinite loop if the type is already part of the types 103364ab3302SCarolineConcatto // being visited. It is possible to have "loops in type" because 103464ab3302SCarolineConcatto // C744 does not forbid to use not yet declared type for 103564ab3302SCarolineConcatto // ALLOCATABLE or POINTER components. 103664ab3302SCarolineConcatto for (const auto &node : componentPath_) { 103764ab3302SCarolineConcatto if (&newTypeSymbol == &node.GetTypeSymbol()) { 103864ab3302SCarolineConcatto return nullptr; 103964ab3302SCarolineConcatto } 104064ab3302SCarolineConcatto } 104164ab3302SCarolineConcatto return derived; 104264ab3302SCarolineConcatto } 104364ab3302SCarolineConcatto } 104464ab3302SCarolineConcatto } // intrinsic & unlimited polymorphic not traversable 104564ab3302SCarolineConcatto } 104664ab3302SCarolineConcatto return nullptr; 104764ab3302SCarolineConcatto } 104864ab3302SCarolineConcatto 104964ab3302SCarolineConcatto template<ComponentKind componentKind> 105064ab3302SCarolineConcatto static bool StopAtComponentPre(const Symbol &component) { 105164ab3302SCarolineConcatto if constexpr (componentKind == ComponentKind::Ordered) { 105264ab3302SCarolineConcatto // Parent components need to be iterated upon after their 105364ab3302SCarolineConcatto // sub-components in structure constructor analysis. 105464ab3302SCarolineConcatto return !component.test(Symbol::Flag::ParentComp); 105564ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Direct) { 105664ab3302SCarolineConcatto return true; 105764ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Ultimate) { 105864ab3302SCarolineConcatto return component.has<ProcEntityDetails>() || 105964ab3302SCarolineConcatto IsAllocatableOrPointer(component) || 106064ab3302SCarolineConcatto (component.get<ObjectEntityDetails>().type() && 106164ab3302SCarolineConcatto component.get<ObjectEntityDetails>().type()->AsIntrinsic()); 106264ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Potential) { 106364ab3302SCarolineConcatto return !IsPointer(component); 106464ab3302SCarolineConcatto } 106564ab3302SCarolineConcatto } 106664ab3302SCarolineConcatto 106764ab3302SCarolineConcatto template<ComponentKind componentKind> 106864ab3302SCarolineConcatto static bool StopAtComponentPost(const Symbol &component) { 106964ab3302SCarolineConcatto return componentKind == ComponentKind::Ordered && 107064ab3302SCarolineConcatto component.test(Symbol::Flag::ParentComp); 107164ab3302SCarolineConcatto } 107264ab3302SCarolineConcatto 107364ab3302SCarolineConcatto template<ComponentKind componentKind> 107464ab3302SCarolineConcatto void ComponentIterator<componentKind>::const_iterator::Increment() { 107564ab3302SCarolineConcatto while (!componentPath_.empty()) { 107664ab3302SCarolineConcatto ComponentPathNode &deepest{componentPath_.back()}; 107764ab3302SCarolineConcatto if (deepest.component()) { 107864ab3302SCarolineConcatto if (!deepest.descended()) { 107964ab3302SCarolineConcatto deepest.set_descended(true); 108064ab3302SCarolineConcatto if (const DerivedTypeSpec * 108164ab3302SCarolineConcatto derived{PlanComponentTraversal(*deepest.component())}) { 108264ab3302SCarolineConcatto componentPath_.emplace_back(*derived); 108364ab3302SCarolineConcatto continue; 108464ab3302SCarolineConcatto } 108564ab3302SCarolineConcatto } else if (!deepest.visited()) { 108664ab3302SCarolineConcatto deepest.set_visited(true); 108764ab3302SCarolineConcatto return; // this is the next component to visit, after descending 108864ab3302SCarolineConcatto } 108964ab3302SCarolineConcatto } 109064ab3302SCarolineConcatto auto &nameIterator{deepest.nameIterator()}; 109164ab3302SCarolineConcatto if (nameIterator == deepest.nameEnd()) { 109264ab3302SCarolineConcatto componentPath_.pop_back(); 109364ab3302SCarolineConcatto } else if constexpr (componentKind == ComponentKind::Scope) { 109464ab3302SCarolineConcatto deepest.set_component(*nameIterator++->second); 109564ab3302SCarolineConcatto deepest.set_descended(false); 109664ab3302SCarolineConcatto deepest.set_visited(true); 109764ab3302SCarolineConcatto return; // this is the next component to visit, before descending 109864ab3302SCarolineConcatto } else { 109964ab3302SCarolineConcatto const Scope &scope{deepest.GetScope()}; 110064ab3302SCarolineConcatto auto scopeIter{scope.find(*nameIterator++)}; 110164ab3302SCarolineConcatto if (scopeIter != scope.cend()) { 110264ab3302SCarolineConcatto const Symbol &component{*scopeIter->second}; 110364ab3302SCarolineConcatto deepest.set_component(component); 110464ab3302SCarolineConcatto deepest.set_descended(false); 110564ab3302SCarolineConcatto if (StopAtComponentPre<componentKind>(component)) { 110664ab3302SCarolineConcatto deepest.set_visited(true); 110764ab3302SCarolineConcatto return; // this is the next component to visit, before descending 110864ab3302SCarolineConcatto } else { 110964ab3302SCarolineConcatto deepest.set_visited(!StopAtComponentPost<componentKind>(component)); 111064ab3302SCarolineConcatto } 111164ab3302SCarolineConcatto } 111264ab3302SCarolineConcatto } 111364ab3302SCarolineConcatto } 111464ab3302SCarolineConcatto } 111564ab3302SCarolineConcatto 111664ab3302SCarolineConcatto template<ComponentKind componentKind> 111764ab3302SCarolineConcatto std::string 111864ab3302SCarolineConcatto ComponentIterator<componentKind>::const_iterator::BuildResultDesignatorName() 111964ab3302SCarolineConcatto const { 112064ab3302SCarolineConcatto std::string designator{""}; 112164ab3302SCarolineConcatto for (const auto &node : componentPath_) { 112264ab3302SCarolineConcatto designator += "%" + DEREF(node.component()).name().ToString(); 112364ab3302SCarolineConcatto } 112464ab3302SCarolineConcatto return designator; 112564ab3302SCarolineConcatto } 112664ab3302SCarolineConcatto 112764ab3302SCarolineConcatto template class ComponentIterator<ComponentKind::Ordered>; 112864ab3302SCarolineConcatto template class ComponentIterator<ComponentKind::Direct>; 112964ab3302SCarolineConcatto template class ComponentIterator<ComponentKind::Ultimate>; 113064ab3302SCarolineConcatto template class ComponentIterator<ComponentKind::Potential>; 113164ab3302SCarolineConcatto template class ComponentIterator<ComponentKind::Scope>; 113264ab3302SCarolineConcatto 113364ab3302SCarolineConcatto UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent( 113464ab3302SCarolineConcatto const DerivedTypeSpec &derived) { 113564ab3302SCarolineConcatto UltimateComponentIterator ultimates{derived}; 113664ab3302SCarolineConcatto return std::find_if(ultimates.begin(), ultimates.end(), IsCoarray); 113764ab3302SCarolineConcatto } 113864ab3302SCarolineConcatto 113964ab3302SCarolineConcatto UltimateComponentIterator::const_iterator FindPointerUltimateComponent( 114064ab3302SCarolineConcatto const DerivedTypeSpec &derived) { 114164ab3302SCarolineConcatto UltimateComponentIterator ultimates{derived}; 114264ab3302SCarolineConcatto return std::find_if(ultimates.begin(), ultimates.end(), IsPointer); 114364ab3302SCarolineConcatto } 114464ab3302SCarolineConcatto 114564ab3302SCarolineConcatto PotentialComponentIterator::const_iterator FindEventOrLockPotentialComponent( 114664ab3302SCarolineConcatto const DerivedTypeSpec &derived) { 114764ab3302SCarolineConcatto PotentialComponentIterator potentials{derived}; 114864ab3302SCarolineConcatto return std::find_if( 114964ab3302SCarolineConcatto potentials.begin(), potentials.end(), [](const Symbol &component) { 115064ab3302SCarolineConcatto if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) { 115164ab3302SCarolineConcatto const DeclTypeSpec *type{details->type()}; 115264ab3302SCarolineConcatto return type && IsEventTypeOrLockType(type->AsDerived()); 115364ab3302SCarolineConcatto } 115464ab3302SCarolineConcatto return false; 115564ab3302SCarolineConcatto }); 115664ab3302SCarolineConcatto } 115764ab3302SCarolineConcatto 115864ab3302SCarolineConcatto UltimateComponentIterator::const_iterator FindAllocatableUltimateComponent( 115964ab3302SCarolineConcatto const DerivedTypeSpec &derived) { 116064ab3302SCarolineConcatto UltimateComponentIterator ultimates{derived}; 116164ab3302SCarolineConcatto return std::find_if(ultimates.begin(), ultimates.end(), IsAllocatable); 116264ab3302SCarolineConcatto } 116364ab3302SCarolineConcatto 116464ab3302SCarolineConcatto UltimateComponentIterator::const_iterator 116564ab3302SCarolineConcatto FindPolymorphicAllocatableUltimateComponent(const DerivedTypeSpec &derived) { 116664ab3302SCarolineConcatto UltimateComponentIterator ultimates{derived}; 116764ab3302SCarolineConcatto return std::find_if( 116864ab3302SCarolineConcatto ultimates.begin(), ultimates.end(), IsPolymorphicAllocatable); 116964ab3302SCarolineConcatto } 117064ab3302SCarolineConcatto 117164ab3302SCarolineConcatto UltimateComponentIterator::const_iterator 117264ab3302SCarolineConcatto FindPolymorphicAllocatableNonCoarrayUltimateComponent( 117364ab3302SCarolineConcatto const DerivedTypeSpec &derived) { 117464ab3302SCarolineConcatto UltimateComponentIterator ultimates{derived}; 117564ab3302SCarolineConcatto return std::find_if(ultimates.begin(), ultimates.end(), [](const Symbol &x) { 117664ab3302SCarolineConcatto return IsPolymorphicAllocatable(x) && !IsCoarray(x); 117764ab3302SCarolineConcatto }); 117864ab3302SCarolineConcatto } 117964ab3302SCarolineConcatto 118064ab3302SCarolineConcatto const Symbol *FindUltimateComponent(const DerivedTypeSpec &derived, 118164ab3302SCarolineConcatto const std::function<bool(const Symbol &)> &predicate) { 118264ab3302SCarolineConcatto UltimateComponentIterator ultimates{derived}; 118364ab3302SCarolineConcatto if (auto it{std::find_if(ultimates.begin(), ultimates.end(), 118464ab3302SCarolineConcatto [&predicate](const Symbol &component) -> bool { 118564ab3302SCarolineConcatto return predicate(component); 118664ab3302SCarolineConcatto })}) { 118764ab3302SCarolineConcatto return &*it; 118864ab3302SCarolineConcatto } 118964ab3302SCarolineConcatto return nullptr; 119064ab3302SCarolineConcatto } 119164ab3302SCarolineConcatto 119264ab3302SCarolineConcatto const Symbol *FindUltimateComponent(const Symbol &symbol, 119364ab3302SCarolineConcatto const std::function<bool(const Symbol &)> &predicate) { 119464ab3302SCarolineConcatto if (predicate(symbol)) { 119564ab3302SCarolineConcatto return &symbol; 119664ab3302SCarolineConcatto } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 119764ab3302SCarolineConcatto if (const auto *type{object->type()}) { 119864ab3302SCarolineConcatto if (const auto *derived{type->AsDerived()}) { 119964ab3302SCarolineConcatto return FindUltimateComponent(*derived, predicate); 120064ab3302SCarolineConcatto } 120164ab3302SCarolineConcatto } 120264ab3302SCarolineConcatto } 120364ab3302SCarolineConcatto return nullptr; 120464ab3302SCarolineConcatto } 120564ab3302SCarolineConcatto 120664ab3302SCarolineConcatto const Symbol *FindImmediateComponent(const DerivedTypeSpec &type, 120764ab3302SCarolineConcatto const std::function<bool(const Symbol &)> &predicate) { 120864ab3302SCarolineConcatto if (const Scope * scope{type.scope()}) { 120964ab3302SCarolineConcatto const Symbol *parent{nullptr}; 121064ab3302SCarolineConcatto for (const auto &pair : *scope) { 121164ab3302SCarolineConcatto const Symbol *symbol{&*pair.second}; 121264ab3302SCarolineConcatto if (predicate(*symbol)) { 121364ab3302SCarolineConcatto return symbol; 121464ab3302SCarolineConcatto } 121564ab3302SCarolineConcatto if (symbol->test(Symbol::Flag::ParentComp)) { 121664ab3302SCarolineConcatto parent = symbol; 121764ab3302SCarolineConcatto } 121864ab3302SCarolineConcatto } 121964ab3302SCarolineConcatto if (parent) { 122064ab3302SCarolineConcatto if (const auto *object{parent->detailsIf<ObjectEntityDetails>()}) { 122164ab3302SCarolineConcatto if (const auto *type{object->type()}) { 122264ab3302SCarolineConcatto if (const auto *derived{type->AsDerived()}) { 122364ab3302SCarolineConcatto return FindImmediateComponent(*derived, predicate); 122464ab3302SCarolineConcatto } 122564ab3302SCarolineConcatto } 122664ab3302SCarolineConcatto } 122764ab3302SCarolineConcatto } 122864ab3302SCarolineConcatto } 122964ab3302SCarolineConcatto return nullptr; 123064ab3302SCarolineConcatto } 123164ab3302SCarolineConcatto 123264ab3302SCarolineConcatto bool IsFunctionResult(const Symbol &symbol) { 123364ab3302SCarolineConcatto return (symbol.has<semantics::ObjectEntityDetails>() && 123464ab3302SCarolineConcatto symbol.get<semantics::ObjectEntityDetails>().isFuncResult()) || 123564ab3302SCarolineConcatto (symbol.has<semantics::ProcEntityDetails>() && 123664ab3302SCarolineConcatto symbol.get<semantics::ProcEntityDetails>().isFuncResult()); 123764ab3302SCarolineConcatto } 123864ab3302SCarolineConcatto 123964ab3302SCarolineConcatto bool IsFunctionResultWithSameNameAsFunction(const Symbol &symbol) { 124064ab3302SCarolineConcatto if (IsFunctionResult(symbol)) { 124164ab3302SCarolineConcatto if (const Symbol * function{symbol.owner().symbol()}) { 124264ab3302SCarolineConcatto return symbol.name() == function->name(); 124364ab3302SCarolineConcatto } 124464ab3302SCarolineConcatto } 124564ab3302SCarolineConcatto return false; 124664ab3302SCarolineConcatto } 124764ab3302SCarolineConcatto 124864ab3302SCarolineConcatto void LabelEnforce::Post(const parser::GotoStmt &gotoStmt) { 124964ab3302SCarolineConcatto checkLabelUse(gotoStmt.v); 125064ab3302SCarolineConcatto } 125164ab3302SCarolineConcatto void LabelEnforce::Post(const parser::ComputedGotoStmt &computedGotoStmt) { 125264ab3302SCarolineConcatto for (auto &i : std::get<std::list<parser::Label>>(computedGotoStmt.t)) { 125364ab3302SCarolineConcatto checkLabelUse(i); 125464ab3302SCarolineConcatto } 125564ab3302SCarolineConcatto } 125664ab3302SCarolineConcatto 125764ab3302SCarolineConcatto void LabelEnforce::Post(const parser::ArithmeticIfStmt &arithmeticIfStmt) { 125864ab3302SCarolineConcatto checkLabelUse(std::get<1>(arithmeticIfStmt.t)); 125964ab3302SCarolineConcatto checkLabelUse(std::get<2>(arithmeticIfStmt.t)); 126064ab3302SCarolineConcatto checkLabelUse(std::get<3>(arithmeticIfStmt.t)); 126164ab3302SCarolineConcatto } 126264ab3302SCarolineConcatto 126364ab3302SCarolineConcatto void LabelEnforce::Post(const parser::AssignStmt &assignStmt) { 126464ab3302SCarolineConcatto checkLabelUse(std::get<parser::Label>(assignStmt.t)); 126564ab3302SCarolineConcatto } 126664ab3302SCarolineConcatto 126764ab3302SCarolineConcatto void LabelEnforce::Post(const parser::AssignedGotoStmt &assignedGotoStmt) { 126864ab3302SCarolineConcatto for (auto &i : std::get<std::list<parser::Label>>(assignedGotoStmt.t)) { 126964ab3302SCarolineConcatto checkLabelUse(i); 127064ab3302SCarolineConcatto } 127164ab3302SCarolineConcatto } 127264ab3302SCarolineConcatto 127364ab3302SCarolineConcatto void LabelEnforce::Post(const parser::AltReturnSpec &altReturnSpec) { 127464ab3302SCarolineConcatto checkLabelUse(altReturnSpec.v); 127564ab3302SCarolineConcatto } 127664ab3302SCarolineConcatto 127764ab3302SCarolineConcatto void LabelEnforce::Post(const parser::ErrLabel &errLabel) { 127864ab3302SCarolineConcatto checkLabelUse(errLabel.v); 127964ab3302SCarolineConcatto } 128064ab3302SCarolineConcatto void LabelEnforce::Post(const parser::EndLabel &endLabel) { 128164ab3302SCarolineConcatto checkLabelUse(endLabel.v); 128264ab3302SCarolineConcatto } 128364ab3302SCarolineConcatto void LabelEnforce::Post(const parser::EorLabel &eorLabel) { 128464ab3302SCarolineConcatto checkLabelUse(eorLabel.v); 128564ab3302SCarolineConcatto } 128664ab3302SCarolineConcatto 128764ab3302SCarolineConcatto void LabelEnforce::checkLabelUse(const parser::Label &labelUsed) { 128864ab3302SCarolineConcatto if (labels_.find(labelUsed) == labels_.end()) { 128964ab3302SCarolineConcatto SayWithConstruct(context_, currentStatementSourcePosition_, 129064ab3302SCarolineConcatto parser::MessageFormattedText{ 129164ab3302SCarolineConcatto "Control flow escapes from %s"_err_en_US, construct_}, 129264ab3302SCarolineConcatto constructSourcePosition_); 129364ab3302SCarolineConcatto } 129464ab3302SCarolineConcatto } 129564ab3302SCarolineConcatto 129664ab3302SCarolineConcatto parser::MessageFormattedText LabelEnforce::GetEnclosingConstructMsg() { 129764ab3302SCarolineConcatto return {"Enclosing %s statement"_en_US, construct_}; 129864ab3302SCarolineConcatto } 129964ab3302SCarolineConcatto 130064ab3302SCarolineConcatto void LabelEnforce::SayWithConstruct(SemanticsContext &context, 130164ab3302SCarolineConcatto parser::CharBlock stmtLocation, parser::MessageFormattedText &&message, 130264ab3302SCarolineConcatto parser::CharBlock constructLocation) { 130364ab3302SCarolineConcatto context.Say(stmtLocation, message) 130464ab3302SCarolineConcatto .Attach(constructLocation, GetEnclosingConstructMsg()); 130564ab3302SCarolineConcatto } 130664ab3302SCarolineConcatto } 1307