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 const Scope
*FindOpenACCConstructContaining(const Scope
*scope
) {
112 return scope
? FindScopeContaining(*scope
,
114 return s
.kind() == Scope::Kind::OpenACCConstruct
;
119 // 7.5.2.4 "same derived type" test -- rely on IsTkCompatibleWith() and its
120 // infrastructure to detect and handle comparisons on distinct (but "same")
121 // sequence/bind(C) derived types
122 static bool MightBeSameDerivedType(
123 const std::optional
<evaluate::DynamicType
> &lhsType
,
124 const std::optional
<evaluate::DynamicType
> &rhsType
) {
125 return lhsType
&& rhsType
&& lhsType
->IsTkCompatibleWith(*rhsType
);
128 Tristate
IsDefinedAssignment(
129 const std::optional
<evaluate::DynamicType
> &lhsType
, int lhsRank
,
130 const std::optional
<evaluate::DynamicType
> &rhsType
, int rhsRank
) {
131 if (!lhsType
|| !rhsType
) {
132 return Tristate::No
; // error or rhs is untyped
134 if (lhsType
->IsUnlimitedPolymorphic()) {
137 if (rhsType
->IsUnlimitedPolymorphic()) {
138 return Tristate::Maybe
;
140 TypeCategory lhsCat
{lhsType
->category()};
141 TypeCategory rhsCat
{rhsType
->category()};
142 if (rhsRank
> 0 && lhsRank
!= rhsRank
) {
143 return Tristate::Yes
;
144 } else if (lhsCat
!= TypeCategory::Derived
) {
145 return ToTristate(lhsCat
!= rhsCat
&&
146 (!IsNumericTypeCategory(lhsCat
) || !IsNumericTypeCategory(rhsCat
)));
147 } else if (MightBeSameDerivedType(lhsType
, rhsType
)) {
148 return Tristate::Maybe
; // TYPE(t) = TYPE(t) can be defined or intrinsic
150 return Tristate::Yes
;
154 bool IsIntrinsicRelational(common::RelationalOperator opr
,
155 const evaluate::DynamicType
&type0
, int rank0
,
156 const evaluate::DynamicType
&type1
, int rank1
) {
157 if (!evaluate::AreConformable(rank0
, rank1
)) {
160 auto cat0
{type0
.category()};
161 auto cat1
{type1
.category()};
162 if (IsNumericTypeCategory(cat0
) && IsNumericTypeCategory(cat1
)) {
163 // numeric types: EQ/NE always ok, others ok for non-complex
164 return opr
== common::RelationalOperator::EQ
||
165 opr
== common::RelationalOperator::NE
||
166 (cat0
!= TypeCategory::Complex
&& cat1
!= TypeCategory::Complex
);
168 // not both numeric: only Character is ok
169 return cat0
== TypeCategory::Character
&& cat1
== TypeCategory::Character
;
174 bool IsIntrinsicNumeric(const evaluate::DynamicType
&type0
) {
175 return IsNumericTypeCategory(type0
.category());
177 bool IsIntrinsicNumeric(const evaluate::DynamicType
&type0
, int rank0
,
178 const evaluate::DynamicType
&type1
, int rank1
) {
179 return evaluate::AreConformable(rank0
, rank1
) &&
180 IsNumericTypeCategory(type0
.category()) &&
181 IsNumericTypeCategory(type1
.category());
184 bool IsIntrinsicLogical(const evaluate::DynamicType
&type0
) {
185 return type0
.category() == TypeCategory::Logical
;
187 bool IsIntrinsicLogical(const evaluate::DynamicType
&type0
, int rank0
,
188 const evaluate::DynamicType
&type1
, int rank1
) {
189 return evaluate::AreConformable(rank0
, rank1
) &&
190 type0
.category() == TypeCategory::Logical
&&
191 type1
.category() == TypeCategory::Logical
;
194 bool IsIntrinsicConcat(const evaluate::DynamicType
&type0
, int rank0
,
195 const evaluate::DynamicType
&type1
, int rank1
) {
196 return evaluate::AreConformable(rank0
, rank1
) &&
197 type0
.category() == TypeCategory::Character
&&
198 type1
.category() == TypeCategory::Character
&&
199 type0
.kind() == type1
.kind();
202 bool IsGenericDefinedOp(const Symbol
&symbol
) {
203 const Symbol
&ultimate
{symbol
.GetUltimate()};
204 if (const auto *generic
{ultimate
.detailsIf
<GenericDetails
>()}) {
205 return generic
->kind().IsDefinedOperator();
206 } else if (const auto *misc
{ultimate
.detailsIf
<MiscDetails
>()}) {
207 return misc
->kind() == MiscDetails::Kind::TypeBoundDefinedOp
;
213 bool IsDefinedOperator(SourceName name
) {
214 const char *begin
{name
.begin()};
215 const char *end
{name
.end()};
216 return begin
!= end
&& begin
[0] == '.' && end
[-1] == '.';
219 std::string
MakeOpName(SourceName name
) {
220 std::string result
{name
.ToString()};
221 return IsDefinedOperator(name
) ? "OPERATOR(" + result
+ ")"
222 : result
.find("operator(", 0) == 0 ? parser::ToUpperCaseLetters(result
)
226 bool IsCommonBlockContaining(const Symbol
&block
, const Symbol
&object
) {
227 const auto &objects
{block
.get
<CommonBlockDetails
>().objects()};
228 return llvm::is_contained(objects
, object
);
231 bool IsUseAssociated(const Symbol
&symbol
, const Scope
&scope
) {
232 const Scope
&owner
{GetTopLevelUnitContaining(symbol
.GetUltimate().owner())};
233 return owner
.kind() == Scope::Kind::Module
&&
234 owner
!= GetTopLevelUnitContaining(scope
);
237 bool DoesScopeContain(
238 const Scope
*maybeAncestor
, const Scope
&maybeDescendent
) {
239 return maybeAncestor
&& !maybeDescendent
.IsTopLevel() &&
240 FindScopeContaining(maybeDescendent
.parent(),
241 [&](const Scope
&scope
) { return &scope
== maybeAncestor
; });
244 bool DoesScopeContain(const Scope
*maybeAncestor
, const Symbol
&symbol
) {
245 return DoesScopeContain(maybeAncestor
, symbol
.owner());
248 static const Symbol
&FollowHostAssoc(const Symbol
&symbol
) {
249 for (const Symbol
*s
{&symbol
};;) {
250 const auto *details
{s
->detailsIf
<HostAssocDetails
>()};
254 s
= &details
->symbol();
258 bool IsHostAssociated(const Symbol
&symbol
, const Scope
&scope
) {
259 const Symbol
&base
{FollowHostAssoc(symbol
)};
260 return base
.owner().IsTopLevel() ||
261 DoesScopeContain(&GetProgramUnitOrBlockConstructContaining(base
),
262 GetProgramUnitOrBlockConstructContaining(scope
));
265 bool IsHostAssociatedIntoSubprogram(const Symbol
&symbol
, const Scope
&scope
) {
266 const Symbol
&base
{FollowHostAssoc(symbol
)};
267 return base
.owner().IsTopLevel() ||
268 DoesScopeContain(&GetProgramUnitOrBlockConstructContaining(base
),
269 GetProgramUnitContaining(scope
));
272 bool IsInStmtFunction(const Symbol
&symbol
) {
273 if (const Symbol
* function
{symbol
.owner().symbol()}) {
274 return IsStmtFunction(*function
);
279 bool IsStmtFunctionDummy(const Symbol
&symbol
) {
280 return IsDummy(symbol
) && IsInStmtFunction(symbol
);
283 bool IsStmtFunctionResult(const Symbol
&symbol
) {
284 return IsFunctionResult(symbol
) && IsInStmtFunction(symbol
);
287 bool IsPointerDummy(const Symbol
&symbol
) {
288 return IsPointer(symbol
) && IsDummy(symbol
);
291 bool IsBindCProcedure(const Symbol
&original
) {
292 const Symbol
&symbol
{original
.GetUltimate()};
293 if (const auto *procDetails
{symbol
.detailsIf
<ProcEntityDetails
>()}) {
294 if (procDetails
->procInterface()) {
295 // procedure component with a BIND(C) interface
296 return IsBindCProcedure(*procDetails
->procInterface());
299 return symbol
.attrs().test(Attr::BIND_C
) && IsProcedure(symbol
);
302 bool IsBindCProcedure(const Scope
&scope
) {
303 if (const Symbol
* symbol
{scope
.GetSymbol()}) {
304 return IsBindCProcedure(*symbol
);
310 static const Symbol
*FindPointerComponent(
311 const Scope
&scope
, std::set
<const Scope
*> &visited
) {
312 if (!scope
.IsDerivedType()) {
315 if (!visited
.insert(&scope
).second
) {
318 // If there's a top-level pointer component, return it for clearer error
320 for (const auto &pair
: scope
) {
321 const Symbol
&symbol
{*pair
.second
};
322 if (IsPointer(symbol
)) {
326 for (const auto &pair
: scope
) {
327 const Symbol
&symbol
{*pair
.second
};
328 if (const auto *details
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
329 if (const DeclTypeSpec
* type
{details
->type()}) {
330 if (const DerivedTypeSpec
* derived
{type
->AsDerived()}) {
331 if (const Scope
* nested
{derived
->scope()}) {
333 pointer
{FindPointerComponent(*nested
, visited
)}) {
344 const Symbol
*FindPointerComponent(const Scope
&scope
) {
345 std::set
<const Scope
*> visited
;
346 return FindPointerComponent(scope
, visited
);
349 const Symbol
*FindPointerComponent(const DerivedTypeSpec
&derived
) {
350 if (const Scope
* scope
{derived
.scope()}) {
351 return FindPointerComponent(*scope
);
357 const Symbol
*FindPointerComponent(const DeclTypeSpec
&type
) {
358 if (const DerivedTypeSpec
* derived
{type
.AsDerived()}) {
359 return FindPointerComponent(*derived
);
365 const Symbol
*FindPointerComponent(const DeclTypeSpec
*type
) {
366 return type
? FindPointerComponent(*type
) : nullptr;
369 const Symbol
*FindPointerComponent(const Symbol
&symbol
) {
370 return IsPointer(symbol
) ? &symbol
: FindPointerComponent(symbol
.GetType());
373 // C1594 specifies several ways by which an object might be globally visible.
374 const Symbol
*FindExternallyVisibleObject(
375 const Symbol
&object
, const Scope
&scope
, bool isPointerDefinition
) {
376 // TODO: Storage association with any object for which this predicate holds,
377 // once EQUIVALENCE is supported.
378 const Symbol
&ultimate
{GetAssociationRoot(object
)};
379 if (IsDummy(ultimate
)) {
380 if (IsIntentIn(ultimate
)) {
383 if (!isPointerDefinition
&& IsPointer(ultimate
) &&
384 IsPureProcedure(ultimate
.owner()) && IsFunction(ultimate
.owner())) {
387 } else if (ultimate
.owner().IsDerivedType()) {
389 } else if (&GetProgramUnitContaining(ultimate
) !=
390 &GetProgramUnitContaining(scope
)) {
392 } else if (const Symbol
* block
{FindCommonBlockContaining(ultimate
)}) {
398 const Symbol
&BypassGeneric(const Symbol
&symbol
) {
399 const Symbol
&ultimate
{symbol
.GetUltimate()};
400 if (const auto *generic
{ultimate
.detailsIf
<GenericDetails
>()}) {
401 if (const Symbol
* specific
{generic
->specific()}) {
408 const Symbol
&GetCrayPointer(const Symbol
&crayPointee
) {
409 const Symbol
*found
{nullptr};
410 for (const auto &[pointee
, pointer
] :
411 crayPointee
.GetUltimate().owner().crayPointers()) {
412 if (pointee
== crayPointee
.name()) {
413 found
= &pointer
.get();
420 bool ExprHasTypeCategory(
421 const SomeExpr
&expr
, const common::TypeCategory
&type
) {
422 auto dynamicType
{expr
.GetType()};
423 return dynamicType
&& dynamicType
->category() == type
;
426 bool ExprTypeKindIsDefault(
427 const SomeExpr
&expr
, const SemanticsContext
&context
) {
428 auto dynamicType
{expr
.GetType()};
429 return dynamicType
&&
430 dynamicType
->category() != common::TypeCategory::Derived
&&
431 dynamicType
->kind() == context
.GetDefaultKind(dynamicType
->category());
434 // If an analyzed expr or assignment is missing, dump the node and die.
435 template <typename T
>
436 static void CheckMissingAnalysis(
437 bool crash
, SemanticsContext
*context
, const T
&x
) {
438 if (crash
&& !(context
&& context
->AnyFatalError())) {
440 llvm::raw_string_ostream ss
{buf
};
441 ss
<< "node has not been analyzed:\n";
442 parser::DumpTree(ss
, x
);
443 common::die(buf
.c_str());
447 const SomeExpr
*GetExprHelper::Get(const parser::Expr
&x
) {
448 CheckMissingAnalysis(crashIfNoExpr_
&& !x
.typedExpr
, context_
, x
);
449 return x
.typedExpr
? common::GetPtrFromOptional(x
.typedExpr
->v
) : nullptr;
451 const SomeExpr
*GetExprHelper::Get(const parser::Variable
&x
) {
452 CheckMissingAnalysis(crashIfNoExpr_
&& !x
.typedExpr
, context_
, x
);
453 return x
.typedExpr
? common::GetPtrFromOptional(x
.typedExpr
->v
) : nullptr;
455 const SomeExpr
*GetExprHelper::Get(const parser::DataStmtConstant
&x
) {
456 CheckMissingAnalysis(crashIfNoExpr_
&& !x
.typedExpr
, context_
, x
);
457 return x
.typedExpr
? common::GetPtrFromOptional(x
.typedExpr
->v
) : nullptr;
459 const SomeExpr
*GetExprHelper::Get(const parser::AllocateObject
&x
) {
460 CheckMissingAnalysis(crashIfNoExpr_
&& !x
.typedExpr
, context_
, x
);
461 return x
.typedExpr
? common::GetPtrFromOptional(x
.typedExpr
->v
) : nullptr;
463 const SomeExpr
*GetExprHelper::Get(const parser::PointerObject
&x
) {
464 CheckMissingAnalysis(crashIfNoExpr_
&& !x
.typedExpr
, context_
, x
);
465 return x
.typedExpr
? common::GetPtrFromOptional(x
.typedExpr
->v
) : nullptr;
468 const evaluate::Assignment
*GetAssignment(const parser::AssignmentStmt
&x
) {
469 return x
.typedAssignment
? common::GetPtrFromOptional(x
.typedAssignment
->v
)
472 const evaluate::Assignment
*GetAssignment(
473 const parser::PointerAssignmentStmt
&x
) {
474 return x
.typedAssignment
? common::GetPtrFromOptional(x
.typedAssignment
->v
)
478 const Symbol
*FindInterface(const Symbol
&symbol
) {
479 return common::visit(
481 [](const ProcEntityDetails
&details
) {
482 const Symbol
*interface
{details
.procInterface()};
483 return interface
? FindInterface(*interface
) : nullptr;
485 [](const ProcBindingDetails
&details
) {
486 return FindInterface(details
.symbol());
488 [&](const SubprogramDetails
&) { return &symbol
; },
489 [](const UseDetails
&details
) {
490 return FindInterface(details
.symbol());
492 [](const HostAssocDetails
&details
) {
493 return FindInterface(details
.symbol());
495 [](const GenericDetails
&details
) {
496 return details
.specific() ? FindInterface(*details
.specific())
499 [](const auto &) -> const Symbol
* { return nullptr; },
504 const Symbol
*FindSubprogram(const Symbol
&symbol
) {
505 return common::visit(
507 [&](const ProcEntityDetails
&details
) -> const Symbol
* {
508 if (details
.procInterface()) {
509 return FindSubprogram(*details
.procInterface());
514 [](const ProcBindingDetails
&details
) {
515 return FindSubprogram(details
.symbol());
517 [&](const SubprogramDetails
&) { return &symbol
; },
518 [](const UseDetails
&details
) {
519 return FindSubprogram(details
.symbol());
521 [](const HostAssocDetails
&details
) {
522 return FindSubprogram(details
.symbol());
524 [](const GenericDetails
&details
) {
525 return details
.specific() ? FindSubprogram(*details
.specific())
528 [](const auto &) -> const Symbol
* { return nullptr; },
533 const Symbol
*FindOverriddenBinding(
534 const Symbol
&symbol
, bool &isInaccessibleDeferred
) {
535 isInaccessibleDeferred
= false;
536 if (symbol
.has
<ProcBindingDetails
>()) {
537 if (const DeclTypeSpec
* parentType
{FindParentTypeSpec(symbol
.owner())}) {
538 if (const DerivedTypeSpec
* parentDerived
{parentType
->AsDerived()}) {
539 if (const Scope
* parentScope
{parentDerived
->typeSymbol().scope()}) {
541 overridden
{parentScope
->FindComponent(symbol
.name())}) {
542 // 7.5.7.3 p1: only accessible bindings are overridden
543 if (!overridden
->attrs().test(Attr::PRIVATE
) ||
544 FindModuleContaining(overridden
->owner()) ==
545 FindModuleContaining(symbol
.owner())) {
547 } else if (overridden
->attrs().test(Attr::DEFERRED
)) {
548 isInaccessibleDeferred
= true;
559 const Symbol
*FindGlobal(const Symbol
&original
) {
560 const Symbol
&ultimate
{original
.GetUltimate()};
561 if (ultimate
.owner().IsGlobal()) {
565 if (IsDummy(ultimate
)) {
566 } else if (IsPointer(ultimate
)) {
567 } else if (ultimate
.has
<ProcEntityDetails
>()) {
568 isLocal
= IsExternal(ultimate
);
569 } else if (const auto *subp
{ultimate
.detailsIf
<SubprogramDetails
>()}) {
570 isLocal
= subp
->isInterface();
573 const std::string
*bind
{ultimate
.GetBindName()};
574 if (!bind
|| ultimate
.name() == *bind
) {
575 const Scope
&globalScope
{ultimate
.owner().context().globalScope()};
576 if (auto iter
{globalScope
.find(ultimate
.name())};
577 iter
!= globalScope
.end()) {
578 const Symbol
&global
{*iter
->second
};
579 const std::string
*globalBind
{global
.GetBindName()};
580 if (!globalBind
|| global
.name() == *globalBind
) {
589 const DeclTypeSpec
*FindParentTypeSpec(const DerivedTypeSpec
&derived
) {
590 return FindParentTypeSpec(derived
.typeSymbol());
593 const DeclTypeSpec
*FindParentTypeSpec(const DeclTypeSpec
&decl
) {
594 if (const DerivedTypeSpec
* derived
{decl
.AsDerived()}) {
595 return FindParentTypeSpec(*derived
);
601 const DeclTypeSpec
*FindParentTypeSpec(const Scope
&scope
) {
602 if (scope
.kind() == Scope::Kind::DerivedType
) {
603 if (const auto *symbol
{scope
.symbol()}) {
604 return FindParentTypeSpec(*symbol
);
610 const DeclTypeSpec
*FindParentTypeSpec(const Symbol
&symbol
) {
611 if (const Scope
* scope
{symbol
.scope()}) {
612 if (const auto *details
{symbol
.detailsIf
<DerivedTypeDetails
>()}) {
613 if (const Symbol
* parent
{details
->GetParentComponent(*scope
)}) {
614 return parent
->GetType();
621 const EquivalenceSet
*FindEquivalenceSet(const Symbol
&symbol
) {
622 const Symbol
&ultimate
{symbol
.GetUltimate()};
623 for (const EquivalenceSet
&set
: ultimate
.owner().equivalenceSets()) {
624 for (const EquivalenceObject
&object
: set
) {
625 if (object
.symbol
== ultimate
) {
633 bool IsOrContainsEventOrLockComponent(const Symbol
&original
) {
634 const Symbol
&symbol
{ResolveAssociations(original
)};
635 if (const auto *details
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
636 if (const DeclTypeSpec
* type
{details
->type()}) {
637 if (const DerivedTypeSpec
* derived
{type
->AsDerived()}) {
638 return IsEventTypeOrLockType(derived
) ||
639 FindEventOrLockPotentialComponent(*derived
);
646 // Check this symbol suitable as a type-bound procedure - C769
647 bool CanBeTypeBoundProc(const Symbol
&symbol
) {
648 if (IsDummy(symbol
) || IsProcedurePointer(symbol
)) {
650 } else if (symbol
.has
<SubprogramNameDetails
>()) {
651 return symbol
.owner().kind() == Scope::Kind::Module
;
652 } else if (auto *details
{symbol
.detailsIf
<SubprogramDetails
>()}) {
653 if (details
->isInterface()) {
654 return !symbol
.attrs().test(Attr::ABSTRACT
);
656 return symbol
.owner().kind() == Scope::Kind::Module
;
658 } else if (const auto *proc
{symbol
.detailsIf
<ProcEntityDetails
>()}) {
659 return !symbol
.attrs().test(Attr::INTRINSIC
) &&
660 proc
->HasExplicitInterface();
666 bool HasDeclarationInitializer(const Symbol
&symbol
) {
667 if (IsNamedConstant(symbol
)) {
669 } else if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
670 return object
->init().has_value();
671 } else if (const auto *proc
{symbol
.detailsIf
<ProcEntityDetails
>()}) {
672 return proc
->init().has_value();
678 bool IsInitialized(const Symbol
&symbol
, bool ignoreDataStatements
,
679 bool ignoreAllocatable
, bool ignorePointer
) {
680 if (!ignoreAllocatable
&& IsAllocatable(symbol
)) {
682 } else if (!ignoreDataStatements
&& symbol
.test(Symbol::Flag::InDataStmt
)) {
684 } else if (HasDeclarationInitializer(symbol
)) {
686 } else if (IsPointer(symbol
)) {
687 return !ignorePointer
;
688 } else if (IsNamedConstant(symbol
)) {
690 } else if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
691 if ((!object
->isDummy() || IsIntentOut(symbol
)) && object
->type()) {
692 if (const auto *derived
{object
->type()->AsDerived()}) {
693 return derived
->HasDefaultInitialization(
694 ignoreAllocatable
, ignorePointer
);
701 bool IsDestructible(const Symbol
&symbol
, const Symbol
*derivedTypeSymbol
) {
702 if (IsAllocatable(symbol
) || IsAutomatic(symbol
)) {
704 } else if (IsNamedConstant(symbol
) || IsFunctionResult(symbol
) ||
707 } else if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
708 if ((!object
->isDummy() || IsIntentOut(symbol
)) && object
->type()) {
709 if (const auto *derived
{object
->type()->AsDerived()}) {
710 return &derived
->typeSymbol() != derivedTypeSymbol
&&
711 derived
->HasDestruction();
718 bool HasIntrinsicTypeName(const Symbol
&symbol
) {
719 std::string name
{symbol
.name().ToString()};
720 if (name
== "doubleprecision") {
722 } else if (name
== "derived") {
725 for (int i
{0}; i
!= common::TypeCategory_enumSize
; ++i
) {
726 if (name
== parser::ToLowerCaseLetters(EnumToString(TypeCategory
{i
}))) {
734 bool IsSeparateModuleProcedureInterface(const Symbol
*symbol
) {
735 if (symbol
&& symbol
->attrs().test(Attr::MODULE
)) {
736 if (auto *details
{symbol
->detailsIf
<SubprogramDetails
>()}) {
737 return details
->isInterface();
743 SymbolVector
FinalsForDerivedTypeInstantiation(const DerivedTypeSpec
&spec
) {
745 const Symbol
&typeSymbol
{spec
.typeSymbol()};
746 if (const auto *derived
{typeSymbol
.detailsIf
<DerivedTypeDetails
>()}) {
747 for (const auto &pair
: derived
->finals()) {
748 const Symbol
&subr
{*pair
.second
};
749 // Errors in FINAL subroutines are caught in CheckFinal
750 // in check-declarations.cpp.
751 if (const auto *subprog
{subr
.detailsIf
<SubprogramDetails
>()};
752 subprog
&& subprog
->dummyArgs().size() == 1) {
753 if (const Symbol
* arg
{subprog
->dummyArgs()[0]}) {
754 if (const DeclTypeSpec
* type
{arg
->GetType()}) {
755 if (type
->category() == DeclTypeSpec::TypeDerived
&&
756 evaluate::AreSameDerivedType(spec
, type
->derivedTypeSpec())) {
757 result
.emplace_back(subr
);
767 const Symbol
*IsFinalizable(const Symbol
&symbol
,
768 std::set
<const DerivedTypeSpec
*> *inProgress
, bool withImpureFinalizer
) {
769 if (IsPointer(symbol
) || evaluate::IsAssumedRank(symbol
)) {
772 if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
773 if (object
->isDummy() && !IsIntentOut(symbol
)) {
776 const DeclTypeSpec
*type
{object
->type()};
777 if (const DerivedTypeSpec
* typeSpec
{type
? type
->AsDerived() : nullptr}) {
778 return IsFinalizable(
779 *typeSpec
, inProgress
, withImpureFinalizer
, symbol
.Rank());
785 const Symbol
*IsFinalizable(const DerivedTypeSpec
&derived
,
786 std::set
<const DerivedTypeSpec
*> *inProgress
, bool withImpureFinalizer
,
787 std::optional
<int> rank
) {
788 const Symbol
*elemental
{nullptr};
789 for (auto ref
: FinalsForDerivedTypeInstantiation(derived
)) {
790 const Symbol
*symbol
{&ref
->GetUltimate()};
791 if (const auto *binding
{symbol
->detailsIf
<ProcBindingDetails
>()}) {
792 symbol
= &binding
->symbol();
794 if (const auto *proc
{symbol
->detailsIf
<ProcEntityDetails
>()}) {
795 symbol
= proc
->procInterface();
798 } else if (IsElementalProcedure(*symbol
)) {
802 if (const SubprogramDetails
*
803 subp
{symbol
->detailsIf
<SubprogramDetails
>()}) {
804 if (const auto &args
{subp
->dummyArgs()}; !args
.empty() &&
805 args
.at(0) && !evaluate::IsAssumedRank(*args
.at(0)) &&
806 args
.at(0)->Rank() != *rank
) {
807 continue; // not a finalizer for this rank
811 if (!withImpureFinalizer
|| !IsPureProcedure(*symbol
)) {
814 // Found non-elemental pure finalizer of matching rank, but still
815 // need to check components for an impure finalizer.
820 if (elemental
&& (!withImpureFinalizer
|| !IsPureProcedure(*elemental
))) {
823 // Check components (including ancestors)
824 std::set
<const DerivedTypeSpec
*> basis
;
826 if (inProgress
->find(&derived
) != inProgress
->end()) {
827 return nullptr; // don't loop on recursive type
832 auto iterator
{inProgress
->insert(&derived
).first
};
833 const Symbol
*result
{nullptr};
834 for (const Symbol
&component
: PotentialComponentIterator
{derived
}) {
835 result
= IsFinalizable(component
, inProgress
, withImpureFinalizer
);
840 inProgress
->erase(iterator
);
844 static const Symbol
*HasImpureFinal(
845 const DerivedTypeSpec
&derived
, std::optional
<int> rank
) {
846 return IsFinalizable(derived
, nullptr, /*withImpureFinalizer=*/true, rank
);
849 const Symbol
*HasImpureFinal(const Symbol
&original
, std::optional
<int> rank
) {
850 const Symbol
&symbol
{ResolveAssociations(original
)};
851 if (symbol
.has
<ObjectEntityDetails
>()) {
852 if (const DeclTypeSpec
* symType
{symbol
.GetType()}) {
853 if (const DerivedTypeSpec
* derived
{symType
->AsDerived()}) {
854 if (evaluate::IsAssumedRank(symbol
)) {
855 // finalizable assumed-rank not allowed (C839)
858 int actualRank
{rank
.value_or(symbol
.Rank())};
859 return HasImpureFinal(*derived
, actualRank
);
867 bool MayRequireFinalization(const DerivedTypeSpec
&derived
) {
868 return IsFinalizable(derived
) ||
869 FindPolymorphicAllocatablePotentialComponent(derived
);
872 bool HasAllocatableDirectComponent(const DerivedTypeSpec
&derived
) {
873 DirectComponentIterator directs
{derived
};
874 return std::any_of(directs
.begin(), directs
.end(), IsAllocatable
);
877 bool IsAssumedLengthCharacter(const Symbol
&symbol
) {
878 if (const DeclTypeSpec
* type
{symbol
.GetType()}) {
879 return type
->category() == DeclTypeSpec::Character
&&
880 type
->characterTypeSpec().length().isAssumed();
886 bool IsInBlankCommon(const Symbol
&symbol
) {
887 const Symbol
*block
{FindCommonBlockContaining(symbol
)};
888 return block
&& block
->name().empty();
891 // C722 and C723: For a function to be assumed length, it must be external and
893 bool IsExternal(const Symbol
&symbol
) {
894 return ClassifyProcedure(symbol
) == ProcedureDefinitionClass::External
;
897 // Most scopes have no EQUIVALENCE, and this function is a fast no-op for them.
898 std::list
<std::list
<SymbolRef
>> GetStorageAssociations(const Scope
&scope
) {
899 UnorderedSymbolSet distinct
;
900 for (const EquivalenceSet
&set
: scope
.equivalenceSets()) {
901 for (const EquivalenceObject
&object
: set
) {
902 distinct
.emplace(object
.symbol
);
905 // This set is ordered by ascending offsets, with ties broken by greatest
906 // size. A multiset is used here because multiple symbols may have the
907 // same offset and size; the symbols in the set, however, are distinct.
908 std::multiset
<SymbolRef
, SymbolOffsetCompare
> associated
;
909 for (SymbolRef ref
: distinct
) {
910 associated
.emplace(*ref
);
912 std::list
<std::list
<SymbolRef
>> result
;
913 std::size_t limit
{0};
914 const Symbol
*currentCommon
{nullptr};
915 for (const Symbol
&symbol
: associated
) {
916 const Symbol
*thisCommon
{FindCommonBlockContaining(symbol
)};
917 if (result
.empty() || symbol
.offset() >= limit
||
918 thisCommon
!= currentCommon
) {
920 result
.emplace_back(std::list
<SymbolRef
>{});
922 currentCommon
= thisCommon
;
924 result
.back().emplace_back(symbol
);
925 limit
= std::max(limit
, symbol
.offset() + symbol
.size());
930 bool IsModuleProcedure(const Symbol
&symbol
) {
931 return ClassifyProcedure(symbol
) == ProcedureDefinitionClass::Module
;
934 class ImageControlStmtHelper
{
935 using ImageControlStmts
=
936 std::variant
<parser::ChangeTeamConstruct
, parser::CriticalConstruct
,
937 parser::EventPostStmt
, parser::EventWaitStmt
, parser::FormTeamStmt
,
938 parser::LockStmt
, parser::SyncAllStmt
, parser::SyncImagesStmt
,
939 parser::SyncMemoryStmt
, parser::SyncTeamStmt
, parser::UnlockStmt
>;
942 template <typename T
> bool operator()(const T
&) {
943 return common::HasMember
<T
, ImageControlStmts
>;
945 template <typename T
> bool operator()(const common::Indirection
<T
> &x
) {
946 return (*this)(x
.value());
948 template <typename A
> bool operator()(const parser::Statement
<A
> &x
) {
949 return (*this)(x
.statement
);
951 bool operator()(const parser::AllocateStmt
&stmt
) {
952 const auto &allocationList
{std::get
<std::list
<parser::Allocation
>>(stmt
.t
)};
953 for (const auto &allocation
: allocationList
) {
954 const auto &allocateObject
{
955 std::get
<parser::AllocateObject
>(allocation
.t
)};
956 if (IsCoarrayObject(allocateObject
)) {
962 bool operator()(const parser::DeallocateStmt
&stmt
) {
963 const auto &allocateObjectList
{
964 std::get
<std::list
<parser::AllocateObject
>>(stmt
.t
)};
965 for (const auto &allocateObject
: allocateObjectList
) {
966 if (IsCoarrayObject(allocateObject
)) {
972 bool operator()(const parser::CallStmt
&stmt
) {
973 const auto &procedureDesignator
{
974 std::get
<parser::ProcedureDesignator
>(stmt
.call
.t
)};
975 if (auto *name
{std::get_if
<parser::Name
>(&procedureDesignator
.u
)}) {
976 // TODO: also ensure that the procedure is, in fact, an intrinsic
977 if (name
->source
== "move_alloc") {
979 std::get
<std::list
<parser::ActualArgSpec
>>(stmt
.call
.t
)};
981 const parser::ActualArg
&actualArg
{
982 std::get
<parser::ActualArg
>(args
.front().t
)};
983 if (const auto *argExpr
{
984 std::get_if
<common::Indirection
<parser::Expr
>>(
986 return HasCoarray(argExpr
->value());
993 bool operator()(const parser::StopStmt
&stmt
) {
994 // STOP is an image control statement; ERROR STOP is not
995 return std::get
<parser::StopStmt::Kind
>(stmt
.t
) ==
996 parser::StopStmt::Kind::Stop
;
998 bool operator()(const parser::IfStmt
&stmt
) {
1000 std::get
<parser::UnlabeledStatement
<parser::ActionStmt
>>(stmt
.t
)
1003 bool operator()(const parser::ActionStmt
&stmt
) {
1004 return common::visit(*this, stmt
.u
);
1008 bool IsCoarrayObject(const parser::AllocateObject
&allocateObject
) {
1009 const parser::Name
&name
{GetLastName(allocateObject
)};
1010 return name
.symbol
&& evaluate::IsCoarray(*name
.symbol
);
1014 bool IsImageControlStmt(const parser::ExecutableConstruct
&construct
) {
1015 return common::visit(ImageControlStmtHelper
{}, construct
.u
);
1018 std::optional
<parser::MessageFixedText
> GetImageControlStmtCoarrayMsg(
1019 const parser::ExecutableConstruct
&construct
) {
1020 if (const auto *actionStmt
{
1021 std::get_if
<parser::Statement
<parser::ActionStmt
>>(&construct
.u
)}) {
1022 return common::visit(
1024 [](const common::Indirection
<parser::AllocateStmt
> &)
1025 -> std::optional
<parser::MessageFixedText
> {
1026 return "ALLOCATE of a coarray is an image control"
1029 [](const common::Indirection
<parser::DeallocateStmt
> &)
1030 -> std::optional
<parser::MessageFixedText
> {
1031 return "DEALLOCATE of a coarray is an image control"
1034 [](const common::Indirection
<parser::CallStmt
> &)
1035 -> std::optional
<parser::MessageFixedText
> {
1036 return "MOVE_ALLOC of a coarray is an image control"
1037 " statement "_en_US
;
1039 [](const auto &) -> std::optional
<parser::MessageFixedText
> {
1040 return std::nullopt
;
1043 actionStmt
->statement
.u
);
1045 return std::nullopt
;
1048 parser::CharBlock
GetImageControlStmtLocation(
1049 const parser::ExecutableConstruct
&executableConstruct
) {
1050 return common::visit(
1052 [](const common::Indirection
<parser::ChangeTeamConstruct
>
1054 return std::get
<parser::Statement
<parser::ChangeTeamStmt
>>(
1055 construct
.value().t
)
1058 [](const common::Indirection
<parser::CriticalConstruct
> &construct
) {
1059 return std::get
<parser::Statement
<parser::CriticalStmt
>>(
1060 construct
.value().t
)
1063 [](const parser::Statement
<parser::ActionStmt
> &actionStmt
) {
1064 return actionStmt
.source
;
1066 [](const auto &) { return parser::CharBlock
{}; },
1068 executableConstruct
.u
);
1071 bool HasCoarray(const parser::Expr
&expression
) {
1072 if (const auto *expr
{GetExpr(nullptr, expression
)}) {
1073 for (const Symbol
&symbol
: evaluate::CollectSymbols(*expr
)) {
1074 if (evaluate::IsCoarray(symbol
)) {
1082 bool IsAssumedType(const Symbol
&symbol
) {
1083 if (const DeclTypeSpec
* type
{symbol
.GetType()}) {
1084 return type
->IsAssumedType();
1089 bool IsPolymorphic(const Symbol
&symbol
) {
1090 if (const DeclTypeSpec
* type
{symbol
.GetType()}) {
1091 return type
->IsPolymorphic();
1096 bool IsUnlimitedPolymorphic(const Symbol
&symbol
) {
1097 if (const DeclTypeSpec
* type
{symbol
.GetType()}) {
1098 return type
->IsUnlimitedPolymorphic();
1103 bool IsPolymorphicAllocatable(const Symbol
&symbol
) {
1104 return IsAllocatable(symbol
) && IsPolymorphic(symbol
);
1107 const Scope
*FindCUDADeviceContext(const Scope
*scope
) {
1108 return !scope
? nullptr : FindScopeContaining(*scope
, [](const Scope
&s
) {
1109 return IsCUDADeviceContext(&s
);
1113 std::optional
<common::CUDADataAttr
> GetCUDADataAttr(const Symbol
*symbol
) {
1115 symbol
? symbol
->detailsIf
<ObjectEntityDetails
>() : nullptr};
1116 return object
? object
->cudaDataAttr() : std::nullopt
;
1119 std::optional
<parser::MessageFormattedText
> CheckAccessibleSymbol(
1120 const Scope
&scope
, const Symbol
&symbol
) {
1121 if (symbol
.attrs().test(Attr::PRIVATE
)) {
1122 if (FindModuleFileContaining(scope
)) {
1123 // Don't enforce component accessibility checks in module files;
1124 // there may be forward-substituted named constants of derived type
1125 // whose structure constructors reference private components.
1126 } else if (const Scope
*
1127 moduleScope
{FindModuleContaining(symbol
.owner())}) {
1128 if (!moduleScope
->Contains(scope
)) {
1129 return parser::MessageFormattedText
{
1130 "PRIVATE name '%s' is only accessible within module '%s'"_err_en_US
,
1131 symbol
.name(), moduleScope
->GetName().value()};
1135 return std::nullopt
;
1138 SymbolVector
OrderParameterNames(const Symbol
&typeSymbol
) {
1139 SymbolVector result
;
1140 if (const DerivedTypeSpec
* spec
{typeSymbol
.GetParentTypeSpec()}) {
1141 result
= OrderParameterNames(spec
->typeSymbol());
1143 const auto ¶mNames
{typeSymbol
.get
<DerivedTypeDetails
>().paramNameOrder()};
1144 result
.insert(result
.end(), paramNames
.begin(), paramNames
.end());
1148 SymbolVector
OrderParameterDeclarations(const Symbol
&typeSymbol
) {
1149 SymbolVector result
;
1150 if (const DerivedTypeSpec
* spec
{typeSymbol
.GetParentTypeSpec()}) {
1151 result
= OrderParameterDeclarations(spec
->typeSymbol());
1153 const auto ¶mDecls
{typeSymbol
.get
<DerivedTypeDetails
>().paramDeclOrder()};
1154 result
.insert(result
.end(), paramDecls
.begin(), paramDecls
.end());
1158 const DeclTypeSpec
&FindOrInstantiateDerivedType(
1159 Scope
&scope
, DerivedTypeSpec
&&spec
, DeclTypeSpec::Category category
) {
1160 spec
.EvaluateParameters(scope
.context());
1161 if (const DeclTypeSpec
*
1162 type
{scope
.FindInstantiatedDerivedType(spec
, category
)}) {
1165 // Create a new instantiation of this parameterized derived type
1166 // for this particular distinct set of actual parameter values.
1167 DeclTypeSpec
&type
{scope
.MakeDerivedType(category
, std::move(spec
))};
1168 type
.derivedTypeSpec().Instantiate(scope
);
1172 const Symbol
*FindSeparateModuleSubprogramInterface(const Symbol
*proc
) {
1174 if (const auto *subprogram
{proc
->detailsIf
<SubprogramDetails
>()}) {
1175 if (const Symbol
* iface
{subprogram
->moduleInterface()}) {
1183 ProcedureDefinitionClass
ClassifyProcedure(const Symbol
&symbol
) { // 15.2.2
1184 const Symbol
&ultimate
{symbol
.GetUltimate()};
1185 if (!IsProcedure(ultimate
)) {
1186 return ProcedureDefinitionClass::None
;
1187 } else if (ultimate
.attrs().test(Attr::INTRINSIC
)) {
1188 return ProcedureDefinitionClass::Intrinsic
;
1189 } else if (IsDummy(ultimate
)) {
1190 return ProcedureDefinitionClass::Dummy
;
1191 } else if (IsProcedurePointer(symbol
)) {
1192 return ProcedureDefinitionClass::Pointer
;
1193 } else if (ultimate
.attrs().test(Attr::EXTERNAL
)) {
1194 return ProcedureDefinitionClass::External
;
1195 } else if (const auto *nameDetails
{
1196 ultimate
.detailsIf
<SubprogramNameDetails
>()}) {
1197 switch (nameDetails
->kind()) {
1198 case SubprogramKind::Module
:
1199 return ProcedureDefinitionClass::Module
;
1200 case SubprogramKind::Internal
:
1201 return ProcedureDefinitionClass::Internal
;
1203 } else if (const Symbol
* subp
{FindSubprogram(symbol
)}) {
1204 if (const auto *subpDetails
{subp
->detailsIf
<SubprogramDetails
>()}) {
1205 if (subpDetails
->stmtFunction()) {
1206 return ProcedureDefinitionClass::StatementFunction
;
1209 switch (ultimate
.owner().kind()) {
1210 case Scope::Kind::Global
:
1211 case Scope::Kind::IntrinsicModules
:
1212 return ProcedureDefinitionClass::External
;
1213 case Scope::Kind::Module
:
1214 return ProcedureDefinitionClass::Module
;
1215 case Scope::Kind::MainProgram
:
1216 case Scope::Kind::Subprogram
:
1217 return ProcedureDefinitionClass::Internal
;
1222 return ProcedureDefinitionClass::None
;
1225 // ComponentIterator implementation
1227 template <ComponentKind componentKind
>
1228 typename ComponentIterator
<componentKind
>::const_iterator
1229 ComponentIterator
<componentKind
>::const_iterator::Create(
1230 const DerivedTypeSpec
&derived
) {
1231 const_iterator it
{};
1232 it
.componentPath_
.emplace_back(derived
);
1233 it
.Increment(); // cue up first relevant component, if any
1237 template <ComponentKind componentKind
>
1238 const DerivedTypeSpec
*
1239 ComponentIterator
<componentKind
>::const_iterator::PlanComponentTraversal(
1240 const Symbol
&component
) const {
1241 if (const auto *details
{component
.detailsIf
<ObjectEntityDetails
>()}) {
1242 if (const DeclTypeSpec
* type
{details
->type()}) {
1243 if (const auto *derived
{type
->AsDerived()}) {
1244 bool traverse
{false};
1245 if constexpr (componentKind
== ComponentKind::Ordered
) {
1246 // Order Component (only visit parents)
1247 traverse
= component
.test(Symbol::Flag::ParentComp
);
1248 } else if constexpr (componentKind
== ComponentKind::Direct
) {
1249 traverse
= !IsAllocatableOrObjectPointer(&component
);
1250 } else if constexpr (componentKind
== ComponentKind::Ultimate
) {
1251 traverse
= !IsAllocatableOrObjectPointer(&component
);
1252 } else if constexpr (componentKind
== ComponentKind::Potential
) {
1253 traverse
= !IsPointer(component
);
1254 } else if constexpr (componentKind
== ComponentKind::Scope
) {
1255 traverse
= !IsAllocatableOrObjectPointer(&component
);
1256 } else if constexpr (componentKind
==
1257 ComponentKind::PotentialAndPointer
) {
1258 traverse
= !IsPointer(component
);
1261 const Symbol
&newTypeSymbol
{derived
->typeSymbol()};
1262 // Avoid infinite loop if the type is already part of the types
1263 // being visited. It is possible to have "loops in type" because
1264 // C744 does not forbid to use not yet declared type for
1265 // ALLOCATABLE or POINTER components.
1266 for (const auto &node
: componentPath_
) {
1267 if (&newTypeSymbol
== &node
.GetTypeSymbol()) {
1274 } // intrinsic & unlimited polymorphic not traversable
1279 template <ComponentKind componentKind
>
1280 static bool StopAtComponentPre(const Symbol
&component
) {
1281 if constexpr (componentKind
== ComponentKind::Ordered
) {
1282 // Parent components need to be iterated upon after their
1283 // sub-components in structure constructor analysis.
1284 return !component
.test(Symbol::Flag::ParentComp
);
1285 } else if constexpr (componentKind
== ComponentKind::Direct
) {
1287 } else if constexpr (componentKind
== ComponentKind::Ultimate
) {
1288 return component
.has
<ProcEntityDetails
>() ||
1289 IsAllocatableOrObjectPointer(&component
) ||
1290 (component
.has
<ObjectEntityDetails
>() &&
1291 component
.get
<ObjectEntityDetails
>().type() &&
1292 component
.get
<ObjectEntityDetails
>().type()->AsIntrinsic());
1293 } else if constexpr (componentKind
== ComponentKind::Potential
) {
1294 return !IsPointer(component
);
1295 } else if constexpr (componentKind
== ComponentKind::PotentialAndPointer
) {
1298 DIE("unexpected ComponentKind");
1302 template <ComponentKind componentKind
>
1303 static bool StopAtComponentPost(const Symbol
&component
) {
1304 return componentKind
== ComponentKind::Ordered
&&
1305 component
.test(Symbol::Flag::ParentComp
);
1308 template <ComponentKind componentKind
>
1309 void ComponentIterator
<componentKind
>::const_iterator::Increment() {
1310 while (!componentPath_
.empty()) {
1311 ComponentPathNode
&deepest
{componentPath_
.back()};
1312 if (deepest
.component()) {
1313 if (!deepest
.descended()) {
1314 deepest
.set_descended(true);
1315 if (const DerivedTypeSpec
*
1316 derived
{PlanComponentTraversal(*deepest
.component())}) {
1317 componentPath_
.emplace_back(*derived
);
1320 } else if (!deepest
.visited()) {
1321 deepest
.set_visited(true);
1322 return; // this is the next component to visit, after descending
1325 auto &nameIterator
{deepest
.nameIterator()};
1326 if (nameIterator
== deepest
.nameEnd()) {
1327 componentPath_
.pop_back();
1328 } else if constexpr (componentKind
== ComponentKind::Scope
) {
1329 deepest
.set_component(*nameIterator
++->second
);
1330 deepest
.set_descended(false);
1331 deepest
.set_visited(true);
1332 return; // this is the next component to visit, before descending
1334 const Scope
&scope
{deepest
.GetScope()};
1335 auto scopeIter
{scope
.find(*nameIterator
++)};
1336 if (scopeIter
!= scope
.cend()) {
1337 const Symbol
&component
{*scopeIter
->second
};
1338 deepest
.set_component(component
);
1339 deepest
.set_descended(false);
1340 if (StopAtComponentPre
<componentKind
>(component
)) {
1341 deepest
.set_visited(true);
1342 return; // this is the next component to visit, before descending
1344 deepest
.set_visited(!StopAtComponentPost
<componentKind
>(component
));
1351 template <ComponentKind componentKind
>
1353 ComponentIterator
<componentKind
>::const_iterator::BuildResultDesignatorName()
1355 std::string designator
;
1356 for (const auto &node
: componentPath_
) {
1357 designator
+= "%"s
+ DEREF(node
.component()).name().ToString();
1362 template class ComponentIterator
<ComponentKind::Ordered
>;
1363 template class ComponentIterator
<ComponentKind::Direct
>;
1364 template class ComponentIterator
<ComponentKind::Ultimate
>;
1365 template class ComponentIterator
<ComponentKind::Potential
>;
1366 template class ComponentIterator
<ComponentKind::Scope
>;
1367 template class ComponentIterator
<ComponentKind::PotentialAndPointer
>;
1369 UltimateComponentIterator::const_iterator
FindCoarrayUltimateComponent(
1370 const DerivedTypeSpec
&derived
) {
1371 UltimateComponentIterator ultimates
{derived
};
1372 return std::find_if(ultimates
.begin(), ultimates
.end(),
1373 [](const Symbol
&symbol
) { return evaluate::IsCoarray(symbol
); });
1376 UltimateComponentIterator::const_iterator
FindPointerUltimateComponent(
1377 const DerivedTypeSpec
&derived
) {
1378 UltimateComponentIterator ultimates
{derived
};
1379 return std::find_if(ultimates
.begin(), ultimates
.end(), IsPointer
);
1382 PotentialComponentIterator::const_iterator
FindEventOrLockPotentialComponent(
1383 const DerivedTypeSpec
&derived
) {
1384 PotentialComponentIterator potentials
{derived
};
1385 return std::find_if(
1386 potentials
.begin(), potentials
.end(), [](const Symbol
&component
) {
1387 if (const auto *details
{component
.detailsIf
<ObjectEntityDetails
>()}) {
1388 const DeclTypeSpec
*type
{details
->type()};
1389 return type
&& IsEventTypeOrLockType(type
->AsDerived());
1395 UltimateComponentIterator::const_iterator
FindAllocatableUltimateComponent(
1396 const DerivedTypeSpec
&derived
) {
1397 UltimateComponentIterator ultimates
{derived
};
1398 return std::find_if(ultimates
.begin(), ultimates
.end(), IsAllocatable
);
1401 DirectComponentIterator::const_iterator
FindAllocatableOrPointerDirectComponent(
1402 const DerivedTypeSpec
&derived
) {
1403 DirectComponentIterator directs
{derived
};
1404 return std::find_if(directs
.begin(), directs
.end(), IsAllocatableOrPointer
);
1407 PotentialComponentIterator::const_iterator
1408 FindPolymorphicAllocatablePotentialComponent(const DerivedTypeSpec
&derived
) {
1409 PotentialComponentIterator potentials
{derived
};
1410 return std::find_if(
1411 potentials
.begin(), potentials
.end(), IsPolymorphicAllocatable
);
1414 const Symbol
*FindUltimateComponent(const DerivedTypeSpec
&derived
,
1415 const std::function
<bool(const Symbol
&)> &predicate
) {
1416 UltimateComponentIterator ultimates
{derived
};
1417 if (auto it
{std::find_if(ultimates
.begin(), ultimates
.end(),
1418 [&predicate
](const Symbol
&component
) -> bool {
1419 return predicate(component
);
1426 const Symbol
*FindUltimateComponent(const Symbol
&symbol
,
1427 const std::function
<bool(const Symbol
&)> &predicate
) {
1428 if (predicate(symbol
)) {
1430 } else if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
1431 if (const auto *type
{object
->type()}) {
1432 if (const auto *derived
{type
->AsDerived()}) {
1433 return FindUltimateComponent(*derived
, predicate
);
1440 const Symbol
*FindImmediateComponent(const DerivedTypeSpec
&type
,
1441 const std::function
<bool(const Symbol
&)> &predicate
) {
1442 if (const Scope
* scope
{type
.scope()}) {
1443 const Symbol
*parent
{nullptr};
1444 for (const auto &pair
: *scope
) {
1445 const Symbol
*symbol
{&*pair
.second
};
1446 if (predicate(*symbol
)) {
1449 if (symbol
->test(Symbol::Flag::ParentComp
)) {
1454 if (const auto *object
{parent
->detailsIf
<ObjectEntityDetails
>()}) {
1455 if (const auto *type
{object
->type()}) {
1456 if (const auto *derived
{type
->AsDerived()}) {
1457 return FindImmediateComponent(*derived
, predicate
);
1466 const Symbol
*IsFunctionResultWithSameNameAsFunction(const Symbol
&symbol
) {
1467 if (IsFunctionResult(symbol
)) {
1468 if (const Symbol
* function
{symbol
.owner().symbol()}) {
1469 if (symbol
.name() == function
->name()) {
1473 // Check ENTRY result symbols too
1474 const Scope
&outer
{symbol
.owner().parent()};
1475 auto iter
{outer
.find(symbol
.name())};
1476 if (iter
!= outer
.end()) {
1477 const Symbol
&outerSym
{*iter
->second
};
1478 if (const auto *subp
{outerSym
.detailsIf
<SubprogramDetails
>()}) {
1479 if (subp
->entryScope() == &symbol
.owner() &&
1480 symbol
.name() == outerSym
.name()) {
1489 void LabelEnforce::Post(const parser::GotoStmt
&gotoStmt
) {
1490 CheckLabelUse(gotoStmt
.v
);
1492 void LabelEnforce::Post(const parser::ComputedGotoStmt
&computedGotoStmt
) {
1493 for (auto &i
: std::get
<std::list
<parser::Label
>>(computedGotoStmt
.t
)) {
1498 void LabelEnforce::Post(const parser::ArithmeticIfStmt
&arithmeticIfStmt
) {
1499 CheckLabelUse(std::get
<1>(arithmeticIfStmt
.t
));
1500 CheckLabelUse(std::get
<2>(arithmeticIfStmt
.t
));
1501 CheckLabelUse(std::get
<3>(arithmeticIfStmt
.t
));
1504 void LabelEnforce::Post(const parser::AssignStmt
&assignStmt
) {
1505 CheckLabelUse(std::get
<parser::Label
>(assignStmt
.t
));
1508 void LabelEnforce::Post(const parser::AssignedGotoStmt
&assignedGotoStmt
) {
1509 for (auto &i
: std::get
<std::list
<parser::Label
>>(assignedGotoStmt
.t
)) {
1514 void LabelEnforce::Post(const parser::AltReturnSpec
&altReturnSpec
) {
1515 CheckLabelUse(altReturnSpec
.v
);
1518 void LabelEnforce::Post(const parser::ErrLabel
&errLabel
) {
1519 CheckLabelUse(errLabel
.v
);
1521 void LabelEnforce::Post(const parser::EndLabel
&endLabel
) {
1522 CheckLabelUse(endLabel
.v
);
1524 void LabelEnforce::Post(const parser::EorLabel
&eorLabel
) {
1525 CheckLabelUse(eorLabel
.v
);
1528 void LabelEnforce::CheckLabelUse(const parser::Label
&labelUsed
) {
1529 if (labels_
.find(labelUsed
) == labels_
.end()) {
1530 SayWithConstruct(context_
, currentStatementSourcePosition_
,
1531 parser::MessageFormattedText
{
1532 "Control flow escapes from %s"_err_en_US
, construct_
},
1533 constructSourcePosition_
);
1537 parser::MessageFormattedText
LabelEnforce::GetEnclosingConstructMsg() {
1538 return {"Enclosing %s statement"_en_US
, construct_
};
1541 void LabelEnforce::SayWithConstruct(SemanticsContext
&context
,
1542 parser::CharBlock stmtLocation
, parser::MessageFormattedText
&&message
,
1543 parser::CharBlock constructLocation
) {
1544 context
.Say(stmtLocation
, message
)
1545 .Attach(constructLocation
, GetEnclosingConstructMsg());
1548 bool HasAlternateReturns(const Symbol
&subprogram
) {
1549 for (const auto *dummyArg
: subprogram
.get
<SubprogramDetails
>().dummyArgs()) {
1557 bool IsAutomaticallyDestroyed(const Symbol
&symbol
) {
1558 return symbol
.has
<ObjectEntityDetails
>() &&
1559 (symbol
.owner().kind() == Scope::Kind::Subprogram
||
1560 symbol
.owner().kind() == Scope::Kind::BlockConstruct
) &&
1561 !IsNamedConstant(symbol
) && (!IsDummy(symbol
) || IsIntentOut(symbol
)) &&
1562 !IsPointer(symbol
) && !IsSaved(symbol
) &&
1563 !FindCommonBlockContaining(symbol
);
1566 const std::optional
<parser::Name
> &MaybeGetNodeName(
1567 const ConstructNode
&construct
) {
1568 return common::visit(
1570 [&](const parser::BlockConstruct
*blockConstruct
)
1571 -> const std::optional
<parser::Name
> & {
1572 return std::get
<0>(blockConstruct
->t
).statement
.v
;
1574 [&](const auto *a
) -> const std::optional
<parser::Name
> & {
1575 return std::get
<0>(std::get
<0>(a
->t
).statement
.t
);
1581 std::optional
<ArraySpec
> ToArraySpec(
1582 evaluate::FoldingContext
&context
, const evaluate::Shape
&shape
) {
1583 if (auto extents
{evaluate::AsConstantExtents(context
, shape
)}) {
1585 for (const auto &extent
: *extents
) {
1586 result
.emplace_back(ShapeSpec::MakeExplicit(Bound
{extent
}));
1588 return {std::move(result
)};
1590 return std::nullopt
;
1594 std::optional
<ArraySpec
> ToArraySpec(evaluate::FoldingContext
&context
,
1595 const std::optional
<evaluate::Shape
> &shape
) {
1596 return shape
? ToArraySpec(context
, *shape
) : std::nullopt
;
1599 static const DeclTypeSpec
*GetDtvArgTypeSpec(const Symbol
&proc
) {
1600 if (const auto *subp
{proc
.detailsIf
<SubprogramDetails
>()};
1601 subp
&& !subp
->dummyArgs().empty()) {
1602 if (const auto *arg
{subp
->dummyArgs()[0]}) {
1603 return arg
->GetType();
1609 const DerivedTypeSpec
*GetDtvArgDerivedType(const Symbol
&proc
) {
1610 if (const auto *type
{GetDtvArgTypeSpec(proc
)}) {
1611 return type
->AsDerived();
1617 bool HasDefinedIo(common::DefinedIo which
, const DerivedTypeSpec
&derived
,
1618 const Scope
*scope
) {
1619 if (const Scope
* dtScope
{derived
.scope()}) {
1620 for (const auto &pair
: *dtScope
) {
1621 const Symbol
&symbol
{*pair
.second
};
1622 if (const auto *generic
{symbol
.detailsIf
<GenericDetails
>()}) {
1623 GenericKind kind
{generic
->kind()};
1624 if (const auto *io
{std::get_if
<common::DefinedIo
>(&kind
.u
)}) {
1626 return true; // type-bound GENERIC exists
1633 SourceName name
{GenericKind::AsFortran(which
)};
1634 evaluate::DynamicType dyDerived
{derived
};
1635 for (; scope
&& !scope
->IsGlobal(); scope
= &scope
->parent()) {
1636 auto iter
{scope
->find(name
)};
1637 if (iter
!= scope
->end()) {
1638 const auto &generic
{iter
->second
->GetUltimate().get
<GenericDetails
>()};
1639 for (auto ref
: generic
.specificProcs()) {
1640 const Symbol
&procSym
{ref
->GetUltimate()};
1641 if (const DeclTypeSpec
* dtSpec
{GetDtvArgTypeSpec(procSym
)}) {
1642 if (auto dyDummy
{evaluate::DynamicType::From(*dtSpec
)}) {
1643 if (dyDummy
->IsTkCompatibleWith(dyDerived
)) {
1644 return true; // GENERIC or INTERFACE not in type
1652 // Check for inherited defined I/O
1653 const auto *parentType
{derived
.typeSymbol().GetParentTypeSpec()};
1654 return parentType
&& HasDefinedIo(which
, *parentType
, scope
);
1657 template <typename E
>
1658 std::forward_list
<std::string
> GetOperatorNames(
1659 const SemanticsContext
&context
, E opr
) {
1660 std::forward_list
<std::string
> result
;
1661 for (const char *name
: context
.languageFeatures().GetNames(opr
)) {
1662 result
.emplace_front("operator("s
+ name
+ ')');
1667 std::forward_list
<std::string
> GetAllNames(
1668 const SemanticsContext
&context
, const SourceName
&name
) {
1669 std::string str
{name
.ToString()};
1670 if (!name
.empty() && name
.end()[-1] == ')' &&
1671 name
.ToString().rfind("operator(", 0) == 0) {
1672 for (int i
{0}; i
!= common::LogicalOperator_enumSize
; ++i
) {
1673 auto names
{GetOperatorNames(context
, common::LogicalOperator
{i
})};
1674 if (llvm::is_contained(names
, str
)) {
1678 for (int i
{0}; i
!= common::RelationalOperator_enumSize
; ++i
) {
1679 auto names
{GetOperatorNames(context
, common::RelationalOperator
{i
})};
1680 if (llvm::is_contained(names
, str
)) {
1688 void WarnOnDeferredLengthCharacterScalar(SemanticsContext
&context
,
1689 const SomeExpr
*expr
, parser::CharBlock at
, const char *what
) {
1690 if (context
.languageFeatures().ShouldWarn(
1691 common::UsageWarning::F202XAllocatableBreakingChange
)) {
1693 symbol
{evaluate::UnwrapWholeSymbolOrComponentDataRef(expr
)}) {
1694 const Symbol
&ultimate
{ResolveAssociations(*symbol
)};
1695 if (const DeclTypeSpec
* type
{ultimate
.GetType()}; type
&&
1696 type
->category() == DeclTypeSpec::Category::Character
&&
1697 type
->characterTypeSpec().length().isDeferred() &&
1698 IsAllocatable(ultimate
) && ultimate
.Rank() == 0) {
1700 "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
,
1701 symbol
->name(), what
);
1707 bool CouldBeDataPointerValuedFunction(const Symbol
*original
) {
1709 const Symbol
&ultimate
{original
->GetUltimate()};
1710 if (const Symbol
* result
{FindFunctionResult(ultimate
)}) {
1711 return IsPointer(*result
) && !IsProcedure(*result
);
1713 if (const auto *generic
{ultimate
.detailsIf
<GenericDetails
>()}) {
1714 for (const SymbolRef
&ref
: generic
->specificProcs()) {
1715 if (CouldBeDataPointerValuedFunction(&*ref
)) {
1724 std::string
GetModuleOrSubmoduleName(const Symbol
&symbol
) {
1725 const auto &details
{symbol
.get
<ModuleDetails
>()};
1726 std::string result
{symbol
.name().ToString()};
1727 if (details
.ancestor() && details
.ancestor()->symbol()) {
1728 result
= details
.ancestor()->symbol()->name().ToString() + ':' + result
;
1733 std::string
GetCommonBlockObjectName(const Symbol
&common
, bool underscoring
) {
1734 if (const std::string
* bind
{common
.GetBindName()}) {
1737 if (common
.name().empty()) {
1738 return Fortran::common::blankCommonObjectName
;
1740 return underscoring
? common
.name().ToString() + "_"s
1741 : common
.name().ToString();
1745 SemanticsContext
&context
, SourceName at
, const Symbol
*symbol
) {
1746 if (const auto *details
{
1747 symbol
? symbol
->detailsIf
<UseErrorDetails
>() : nullptr}) {
1748 auto &msg
{context
.Say(
1749 at
, "Reference to '%s' is ambiguous"_err_en_US
, symbol
->name())};
1750 for (const auto &[location
, module
] : details
->occurrences()) {
1751 msg
.Attach(location
, "'%s' was use-associated from module '%s'"_en_US
, at
,
1752 module
->GetName().value());
1754 context
.SetError(*symbol
);
1761 } // namespace Fortran::semantics