1 //===-- lib/Semantics/tools.cpp -------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "flang/Parser/tools.h"
10 #include "flang/Common/Fortran.h"
11 #include "flang/Common/indirection.h"
12 #include "flang/Parser/dump-parse-tree.h"
13 #include "flang/Parser/message.h"
14 #include "flang/Parser/parse-tree.h"
15 #include "flang/Semantics/scope.h"
16 #include "flang/Semantics/semantics.h"
17 #include "flang/Semantics/symbol.h"
18 #include "flang/Semantics/tools.h"
19 #include "flang/Semantics/type.h"
20 #include "llvm/Support/raw_ostream.h"
25 namespace Fortran::semantics
{
27 // Find this or containing scope that matches predicate
28 static const Scope
*FindScopeContaining(
29 const Scope
&start
, std::function
<bool(const Scope
&)> predicate
) {
30 for (const Scope
*scope
{&start
};; scope
= &scope
->parent()) {
31 if (predicate(*scope
)) {
34 if (scope
->IsTopLevel()) {
40 const Scope
&GetTopLevelUnitContaining(const Scope
&start
) {
41 CHECK(!start
.IsTopLevel());
42 return DEREF(FindScopeContaining(
43 start
, [](const Scope
&scope
) { return scope
.parent().IsTopLevel(); }));
46 const Scope
&GetTopLevelUnitContaining(const Symbol
&symbol
) {
47 return GetTopLevelUnitContaining(symbol
.owner());
50 const Scope
*FindModuleContaining(const Scope
&start
) {
51 return FindScopeContaining(
52 start
, [](const Scope
&scope
) { return scope
.IsModule(); });
55 const Scope
*FindModuleFileContaining(const Scope
&start
) {
56 return FindScopeContaining(
57 start
, [](const Scope
&scope
) { return scope
.IsModuleFile(); });
60 const Scope
&GetProgramUnitContaining(const Scope
&start
) {
61 CHECK(!start
.IsTopLevel());
62 return DEREF(FindScopeContaining(start
, [](const Scope
&scope
) {
63 switch (scope
.kind()) {
64 case Scope::Kind::Module
:
65 case Scope::Kind::MainProgram
:
66 case Scope::Kind::Subprogram
:
67 case Scope::Kind::BlockData
:
75 const Scope
&GetProgramUnitContaining(const Symbol
&symbol
) {
76 return GetProgramUnitContaining(symbol
.owner());
79 const Scope
&GetProgramUnitOrBlockConstructContaining(const Scope
&start
) {
80 CHECK(!start
.IsTopLevel());
81 return DEREF(FindScopeContaining(start
, [](const Scope
&scope
) {
82 switch (scope
.kind()) {
83 case Scope::Kind::Module
:
84 case Scope::Kind::MainProgram
:
85 case Scope::Kind::Subprogram
:
86 case Scope::Kind::BlockData
:
87 case Scope::Kind::BlockConstruct
:
95 const Scope
&GetProgramUnitOrBlockConstructContaining(const Symbol
&symbol
) {
96 return GetProgramUnitOrBlockConstructContaining(symbol
.owner());
99 const Scope
*FindPureProcedureContaining(const Scope
&start
) {
100 // N.B. We only need to examine the innermost containing program unit
101 // because an internal subprogram of a pure subprogram must also
103 if (start
.IsTopLevel()) {
106 const Scope
&scope
{GetProgramUnitContaining(start
)};
107 return IsPureProcedure(scope
) ? &scope
: nullptr;
111 // 7.5.2.4 "same derived type" test -- rely on IsTkCompatibleWith() and its
112 // infrastructure to detect and handle comparisons on distinct (but "same")
113 // sequence/bind(C) derived types
114 static bool MightBeSameDerivedType(
115 const std::optional
<evaluate::DynamicType
> &lhsType
,
116 const std::optional
<evaluate::DynamicType
> &rhsType
) {
117 return lhsType
&& rhsType
&& lhsType
->IsTkCompatibleWith(*rhsType
);
120 Tristate
IsDefinedAssignment(
121 const std::optional
<evaluate::DynamicType
> &lhsType
, int lhsRank
,
122 const std::optional
<evaluate::DynamicType
> &rhsType
, int rhsRank
) {
123 if (!lhsType
|| !rhsType
) {
124 return Tristate::No
; // error or rhs is untyped
126 if (lhsType
->IsUnlimitedPolymorphic()) {
129 if (rhsType
->IsUnlimitedPolymorphic()) {
130 return Tristate::Maybe
;
132 TypeCategory lhsCat
{lhsType
->category()};
133 TypeCategory rhsCat
{rhsType
->category()};
134 if (rhsRank
> 0 && lhsRank
!= rhsRank
) {
135 return Tristate::Yes
;
136 } else if (lhsCat
!= TypeCategory::Derived
) {
137 return ToTristate(lhsCat
!= rhsCat
&&
138 (!IsNumericTypeCategory(lhsCat
) || !IsNumericTypeCategory(rhsCat
)));
139 } else if (MightBeSameDerivedType(lhsType
, rhsType
)) {
140 return Tristate::Maybe
; // TYPE(t) = TYPE(t) can be defined or intrinsic
142 return Tristate::Yes
;
146 bool IsIntrinsicRelational(common::RelationalOperator opr
,
147 const evaluate::DynamicType
&type0
, int rank0
,
148 const evaluate::DynamicType
&type1
, int rank1
) {
149 if (!evaluate::AreConformable(rank0
, rank1
)) {
152 auto cat0
{type0
.category()};
153 auto cat1
{type1
.category()};
154 if (IsNumericTypeCategory(cat0
) && IsNumericTypeCategory(cat1
)) {
155 // numeric types: EQ/NE always ok, others ok for non-complex
156 return opr
== common::RelationalOperator::EQ
||
157 opr
== common::RelationalOperator::NE
||
158 (cat0
!= TypeCategory::Complex
&& cat1
!= TypeCategory::Complex
);
160 // not both numeric: only Character is ok
161 return cat0
== TypeCategory::Character
&& cat1
== TypeCategory::Character
;
166 bool IsIntrinsicNumeric(const evaluate::DynamicType
&type0
) {
167 return IsNumericTypeCategory(type0
.category());
169 bool IsIntrinsicNumeric(const evaluate::DynamicType
&type0
, int rank0
,
170 const evaluate::DynamicType
&type1
, int rank1
) {
171 return evaluate::AreConformable(rank0
, rank1
) &&
172 IsNumericTypeCategory(type0
.category()) &&
173 IsNumericTypeCategory(type1
.category());
176 bool IsIntrinsicLogical(const evaluate::DynamicType
&type0
) {
177 return type0
.category() == TypeCategory::Logical
;
179 bool IsIntrinsicLogical(const evaluate::DynamicType
&type0
, int rank0
,
180 const evaluate::DynamicType
&type1
, int rank1
) {
181 return evaluate::AreConformable(rank0
, rank1
) &&
182 type0
.category() == TypeCategory::Logical
&&
183 type1
.category() == TypeCategory::Logical
;
186 bool IsIntrinsicConcat(const evaluate::DynamicType
&type0
, int rank0
,
187 const evaluate::DynamicType
&type1
, int rank1
) {
188 return evaluate::AreConformable(rank0
, rank1
) &&
189 type0
.category() == TypeCategory::Character
&&
190 type1
.category() == TypeCategory::Character
&&
191 type0
.kind() == type1
.kind();
194 bool IsGenericDefinedOp(const Symbol
&symbol
) {
195 const Symbol
&ultimate
{symbol
.GetUltimate()};
196 if (const auto *generic
{ultimate
.detailsIf
<GenericDetails
>()}) {
197 return generic
->kind().IsDefinedOperator();
198 } else if (const auto *misc
{ultimate
.detailsIf
<MiscDetails
>()}) {
199 return misc
->kind() == MiscDetails::Kind::TypeBoundDefinedOp
;
205 bool IsDefinedOperator(SourceName name
) {
206 const char *begin
{name
.begin()};
207 const char *end
{name
.end()};
208 return begin
!= end
&& begin
[0] == '.' && end
[-1] == '.';
211 std::string
MakeOpName(SourceName name
) {
212 std::string result
{name
.ToString()};
213 return IsDefinedOperator(name
) ? "OPERATOR(" + result
+ ")"
214 : result
.find("operator(", 0) == 0 ? parser::ToUpperCaseLetters(result
)
218 bool IsCommonBlockContaining(const Symbol
&block
, const Symbol
&object
) {
219 const auto &objects
{block
.get
<CommonBlockDetails
>().objects()};
220 return llvm::is_contained(objects
, object
);
223 bool IsUseAssociated(const Symbol
&symbol
, const Scope
&scope
) {
224 const Scope
&owner
{GetTopLevelUnitContaining(symbol
.GetUltimate().owner())};
225 return owner
.kind() == Scope::Kind::Module
&&
226 owner
!= GetTopLevelUnitContaining(scope
);
229 bool DoesScopeContain(
230 const Scope
*maybeAncestor
, const Scope
&maybeDescendent
) {
231 return maybeAncestor
&& !maybeDescendent
.IsTopLevel() &&
232 FindScopeContaining(maybeDescendent
.parent(),
233 [&](const Scope
&scope
) { return &scope
== maybeAncestor
; });
236 bool DoesScopeContain(const Scope
*maybeAncestor
, const Symbol
&symbol
) {
237 return DoesScopeContain(maybeAncestor
, symbol
.owner());
240 static const Symbol
&FollowHostAssoc(const Symbol
&symbol
) {
241 for (const Symbol
*s
{&symbol
};;) {
242 const auto *details
{s
->detailsIf
<HostAssocDetails
>()};
246 s
= &details
->symbol();
250 bool IsHostAssociated(const Symbol
&symbol
, const Scope
&scope
) {
251 return DoesScopeContain(
252 &GetProgramUnitOrBlockConstructContaining(FollowHostAssoc(symbol
)),
253 GetProgramUnitOrBlockConstructContaining(scope
));
256 bool IsHostAssociatedIntoSubprogram(const Symbol
&symbol
, const Scope
&scope
) {
257 return DoesScopeContain(
258 &GetProgramUnitOrBlockConstructContaining(FollowHostAssoc(symbol
)),
259 GetProgramUnitContaining(scope
));
262 bool IsInStmtFunction(const Symbol
&symbol
) {
263 if (const Symbol
* function
{symbol
.owner().symbol()}) {
264 return IsStmtFunction(*function
);
269 bool IsStmtFunctionDummy(const Symbol
&symbol
) {
270 return IsDummy(symbol
) && IsInStmtFunction(symbol
);
273 bool IsStmtFunctionResult(const Symbol
&symbol
) {
274 return IsFunctionResult(symbol
) && IsInStmtFunction(symbol
);
277 bool IsPointerDummy(const Symbol
&symbol
) {
278 return IsPointer(symbol
) && IsDummy(symbol
);
281 bool IsBindCProcedure(const Symbol
&original
) {
282 const Symbol
&symbol
{original
.GetUltimate()};
283 if (const auto *procDetails
{symbol
.detailsIf
<ProcEntityDetails
>()}) {
284 if (procDetails
->procInterface()) {
285 // procedure component with a BIND(C) interface
286 return IsBindCProcedure(*procDetails
->procInterface());
289 return symbol
.attrs().test(Attr::BIND_C
) && IsProcedure(symbol
);
292 bool IsBindCProcedure(const Scope
&scope
) {
293 if (const Symbol
* symbol
{scope
.GetSymbol()}) {
294 return IsBindCProcedure(*symbol
);
300 static const Symbol
*FindPointerComponent(
301 const Scope
&scope
, std::set
<const Scope
*> &visited
) {
302 if (!scope
.IsDerivedType()) {
305 if (!visited
.insert(&scope
).second
) {
308 // If there's a top-level pointer component, return it for clearer error
310 for (const auto &pair
: scope
) {
311 const Symbol
&symbol
{*pair
.second
};
312 if (IsPointer(symbol
)) {
316 for (const auto &pair
: scope
) {
317 const Symbol
&symbol
{*pair
.second
};
318 if (const auto *details
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
319 if (const DeclTypeSpec
* type
{details
->type()}) {
320 if (const DerivedTypeSpec
* derived
{type
->AsDerived()}) {
321 if (const Scope
* nested
{derived
->scope()}) {
323 pointer
{FindPointerComponent(*nested
, visited
)}) {
334 const Symbol
*FindPointerComponent(const Scope
&scope
) {
335 std::set
<const Scope
*> visited
;
336 return FindPointerComponent(scope
, visited
);
339 const Symbol
*FindPointerComponent(const DerivedTypeSpec
&derived
) {
340 if (const Scope
* scope
{derived
.scope()}) {
341 return FindPointerComponent(*scope
);
347 const Symbol
*FindPointerComponent(const DeclTypeSpec
&type
) {
348 if (const DerivedTypeSpec
* derived
{type
.AsDerived()}) {
349 return FindPointerComponent(*derived
);
355 const Symbol
*FindPointerComponent(const DeclTypeSpec
*type
) {
356 return type
? FindPointerComponent(*type
) : nullptr;
359 const Symbol
*FindPointerComponent(const Symbol
&symbol
) {
360 return IsPointer(symbol
) ? &symbol
: FindPointerComponent(symbol
.GetType());
363 // C1594 specifies several ways by which an object might be globally visible.
364 const Symbol
*FindExternallyVisibleObject(
365 const Symbol
&object
, const Scope
&scope
, bool isPointerDefinition
) {
366 // TODO: Storage association with any object for which this predicate holds,
367 // once EQUIVALENCE is supported.
368 const Symbol
&ultimate
{GetAssociationRoot(object
)};
369 if (IsDummy(ultimate
)) {
370 if (IsIntentIn(ultimate
)) {
373 if (!isPointerDefinition
&& IsPointer(ultimate
) &&
374 IsPureProcedure(ultimate
.owner()) && IsFunction(ultimate
.owner())) {
377 } else if (ultimate
.owner().IsDerivedType()) {
379 } else if (&GetProgramUnitContaining(ultimate
) !=
380 &GetProgramUnitContaining(scope
)) {
382 } else if (const Symbol
* block
{FindCommonBlockContaining(ultimate
)}) {
388 const Symbol
&BypassGeneric(const Symbol
&symbol
) {
389 const Symbol
&ultimate
{symbol
.GetUltimate()};
390 if (const auto *generic
{ultimate
.detailsIf
<GenericDetails
>()}) {
391 if (const Symbol
* specific
{generic
->specific()}) {
398 bool ExprHasTypeCategory(
399 const SomeExpr
&expr
, const common::TypeCategory
&type
) {
400 auto dynamicType
{expr
.GetType()};
401 return dynamicType
&& dynamicType
->category() == type
;
404 bool ExprTypeKindIsDefault(
405 const SomeExpr
&expr
, const SemanticsContext
&context
) {
406 auto dynamicType
{expr
.GetType()};
407 return dynamicType
&&
408 dynamicType
->category() != common::TypeCategory::Derived
&&
409 dynamicType
->kind() == context
.GetDefaultKind(dynamicType
->category());
412 // If an analyzed expr or assignment is missing, dump the node and die.
413 template <typename T
>
414 static void CheckMissingAnalysis(
415 bool crash
, SemanticsContext
*context
, const T
&x
) {
416 if (crash
&& !(context
&& context
->AnyFatalError())) {
418 llvm::raw_string_ostream ss
{buf
};
419 ss
<< "node has not been analyzed:\n";
420 parser::DumpTree(ss
, x
);
421 common::die(ss
.str().c_str());
425 const SomeExpr
*GetExprHelper::Get(const parser::Expr
&x
) {
426 CheckMissingAnalysis(crashIfNoExpr_
&& !x
.typedExpr
, context_
, x
);
427 return x
.typedExpr
? common::GetPtrFromOptional(x
.typedExpr
->v
) : nullptr;
429 const SomeExpr
*GetExprHelper::Get(const parser::Variable
&x
) {
430 CheckMissingAnalysis(crashIfNoExpr_
&& !x
.typedExpr
, context_
, x
);
431 return x
.typedExpr
? common::GetPtrFromOptional(x
.typedExpr
->v
) : nullptr;
433 const SomeExpr
*GetExprHelper::Get(const parser::DataStmtConstant
&x
) {
434 CheckMissingAnalysis(crashIfNoExpr_
&& !x
.typedExpr
, context_
, x
);
435 return x
.typedExpr
? common::GetPtrFromOptional(x
.typedExpr
->v
) : nullptr;
437 const SomeExpr
*GetExprHelper::Get(const parser::AllocateObject
&x
) {
438 CheckMissingAnalysis(crashIfNoExpr_
&& !x
.typedExpr
, context_
, x
);
439 return x
.typedExpr
? common::GetPtrFromOptional(x
.typedExpr
->v
) : nullptr;
441 const SomeExpr
*GetExprHelper::Get(const parser::PointerObject
&x
) {
442 CheckMissingAnalysis(crashIfNoExpr_
&& !x
.typedExpr
, context_
, x
);
443 return x
.typedExpr
? common::GetPtrFromOptional(x
.typedExpr
->v
) : nullptr;
446 const evaluate::Assignment
*GetAssignment(const parser::AssignmentStmt
&x
) {
447 return x
.typedAssignment
? common::GetPtrFromOptional(x
.typedAssignment
->v
)
450 const evaluate::Assignment
*GetAssignment(
451 const parser::PointerAssignmentStmt
&x
) {
452 return x
.typedAssignment
? common::GetPtrFromOptional(x
.typedAssignment
->v
)
456 const Symbol
*FindInterface(const Symbol
&symbol
) {
457 return common::visit(
459 [](const ProcEntityDetails
&details
) {
460 const Symbol
*interface
{
461 details
.procInterface()
463 return interface
? FindInterface(*interface
) : nullptr;
465 [](const ProcBindingDetails
&details
) {
466 return FindInterface(details
.symbol());
468 [&](const SubprogramDetails
&) { return &symbol
; },
469 [](const UseDetails
&details
) {
470 return FindInterface(details
.symbol());
472 [](const HostAssocDetails
&details
) {
473 return FindInterface(details
.symbol());
475 [](const GenericDetails
&details
) {
476 return details
.specific() ? FindInterface(*details
.specific())
479 [](const auto &) -> const Symbol
* { return nullptr; },
484 const Symbol
*FindSubprogram(const Symbol
&symbol
) {
485 return common::visit(
487 [&](const ProcEntityDetails
&details
) -> const Symbol
* {
488 if (details
.procInterface()) {
489 return FindSubprogram(*details
.procInterface());
494 [](const ProcBindingDetails
&details
) {
495 return FindSubprogram(details
.symbol());
497 [&](const SubprogramDetails
&) { return &symbol
; },
498 [](const UseDetails
&details
) {
499 return FindSubprogram(details
.symbol());
501 [](const HostAssocDetails
&details
) {
502 return FindSubprogram(details
.symbol());
504 [](const GenericDetails
&details
) {
505 return details
.specific() ? FindSubprogram(*details
.specific())
508 [](const auto &) -> const Symbol
* { return nullptr; },
513 const Symbol
*FindOverriddenBinding(const Symbol
&symbol
) {
514 if (symbol
.has
<ProcBindingDetails
>()) {
515 if (const DeclTypeSpec
* parentType
{FindParentTypeSpec(symbol
.owner())}) {
516 if (const DerivedTypeSpec
* parentDerived
{parentType
->AsDerived()}) {
517 if (const Scope
* parentScope
{parentDerived
->typeSymbol().scope()}) {
518 return parentScope
->FindComponent(symbol
.name());
526 const Symbol
*FindGlobal(const Symbol
&original
) {
527 const Symbol
&ultimate
{original
.GetUltimate()};
528 if (ultimate
.owner().IsGlobal()) {
532 if (IsDummy(ultimate
)) {
533 } else if (IsPointer(ultimate
)) {
534 } else if (ultimate
.has
<ProcEntityDetails
>()) {
535 isLocal
= IsExternal(ultimate
);
536 } else if (const auto *subp
{ultimate
.detailsIf
<SubprogramDetails
>()}) {
537 isLocal
= subp
->isInterface();
540 const std::string
*bind
{ultimate
.GetBindName()};
541 if (!bind
|| ultimate
.name() == *bind
) {
542 const Scope
&globalScope
{ultimate
.owner().context().globalScope()};
543 if (auto iter
{globalScope
.find(ultimate
.name())};
544 iter
!= globalScope
.end()) {
545 const Symbol
&global
{*iter
->second
};
546 const std::string
*globalBind
{global
.GetBindName()};
547 if (!globalBind
|| global
.name() == *globalBind
) {
556 const DeclTypeSpec
*FindParentTypeSpec(const DerivedTypeSpec
&derived
) {
557 return FindParentTypeSpec(derived
.typeSymbol());
560 const DeclTypeSpec
*FindParentTypeSpec(const DeclTypeSpec
&decl
) {
561 if (const DerivedTypeSpec
* derived
{decl
.AsDerived()}) {
562 return FindParentTypeSpec(*derived
);
568 const DeclTypeSpec
*FindParentTypeSpec(const Scope
&scope
) {
569 if (scope
.kind() == Scope::Kind::DerivedType
) {
570 if (const auto *symbol
{scope
.symbol()}) {
571 return FindParentTypeSpec(*symbol
);
577 const DeclTypeSpec
*FindParentTypeSpec(const Symbol
&symbol
) {
578 if (const Scope
* scope
{symbol
.scope()}) {
579 if (const auto *details
{symbol
.detailsIf
<DerivedTypeDetails
>()}) {
580 if (const Symbol
* parent
{details
->GetParentComponent(*scope
)}) {
581 return parent
->GetType();
588 const EquivalenceSet
*FindEquivalenceSet(const Symbol
&symbol
) {
589 const Symbol
&ultimate
{symbol
.GetUltimate()};
590 for (const EquivalenceSet
&set
: ultimate
.owner().equivalenceSets()) {
591 for (const EquivalenceObject
&object
: set
) {
592 if (object
.symbol
== ultimate
) {
600 bool IsOrContainsEventOrLockComponent(const Symbol
&original
) {
601 const Symbol
&symbol
{ResolveAssociations(original
)};
602 if (const auto *details
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
603 if (const DeclTypeSpec
* type
{details
->type()}) {
604 if (const DerivedTypeSpec
* derived
{type
->AsDerived()}) {
605 return IsEventTypeOrLockType(derived
) ||
606 FindEventOrLockPotentialComponent(*derived
);
613 // Check this symbol suitable as a type-bound procedure - C769
614 bool CanBeTypeBoundProc(const Symbol
&symbol
) {
615 if (IsDummy(symbol
) || IsProcedurePointer(symbol
)) {
617 } else if (symbol
.has
<SubprogramNameDetails
>()) {
618 return symbol
.owner().kind() == Scope::Kind::Module
;
619 } else if (auto *details
{symbol
.detailsIf
<SubprogramDetails
>()}) {
620 if (details
->isInterface()) {
621 return !symbol
.attrs().test(Attr::ABSTRACT
);
623 return symbol
.owner().kind() == Scope::Kind::Module
;
625 } else if (const auto *proc
{symbol
.detailsIf
<ProcEntityDetails
>()}) {
626 return !symbol
.attrs().test(Attr::INTRINSIC
) &&
627 proc
->HasExplicitInterface();
633 bool HasDeclarationInitializer(const Symbol
&symbol
) {
634 if (IsNamedConstant(symbol
)) {
636 } else if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
637 return object
->init().has_value();
638 } else if (const auto *proc
{symbol
.detailsIf
<ProcEntityDetails
>()}) {
639 return proc
->init().has_value();
646 const Symbol
&symbol
, bool ignoreDataStatements
, bool ignoreAllocatable
) {
647 if (!ignoreAllocatable
&& IsAllocatable(symbol
)) {
649 } else if (!ignoreDataStatements
&& symbol
.test(Symbol::Flag::InDataStmt
)) {
651 } else if (HasDeclarationInitializer(symbol
)) {
653 } else if (IsNamedConstant(symbol
) || IsFunctionResult(symbol
) ||
656 } else if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
657 if (!object
->isDummy() && object
->type()) {
658 if (const auto *derived
{object
->type()->AsDerived()}) {
659 return derived
->HasDefaultInitialization(ignoreAllocatable
);
666 bool IsDestructible(const Symbol
&symbol
, const Symbol
*derivedTypeSymbol
) {
667 if (IsAllocatable(symbol
) || IsAutomatic(symbol
)) {
669 } else if (IsNamedConstant(symbol
) || IsFunctionResult(symbol
) ||
672 } else if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
673 if (!object
->isDummy() && object
->type()) {
674 if (const auto *derived
{object
->type()->AsDerived()}) {
675 return &derived
->typeSymbol() != derivedTypeSymbol
&&
676 derived
->HasDestruction();
683 bool HasIntrinsicTypeName(const Symbol
&symbol
) {
684 std::string name
{symbol
.name().ToString()};
685 if (name
== "doubleprecision") {
687 } else if (name
== "derived") {
690 for (int i
{0}; i
!= common::TypeCategory_enumSize
; ++i
) {
691 if (name
== parser::ToLowerCaseLetters(EnumToString(TypeCategory
{i
}))) {
699 bool IsSeparateModuleProcedureInterface(const Symbol
*symbol
) {
700 if (symbol
&& symbol
->attrs().test(Attr::MODULE
)) {
701 if (auto *details
{symbol
->detailsIf
<SubprogramDetails
>()}) {
702 return details
->isInterface();
708 SymbolVector
FinalsForDerivedTypeInstantiation(const DerivedTypeSpec
&spec
) {
710 const Symbol
&typeSymbol
{spec
.typeSymbol()};
711 if (const auto *derived
{typeSymbol
.detailsIf
<DerivedTypeDetails
>()}) {
712 for (const auto &pair
: derived
->finals()) {
713 const Symbol
&subr
{*pair
.second
};
714 // Errors in FINAL subroutines are caught in CheckFinal
715 // in check-declarations.cpp.
716 if (const auto *subprog
{subr
.detailsIf
<SubprogramDetails
>()};
717 subprog
&& subprog
->dummyArgs().size() == 1) {
718 if (const Symbol
* arg
{subprog
->dummyArgs()[0]}) {
719 if (const DeclTypeSpec
* type
{arg
->GetType()}) {
720 if (type
->category() == DeclTypeSpec::TypeDerived
&&
721 evaluate::AreSameDerivedType(spec
, type
->derivedTypeSpec())) {
722 result
.emplace_back(subr
);
733 const Symbol
&symbol
, std::set
<const DerivedTypeSpec
*> *inProgress
) {
734 if (IsPointer(symbol
)) {
737 if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
738 if (object
->isDummy() && !IsIntentOut(symbol
)) {
741 const DeclTypeSpec
*type
{object
->type()};
742 const DerivedTypeSpec
*typeSpec
{type
? type
->AsDerived() : nullptr};
743 return typeSpec
&& IsFinalizable(*typeSpec
, inProgress
);
748 bool IsFinalizable(const DerivedTypeSpec
&derived
,
749 std::set
<const DerivedTypeSpec
*> *inProgress
) {
750 if (!FinalsForDerivedTypeInstantiation(derived
).empty()) {
753 std::set
<const DerivedTypeSpec
*> basis
;
755 if (inProgress
->find(&derived
) != inProgress
->end()) {
756 return false; // don't loop on recursive type
761 auto iterator
{inProgress
->insert(&derived
).first
};
762 PotentialComponentIterator components
{derived
};
763 bool result
{bool{std::find_if(
764 components
.begin(), components
.end(), [=](const Symbol
&component
) {
765 return IsFinalizable(component
, inProgress
);
767 inProgress
->erase(iterator
);
771 bool HasImpureFinal(const DerivedTypeSpec
&derived
) {
772 for (auto ref
: FinalsForDerivedTypeInstantiation(derived
)) {
773 if (!IsPureProcedure(*ref
)) {
780 bool IsAssumedLengthCharacter(const Symbol
&symbol
) {
781 if (const DeclTypeSpec
* type
{symbol
.GetType()}) {
782 return type
->category() == DeclTypeSpec::Character
&&
783 type
->characterTypeSpec().length().isAssumed();
789 bool IsInBlankCommon(const Symbol
&symbol
) {
790 const Symbol
*block
{FindCommonBlockContaining(symbol
)};
791 return block
&& block
->name().empty();
794 // C722 and C723: For a function to be assumed length, it must be external and
796 bool IsExternal(const Symbol
&symbol
) {
797 return ClassifyProcedure(symbol
) == ProcedureDefinitionClass::External
;
800 // Most scopes have no EQUIVALENCE, and this function is a fast no-op for them.
801 std::list
<std::list
<SymbolRef
>> GetStorageAssociations(const Scope
&scope
) {
802 UnorderedSymbolSet distinct
;
803 for (const EquivalenceSet
&set
: scope
.equivalenceSets()) {
804 for (const EquivalenceObject
&object
: set
) {
805 distinct
.emplace(object
.symbol
);
808 // This set is ordered by ascending offsets, with ties broken by greatest
809 // size. A multiset is used here because multiple symbols may have the
810 // same offset and size; the symbols in the set, however, are distinct.
811 std::multiset
<SymbolRef
, SymbolOffsetCompare
> associated
;
812 for (SymbolRef ref
: distinct
) {
813 associated
.emplace(*ref
);
815 std::list
<std::list
<SymbolRef
>> result
;
816 std::size_t limit
{0};
817 const Symbol
*currentCommon
{nullptr};
818 for (const Symbol
&symbol
: associated
) {
819 const Symbol
*thisCommon
{FindCommonBlockContaining(symbol
)};
820 if (result
.empty() || symbol
.offset() >= limit
||
821 thisCommon
!= currentCommon
) {
823 result
.emplace_back(std::list
<SymbolRef
>{});
825 currentCommon
= thisCommon
;
827 result
.back().emplace_back(symbol
);
828 limit
= std::max(limit
, symbol
.offset() + symbol
.size());
833 bool IsModuleProcedure(const Symbol
&symbol
) {
834 return ClassifyProcedure(symbol
) == ProcedureDefinitionClass::Module
;
837 class ImageControlStmtHelper
{
838 using ImageControlStmts
=
839 std::variant
<parser::ChangeTeamConstruct
, parser::CriticalConstruct
,
840 parser::EventPostStmt
, parser::EventWaitStmt
, parser::FormTeamStmt
,
841 parser::LockStmt
, parser::SyncAllStmt
, parser::SyncImagesStmt
,
842 parser::SyncMemoryStmt
, parser::SyncTeamStmt
, parser::UnlockStmt
>;
845 template <typename T
> bool operator()(const T
&) {
846 return common::HasMember
<T
, ImageControlStmts
>;
848 template <typename T
> bool operator()(const common::Indirection
<T
> &x
) {
849 return (*this)(x
.value());
851 bool operator()(const parser::AllocateStmt
&stmt
) {
852 const auto &allocationList
{std::get
<std::list
<parser::Allocation
>>(stmt
.t
)};
853 for (const auto &allocation
: allocationList
) {
854 const auto &allocateObject
{
855 std::get
<parser::AllocateObject
>(allocation
.t
)};
856 if (IsCoarrayObject(allocateObject
)) {
862 bool operator()(const parser::DeallocateStmt
&stmt
) {
863 const auto &allocateObjectList
{
864 std::get
<std::list
<parser::AllocateObject
>>(stmt
.t
)};
865 for (const auto &allocateObject
: allocateObjectList
) {
866 if (IsCoarrayObject(allocateObject
)) {
872 bool operator()(const parser::CallStmt
&stmt
) {
873 const auto &procedureDesignator
{
874 std::get
<parser::ProcedureDesignator
>(stmt
.v
.t
)};
875 if (auto *name
{std::get_if
<parser::Name
>(&procedureDesignator
.u
)}) {
876 // TODO: also ensure that the procedure is, in fact, an intrinsic
877 if (name
->source
== "move_alloc") {
878 const auto &args
{std::get
<std::list
<parser::ActualArgSpec
>>(stmt
.v
.t
)};
880 const parser::ActualArg
&actualArg
{
881 std::get
<parser::ActualArg
>(args
.front().t
)};
882 if (const auto *argExpr
{
883 std::get_if
<common::Indirection
<parser::Expr
>>(
885 return HasCoarray(argExpr
->value());
892 bool operator()(const parser::StopStmt
&stmt
) {
893 // STOP is an image control statement; ERROR STOP is not
894 return std::get
<parser::StopStmt::Kind
>(stmt
.t
) ==
895 parser::StopStmt::Kind::Stop
;
897 bool operator()(const parser::Statement
<parser::ActionStmt
> &stmt
) {
898 return common::visit(*this, stmt
.statement
.u
);
902 bool IsCoarrayObject(const parser::AllocateObject
&allocateObject
) {
903 const parser::Name
&name
{GetLastName(allocateObject
)};
904 return name
.symbol
&& evaluate::IsCoarray(*name
.symbol
);
908 bool IsImageControlStmt(const parser::ExecutableConstruct
&construct
) {
909 return common::visit(ImageControlStmtHelper
{}, construct
.u
);
912 std::optional
<parser::MessageFixedText
> GetImageControlStmtCoarrayMsg(
913 const parser::ExecutableConstruct
&construct
) {
914 if (const auto *actionStmt
{
915 std::get_if
<parser::Statement
<parser::ActionStmt
>>(&construct
.u
)}) {
916 return common::visit(
918 [](const common::Indirection
<parser::AllocateStmt
> &)
919 -> std::optional
<parser::MessageFixedText
> {
920 return "ALLOCATE of a coarray is an image control"
923 [](const common::Indirection
<parser::DeallocateStmt
> &)
924 -> std::optional
<parser::MessageFixedText
> {
925 return "DEALLOCATE of a coarray is an image control"
928 [](const common::Indirection
<parser::CallStmt
> &)
929 -> std::optional
<parser::MessageFixedText
> {
930 return "MOVE_ALLOC of a coarray is an image control"
933 [](const auto &) -> std::optional
<parser::MessageFixedText
> {
937 actionStmt
->statement
.u
);
942 parser::CharBlock
GetImageControlStmtLocation(
943 const parser::ExecutableConstruct
&executableConstruct
) {
944 return common::visit(
946 [](const common::Indirection
<parser::ChangeTeamConstruct
>
948 return std::get
<parser::Statement
<parser::ChangeTeamStmt
>>(
952 [](const common::Indirection
<parser::CriticalConstruct
> &construct
) {
953 return std::get
<parser::Statement
<parser::CriticalStmt
>>(
957 [](const parser::Statement
<parser::ActionStmt
> &actionStmt
) {
958 return actionStmt
.source
;
960 [](const auto &) { return parser::CharBlock
{}; },
962 executableConstruct
.u
);
965 bool HasCoarray(const parser::Expr
&expression
) {
966 if (const auto *expr
{GetExpr(nullptr, expression
)}) {
967 for (const Symbol
&symbol
: evaluate::CollectSymbols(*expr
)) {
968 if (evaluate::IsCoarray(symbol
)) {
976 bool IsAssumedType(const Symbol
&symbol
) {
977 if (const DeclTypeSpec
* type
{symbol
.GetType()}) {
978 return type
->IsAssumedType();
983 bool IsPolymorphic(const Symbol
&symbol
) {
984 if (const DeclTypeSpec
* type
{symbol
.GetType()}) {
985 return type
->IsPolymorphic();
990 bool IsUnlimitedPolymorphic(const Symbol
&symbol
) {
991 if (const DeclTypeSpec
* type
{symbol
.GetType()}) {
992 return type
->IsUnlimitedPolymorphic();
997 bool IsPolymorphicAllocatable(const Symbol
&symbol
) {
998 return IsAllocatable(symbol
) && IsPolymorphic(symbol
);
1001 std::optional
<parser::MessageFormattedText
> CheckAccessibleSymbol(
1002 const Scope
&scope
, const Symbol
&symbol
) {
1003 if (symbol
.attrs().test(Attr::PRIVATE
)) {
1004 if (FindModuleFileContaining(scope
)) {
1005 // Don't enforce component accessibility checks in module files;
1006 // there may be forward-substituted named constants of derived type
1007 // whose structure constructors reference private components.
1008 } else if (const Scope
*
1009 moduleScope
{FindModuleContaining(symbol
.owner())}) {
1010 if (!moduleScope
->Contains(scope
)) {
1011 return parser::MessageFormattedText
{
1012 "PRIVATE name '%s' is only accessible within module '%s'"_err_en_US
,
1013 symbol
.name(), moduleScope
->GetName().value()};
1017 return std::nullopt
;
1020 std::list
<SourceName
> OrderParameterNames(const Symbol
&typeSymbol
) {
1021 std::list
<SourceName
> result
;
1022 if (const DerivedTypeSpec
* spec
{typeSymbol
.GetParentTypeSpec()}) {
1023 result
= OrderParameterNames(spec
->typeSymbol());
1025 const auto ¶mNames
{typeSymbol
.get
<DerivedTypeDetails
>().paramNames()};
1026 result
.insert(result
.end(), paramNames
.begin(), paramNames
.end());
1030 SymbolVector
OrderParameterDeclarations(const Symbol
&typeSymbol
) {
1031 SymbolVector result
;
1032 if (const DerivedTypeSpec
* spec
{typeSymbol
.GetParentTypeSpec()}) {
1033 result
= OrderParameterDeclarations(spec
->typeSymbol());
1035 const auto ¶mDecls
{typeSymbol
.get
<DerivedTypeDetails
>().paramDecls()};
1036 result
.insert(result
.end(), paramDecls
.begin(), paramDecls
.end());
1040 const DeclTypeSpec
&FindOrInstantiateDerivedType(
1041 Scope
&scope
, DerivedTypeSpec
&&spec
, DeclTypeSpec::Category category
) {
1042 spec
.EvaluateParameters(scope
.context());
1043 if (const DeclTypeSpec
*
1044 type
{scope
.FindInstantiatedDerivedType(spec
, category
)}) {
1047 // Create a new instantiation of this parameterized derived type
1048 // for this particular distinct set of actual parameter values.
1049 DeclTypeSpec
&type
{scope
.MakeDerivedType(category
, std::move(spec
))};
1050 type
.derivedTypeSpec().Instantiate(scope
);
1054 const Symbol
*FindSeparateModuleSubprogramInterface(const Symbol
*proc
) {
1056 if (const auto *subprogram
{proc
->detailsIf
<SubprogramDetails
>()}) {
1057 if (const Symbol
* iface
{subprogram
->moduleInterface()}) {
1065 ProcedureDefinitionClass
ClassifyProcedure(const Symbol
&symbol
) { // 15.2.2
1066 const Symbol
&ultimate
{symbol
.GetUltimate()};
1067 if (!IsProcedure(ultimate
)) {
1068 return ProcedureDefinitionClass::None
;
1069 } else if (ultimate
.attrs().test(Attr::INTRINSIC
)) {
1070 return ProcedureDefinitionClass::Intrinsic
;
1071 } else if (IsDummy(ultimate
)) {
1072 return ProcedureDefinitionClass::Dummy
;
1073 } else if (IsProcedurePointer(symbol
)) {
1074 return ProcedureDefinitionClass::Pointer
;
1075 } else if (ultimate
.attrs().test(Attr::EXTERNAL
)) {
1076 return ProcedureDefinitionClass::External
;
1077 } else if (const auto *nameDetails
{
1078 ultimate
.detailsIf
<SubprogramNameDetails
>()}) {
1079 switch (nameDetails
->kind()) {
1080 case SubprogramKind::Module
:
1081 return ProcedureDefinitionClass::Module
;
1082 case SubprogramKind::Internal
:
1083 return ProcedureDefinitionClass::Internal
;
1085 } else if (const Symbol
* subp
{FindSubprogram(symbol
)}) {
1086 if (const auto *subpDetails
{subp
->detailsIf
<SubprogramDetails
>()}) {
1087 if (subpDetails
->stmtFunction()) {
1088 return ProcedureDefinitionClass::StatementFunction
;
1091 switch (ultimate
.owner().kind()) {
1092 case Scope::Kind::Global
:
1093 case Scope::Kind::IntrinsicModules
:
1094 return ProcedureDefinitionClass::External
;
1095 case Scope::Kind::Module
:
1096 return ProcedureDefinitionClass::Module
;
1097 case Scope::Kind::MainProgram
:
1098 case Scope::Kind::Subprogram
:
1099 return ProcedureDefinitionClass::Internal
;
1104 return ProcedureDefinitionClass::None
;
1107 // ComponentIterator implementation
1109 template <ComponentKind componentKind
>
1110 typename ComponentIterator
<componentKind
>::const_iterator
1111 ComponentIterator
<componentKind
>::const_iterator::Create(
1112 const DerivedTypeSpec
&derived
) {
1113 const_iterator it
{};
1114 it
.componentPath_
.emplace_back(derived
);
1115 it
.Increment(); // cue up first relevant component, if any
1119 template <ComponentKind componentKind
>
1120 const DerivedTypeSpec
*
1121 ComponentIterator
<componentKind
>::const_iterator::PlanComponentTraversal(
1122 const Symbol
&component
) const {
1123 if (const auto *details
{component
.detailsIf
<ObjectEntityDetails
>()}) {
1124 if (const DeclTypeSpec
* type
{details
->type()}) {
1125 if (const auto *derived
{type
->AsDerived()}) {
1126 bool traverse
{false};
1127 if constexpr (componentKind
== ComponentKind::Ordered
) {
1128 // Order Component (only visit parents)
1129 traverse
= component
.test(Symbol::Flag::ParentComp
);
1130 } else if constexpr (componentKind
== ComponentKind::Direct
) {
1131 traverse
= !IsAllocatableOrPointer(component
);
1132 } else if constexpr (componentKind
== ComponentKind::Ultimate
) {
1133 traverse
= !IsAllocatableOrPointer(component
);
1134 } else if constexpr (componentKind
== ComponentKind::Potential
) {
1135 traverse
= !IsPointer(component
);
1136 } else if constexpr (componentKind
== ComponentKind::Scope
) {
1137 traverse
= !IsAllocatableOrPointer(component
);
1138 } else if constexpr (componentKind
==
1139 ComponentKind::PotentialAndPointer
) {
1140 traverse
= !IsPointer(component
);
1143 const Symbol
&newTypeSymbol
{derived
->typeSymbol()};
1144 // Avoid infinite loop if the type is already part of the types
1145 // being visited. It is possible to have "loops in type" because
1146 // C744 does not forbid to use not yet declared type for
1147 // ALLOCATABLE or POINTER components.
1148 for (const auto &node
: componentPath_
) {
1149 if (&newTypeSymbol
== &node
.GetTypeSymbol()) {
1156 } // intrinsic & unlimited polymorphic not traversable
1161 template <ComponentKind componentKind
>
1162 static bool StopAtComponentPre(const Symbol
&component
) {
1163 if constexpr (componentKind
== ComponentKind::Ordered
) {
1164 // Parent components need to be iterated upon after their
1165 // sub-components in structure constructor analysis.
1166 return !component
.test(Symbol::Flag::ParentComp
);
1167 } else if constexpr (componentKind
== ComponentKind::Direct
) {
1169 } else if constexpr (componentKind
== ComponentKind::Ultimate
) {
1170 return component
.has
<ProcEntityDetails
>() ||
1171 IsAllocatableOrPointer(component
) ||
1172 (component
.get
<ObjectEntityDetails
>().type() &&
1173 component
.get
<ObjectEntityDetails
>().type()->AsIntrinsic());
1174 } else if constexpr (componentKind
== ComponentKind::Potential
) {
1175 return !IsPointer(component
);
1176 } else if constexpr (componentKind
== ComponentKind::PotentialAndPointer
) {
1181 template <ComponentKind componentKind
>
1182 static bool StopAtComponentPost(const Symbol
&component
) {
1183 return componentKind
== ComponentKind::Ordered
&&
1184 component
.test(Symbol::Flag::ParentComp
);
1187 template <ComponentKind componentKind
>
1188 void ComponentIterator
<componentKind
>::const_iterator::Increment() {
1189 while (!componentPath_
.empty()) {
1190 ComponentPathNode
&deepest
{componentPath_
.back()};
1191 if (deepest
.component()) {
1192 if (!deepest
.descended()) {
1193 deepest
.set_descended(true);
1194 if (const DerivedTypeSpec
*
1195 derived
{PlanComponentTraversal(*deepest
.component())}) {
1196 componentPath_
.emplace_back(*derived
);
1199 } else if (!deepest
.visited()) {
1200 deepest
.set_visited(true);
1201 return; // this is the next component to visit, after descending
1204 auto &nameIterator
{deepest
.nameIterator()};
1205 if (nameIterator
== deepest
.nameEnd()) {
1206 componentPath_
.pop_back();
1207 } else if constexpr (componentKind
== ComponentKind::Scope
) {
1208 deepest
.set_component(*nameIterator
++->second
);
1209 deepest
.set_descended(false);
1210 deepest
.set_visited(true);
1211 return; // this is the next component to visit, before descending
1213 const Scope
&scope
{deepest
.GetScope()};
1214 auto scopeIter
{scope
.find(*nameIterator
++)};
1215 if (scopeIter
!= scope
.cend()) {
1216 const Symbol
&component
{*scopeIter
->second
};
1217 deepest
.set_component(component
);
1218 deepest
.set_descended(false);
1219 if (StopAtComponentPre
<componentKind
>(component
)) {
1220 deepest
.set_visited(true);
1221 return; // this is the next component to visit, before descending
1223 deepest
.set_visited(!StopAtComponentPost
<componentKind
>(component
));
1230 template <ComponentKind componentKind
>
1232 ComponentIterator
<componentKind
>::const_iterator::BuildResultDesignatorName()
1234 std::string designator
;
1235 for (const auto &node
: componentPath_
) {
1236 designator
+= "%" + DEREF(node
.component()).name().ToString();
1241 template class ComponentIterator
<ComponentKind::Ordered
>;
1242 template class ComponentIterator
<ComponentKind::Direct
>;
1243 template class ComponentIterator
<ComponentKind::Ultimate
>;
1244 template class ComponentIterator
<ComponentKind::Potential
>;
1245 template class ComponentIterator
<ComponentKind::Scope
>;
1246 template class ComponentIterator
<ComponentKind::PotentialAndPointer
>;
1248 UltimateComponentIterator::const_iterator
FindCoarrayUltimateComponent(
1249 const DerivedTypeSpec
&derived
) {
1250 UltimateComponentIterator ultimates
{derived
};
1251 return std::find_if(ultimates
.begin(), ultimates
.end(),
1252 [](const Symbol
&symbol
) { return evaluate::IsCoarray(symbol
); });
1255 UltimateComponentIterator::const_iterator
FindPointerUltimateComponent(
1256 const DerivedTypeSpec
&derived
) {
1257 UltimateComponentIterator ultimates
{derived
};
1258 return std::find_if(ultimates
.begin(), ultimates
.end(), IsPointer
);
1261 PotentialComponentIterator::const_iterator
FindEventOrLockPotentialComponent(
1262 const DerivedTypeSpec
&derived
) {
1263 PotentialComponentIterator potentials
{derived
};
1264 return std::find_if(
1265 potentials
.begin(), potentials
.end(), [](const Symbol
&component
) {
1266 if (const auto *details
{component
.detailsIf
<ObjectEntityDetails
>()}) {
1267 const DeclTypeSpec
*type
{details
->type()};
1268 return type
&& IsEventTypeOrLockType(type
->AsDerived());
1274 UltimateComponentIterator::const_iterator
FindAllocatableUltimateComponent(
1275 const DerivedTypeSpec
&derived
) {
1276 UltimateComponentIterator ultimates
{derived
};
1277 return std::find_if(ultimates
.begin(), ultimates
.end(), IsAllocatable
);
1280 DirectComponentIterator::const_iterator
FindAllocatableOrPointerDirectComponent(
1281 const DerivedTypeSpec
&derived
) {
1282 DirectComponentIterator directs
{derived
};
1283 return std::find_if(directs
.begin(), directs
.end(), IsAllocatableOrPointer
);
1286 UltimateComponentIterator::const_iterator
1287 FindPolymorphicAllocatableUltimateComponent(const DerivedTypeSpec
&derived
) {
1288 UltimateComponentIterator ultimates
{derived
};
1289 return std::find_if(
1290 ultimates
.begin(), ultimates
.end(), IsPolymorphicAllocatable
);
1293 UltimateComponentIterator::const_iterator
1294 FindPolymorphicAllocatableNonCoarrayUltimateComponent(
1295 const DerivedTypeSpec
&derived
) {
1296 UltimateComponentIterator ultimates
{derived
};
1297 return std::find_if(ultimates
.begin(), ultimates
.end(), [](const Symbol
&x
) {
1298 return IsPolymorphicAllocatable(x
) && !evaluate::IsCoarray(x
);
1302 const Symbol
*FindUltimateComponent(const DerivedTypeSpec
&derived
,
1303 const std::function
<bool(const Symbol
&)> &predicate
) {
1304 UltimateComponentIterator ultimates
{derived
};
1305 if (auto it
{std::find_if(ultimates
.begin(), ultimates
.end(),
1306 [&predicate
](const Symbol
&component
) -> bool {
1307 return predicate(component
);
1314 const Symbol
*FindUltimateComponent(const Symbol
&symbol
,
1315 const std::function
<bool(const Symbol
&)> &predicate
) {
1316 if (predicate(symbol
)) {
1318 } else if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
1319 if (const auto *type
{object
->type()}) {
1320 if (const auto *derived
{type
->AsDerived()}) {
1321 return FindUltimateComponent(*derived
, predicate
);
1328 const Symbol
*FindImmediateComponent(const DerivedTypeSpec
&type
,
1329 const std::function
<bool(const Symbol
&)> &predicate
) {
1330 if (const Scope
* scope
{type
.scope()}) {
1331 const Symbol
*parent
{nullptr};
1332 for (const auto &pair
: *scope
) {
1333 const Symbol
*symbol
{&*pair
.second
};
1334 if (predicate(*symbol
)) {
1337 if (symbol
->test(Symbol::Flag::ParentComp
)) {
1342 if (const auto *object
{parent
->detailsIf
<ObjectEntityDetails
>()}) {
1343 if (const auto *type
{object
->type()}) {
1344 if (const auto *derived
{type
->AsDerived()}) {
1345 return FindImmediateComponent(*derived
, predicate
);
1354 const Symbol
*IsFunctionResultWithSameNameAsFunction(const Symbol
&symbol
) {
1355 if (IsFunctionResult(symbol
)) {
1356 if (const Symbol
* function
{symbol
.owner().symbol()}) {
1357 if (symbol
.name() == function
->name()) {
1361 // Check ENTRY result symbols too
1362 const Scope
&outer
{symbol
.owner().parent()};
1363 auto iter
{outer
.find(symbol
.name())};
1364 if (iter
!= outer
.end()) {
1365 const Symbol
&outerSym
{*iter
->second
};
1366 if (const auto *subp
{outerSym
.detailsIf
<SubprogramDetails
>()}) {
1367 if (subp
->entryScope() == &symbol
.owner() &&
1368 symbol
.name() == outerSym
.name()) {
1377 void LabelEnforce::Post(const parser::GotoStmt
&gotoStmt
) {
1378 checkLabelUse(gotoStmt
.v
);
1380 void LabelEnforce::Post(const parser::ComputedGotoStmt
&computedGotoStmt
) {
1381 for (auto &i
: std::get
<std::list
<parser::Label
>>(computedGotoStmt
.t
)) {
1386 void LabelEnforce::Post(const parser::ArithmeticIfStmt
&arithmeticIfStmt
) {
1387 checkLabelUse(std::get
<1>(arithmeticIfStmt
.t
));
1388 checkLabelUse(std::get
<2>(arithmeticIfStmt
.t
));
1389 checkLabelUse(std::get
<3>(arithmeticIfStmt
.t
));
1392 void LabelEnforce::Post(const parser::AssignStmt
&assignStmt
) {
1393 checkLabelUse(std::get
<parser::Label
>(assignStmt
.t
));
1396 void LabelEnforce::Post(const parser::AssignedGotoStmt
&assignedGotoStmt
) {
1397 for (auto &i
: std::get
<std::list
<parser::Label
>>(assignedGotoStmt
.t
)) {
1402 void LabelEnforce::Post(const parser::AltReturnSpec
&altReturnSpec
) {
1403 checkLabelUse(altReturnSpec
.v
);
1406 void LabelEnforce::Post(const parser::ErrLabel
&errLabel
) {
1407 checkLabelUse(errLabel
.v
);
1409 void LabelEnforce::Post(const parser::EndLabel
&endLabel
) {
1410 checkLabelUse(endLabel
.v
);
1412 void LabelEnforce::Post(const parser::EorLabel
&eorLabel
) {
1413 checkLabelUse(eorLabel
.v
);
1416 void LabelEnforce::checkLabelUse(const parser::Label
&labelUsed
) {
1417 if (labels_
.find(labelUsed
) == labels_
.end()) {
1418 SayWithConstruct(context_
, currentStatementSourcePosition_
,
1419 parser::MessageFormattedText
{
1420 "Control flow escapes from %s"_err_en_US
, construct_
},
1421 constructSourcePosition_
);
1425 parser::MessageFormattedText
LabelEnforce::GetEnclosingConstructMsg() {
1426 return {"Enclosing %s statement"_en_US
, construct_
};
1429 void LabelEnforce::SayWithConstruct(SemanticsContext
&context
,
1430 parser::CharBlock stmtLocation
, parser::MessageFormattedText
&&message
,
1431 parser::CharBlock constructLocation
) {
1432 context
.Say(stmtLocation
, message
)
1433 .Attach(constructLocation
, GetEnclosingConstructMsg());
1436 bool HasAlternateReturns(const Symbol
&subprogram
) {
1437 for (const auto *dummyArg
: subprogram
.get
<SubprogramDetails
>().dummyArgs()) {
1445 const std::optional
<parser::Name
> &MaybeGetNodeName(
1446 const ConstructNode
&construct
) {
1447 return common::visit(
1449 [&](const parser::BlockConstruct
*blockConstruct
)
1450 -> const std::optional
<parser::Name
> & {
1451 return std::get
<0>(blockConstruct
->t
).statement
.v
;
1453 [&](const auto *a
) -> const std::optional
<parser::Name
> & {
1454 return std::get
<0>(std::get
<0>(a
->t
).statement
.t
);
1460 std::optional
<ArraySpec
> ToArraySpec(
1461 evaluate::FoldingContext
&context
, const evaluate::Shape
&shape
) {
1462 if (auto extents
{evaluate::AsConstantExtents(context
, shape
)}) {
1464 for (const auto &extent
: *extents
) {
1465 result
.emplace_back(ShapeSpec::MakeExplicit(Bound
{extent
}));
1467 return {std::move(result
)};
1469 return std::nullopt
;
1473 std::optional
<ArraySpec
> ToArraySpec(evaluate::FoldingContext
&context
,
1474 const std::optional
<evaluate::Shape
> &shape
) {
1475 return shape
? ToArraySpec(context
, *shape
) : std::nullopt
;
1478 bool HasDefinedIo(GenericKind::DefinedIo which
, const DerivedTypeSpec
&derived
,
1479 const Scope
*scope
) {
1480 if (const Scope
* dtScope
{derived
.scope()}) {
1481 for (const auto &pair
: *dtScope
) {
1482 const Symbol
&symbol
{*pair
.second
};
1483 if (const auto *generic
{symbol
.detailsIf
<GenericDetails
>()}) {
1484 GenericKind kind
{generic
->kind()};
1485 if (const auto *io
{std::get_if
<GenericKind::DefinedIo
>(&kind
.u
)}) {
1487 return true; // type-bound GENERIC exists
1494 SourceName name
{GenericKind::AsFortran(which
)};
1495 evaluate::DynamicType dyDerived
{derived
};
1496 for (; scope
&& !scope
->IsGlobal(); scope
= &scope
->parent()) {
1497 auto iter
{scope
->find(name
)};
1498 if (iter
!= scope
->end()) {
1499 const auto &generic
{iter
->second
->GetUltimate().get
<GenericDetails
>()};
1500 for (auto ref
: generic
.specificProcs()) {
1501 const Symbol
&procSym
{ref
->GetUltimate()};
1502 if (const auto *subp
{procSym
.detailsIf
<SubprogramDetails
>()}) {
1503 if (!subp
->dummyArgs().empty()) {
1504 if (const Symbol
* first
{subp
->dummyArgs().at(0)}) {
1505 if (const DeclTypeSpec
* dtSpec
{first
->GetType()}) {
1506 if (auto dyDummy
{evaluate::DynamicType::From(*dtSpec
)}) {
1507 if (dyDummy
->IsTkCompatibleWith(dyDerived
)) {
1508 return true; // GENERIC or INTERFACE not in type
1522 } // namespace Fortran::semantics