1 //===-- include/flang/Semantics/tools.h -------------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef FORTRAN_SEMANTICS_TOOLS_H_
10 #define FORTRAN_SEMANTICS_TOOLS_H_
11 
12 // Simple predicates and look-up functions that are best defined
13 // canonically for use in semantic checking.
14 
15 #include "flang/Common/Fortran.h"
16 #include "flang/Evaluate/expression.h"
17 #include "flang/Evaluate/shape.h"
18 #include "flang/Evaluate/type.h"
19 #include "flang/Evaluate/variable.h"
20 #include "flang/Parser/message.h"
21 #include "flang/Parser/parse-tree.h"
22 #include "flang/Semantics/attr.h"
23 #include "flang/Semantics/expression.h"
24 #include "flang/Semantics/semantics.h"
25 #include <functional>
26 
27 namespace Fortran::semantics {
28 
29 class DeclTypeSpec;
30 class DerivedTypeSpec;
31 class Scope;
32 class Symbol;
33 
34 // Note: Here ProgramUnit includes internal subprograms while TopLevelUnit
35 // does not. "program-unit" in the Fortran standard matches TopLevelUnit.
36 const Scope &GetTopLevelUnitContaining(const Scope &);
37 const Scope &GetTopLevelUnitContaining(const Symbol &);
38 const Scope &GetProgramUnitContaining(const Scope &);
39 const Scope &GetProgramUnitContaining(const Symbol &);
40 
41 const Scope *FindModuleContaining(const Scope &);
42 const Scope *FindModuleFileContaining(const Scope &);
43 const Scope *FindPureProcedureContaining(const Scope &);
44 const Scope *FindPureProcedureContaining(const Symbol &);
45 const Symbol *FindPointerComponent(const Scope &);
46 const Symbol *FindPointerComponent(const DerivedTypeSpec &);
47 const Symbol *FindPointerComponent(const DeclTypeSpec &);
48 const Symbol *FindPointerComponent(const Symbol &);
49 const Symbol *FindInterface(const Symbol &);
50 const Symbol *FindSubprogram(const Symbol &);
51 const Symbol *FindFunctionResult(const Symbol &);
52 const Symbol *FindOverriddenBinding(const Symbol &);
53 
54 const DeclTypeSpec *FindParentTypeSpec(const DerivedTypeSpec &);
55 const DeclTypeSpec *FindParentTypeSpec(const DeclTypeSpec &);
56 const DeclTypeSpec *FindParentTypeSpec(const Scope &);
57 const DeclTypeSpec *FindParentTypeSpec(const Symbol &);
58 
59 enum class Tristate { No, Yes, Maybe };
ToTristate(bool x)60 inline Tristate ToTristate(bool x) { return x ? Tristate::Yes : Tristate::No; }
61 
62 // Is this a user-defined assignment? If both sides are the same derived type
63 // (and the ranks are okay) the answer is Maybe.
64 Tristate IsDefinedAssignment(
65     const std::optional<evaluate::DynamicType> &lhsType, int lhsRank,
66     const std::optional<evaluate::DynamicType> &rhsType, int rhsRank);
67 // Test for intrinsic unary and binary operators based on types and ranks
68 bool IsIntrinsicRelational(common::RelationalOperator,
69     const evaluate::DynamicType &, int, const evaluate::DynamicType &, int);
70 bool IsIntrinsicNumeric(const evaluate::DynamicType &);
71 bool IsIntrinsicNumeric(
72     const evaluate::DynamicType &, int, const evaluate::DynamicType &, int);
73 bool IsIntrinsicLogical(const evaluate::DynamicType &);
74 bool IsIntrinsicLogical(
75     const evaluate::DynamicType &, int, const evaluate::DynamicType &, int);
76 bool IsIntrinsicConcat(
77     const evaluate::DynamicType &, int, const evaluate::DynamicType &, int);
78 
79 bool IsGenericDefinedOp(const Symbol &);
80 bool IsDefinedOperator(SourceName);
81 std::string MakeOpName(SourceName);
82 bool DoesScopeContain(const Scope *maybeAncestor, const Scope &maybeDescendent);
83 bool DoesScopeContain(const Scope *, const Symbol &);
84 bool IsUseAssociated(const Symbol &, const Scope &);
85 bool IsHostAssociated(const Symbol &, const Scope &);
IsStmtFunction(const Symbol & symbol)86 inline bool IsStmtFunction(const Symbol &symbol) {
87   const auto *subprogram{symbol.detailsIf<SubprogramDetails>()};
88   return subprogram && subprogram->stmtFunction();
89 }
90 bool IsInStmtFunction(const Symbol &);
91 bool IsStmtFunctionDummy(const Symbol &);
92 bool IsStmtFunctionResult(const Symbol &);
93 bool IsPointerDummy(const Symbol &);
94 bool IsBindCProcedure(const Symbol &);
95 bool IsBindCProcedure(const Scope &);
96 bool IsProcName(const Symbol &); // proc-name
97 bool IsFunctionResultWithSameNameAsFunction(const Symbol &);
98 bool IsExtensibleType(const DerivedTypeSpec *);
99 bool IsBuiltinDerivedType(const DerivedTypeSpec *derived, const char *name);
100 // Is this derived type TEAM_TYPE from module ISO_FORTRAN_ENV
101 bool IsTeamType(const DerivedTypeSpec *);
102 // Is this derived type either C_PTR or C_FUNPTR from module ISO_C_BINDING
103 bool IsIsoCType(const DerivedTypeSpec *);
104 bool IsEventTypeOrLockType(const DerivedTypeSpec *);
105 bool IsOrContainsEventOrLockComponent(const Symbol &);
106 bool CanBeTypeBoundProc(const Symbol *);
107 // Does a non-PARAMETER symbol have explicit initialization with =value or
108 // =>target in its declaration, or optionally in a DATA statement? (Being
109 // ALLOCATABLE or having a derived type with default component initialization
110 // doesn't count; it must be a variable initialization that implies the SAVE
111 // attribute, or a derived type component default value.)
112 bool IsStaticallyInitialized(const Symbol &, bool ignoreDATAstatements = false);
113 // Is the symbol explicitly or implicitly initialized in any way?
114 bool IsInitialized(const Symbol &, bool ignoreDATAstatements = false,
115     const Symbol *derivedType = nullptr);
116 // Is the symbol a component subject to deallocation or finalization?
117 bool IsDestructible(const Symbol &, const Symbol *derivedType = nullptr);
118 bool HasIntrinsicTypeName(const Symbol &);
119 bool IsSeparateModuleProcedureInterface(const Symbol *);
120 bool IsAutomatic(const Symbol &);
121 bool HasAlternateReturns(const Symbol &);
122 bool InCommonBlock(const Symbol &);
123 
124 // Return an ultimate component of type that matches predicate, or nullptr.
125 const Symbol *FindUltimateComponent(const DerivedTypeSpec &type,
126     const std::function<bool(const Symbol &)> &predicate);
127 const Symbol *FindUltimateComponent(
128     const Symbol &symbol, const std::function<bool(const Symbol &)> &predicate);
129 
130 // Returns an immediate component of type that matches predicate, or nullptr.
131 // An immediate component of a type is one declared for that type or is an
132 // immediate component of the type that it extends.
133 const Symbol *FindImmediateComponent(
134     const DerivedTypeSpec &, const std::function<bool(const Symbol &)> &);
135 
IsPointer(const Symbol & symbol)136 inline bool IsPointer(const Symbol &symbol) {
137   return symbol.attrs().test(Attr::POINTER);
138 }
IsAllocatable(const Symbol & symbol)139 inline bool IsAllocatable(const Symbol &symbol) {
140   return symbol.attrs().test(Attr::ALLOCATABLE);
141 }
IsAllocatableOrPointer(const Symbol & symbol)142 inline bool IsAllocatableOrPointer(const Symbol &symbol) {
143   return IsPointer(symbol) || IsAllocatable(symbol);
144 }
IsSave(const Symbol & symbol)145 inline bool IsSave(const Symbol &symbol) {
146   return symbol.attrs().test(Attr::SAVE);
147 }
IsNamedConstant(const Symbol & symbol)148 inline bool IsNamedConstant(const Symbol &symbol) {
149   return symbol.attrs().test(Attr::PARAMETER);
150 }
IsOptional(const Symbol & symbol)151 inline bool IsOptional(const Symbol &symbol) {
152   return symbol.attrs().test(Attr::OPTIONAL);
153 }
IsIntentIn(const Symbol & symbol)154 inline bool IsIntentIn(const Symbol &symbol) {
155   return symbol.attrs().test(Attr::INTENT_IN);
156 }
IsIntentInOut(const Symbol & symbol)157 inline bool IsIntentInOut(const Symbol &symbol) {
158   return symbol.attrs().test(Attr::INTENT_INOUT);
159 }
IsIntentOut(const Symbol & symbol)160 inline bool IsIntentOut(const Symbol &symbol) {
161   return symbol.attrs().test(Attr::INTENT_OUT);
162 }
IsProtected(const Symbol & symbol)163 inline bool IsProtected(const Symbol &symbol) {
164   return symbol.attrs().test(Attr::PROTECTED);
165 }
IsImpliedDoIndex(const Symbol & symbol)166 inline bool IsImpliedDoIndex(const Symbol &symbol) {
167   return symbol.owner().kind() == Scope::Kind::ImpliedDos;
168 }
169 bool IsFinalizable(const Symbol &);
170 bool IsFinalizable(const DerivedTypeSpec &);
171 bool HasImpureFinal(const DerivedTypeSpec &);
172 bool IsCoarray(const Symbol &);
173 bool IsInBlankCommon(const Symbol &);
174 bool IsAutomaticObject(const Symbol &);
IsAssumedSizeArray(const Symbol & symbol)175 inline bool IsAssumedSizeArray(const Symbol &symbol) {
176   const auto *details{symbol.detailsIf<ObjectEntityDetails>()};
177   return details && details->IsAssumedSize();
178 }
IsAssumedRankArray(const Symbol & symbol)179 inline bool IsAssumedRankArray(const Symbol &symbol) {
180   const auto *details{symbol.detailsIf<ObjectEntityDetails>()};
181   return details && details->IsAssumedRank();
182 }
183 bool IsAssumedLengthCharacter(const Symbol &);
184 bool IsExternal(const Symbol &);
185 bool IsModuleProcedure(const Symbol &);
186 // Is the symbol modifiable in this scope
187 std::optional<parser::MessageFixedText> WhyNotModifiable(
188     const Symbol &, const Scope &);
189 std::optional<parser::Message> WhyNotModifiable(SourceName, const SomeExpr &,
190     const Scope &, bool vectorSubscriptIsOk = false);
191 const Symbol *IsExternalInPureContext(const Symbol &, const Scope &);
192 bool HasCoarray(const parser::Expr &);
193 bool IsPolymorphicAllocatable(const Symbol &);
194 // Return an error if component symbol is not accessible from scope (7.5.4.8(2))
195 std::optional<parser::MessageFormattedText> CheckAccessibleComponent(
196     const semantics::Scope &, const Symbol &);
197 
198 // Analysis of image control statements
199 bool IsImageControlStmt(const parser::ExecutableConstruct &);
200 // Get the location of the image control statement in this ExecutableConstruct
201 parser::CharBlock GetImageControlStmtLocation(
202     const parser::ExecutableConstruct &);
203 // Image control statements that reference coarrays need an extra message
204 // to clarify why they're image control statements.  This function returns
205 // std::nullopt for ExecutableConstructs that do not require an extra message.
206 std::optional<parser::MessageFixedText> GetImageControlStmtCoarrayMsg(
207     const parser::ExecutableConstruct &);
208 
209 // Returns the complete list of derived type parameter symbols in
210 // the order in which their declarations appear in the derived type
211 // definitions (parents first).
212 SymbolVector OrderParameterDeclarations(const Symbol &);
213 // Returns the complete list of derived type parameter names in the
214 // order defined by 7.5.3.2.
215 std::list<SourceName> OrderParameterNames(const Symbol &);
216 
217 // Return an existing or new derived type instance
218 const DeclTypeSpec &FindOrInstantiateDerivedType(Scope &, DerivedTypeSpec &&,
219     DeclTypeSpec::Category = DeclTypeSpec::TypeDerived);
220 
221 // When a subprogram defined in a submodule defines a separate module
222 // procedure whose interface is defined in an ancestor (sub)module,
223 // returns a pointer to that interface, else null.
224 const Symbol *FindSeparateModuleSubprogramInterface(const Symbol *);
225 
226 // Determines whether an object might be visible outside a
227 // pure function (C1594); returns a non-null Symbol pointer for
228 // diagnostic purposes if so.
229 const Symbol *FindExternallyVisibleObject(const Symbol &, const Scope &);
230 
231 template <typename A>
FindExternallyVisibleObject(const A &,const Scope &)232 const Symbol *FindExternallyVisibleObject(const A &, const Scope &) {
233   return nullptr; // default base case
234 }
235 
236 template <typename T>
FindExternallyVisibleObject(const evaluate::Designator<T> & designator,const Scope & scope)237 const Symbol *FindExternallyVisibleObject(
238     const evaluate::Designator<T> &designator, const Scope &scope) {
239   if (const Symbol * symbol{designator.GetBaseObject().symbol()}) {
240     return FindExternallyVisibleObject(*symbol, scope);
241   } else if (std::holds_alternative<evaluate::CoarrayRef>(designator.u)) {
242     // Coindexed values are visible even if their image-local objects are not.
243     return designator.GetBaseObject().symbol();
244   } else {
245     return nullptr;
246   }
247 }
248 
249 template <typename T>
FindExternallyVisibleObject(const evaluate::Expr<T> & expr,const Scope & scope)250 const Symbol *FindExternallyVisibleObject(
251     const evaluate::Expr<T> &expr, const Scope &scope) {
252   return std::visit(
253       [&](const auto &x) { return FindExternallyVisibleObject(x, scope); },
254       expr.u);
255 }
256 
257 // Apply GetUltimate(), then if the symbol is a generic procedure shadowing a
258 // specific procedure of the same name, return it instead.
259 const Symbol &BypassGeneric(const Symbol &);
260 
261 using SomeExpr = evaluate::Expr<evaluate::SomeType>;
262 
263 bool ExprHasTypeCategory(
264     const SomeExpr &expr, const common::TypeCategory &type);
265 bool ExprTypeKindIsDefault(
266     const SomeExpr &expr, const SemanticsContext &context);
267 
268 struct GetExprHelper {
269   // Specializations for parse tree nodes that have a typedExpr member.
270   static const SomeExpr *Get(const parser::Expr &);
271   static const SomeExpr *Get(const parser::Variable &);
272   static const SomeExpr *Get(const parser::DataStmtConstant &);
273   static const SomeExpr *Get(const parser::AllocateObject &);
274   static const SomeExpr *Get(const parser::PointerObject &);
275 
276   template <typename T>
GetGetExprHelper277   static const SomeExpr *Get(const common::Indirection<T> &x) {
278     return Get(x.value());
279   }
GetGetExprHelper280   template <typename T> static const SomeExpr *Get(const std::optional<T> &x) {
281     return x ? Get(*x) : nullptr;
282   }
GetGetExprHelper283   template <typename T> static const SomeExpr *Get(const T &x) {
284     static_assert(
285         !parser::HasTypedExpr<T>::value, "explicit Get overload must be added");
286     if constexpr (ConstraintTrait<T>) {
287       return Get(x.thing);
288     } else if constexpr (WrapperTrait<T>) {
289       return Get(x.v);
290     } else {
291       return nullptr;
292     }
293   }
294 };
295 
GetExpr(const T & x)296 template <typename T> const SomeExpr *GetExpr(const T &x) {
297   return GetExprHelper{}.Get(x);
298 }
299 
300 const evaluate::Assignment *GetAssignment(const parser::AssignmentStmt &);
301 const evaluate::Assignment *GetAssignment(
302     const parser::PointerAssignmentStmt &);
303 
GetIntValue(const T & x)304 template <typename T> std::optional<std::int64_t> GetIntValue(const T &x) {
305   if (const auto *expr{GetExpr(x)}) {
306     return evaluate::ToInt64(*expr);
307   } else {
308     return std::nullopt;
309   }
310 }
311 
IsZero(const T & expr)312 template <typename T> bool IsZero(const T &expr) {
313   auto value{GetIntValue(expr)};
314   return value && *value == 0;
315 }
316 
317 // 15.2.2
318 enum class ProcedureDefinitionClass {
319   None,
320   Intrinsic,
321   External,
322   Internal,
323   Module,
324   Dummy,
325   Pointer,
326   StatementFunction
327 };
328 
329 ProcedureDefinitionClass ClassifyProcedure(const Symbol &);
330 
331 // Derived type component iterator that provides a C++ LegacyForwardIterator
332 // iterator over the Ordered, Direct, Ultimate or Potential components of a
333 // DerivedTypeSpec. These iterators can be used with STL algorithms
334 // accepting LegacyForwardIterator.
335 // The kind of component is a template argument of the iterator factory
336 // ComponentIterator.
337 //
338 // - Ordered components are the components from the component order defined
339 // in 7.5.4.7, except that the parent component IS added between the parent
340 // component order and the components in order of declaration.
341 // This "deviation" is important for structure-constructor analysis.
342 // For this kind of iterator, the component tree is recursively visited in the
343 // following order:
344 //  - first, the Ordered components of the parent type (if relevant)
345 //  - then, the parent component (if relevant, different from 7.5.4.7!)
346 //  - then, the components in declaration order (without visiting subcomponents)
347 //
348 // - Ultimate, Direct and Potential components are as defined in 7.5.1.
349 //   - Ultimate components of a derived type are the closure of its components
350 //     of intrinsic type, its ALLOCATABLE or POINTER components, and the
351 //     ultimate components of its non-ALLOCATABLE non-POINTER derived type
352 //     components.  (No ultimate component has a derived type unless it is
353 //     ALLOCATABLE or POINTER.)
354 //   - Direct components of a derived type are all of its components, and all
355 //     of the direct components of its non-ALLOCATABLE non-POINTER derived type
356 //     components.  (Direct components are always present.)
357 //   - Potential subobject components of a derived type are the closure of
358 //     its non-POINTER components and the potential subobject components of
359 //     its non-POINTER derived type components.  (The lifetime of each
360 //     potential subobject component is that of the entire instance.)
361 // Parent and procedure components are considered against these definitions.
362 // For this kind of iterator, the component tree is recursively visited in the
363 // following order:
364 //  - the parent component first (if relevant)
365 //  - then, the components of the parent type (if relevant)
366 //      + visiting the component and then, if it is derived type data component,
367 //        visiting the subcomponents before visiting the next
368 //        component in declaration order.
369 //  - then, components in declaration order, similarly to components of parent
370 //    type.
371 //  Here, the parent component is visited first so that search for a component
372 //  verifying a property will never descend into a component that already
373 //  verifies the property (this helps giving clearer feedback).
374 //
375 // ComponentIterator::const_iterator remain valid during the whole lifetime of
376 // the DerivedTypeSpec passed by reference to the ComponentIterator factory.
377 // Their validity is independent of the ComponentIterator factory lifetime.
378 //
379 // For safety and simplicity, the iterators are read only and can only be
380 // incremented. This could be changed if desired.
381 //
382 // Note that iterators are made in such a way that one can easily test and build
383 // info message in the following way:
384 //    ComponentIterator<ComponentKind::...> comp{derived}
385 //    if (auto it{std::find_if(comp.begin(), comp.end(), predicate)}) {
386 //       msg = it.BuildResultDesignatorName() + " verifies predicates";
387 //       const Symbol *component{*it};
388 //       ....
389 //    }
390 
ENUM_CLASS(ComponentKind,Ordered,Direct,Ultimate,Potential,Scope)391 ENUM_CLASS(ComponentKind, Ordered, Direct, Ultimate, Potential, Scope)
392 
393 template <ComponentKind componentKind> class ComponentIterator {
394 public:
395   ComponentIterator(const DerivedTypeSpec &derived) : derived_{derived} {}
396   class const_iterator {
397   public:
398     using iterator_category = std::forward_iterator_tag;
399     using value_type = SymbolRef;
400     using difference_type = void;
401     using pointer = const Symbol *;
402     using reference = const Symbol &;
403 
404     static const_iterator Create(const DerivedTypeSpec &);
405 
406     const_iterator &operator++() {
407       Increment();
408       return *this;
409     }
410     const_iterator operator++(int) {
411       const_iterator tmp(*this);
412       Increment();
413       return tmp;
414     }
415     reference operator*() const {
416       CHECK(!componentPath_.empty());
417       return DEREF(componentPath_.back().component());
418     }
419     pointer operator->() const { return &**this; }
420 
421     bool operator==(const const_iterator &other) const {
422       return componentPath_ == other.componentPath_;
423     }
424     bool operator!=(const const_iterator &other) const {
425       return !(*this == other);
426     }
427 
428     // bool() operator indicates if the iterator can be dereferenced without
429     // having to check against an end() iterator.
430     explicit operator bool() const { return !componentPath_.empty(); }
431 
432     // Builds a designator name of the referenced component for messages.
433     // The designator helps when the component referred to by the iterator
434     // may be "buried" into other components. This gives the full
435     // path inside the iterated derived type: e.g "%a%b%c%ultimate"
436     // when it->name() only gives "ultimate". Parent components are
437     // part of the path for clarity, even though they could be
438     // skipped.
439     std::string BuildResultDesignatorName() const;
440 
441   private:
442     using name_iterator =
443         std::conditional_t<componentKind == ComponentKind::Scope,
444             typename Scope::const_iterator,
445             typename std::list<SourceName>::const_iterator>;
446 
447     class ComponentPathNode {
448     public:
449       explicit ComponentPathNode(const DerivedTypeSpec &derived)
450           : derived_{derived} {
451         if constexpr (componentKind == ComponentKind::Scope) {
452           const Scope &scope{DEREF(derived.scope())};
453           nameIterator_ = scope.cbegin();
454           nameEnd_ = scope.cend();
455         } else {
456           const std::list<SourceName> &nameList{
457               derived.typeSymbol().get<DerivedTypeDetails>().componentNames()};
458           nameIterator_ = nameList.cbegin();
459           nameEnd_ = nameList.cend();
460         }
461       }
462       const Symbol *component() const { return component_; }
463       void set_component(const Symbol &component) { component_ = &component; }
464       bool visited() const { return visited_; }
465       void set_visited(bool yes) { visited_ = yes; }
466       bool descended() const { return descended_; }
467       void set_descended(bool yes) { descended_ = yes; }
468       name_iterator &nameIterator() { return nameIterator_; }
469       name_iterator nameEnd() { return nameEnd_; }
470       const Symbol &GetTypeSymbol() const { return derived_->typeSymbol(); }
471       const Scope &GetScope() const {
472         return derived_->scope() ? *derived_->scope()
473                                  : DEREF(GetTypeSymbol().scope());
474       }
475       bool operator==(const ComponentPathNode &that) const {
476         return &*derived_ == &*that.derived_ &&
477             nameIterator_ == that.nameIterator_ &&
478             component_ == that.component_;
479       }
480 
481     private:
482       common::Reference<const DerivedTypeSpec> derived_;
483       name_iterator nameEnd_;
484       name_iterator nameIterator_;
485       const Symbol *component_{nullptr}; // until Increment()
486       bool visited_{false};
487       bool descended_{false};
488     };
489 
490     const DerivedTypeSpec *PlanComponentTraversal(
491         const Symbol &component) const;
492     // Advances to the next relevant symbol, if any.  Afterwards, the
493     // iterator will either be at its end or contain no null component().
494     void Increment();
495 
496     std::vector<ComponentPathNode> componentPath_;
497   };
498 
499   const_iterator begin() { return cbegin(); }
500   const_iterator end() { return cend(); }
501   const_iterator cbegin() { return const_iterator::Create(derived_); }
502   const_iterator cend() { return const_iterator{}; }
503 
504 private:
505   const DerivedTypeSpec &derived_;
506 };
507 
508 extern template class ComponentIterator<ComponentKind::Ordered>;
509 extern template class ComponentIterator<ComponentKind::Direct>;
510 extern template class ComponentIterator<ComponentKind::Ultimate>;
511 extern template class ComponentIterator<ComponentKind::Potential>;
512 extern template class ComponentIterator<ComponentKind::Scope>;
513 using OrderedComponentIterator = ComponentIterator<ComponentKind::Ordered>;
514 using DirectComponentIterator = ComponentIterator<ComponentKind::Direct>;
515 using UltimateComponentIterator = ComponentIterator<ComponentKind::Ultimate>;
516 using PotentialComponentIterator = ComponentIterator<ComponentKind::Potential>;
517 using ScopeComponentIterator = ComponentIterator<ComponentKind::Scope>;
518 
519 // Common component searches, the iterator returned is referring to the first
520 // component, according to the order defined for the related ComponentIterator,
521 // that verifies the property from the name.
522 // If no component verifies the property, an end iterator (casting to false)
523 // is returned. Otherwise, the returned iterator casts to true and can be
524 // dereferenced.
525 PotentialComponentIterator::const_iterator FindEventOrLockPotentialComponent(
526     const DerivedTypeSpec &);
527 UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent(
528     const DerivedTypeSpec &);
529 UltimateComponentIterator::const_iterator FindPointerUltimateComponent(
530     const DerivedTypeSpec &);
531 UltimateComponentIterator::const_iterator FindAllocatableUltimateComponent(
532     const DerivedTypeSpec &);
533 UltimateComponentIterator::const_iterator
534 FindPolymorphicAllocatableUltimateComponent(const DerivedTypeSpec &);
535 UltimateComponentIterator::const_iterator
536 FindPolymorphicAllocatableNonCoarrayUltimateComponent(const DerivedTypeSpec &);
537 
538 // The LabelEnforce class (given a set of labels) provides an error message if
539 // there is a branch to a label which is not in the given set.
540 class LabelEnforce {
541 public:
LabelEnforce(SemanticsContext & context,std::set<parser::Label> && labels,parser::CharBlock constructSourcePosition,const char * construct)542   LabelEnforce(SemanticsContext &context, std::set<parser::Label> &&labels,
543       parser::CharBlock constructSourcePosition, const char *construct)
544       : context_{context}, labels_{labels},
545         constructSourcePosition_{constructSourcePosition}, construct_{
546                                                                construct} {}
Pre(const T &)547   template <typename T> bool Pre(const T &) { return true; }
Pre(const parser::Statement<T> & statement)548   template <typename T> bool Pre(const parser::Statement<T> &statement) {
549     currentStatementSourcePosition_ = statement.source;
550     return true;
551   }
552 
Post(const T &)553   template <typename T> void Post(const T &) {}
554 
555   void Post(const parser::GotoStmt &gotoStmt);
556   void Post(const parser::ComputedGotoStmt &computedGotoStmt);
557   void Post(const parser::ArithmeticIfStmt &arithmeticIfStmt);
558   void Post(const parser::AssignStmt &assignStmt);
559   void Post(const parser::AssignedGotoStmt &assignedGotoStmt);
560   void Post(const parser::AltReturnSpec &altReturnSpec);
561   void Post(const parser::ErrLabel &errLabel);
562   void Post(const parser::EndLabel &endLabel);
563   void Post(const parser::EorLabel &eorLabel);
564   void checkLabelUse(const parser::Label &labelUsed);
565 
566 private:
567   SemanticsContext &context_;
568   std::set<parser::Label> labels_;
569   parser::CharBlock currentStatementSourcePosition_{nullptr};
570   parser::CharBlock constructSourcePosition_{nullptr};
571   const char *construct_{nullptr};
572 
573   parser::MessageFormattedText GetEnclosingConstructMsg();
574   void SayWithConstruct(SemanticsContext &context,
575       parser::CharBlock stmtLocation, parser::MessageFormattedText &&message,
576       parser::CharBlock constructLocation);
577 };
578 // Return the (possibly null) name of the ConstructNode
579 const std::optional<parser::Name> &MaybeGetNodeName(
580     const ConstructNode &construct);
581 
582 // Convert evaluate::GetShape() result into an ArraySpec
583 std::optional<ArraySpec> ToArraySpec(
584     evaluate::FoldingContext &, const evaluate::Shape &);
585 std::optional<ArraySpec> ToArraySpec(
586     evaluate::FoldingContext &, const std::optional<evaluate::Shape> &);
587 
588 } // namespace Fortran::semantics
589 #endif // FORTRAN_SEMANTICS_TOOLS_H_
590