info.typeSpecLoc = parser::FindSourceLocation(*typeSpec);
if (const DerivedTypeSpec * derived{info.typeSpec->AsDerived()}) {
// C937
- if (auto coarraySearch{ComponentVisitor::HasCoarrayUltimate(*derived)}) {
+ if (auto it{FindCoarrayUltimateComponent(*derived)}) {
context
.Say("Type-spec in ALLOCATE must not specify a type with a coarray"
" ultimate component"_err_en_US)
- .Attach(coarraySearch.Result()->name(),
+ .Attach((*it)->name(),
"Type '%s' has coarray ultimate component '%s' declared here"_en_US,
- info.typeSpec->AsFortran(),
- coarraySearch.BuildResultDesignatorName());
+ info.typeSpec->AsFortran(), it.BuildResultDesignatorName());
}
}
}
const DerivedTypeSpec &derived{
info.sourceExprType.value().GetDerivedTypeSpec()};
// C949
- if (auto coarraySearch{ComponentVisitor::HasCoarrayUltimate(derived)}) {
+ if (auto it{FindCoarrayUltimateComponent(derived)}) {
context
.Say(parserSourceExpr->source,
"SOURCE or MOLD expression must not have a type with a coarray ultimate component"_err_en_US)
- .Attach(coarraySearch.Result()->name(),
+ .Attach((*it)->name(),
"Type '%s' has coarray ultimate component '%s' declared here"_en_US,
info.sourceExprType.value().AsFortran(),
- coarraySearch.BuildResultDesignatorName());
+ it.BuildResultDesignatorName());
}
if (info.gotSrc) {
// C948
if (IsEventTypeOrLockType(&derived)) {
context.Say(parserSourceExpr->source,
"SOURCE expression type must not be EVENT_TYPE or LOCK_TYPE from ISO_FORTRAN_ENV"_err_en_US);
- } else if (auto componentSearch{
- ComponentVisitor::HasEventOrLockPotential(derived)}) {
+ } else if (auto it{FindEventOrLockPotentialComponent(derived)}) {
context
.Say(parserSourceExpr->source,
"SOURCE expression type must not have potential subobject "
"component"
" of type EVENT_TYPE or LOCK_TYPE from ISO_FORTRAN_ENV"_err_en_US)
- .Attach(componentSearch.Result()->name(),
+ .Attach((*it)->name(),
"Type '%s' has potential ultimate component '%s' declared here"_en_US,
info.sourceExprType.value().AsFortran(),
- componentSearch.BuildResultDesignatorName());
+ it.BuildResultDesignatorName());
}
}
}
// produces the component list X, A, Y.
// The order is important below because a structure constructor can
// initialize X or A by name, but not both.
- const auto &details{typeSymbol.get<semantics::DerivedTypeDetails>()};
- semantics::SymbolVector components{details.OrderComponents(*spec.scope())};
+ auto components{semantics::OrderedComponentIterator{spec}};
auto nextAnonymous{components.begin()};
std::set<parser::CharBlock> unavailable;
componentNames_.push_back(symbol.name());
}
-SymbolVector DerivedTypeDetails::OrderComponents(const Scope &scope) const {
- SymbolVector result;
- for (SourceName name : componentNames_) {
- auto iter{scope.find(name)};
- if (iter != scope.cend()) {
- const Symbol &symbol{*iter->second};
- if (symbol.test(Symbol::Flag::ParentComp)) {
- CHECK(result.empty()); // parent component must appear first
- const DerivedTypeSpec &spec{
- symbol.get<ObjectEntityDetails>().type()->derivedTypeSpec()};
- result = spec.typeSymbol().get<DerivedTypeDetails>().OrderComponents(
- *spec.scope());
- }
- result.push_back(&symbol);
- }
- }
- return result;
-}
-
const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const {
if (auto extends{GetParentComponentName()}) {
if (auto iter{scope.find(*extends)}; iter != scope.cend()) {
void add_paramDecl(const Symbol &symbol) { paramDecls_.push_back(&symbol); }
void add_component(const Symbol &);
void set_sequence(bool x = true) { sequence_ = x; }
-
- // Returns the complete list of derived type components in the order
- // in which their declarations appear in the derived type definitions
- // (parents first). Parent components appear in the list immediately
- // after the components that belong to them.
- SymbolVector OrderComponents(const Scope &) const;
+ const std::list<SourceName> &componentNames() const {
+ return componentNames_;
+ }
// If this derived type extends another, locate the parent component's symbol.
const Symbol *GetParentComponent(const Scope &) const;
IsDerivedTypeFromModule(derivedTypeSpec, "iso_fortran_env", "lock_type");
}
-static const bool IsEventTypeOrLockTypeObjectEntity(const Symbol &symbol) {
- if (symbol.has<ObjectEntityDetails>()) {
- const DeclTypeSpec *type{symbol.GetType()};
- return type && IsEventTypeOrLockType(type->AsDerived());
- }
- return false;
-}
-
bool IsOrContainsEventOrLockComponent(const Symbol &symbol) {
if (const Symbol * root{GetAssociationRoot(symbol)}) {
if (const auto *details{root->detailsIf<ObjectEntityDetails>()}) {
if (const DeclTypeSpec * type{details->type()}) {
if (const DerivedTypeSpec * derived{type->AsDerived()}) {
return IsEventTypeOrLockType(derived) ||
- ComponentVisitor::HasEventOrLockPotential(*derived);
+ FindEventOrLockPotentialComponent(*derived);
}
}
}
return result;
}
-enum class ComponentKind { Direct, Ultimate, Potential };
-
-template<ComponentKind componentKind> class ComponentVisitorImplementation {
-public:
- ComponentVisitorImplementation(std::function<bool(const Symbol &)> &predicate)
- : predicate_{predicate} {}
- SymbolVector Visit(const DerivedTypeSpec &derived) {
- TraverseDerivedType(derived);
- return std::move(componentStack_);
- }
-
-private:
- const Symbol *TraverseDerivedType(const DerivedTypeSpec &derived) {
- const Symbol &derivedTypeSymbol{derived.typeSymbol()};
- // Avoid infinite loop if the type is already part of the types
- // being visited. It is possible to have "loops in type" because
- // C744 does not forbid to use not yet declared type for
- // ALLOCATABLE or POINTER components.
- // When looking for potential components, the search could fall
- // in an infinite loop. Avoid these in other search for safety.
- for (const Symbol *typeUnderVisit : typeStack_) {
- if (typeUnderVisit == &derivedTypeSymbol) {
- return nullptr;
- }
- }
- typeStack_.push_back(&derivedTypeSymbol);
- const Scope *scope{derivedTypeSymbol.scope()};
- CHECK(scope); // derived type symbol must have a scope
- const Symbol *result{nullptr};
- // Note: parent subcomponents are visited first, then the parent component
- // (if any), then other components by order of declaration
- SymbolVector orederedComponents{
- derivedTypeSymbol.get<DerivedTypeDetails>().OrderComponents(*scope)};
- for (const Symbol *component : orederedComponents) {
- if (component->has<ProcEntityDetails>()) {
- result = VisitProcedureComponent(*component);
- } else if (component->has<ObjectEntityDetails>()) {
- result = VisitDataComponent(*component);
- }
- if (result) {
- return result;
- }
- }
- typeStack_.pop_back();
- return nullptr;
+// ComponentIterator implementation
+
+template<ComponentKind componentKind>
+typename ComponentIterator<componentKind>::const_iterator
+ComponentIterator<componentKind>::const_iterator::Create(
+ const DerivedTypeSpec &derived) {
+ const_iterator it{};
+ const std::list<SourceName> &names{
+ derived.typeSymbol().get<DerivedTypeDetails>().componentNames()};
+ if (names.empty()) {
+ return it; // end iterator
+ } else {
+ it.componentPath_.emplace_back(
+ ComponentPathNode{nullptr, &derived, names.cbegin()});
+ it.Increment(); // search first relevant component (may be the end)
+ return it;
}
+}
- const Symbol *VisitProcedureComponent(const Symbol &component) {
- // Procedure components are pointers (C756)
- if constexpr (componentKind == ComponentKind::Ultimate ||
- componentKind == ComponentKind::Direct) {
- if (predicate_(component)) {
- componentStack_.push_back(&component);
- return &component;
+template<ComponentKind componentKind>
+bool ComponentIterator<componentKind>::const_iterator::PlanComponentTraversal(
+ const Symbol &component) {
+ // only data component can be traversed
+ if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) {
+ const DeclTypeSpec *type{details->type()};
+ if (!type) {
+ return false; // error recovery
+ } else if (const auto *derived{type->AsDerived()}) {
+ bool traverse{false};
+ if constexpr (componentKind == ComponentKind::Ordered) {
+ // Order Component (only visit parents)
+ traverse = component.test(Symbol::Flag::ParentComp);
+ } else if constexpr (componentKind == ComponentKind::Direct) {
+ traverse = !IsAllocatableOrPointer(component);
+ } else if constexpr (componentKind == ComponentKind::Ultimate) {
+ traverse = !IsAllocatableOrPointer(component);
+ } else if constexpr (componentKind == ComponentKind::Potential) {
+ traverse = !IsPointer(component);
}
- }
- return nullptr;
+ if (traverse) {
+ const Symbol *newTypeSymbol{&derived->typeSymbol()};
+ // Avoid infinite loop if the type is already part of the types
+ // being visited. It is possible to have "loops in type" because
+ // C744 does not forbid to use not yet declared type for
+ // ALLOCATABLE or POINTER components.
+ for (const auto &node : componentPath_) {
+ if (newTypeSymbol == &GetTypeSymbol(node)) {
+ return false;
+ }
+ }
+ componentPath_.emplace_back(ComponentPathNode{nullptr, derived,
+ newTypeSymbol->get<DerivedTypeDetails>()
+ .componentNames()
+ .cbegin()});
+ return true;
+ }
+ } // intrinsic & unlimited polymorphic not traversable
}
+ return false;
+}
- const Symbol *VisitDataComponent(const Symbol &component) {
- const DeclTypeSpec *type{component.GetType()};
- if (!type) {
- return nullptr; // error recovery ?
- }
- bool test{false}, descend{false};
- if constexpr (componentKind == ComponentKind::Direct) {
- test = true;
- descend = !IsAllocatableOrPointer(component);
- } else if constexpr (componentKind == ComponentKind::Ultimate) {
- descend = !IsAllocatableOrPointer(component);
- test = !descend || type->AsIntrinsic();
- } else { // Potential
- test = descend = !IsPointer(component);
- }
+template<ComponentKind componentKind>
+static bool StopAtComponentPre(const Symbol &component) {
+ if constexpr (componentKind == ComponentKind::Ordered) {
+ // Parent components need to be iterated upon after their
+ // sub-components in structure constructor analysis.
+ return !component.test(Symbol::Flag::ParentComp);
+ } else if constexpr (componentKind == ComponentKind::Direct) {
+ return true;
+ } else if constexpr (componentKind == ComponentKind::Ultimate) {
+ return component.has<ProcEntityDetails>() ||
+ IsAllocatableOrPointer(component) ||
+ (component.get<ObjectEntityDetails>().type() &&
+ component.get<ObjectEntityDetails>().type()->AsIntrinsic());
+ } else if constexpr (componentKind == ComponentKind::Potential) {
+ return !IsPointer(component);
+ }
+}
+
+template<ComponentKind componentKind>
+static bool StopAtComponentPost(const Symbol &component) {
+ if constexpr (componentKind == ComponentKind::Ordered) {
+ return component.test(Symbol::Flag::ParentComp);
+ } else {
+ return false;
+ }
+}
- // Do not descend into parent components, their components were already
- // included by DerivedTypeDetails::OrderComponents. However, parent
- // components should still be checked against the predicate if relevant.
- descend &= !component.test(Symbol::Flag::ParentComp);
-
- if (test && predicate_(component)) {
- componentStack_.push_back(&component);
- return &component;
- } else if (descend) {
- if (const auto *derived{type->AsDerived()}) {
- componentStack_.push_back(&component);
- if (const Symbol * result{TraverseDerivedType(*derived)}) {
- return result;
+enum class ComponentVisitState { Resume, Pre, Post };
+
+template<ComponentKind componentKind>
+void ComponentIterator<componentKind>::const_iterator::Increment() {
+ std::int64_t level{static_cast<std::int64_t>(componentPath_.size()) - 1};
+ // Need to know if this is the first incrementation or if the visit is resumed
+ // after a user increment.
+ ComponentVisitState state{
+ level >= 0 && GetComponentSymbol(componentPath_[level])
+ ? ComponentVisitState::Resume
+ : ComponentVisitState::Pre};
+ while (level >= 0) {
+ bool descend{false};
+ const Scope *scope{GetScope(componentPath_[level])};
+ CHECK(scope);
+ auto &levelIterator{GetIterator(componentPath_[level])};
+ const auto &levelEndIterator{GetTypeSymbol(componentPath_[level])
+ .template get<DerivedTypeDetails>()
+ .componentNames()
+ .cend()};
+
+ while (!descend && levelIterator != levelEndIterator) {
+ const Symbol *component{GetComponentSymbol(componentPath_[level])};
+
+ switch (state) {
+ case ComponentVisitState::Resume:
+ CHECK(component);
+ if (StopAtComponentPre<componentKind>(*component)) {
+ // The symbol was not yet considered for
+ // traversal.
+ descend = PlanComponentTraversal(*component);
}
- componentStack_.pop_back();
+ break;
+ case ComponentVisitState::Pre:
+ // Search iterator
+ if (auto iter{scope->find(*levelIterator)}; iter != scope->cend()) {
+ const Symbol *newComponent{iter->second};
+ SetComponentSymbol(componentPath_[level], newComponent);
+ if (StopAtComponentPre<componentKind>(*newComponent)) {
+ return;
+ }
+ descend = PlanComponentTraversal(*newComponent);
+ if (!descend && StopAtComponentPost<componentKind>(*newComponent)) {
+ return;
+ }
+ }
+ break;
+ case ComponentVisitState::Post:
+ CHECK(component);
+ if (StopAtComponentPost<componentKind>(*component)) {
+ return;
+ }
+ break;
}
- }
- return nullptr;
- }
- std::vector<const Symbol *> componentStack_; // to build message info
- std::vector<const Symbol *> typeStack_; // to avoid infinite loops
- std::function<bool(const Symbol &)> &predicate_;
-};
+ if (descend) {
+ level++;
+ } else {
+ SetComponentSymbol(componentPath_[level], nullptr); // safety
+ levelIterator++;
+ }
+ state = ComponentVisitState::Pre;
+ }
-ComponentVisitor &ComponentVisitor::VisitPotentialComponents(
- const DerivedTypeSpec &derived) {
- componentStack_.clear();
- componentStack_ =
- ComponentVisitorImplementation<ComponentKind::Potential>{predicate_}
- .Visit(derived);
- return *this;
+ if (!descend) { // Finished level traversal
+ componentPath_.pop_back();
+ --level;
+ state = ComponentVisitState::Post;
+ }
+ }
+ // iterator reached end of components
}
-ComponentVisitor &ComponentVisitor::VisitUltimateComponents(
- const DerivedTypeSpec &derived) {
- componentStack_.clear();
- componentStack_ =
- ComponentVisitorImplementation<ComponentKind::Ultimate>{predicate_}.Visit(
- derived);
- return *this;
+template<ComponentKind componentKind>
+std::string
+ComponentIterator<componentKind>::const_iterator::BuildResultDesignatorName()
+ const {
+ std::string designator{""};
+ for (const auto &node : componentPath_) {
+ designator += "%" + GetComponentSymbol(node)->name().ToString();
+ }
+ return designator;
}
-ComponentVisitor &ComponentVisitor::VisitDirectComponents(
- const DerivedTypeSpec &derived) {
- componentStack_.clear();
- componentStack_ =
- ComponentVisitorImplementation<ComponentKind::Direct>{predicate_}.Visit(
- derived);
- return *this;
-}
+template class ComponentIterator<ComponentKind::Ordered>;
+template class ComponentIterator<ComponentKind::Direct>;
+template class ComponentIterator<ComponentKind::Ultimate>;
+template class ComponentIterator<ComponentKind::Potential>;
-ComponentVisitor ComponentVisitor::HasEventOrLockPotential(
+UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent(
const DerivedTypeSpec &derived) {
- return ComponentVisitor{IsEventTypeOrLockTypeObjectEntity}
- .VisitPotentialComponents(derived);
+ UltimateComponentIterator ultimates{derived};
+ return std::find_if(
+ ultimates.begin(), ultimates.end(), [](const Symbol *component) {
+ CHECK(component);
+ return component->Corank() > 0;
+ });
}
-std::string ComponentVisitor::BuildResultDesignatorName() const {
- std::string designator{""};
- for (const Symbol *component : componentStack_) {
- designator += "%" + component->name().ToString();
- }
- return designator;
+PotentialComponentIterator::const_iterator FindEventOrLockPotentialComponent(
+ const DerivedTypeSpec &derived) {
+ PotentialComponentIterator potentials{derived};
+ return std::find_if(
+ potentials.begin(), potentials.end(), [](const Symbol *component) {
+ CHECK(component);
+ if (const auto *details{component->detailsIf<ObjectEntityDetails>()}) {
+ const DeclTypeSpec *type{details->type()};
+ return type && IsEventTypeOrLockType(type->AsDerived());
+ }
+ return false;
+ });
}
const Symbol *FindUltimateComponent(const DerivedTypeSpec &derived,
std::function<bool(const Symbol &)> predicate) {
- return ComponentVisitor{std::move(predicate)}
- .VisitUltimateComponents(derived)
- .Result();
+ UltimateComponentIterator ultimates{derived};
+ if (auto it{std::find_if(ultimates.begin(), ultimates.end(),
+ [&predicate](const Symbol *component) -> bool {
+ CHECK(component);
+ return predicate(*component);
+ })}) {
+ return *it;
+ }
+ return nullptr;
}
}
}
}
-// Derived type component visitor that applies a predicate on all the direct,
-// ultimate or Potential components. It stops at the first component that
-// verifies the given predicate and keep the component path to the result
-// (included at the end of the path). If no component verifies the predicate
-// the path is empty.
-// The component tree is visited in component declaration order,
-// visiting the subcomponent of a component before visiting the next component.
-// Parent components and procedure pointer components are visited.
-// Note that it is made in such a way that one can easily test and build info
-// message in the following way:
-// if (auto
-// visitor{ComponentVisitor{predicate}.VisitDirectComponents(derived)}) {
-// msg = visitor.BuildResultDesignatorName() + " verifies predicates";
+// Derived type component iterator that provides a C++ LegacyForwadIterator
+// iterator over the Ordered, Direct, Ultimate or Potential components of a
+// DerivedTypeSpec. These iterators can be used with STL algorithms
+// accepting LegacyForwadIterator.
+// The kind of component is a template argument of the iterator factory
+// ComponentIterator.
+//
+//
+// - Ordered components are the components from the component order defined
+// in 7.5.4.7, except that the parent components IS added between the parent
+// component order and the components in order of declaration.
+// This "deviation" is important for structure-constructor analysis.
+// For this kind of iterator, the component tree is recursively visited in the
+// following order:
+// - first, the Ordered components of the parent type (if relevant)
+// - then, the parent component (if relevant, different from 7.5.4.7!)
+// - then, the components in declaration order (without visiting subcomponents)
+//
+// - Ultimate, Direct and Potential components are as defined in 7.5.1.
+// Parent and procedure components are considered against these definitions.
+// For this kind of iterator, the component tree is recursively visited in the
+// following order:
+// - the parent component first (if relevant)
+// - then, the components of the parent type (if relevant)
+// + visiting the component and then, if it is derived type data component,
+// visiting the subcomponents before visiting the next
+// component in declaration order.
+// - then, components in declaration order, similarly to components of parent
+// type.
+// Here, the parent component is visited first so that search for a component
+// verifying a property will never descend into a component that already
+// verifies the property (this helps giving clearer feedback).
+//
+// ComponentIterator::const_iterator remain valid during the whole lifetime of
+// the DerivedTypeSpec passed by reference to the ComponentIterator factory.
+// Their validity is independent of the ComponentIterator factory lifetime.
+//
+// For safety and simplicity, the iterators are read only and can only be
+// incremented. This could be changed if desired.
+//
+// Note that iterators are made in such a way that one can easily test and build
+// info message in the following way:
+// ComponentIterator<ComponentIterator> comp{derived}
+// if (auto it{std::find_if(comp.begin(), comp.end(), predicate)}) {
+// msg = it.BuildResultDesignatorName() + " verifies predicates";
+// const Symbol* component{*it};
// ....
// }
-// It is safe to re-use the same object several times, previous results are
-// cleared before each visit.
-class ComponentVisitor {
+
+ENUM_CLASS(ComponentKind, Ordered, Direct, Ultimate, Potential)
+
+template<ComponentKind componentKind> class ComponentIterator {
public:
- ComponentVisitor(std::function<bool(const Symbol &)> &&predicate)
- : predicate_{std::move(predicate)} {}
-
- // Object is updated with the result during visit and returned by ref
- ComponentVisitor &VisitPotentialComponents(const DerivedTypeSpec &);
- ComponentVisitor &VisitUltimateComponents(const DerivedTypeSpec &);
- ComponentVisitor &VisitDirectComponents(const DerivedTypeSpec &);
-
- // Predefined common tests
- // Look for an ultimate component that is a coarray.
- static ComponentVisitor HasCoarrayUltimate(const DerivedTypeSpec &derived) {
- return ComponentVisitor{IsCoarray}.VisitUltimateComponents(derived);
- }
- // Look for a potential component of EVENT_TYPE or LOCK_TYPE from
- // ISO_FORTRAN_ENV module.
- static ComponentVisitor HasEventOrLockPotential(const DerivedTypeSpec &);
+ ComponentIterator(const DerivedTypeSpec &derived) : derived_{derived} {}
+ class const_iterator {
+ public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = const Symbol *;
+ using difference_type = void;
+ using pointer = const value_type *;
+ using reference = const value_type &;
- const Symbol *Result() const {
- return componentStack_.empty() ? nullptr : componentStack_.back();
- }
+ static const_iterator Create(const DerivedTypeSpec &);
+
+ const_iterator &operator++() {
+ Increment();
+ return *this;
+ }
+ const_iterator operator++(int) {
+ const_iterator tmp(*this);
+ Increment();
+ return tmp;
+ }
+ reference operator*() const {
+ CHECK(!componentPath_.empty());
+ return std::get<0>(componentPath_.back());
+ }
- bool HasResult() const { return Result() != nullptr; }
- explicit operator bool() const { return HasResult(); }
- // build designator name for messages if there is a result
- std::string BuildResultDesignatorName() const;
+ bool operator==(const const_iterator &other) const {
+ return componentPath_ == other.componentPath_;
+ }
+ bool operator!=(const const_iterator &other) const {
+ return !(*this == other);
+ }
+
+ // bool() operator indicates if the iterator can be dereferenced without
+ // having to check against an end() iterator.
+ explicit operator bool() const {
+ return !componentPath_.empty() &&
+ GetComponentSymbol(componentPath_.back());
+ }
+
+ // Build a designator name of the referenced component for messages.
+ // The designator helps when the component referred to by the iterator
+ // may be "buried" into other components. This gives the full
+ // path inside the iterated derived type: e.g "%a%b%c%ultimate"
+ // when (*it)->names() only gives "ultimate". Parent component are
+ // part of the path for clarity, even though they could be
+ // skipped.
+ std::string BuildResultDesignatorName() const;
+
+ private:
+ using name_iterator = typename std::list<SourceName>::const_iterator;
+ using ComponentPathNode =
+ std::tuple<const Symbol *, const DerivedTypeSpec *, name_iterator>;
+ using ComponentPath = std::vector<ComponentPathNode>;
+
+ static const Symbol *GetComponentSymbol(const ComponentPathNode &node) {
+ return std::get<0>(node);
+ }
+ static void SetComponentSymbol(ComponentPathNode &node, const Symbol *sym) {
+ std::get<0>(node) = sym;
+ }
+ static const Symbol &GetTypeSymbol(const ComponentPathNode &node) {
+ return std::get<1>(node)->typeSymbol();
+ }
+ static const Scope *GetScope(const ComponentPathNode &node) {
+ return std::get<1>(node)->scope();
+ }
+ static name_iterator &GetIterator(ComponentPathNode &node) {
+ return std::get<2>(node);
+ }
+ bool PlanComponentTraversal(const Symbol &component);
+ void Increment();
+ ComponentPath componentPath_;
+ };
+
+ const_iterator begin() { return cbegin(); }
+ const_iterator end() { return cend(); }
+ const_iterator cbegin() { return const_iterator::Create(derived_); }
+ const_iterator cend() { return const_iterator{}; }
private:
- SymbolVector componentStack_; // component path to result
- std::function<bool(const Symbol &)> predicate_;
+ const DerivedTypeSpec &derived_;
};
+extern template class ComponentIterator<ComponentKind::Ordered>;
+extern template class ComponentIterator<ComponentKind::Direct>;
+extern template class ComponentIterator<ComponentKind::Ultimate>;
+extern template class ComponentIterator<ComponentKind::Potential>;
+using OrderedComponentIterator = ComponentIterator<ComponentKind::Ordered>;
+using DirectComponentIterator = ComponentIterator<ComponentKind::Direct>;
+using UltimateComponentIterator = ComponentIterator<ComponentKind::Ultimate>;
+using PotentialComponentIterator = ComponentIterator<ComponentKind::Potential>;
+
+// Common component searches, the iterator returned is referring to the first
+// component, according to the order defined for the related ComponentIterator,
+// that verifies the property from the name.
+// If no components verifies the property, an end iterator (casting to false)
+// is returned. Otherwise, the returned iterator cast to true and can be
+// dereferenced.
+PotentialComponentIterator::const_iterator FindEventOrLockPotentialComponent(
+ const DerivedTypeSpec &);
+UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent(
+ const DerivedTypeSpec &);
}
#endif // FORTRAN_SEMANTICS_TOOLS_H_