xref: /llvm-project/flang/lib/Semantics/tools.cpp (revision 2625510ef8094457413661ef0ce2651844f584d2)
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 &paramNames{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 &paramDecls{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