FLANG
tools.h
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/visit.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 "flang/Support/Fortran.h"
26#include <functional>
27
28namespace Fortran::semantics {
29
30class DeclTypeSpec;
31class DerivedTypeSpec;
32class Scope;
33class Symbol;
34
35// Note: Here ProgramUnit includes internal subprograms while TopLevelUnit
36// does not. "program-unit" in the Fortran standard matches TopLevelUnit.
37const Scope &GetTopLevelUnitContaining(const Scope &);
38const Scope &GetTopLevelUnitContaining(const Symbol &);
39const Scope &GetProgramUnitContaining(const Scope &);
40const Scope &GetProgramUnitContaining(const Symbol &);
41const Scope &GetProgramUnitOrBlockConstructContaining(const Scope &);
42const Scope &GetProgramUnitOrBlockConstructContaining(const Symbol &);
43
44const Scope *FindModuleContaining(const Scope &);
45const Scope *FindModuleOrSubmoduleContaining(const Scope &);
46const Scope *FindModuleFileContaining(const Scope &);
47const Scope *FindPureProcedureContaining(const Scope &);
48const Scope *FindOpenACCConstructContaining(const Scope *);
49bool HasOpenACCRoutineDirective(const Scope *);
50
51const Symbol *FindInterface(const Symbol &);
52const Symbol *FindSubprogram(const Symbol &);
53const Symbol *FindOverriddenBinding(
54 const Symbol &, bool &isInaccessibleDeferred);
55const Symbol *FindGlobal(const Symbol &);
56
57const DeclTypeSpec *FindParentTypeSpec(const DerivedTypeSpec &);
58const DeclTypeSpec *FindParentTypeSpec(const DeclTypeSpec &);
59const DeclTypeSpec *FindParentTypeSpec(const Scope &);
60const DeclTypeSpec *FindParentTypeSpec(const Symbol &);
61
62const EquivalenceSet *FindEquivalenceSet(const Symbol &);
63
64enum class Tristate { No, Yes, Maybe };
65inline Tristate ToTristate(bool x) { return x ? Tristate::Yes : Tristate::No; }
66
67// Is this a user-defined assignment? If both sides are the same derived type
68// (and the ranks are okay) the answer is Maybe.
69Tristate IsDefinedAssignment(
70 const std::optional<evaluate::DynamicType> &lhsType, int lhsRank,
71 const std::optional<evaluate::DynamicType> &rhsType, int rhsRank);
72// Test for intrinsic unary and binary operators based on types and ranks
73bool IsIntrinsicRelational(common::RelationalOperator,
74 const evaluate::DynamicType &, int, const evaluate::DynamicType &, int);
75bool IsIntrinsicNumeric(const evaluate::DynamicType &);
76bool IsIntrinsicNumeric(
77 const evaluate::DynamicType &, int, const evaluate::DynamicType &, int);
78bool IsIntrinsicLogical(const evaluate::DynamicType &);
79bool IsIntrinsicLogical(
80 const evaluate::DynamicType &, int, const evaluate::DynamicType &, int);
81bool IsIntrinsicConcat(
82 const evaluate::DynamicType &, int, const evaluate::DynamicType &, int);
83
84bool IsGenericDefinedOp(const Symbol &);
85bool IsDefinedOperator(SourceName);
86std::string MakeOpName(SourceName);
87bool IsCommonBlockContaining(const Symbol &, const Symbol &);
88
89// Returns true if maybeAncestor exists and is a proper ancestor of a
90// descendent scope (or symbol owner). Will be false, unlike Scope::Contains(),
91// if maybeAncestor *is* the descendent.
92bool DoesScopeContain(const Scope *maybeAncestor, const Scope &maybeDescendent);
93bool DoesScopeContain(const Scope *, const Symbol &);
94
95bool IsUseAssociated(const Symbol &, const Scope &);
96bool IsHostAssociated(const Symbol &, const Scope &);
97bool IsHostAssociatedIntoSubprogram(const Symbol &, const Scope &);
98inline bool IsStmtFunction(const Symbol &symbol) {
99 const auto *subprogram{symbol.detailsIf<SubprogramDetails>()};
100 return subprogram && subprogram->stmtFunction();
101}
102bool IsInStmtFunction(const Symbol &);
103bool IsStmtFunctionDummy(const Symbol &);
104bool IsStmtFunctionResult(const Symbol &);
105bool IsPointerDummy(const Symbol &);
106bool IsBindCProcedure(const Symbol &);
107bool IsBindCProcedure(const Scope &);
108// Returns a pointer to the function's symbol when true, else null
109const Symbol *IsFunctionResultWithSameNameAsFunction(const Symbol &);
110bool IsOrContainsEventOrLockComponent(const Symbol &);
111bool IsOrContainsNotifyComponent(const Symbol &);
112bool CanBeTypeBoundProc(const Symbol &);
113// Does a non-PARAMETER symbol have explicit initialization with =value or
114// =>target in its declaration (but not in a DATA statement)? (Being
115// ALLOCATABLE or having a derived type with default component initialization
116// doesn't count; it must be a variable initialization that implies the SAVE
117// attribute, or a derived type component default value.)
118bool HasDeclarationInitializer(const Symbol &);
119// Is the symbol explicitly or implicitly initialized in any way?
120bool IsInitialized(const Symbol &, bool ignoreDATAstatements = false,
121 bool ignoreAllocatable = false, bool ignorePointer = true);
122// Is the symbol a component subject to deallocation or finalization?
123bool IsDestructible(const Symbol &, const Symbol *derivedType = nullptr);
124bool HasIntrinsicTypeName(const Symbol &);
125bool IsSeparateModuleProcedureInterface(const Symbol *);
126bool HasAlternateReturns(const Symbol &);
127bool IsAutomaticallyDestroyed(const Symbol &);
128
129// Return an ultimate component of type that matches predicate, or nullptr.
130const Symbol *FindUltimateComponent(const DerivedTypeSpec &type,
131 const std::function<bool(const Symbol &)> &predicate);
132const Symbol *FindUltimateComponent(
133 const Symbol &symbol, const std::function<bool(const Symbol &)> &predicate);
134
135// Returns an immediate component of type that matches predicate, or nullptr.
136// An immediate component of a type is one declared for that type or is an
137// immediate component of the type that it extends.
138const Symbol *FindImmediateComponent(
139 const DerivedTypeSpec &, const std::function<bool(const Symbol &)> &);
140
141inline bool IsPointer(const Symbol &symbol) {
142 return symbol.attrs().test(Attr::POINTER);
143}
144inline bool IsAllocatable(const Symbol &symbol) {
145 return symbol.attrs().test(Attr::ALLOCATABLE);
146}
147inline bool IsValue(const Symbol &symbol) {
148 return symbol.attrs().test(Attr::VALUE);
149}
150// IsAllocatableOrObjectPointer() may be the better choice
151inline bool IsAllocatableOrPointer(const Symbol &symbol) {
152 return IsPointer(symbol) || IsAllocatable(symbol);
153}
154inline bool IsNamedConstant(const Symbol &symbol) {
155 return symbol.attrs().test(Attr::PARAMETER);
156}
157inline bool IsOptional(const Symbol &symbol) {
158 return symbol.attrs().test(Attr::OPTIONAL);
159}
160inline bool IsIntentIn(const Symbol &symbol) {
161 return symbol.attrs().test(Attr::INTENT_IN);
162}
163inline bool IsIntentInOut(const Symbol &symbol) {
164 return symbol.attrs().test(Attr::INTENT_INOUT);
165}
166inline bool IsIntentOut(const Symbol &symbol) {
167 return symbol.attrs().test(Attr::INTENT_OUT);
168}
169inline bool IsProtected(const Symbol &symbol) {
170 return symbol.attrs().test(Attr::PROTECTED);
171}
172inline bool IsImpliedDoIndex(const Symbol &symbol) {
173 return symbol.owner().kind() == Scope::Kind::ImpliedDos;
174}
175SymbolVector FinalsForDerivedTypeInstantiation(const DerivedTypeSpec &);
176// Returns a non-null pointer to a FINAL procedure, if any.
177const Symbol *IsFinalizable(const Symbol &,
178 std::set<const DerivedTypeSpec *> * = nullptr,
179 bool withImpureFinalizer = false);
180const Symbol *IsFinalizable(const DerivedTypeSpec &,
181 std::set<const DerivedTypeSpec *> * = nullptr,
182 bool withImpureFinalizer = false, std::optional<int> rank = std::nullopt);
183const Symbol *HasImpureFinal(
184 const Symbol &, std::optional<int> rank = std::nullopt);
185// Is this type finalizable or does it contain any polymorphic allocatable
186// ultimate components?
187bool MayRequireFinalization(const DerivedTypeSpec &);
188// Does this type have an allocatable direct component?
189bool HasAllocatableDirectComponent(const DerivedTypeSpec &);
190// Does this type have any defined assignment at any level (or any polymorphic
191// allocatable)?
192bool MayHaveDefinedAssignment(const DerivedTypeSpec &);
193
194bool IsInBlankCommon(const Symbol &);
195bool IsAssumedLengthCharacter(const Symbol &);
196bool IsExternal(const Symbol &);
197bool IsModuleProcedure(const Symbol &);
198bool HasCoarray(const parser::Expr &);
199bool IsAssumedType(const Symbol &);
200bool IsPolymorphic(const Symbol &);
201bool IsUnlimitedPolymorphic(const Symbol &);
202bool IsPolymorphicAllocatable(const Symbol &);
203
204bool IsDeviceAllocatable(const Symbol &symbol);
205
206inline bool IsCUDADeviceContext(const Scope *scope) {
207 if (scope) {
208 if (const Symbol * symbol{scope->symbol()}) {
209 if (const auto *subp{symbol->detailsIf<SubprogramDetails>()}) {
210 if (auto attrs{subp->cudaSubprogramAttrs()}) {
211 return *attrs != common::CUDASubprogramAttrs::Host;
212 }
213 }
214 }
215 }
216 return false;
217}
218
219inline bool HasCUDAAttr(const Symbol &sym) {
220 if (const auto *details{sym.GetUltimate().detailsIf<ObjectEntityDetails>()}) {
221 if (details->cudaDataAttr()) {
222 return true;
223 }
224 }
225 return false;
226}
227
228bool HasCUDAComponent(const Symbol &sym);
229
230inline bool IsCUDADevice(const Symbol &sym) {
231 if (const auto *details{sym.GetUltimate().detailsIf<ObjectEntityDetails>()}) {
232 return details->cudaDataAttr() &&
233 *details->cudaDataAttr() == common::CUDADataAttr::Device;
234 }
235 return false;
236}
237
238inline bool IsCUDAShared(const Symbol &sym) {
239 if (const auto *details{sym.GetUltimate().detailsIf<ObjectEntityDetails>()}) {
240 return details->cudaDataAttr() &&
241 *details->cudaDataAttr() == common::CUDADataAttr::Shared;
242 }
243 return false;
244}
245
246inline bool NeedCUDAAlloc(const Symbol &sym) {
247 if (IsDummy(sym)) {
248 return false;
249 }
250 if (const auto *details{sym.GetUltimate().detailsIf<ObjectEntityDetails>()}) {
251 if (details->cudaDataAttr() &&
252 (*details->cudaDataAttr() == common::CUDADataAttr::Device ||
253 *details->cudaDataAttr() == common::CUDADataAttr::Managed ||
254 *details->cudaDataAttr() == common::CUDADataAttr::Unified ||
255 *details->cudaDataAttr() == common::CUDADataAttr::Shared ||
256 *details->cudaDataAttr() == common::CUDADataAttr::Pinned)) {
257 return true;
258 }
259 }
260 return false;
261}
262
263bool CanCUDASymbolBeGlobal(const Symbol &sym);
264
265const Scope *FindCUDADeviceContext(const Scope *);
266std::optional<common::CUDADataAttr> GetCUDADataAttr(const Symbol *);
267
268bool IsAccessible(const Symbol &, const Scope &);
269
270// Return an error if a symbol is not accessible from a scope
271std::optional<parser::MessageFormattedText> CheckAccessibleSymbol(
272 const Scope &, const Symbol &, bool inStructureConstructor = false);
273
274// Analysis of image control statements
275bool IsImageControlStmt(const parser::ExecutableConstruct &);
276// Get the location of the image control statement in this ExecutableConstruct
277parser::CharBlock GetImageControlStmtLocation(
278 const parser::ExecutableConstruct &);
279// Image control statements that reference coarrays need an extra message
280// to clarify why they're image control statements. This function returns
281// std::nullopt for ExecutableConstructs that do not require an extra message.
282std::optional<parser::MessageFixedText> GetImageControlStmtCoarrayMsg(
283 const parser::ExecutableConstruct &);
284
285// Returns the complete list of derived type parameter symbols in
286// the order in which their declarations appear in the derived type
287// definitions (parents first).
288SymbolVector OrderParameterDeclarations(const Symbol &);
289// Returns the complete list of derived type parameter names in the
290// order defined by 7.5.3.2.
291SymbolVector OrderParameterNames(const Symbol &);
292
293// Return an existing or new derived type instance
294const DeclTypeSpec &FindOrInstantiateDerivedType(Scope &, DerivedTypeSpec &&,
295 DeclTypeSpec::Category = DeclTypeSpec::TypeDerived);
296
297// When a subprogram defined in a submodule defines a separate module
298// procedure whose interface is defined in an ancestor (sub)module,
299// returns a pointer to that interface, else null.
300const Symbol *FindSeparateModuleSubprogramInterface(const Symbol *);
301
302// Determines whether an object might be visible outside a
303// pure function (C1594); returns a non-null Symbol pointer for
304// diagnostic purposes if so.
305const Symbol *FindExternallyVisibleObject(
306 const Symbol &, const Scope &, bool isPointerDefinition);
307
308template <typename A>
309const Symbol *FindExternallyVisibleObject(const A &, const Scope &) {
310 return nullptr; // default base case
311}
312
313template <typename T>
314const Symbol *FindExternallyVisibleObject(
315 const evaluate::Designator<T> &designator, const Scope &scope) {
316 if (const Symbol * symbol{designator.GetBaseObject().symbol()}) {
317 return FindExternallyVisibleObject(*symbol, scope, false);
318 } else if (std::holds_alternative<evaluate::CoarrayRef>(designator.u)) {
319 // Coindexed values are visible even if their image-local objects are not.
320 return designator.GetBaseObject().symbol();
321 } else {
322 return nullptr;
323 }
324}
325
326template <typename T>
327const Symbol *FindExternallyVisibleObject(
328 const evaluate::Expr<T> &expr, const Scope &scope) {
329 return common::visit(
330 [&](const auto &x) { return FindExternallyVisibleObject(x, scope); },
331 expr.u);
332}
333
334// Applies GetUltimate(), then if the symbol is a generic procedure shadowing a
335// specific procedure of the same name, return it instead.
336const Symbol &BypassGeneric(const Symbol &);
337
338using SomeExpr = evaluate::Expr<evaluate::SomeType>;
339
340bool ExprHasTypeCategory(
341 const SomeExpr &expr, const common::TypeCategory &type);
342bool ExprTypeKindIsDefault(
343 const SomeExpr &expr, const SemanticsContext &context);
344
345class GetExprHelper {
346public:
347 explicit GetExprHelper(SemanticsContext *context) : context_{context} {}
348 GetExprHelper() : crashIfNoExpr_{true} {}
349
350 // Specializations for parse tree nodes that have a typedExpr member.
351 const SomeExpr *Get(const parser::Expr &);
352 const SomeExpr *Get(const parser::Variable &);
353 const SomeExpr *Get(const parser::DataStmtConstant &);
354 const SomeExpr *Get(const parser::AllocateObject &);
355 const SomeExpr *Get(const parser::PointerObject &);
356
357 template <typename T> const SomeExpr *Get(const common::Indirection<T> &x) {
358 return Get(x.value());
359 }
360 template <typename T> const SomeExpr *Get(const std::optional<T> &x) {
361 return x ? Get(*x) : nullptr;
362 }
363 template <typename T> const SomeExpr *Get(const T &x) {
364 static_assert(
365 !parser::HasTypedExpr<T>::value, "explicit Get overload must be added");
366 if constexpr (ConstraintTrait<T>) {
367 return Get(x.thing);
368 } else if constexpr (WrapperTrait<T>) {
369 return Get(x.v);
370 } else {
371 return nullptr;
372 }
373 }
374
375private:
376 SemanticsContext *context_{nullptr};
377 const bool crashIfNoExpr_{false};
378};
379
380// If a SemanticsContext is passed, even if null, it is possible for a null
381// pointer to be returned in the event of an expression that had fatal errors.
382// Use these first two forms in semantics checks for best error recovery.
383// If a SemanticsContext is not passed, a missing expression will
384// cause a crash.
385template <typename T>
386const SomeExpr *GetExpr(SemanticsContext *context, const T &x) {
387 return GetExprHelper{context}.Get(x);
388}
389template <typename T>
390const SomeExpr *GetExpr(SemanticsContext &context, const T &x) {
391 return GetExprHelper{&context}.Get(x);
392}
393template <typename T> const SomeExpr *GetExpr(const T &x) {
394 return GetExprHelper{}.Get(x);
395}
396
397const evaluate::Assignment *GetAssignment(const parser::AssignmentStmt &);
398const evaluate::Assignment *GetAssignment(
399 const parser::PointerAssignmentStmt &);
400
401template <typename T> std::optional<std::int64_t> GetIntValue(const T &x) {
402 if (const auto *expr{GetExpr(nullptr, x)}) {
403 return evaluate::ToInt64(*expr);
404 } else {
405 return std::nullopt;
406 }
407}
408
409template <typename T> bool IsZero(const T &expr) {
410 auto value{GetIntValue(expr)};
411 return value && *value == 0;
412}
413
414// 15.2.2
415enum class ProcedureDefinitionClass {
416 None,
417 Intrinsic,
418 External,
419 Internal,
420 Module,
421 Dummy,
422 Pointer,
423 StatementFunction
424};
425
426ProcedureDefinitionClass ClassifyProcedure(const Symbol &);
427
428// Returns a list of storage associations due to EQUIVALENCE in a
429// scope; each storage association is a list of symbol references
430// in ascending order of scope offset. Note that the scope may have
431// more EquivalenceSets than this function's result has storage
432// associations; these are closures over equivalences.
433std::list<std::list<SymbolRef>> GetStorageAssociations(const Scope &);
434
435// Derived type component iterator that provides a C++ LegacyForwardIterator
436// iterator over the Ordered, Direct, Ultimate or Potential components of a
437// DerivedTypeSpec. These iterators can be used with STL algorithms
438// accepting LegacyForwardIterator.
439// The kind of component is a template argument of the iterator factory
440// ComponentIterator.
441//
442// - Ordered components are the components from the component order defined
443// in 7.5.4.7, except that the parent component IS added between the parent
444// component order and the components in order of declaration.
445// This "deviation" is important for structure-constructor analysis.
446// For this kind of iterator, the component tree is recursively visited in the
447// following order:
448// - first, the Ordered components of the parent type (if relevant)
449// - then, the parent component (if relevant, different from 7.5.4.7!)
450// - then, the components in declaration order (without visiting subcomponents)
451//
452// - Ultimate, Direct and Potential components are as defined in 7.5.1.
453// - Ultimate components of a derived type are the closure of its components
454// of intrinsic type, its ALLOCATABLE or POINTER components, and the
455// ultimate components of its non-ALLOCATABLE non-POINTER derived type
456// components. (No ultimate component has a derived type unless it is
457// ALLOCATABLE or POINTER.)
458// - Direct components of a derived type are all of its components, and all
459// of the direct components of its non-ALLOCATABLE non-POINTER derived type
460// components. (Direct components are always present.)
461// - Potential subobject components of a derived type are the closure of
462// its non-POINTER components and the potential subobject components of
463// its non-POINTER derived type components. (The lifetime of each
464// potential subobject component is that of the entire instance.)
465// - PotentialAndPointer subobject components of a derived type are the
466// closure of its components (including POINTERs) and the
467// PotentialAndPointer subobject components of its non-POINTER derived type
468// components.
469//
470// type t1 ultimate components: x, a, p
471// real x direct components: x, a, p
472// real, allocatable :: a potential components: x, a
473// real, pointer :: p potential & pointers: x, a, p
474// end type
475// type t2 ultimate components: y, c%x, c%a, c%p, b
476// real y direct components: y, c, c%x, c%a, c%p, b
477// type(t1) :: c potential components: y, c, c%x, c%a, b, b%x, b%a
478// type(t1), allocatable :: b potential & pointers: potentials + c%p + b%p
479// end type
480//
481// Parent and procedure components are considered against these definitions.
482// For this kind of iterator, the component tree is recursively visited in the
483// following order:
484// - the parent component first (if relevant)
485// - then, the components of the parent type (if relevant)
486// + visiting the component and then, if it is derived type data component,
487// visiting the subcomponents before visiting the next
488// component in declaration order.
489// - then, components in declaration order, similarly to components of parent
490// type.
491// Here, the parent component is visited first so that search for a component
492// verifying a property will never descend into a component that already
493// verifies the property (this helps giving clearer feedback).
494//
495// ComponentIterator::const_iterator remain valid during the whole lifetime of
496// the DerivedTypeSpec passed by reference to the ComponentIterator factory.
497// Their validity is independent of the ComponentIterator factory lifetime.
498//
499// For safety and simplicity, the iterators are read only and can only be
500// incremented. This could be changed if desired.
501//
502// Note that iterators are made in such a way that one can easily test and build
503// info message in the following way:
504// ComponentIterator<ComponentKind::...> comp{derived}
505// if (auto it{std::find_if(comp.begin(), comp.end(), predicate)}) {
506// msg = it.BuildResultDesignatorName() + " verifies predicates";
507// const Symbol *component{*it};
508// ....
509// }
510
511ENUM_CLASS(ComponentKind, Ordered, Direct, Ultimate, Potential, Scope,
512 PotentialAndPointer)
513
514template <ComponentKind componentKind> class ComponentIterator {
515public:
516 ComponentIterator(const DerivedTypeSpec &derived) : derived_{derived} {}
517 class const_iterator {
518 public:
519 using iterator_category = std::forward_iterator_tag;
520 using value_type = SymbolRef;
521 using difference_type = void;
522 using pointer = const Symbol *;
523 using reference = const Symbol &;
524
525 static const_iterator Create(const DerivedTypeSpec &);
526
527 const_iterator &operator++() {
528 Increment();
529 return *this;
530 }
531 const_iterator operator++(int) {
532 const_iterator tmp(*this);
533 Increment();
534 return tmp;
535 }
536 reference operator*() const {
537 CHECK(!componentPath_.empty());
538 return DEREF(componentPath_.back().component());
539 }
540 pointer operator->() const { return &**this; }
541
542 bool operator==(const const_iterator &other) const {
543 return componentPath_ == other.componentPath_;
544 }
545 bool operator!=(const const_iterator &other) const {
546 return !(*this == other);
547 }
548
549 // bool() operator indicates if the iterator can be dereferenced without
550 // having to check against an end() iterator.
551 explicit operator bool() const { return !componentPath_.empty(); }
552
553 // Returns the current sequence of components, including parent components.
554 SymbolVector GetComponentPath() const;
555
556 // Builds a designator name of the referenced component for messages.
557 // The designator helps when the component referred to by the iterator
558 // may be "buried" into other components. This gives the full
559 // path inside the iterated derived type: e.g "%a%b%c%ultimate"
560 // when it->name() only gives "ultimate". Parent components are
561 // part of the path for clarity, even though they could be
562 // skipped.
563 std::string BuildResultDesignatorName() const;
564
565 private:
566 using name_iterator =
567 std::conditional_t<componentKind == ComponentKind::Scope,
568 typename Scope::const_iterator,
569 typename std::list<SourceName>::const_iterator>;
570
571 class ComponentPathNode {
572 public:
573 explicit ComponentPathNode(const DerivedTypeSpec &derived)
574 : derived_{derived} {
575 if constexpr (componentKind == ComponentKind::Scope) {
576 const Scope &scope{DEREF(derived.GetScope())};
577 nameIterator_ = scope.cbegin();
578 nameEnd_ = scope.cend();
579 } else {
580 const std::list<SourceName> &nameList{
581 derived.typeSymbol().get<DerivedTypeDetails>().componentNames()};
582 nameIterator_ = nameList.cbegin();
583 nameEnd_ = nameList.cend();
584 }
585 }
586 const Symbol *component() const { return component_; }
587 void set_component(const Symbol &component) { component_ = &component; }
588 bool visited() const { return visited_; }
589 void set_visited(bool yes) { visited_ = yes; }
590 bool descended() const { return descended_; }
591 void set_descended(bool yes) { descended_ = yes; }
592 name_iterator &nameIterator() { return nameIterator_; }
593 name_iterator nameEnd() { return nameEnd_; }
594 const Symbol &GetTypeSymbol() const { return derived_->typeSymbol(); }
595 const Scope &GetScope() const {
596 return derived_->scope() ? *derived_->scope()
597 : DEREF(GetTypeSymbol().scope());
598 }
599 bool operator==(const ComponentPathNode &that) const {
600 return &*derived_ == &*that.derived_ &&
601 nameIterator_ == that.nameIterator_ &&
602 component_ == that.component_;
603 }
604
605 private:
606 common::Reference<const DerivedTypeSpec> derived_;
607 name_iterator nameEnd_;
608 name_iterator nameIterator_;
609 const Symbol *component_{nullptr}; // until Increment()
610 bool visited_{false};
611 bool descended_{false};
612 };
613
614 const DerivedTypeSpec *PlanComponentTraversal(
615 const Symbol &component) const;
616 // Advances to the next relevant symbol, if any. Afterwards, the
617 // iterator will either be at its end or contain no null component().
618 void Increment();
619
620 std::vector<ComponentPathNode> componentPath_;
621 };
622
623 const_iterator begin() { return cbegin(); }
624 const_iterator end() { return cend(); }
625 const_iterator cbegin() { return const_iterator::Create(derived_); }
626 const_iterator cend() { return const_iterator{}; }
627
628private:
629 const DerivedTypeSpec &derived_;
630};
631
632extern template class ComponentIterator<ComponentKind::Ordered>;
633extern template class ComponentIterator<ComponentKind::Direct>;
634extern template class ComponentIterator<ComponentKind::Ultimate>;
635extern template class ComponentIterator<ComponentKind::Potential>;
636extern template class ComponentIterator<ComponentKind::Scope>;
637extern template class ComponentIterator<ComponentKind::PotentialAndPointer>;
638using OrderedComponentIterator = ComponentIterator<ComponentKind::Ordered>;
639using DirectComponentIterator = ComponentIterator<ComponentKind::Direct>;
640using UltimateComponentIterator = ComponentIterator<ComponentKind::Ultimate>;
641using PotentialComponentIterator = ComponentIterator<ComponentKind::Potential>;
642using ScopeComponentIterator = ComponentIterator<ComponentKind::Scope>;
643using PotentialAndPointerComponentIterator =
644 ComponentIterator<ComponentKind::PotentialAndPointer>;
645
646// Common component searches, the iterator returned is referring to the first
647// component, according to the order defined for the related ComponentIterator,
648// that verifies the property from the name.
649// If no component verifies the property, an end iterator (casting to false)
650// is returned. Otherwise, the returned iterator casts to true and can be
651// dereferenced.
652PotentialComponentIterator::const_iterator FindEventOrLockPotentialComponent(
653 const DerivedTypeSpec &, bool ignoreCoarrays = false);
654PotentialComponentIterator::const_iterator FindNotifyPotentialComponent(
655 const DerivedTypeSpec &, bool ignoreCoarrays = false);
656PotentialComponentIterator::const_iterator FindCoarrayPotentialComponent(
657 const DerivedTypeSpec &);
658PotentialAndPointerComponentIterator::const_iterator
659FindPointerPotentialComponent(const DerivedTypeSpec &);
660UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent(
661 const DerivedTypeSpec &);
662UltimateComponentIterator::const_iterator FindPointerUltimateComponent(
663 const DerivedTypeSpec &);
664UltimateComponentIterator::const_iterator FindAllocatableUltimateComponent(
665 const DerivedTypeSpec &);
666DirectComponentIterator::const_iterator FindAllocatableOrPointerDirectComponent(
667 const DerivedTypeSpec &);
668PotentialComponentIterator::const_iterator
669FindPolymorphicAllocatablePotentialComponent(const DerivedTypeSpec &);
670UltimateComponentIterator::const_iterator
671FindCUDADeviceAllocatableUltimateComponent(const DerivedTypeSpec &);
672
673// The LabelEnforce class (given a set of labels) provides an error message if
674// there is a branch to a label which is not in the given set.
675class LabelEnforce {
676public:
677 LabelEnforce(SemanticsContext &context, std::set<parser::Label> &&labels,
678 parser::CharBlock constructSourcePosition, const char *construct)
679 : context_{context}, labels_{labels},
680 constructSourcePosition_{constructSourcePosition}, construct_{
681 construct} {}
682 template <typename T> bool Pre(const T &) { return true; }
683 template <typename T> bool Pre(const parser::Statement<T> &statement) {
684 currentStatementSourcePosition_ = statement.source;
685 return true;
686 }
687
688 template <typename T> void Post(const T &) {}
689
690 void Post(const parser::GotoStmt &gotoStmt);
691 void Post(const parser::ComputedGotoStmt &computedGotoStmt);
692 void Post(const parser::ArithmeticIfStmt &arithmeticIfStmt);
693 void Post(const parser::AssignStmt &assignStmt);
694 void Post(const parser::AssignedGotoStmt &assignedGotoStmt);
695 void Post(const parser::AltReturnSpec &altReturnSpec);
696 void Post(const parser::ErrLabel &errLabel);
697 void Post(const parser::EndLabel &endLabel);
698 void Post(const parser::EorLabel &eorLabel);
699 void CheckLabelUse(const parser::Label &labelUsed);
700
701private:
702 SemanticsContext &context_;
703 std::set<parser::Label> labels_;
704 parser::CharBlock currentStatementSourcePosition_{nullptr};
705 parser::CharBlock constructSourcePosition_{nullptr};
706 const char *construct_{nullptr};
707
708 parser::MessageFormattedText GetEnclosingConstructMsg();
709 void SayWithConstruct(SemanticsContext &context,
710 parser::CharBlock stmtLocation, parser::MessageFormattedText &&message,
711 parser::CharBlock constructLocation);
712};
713// Return the (possibly null) name of the ConstructNode
714const std::optional<parser::Name> &MaybeGetNodeName(
715 const ConstructNode &construct);
716
717// Convert evaluate::GetShape() result into an ArraySpec
718std::optional<ArraySpec> ToArraySpec(
719 evaluate::FoldingContext &, const evaluate::Shape &);
720std::optional<ArraySpec> ToArraySpec(
721 evaluate::FoldingContext &, const std::optional<evaluate::Shape> &);
722
723// Searches a derived type and a scope for a particular defined I/O procedure.
724bool HasDefinedIo(
725 common::DefinedIo, const DerivedTypeSpec &, const Scope * = nullptr);
726
727// Some intrinsic operators have more than one name (e.g. `operator(.eq.)` and
728// `operator(==)`). GetAllNames() returns them all, including symbolName.
729std::forward_list<std::string> GetAllNames(
730 const SemanticsContext &, const SourceName &);
731
732// Determines the derived type of a procedure's initial "dtv" dummy argument,
733// assuming that the procedure is a specific procedure of a defined I/O
734// generic interface,
735const DerivedTypeSpec *GetDtvArgDerivedType(const Symbol &);
736
737// If "expr" exists and is a designator for a deferred length
738// character allocatable whose semantics might change under Fortran 202X,
739// emit a portability warning.
740void WarnOnDeferredLengthCharacterScalar(SemanticsContext &, const SomeExpr *,
741 parser::CharBlock at, const char *what);
742
743bool CouldBeDataPointerValuedFunction(const Symbol *);
744
745template <typename R, typename T>
746std::optional<R> GetConstExpr(SemanticsContext &semanticsContext, const T &x) {
747 using DefaultCharConstantType = evaluate::Ascii;
748 if (const auto *expr{GetExpr(semanticsContext, x)}) {
749 const auto foldExpr{evaluate::Fold(
750 semanticsContext.foldingContext(), common::Clone(*expr))};
751 if constexpr (std::is_same_v<R, std::string>) {
752 return evaluate::GetScalarConstantValue<DefaultCharConstantType>(
753 foldExpr);
754 }
755 }
756 return std::nullopt;
757}
758
759// Returns "m" for a module, "m:sm" for a submodule.
760std::string GetModuleOrSubmoduleName(const Symbol &);
761
762// Return the assembly name emitted for a common block.
763std::string GetCommonBlockObjectName(const Symbol &, bool underscoring);
764
765// Check for ambiguous USE associations
766bool HadUseError(SemanticsContext &, SourceName at, const Symbol *);
767
768bool AreSameModuleSymbol(const Symbol &, const Symbol &);
769
770} // namespace Fortran::semantics
771#endif // FORTRAN_SEMANTICS_TOOLS_H_
Definition indirection.h:31
Definition common.h:217
Definition char-block.h:28
Definition tools.h:345
Definition scope.h:67
Definition semantics.h:67
Definition symbol.h:825
Definition parse-tree.h:1898
Definition parse-tree.h:3438
Definition parse-tree.h:3443
Definition parse-tree.h:3448
Definition parse-tree.h:2496
Definition parse-tree.h:1467
Definition parse-tree.h:1682
Definition tools.h:140
Definition parse-tree.h:1974
Definition parse-tree.h:359
Definition parse-tree.h:1841