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