164ab3302SCarolineConcatto //===-- lib/Evaluate/variable.cpp -----------------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto 
964ab3302SCarolineConcatto #include "flang/Evaluate/variable.h"
1064ab3302SCarolineConcatto #include "flang/Common/idioms.h"
118f0f9eadSpeter klausler #include "flang/Evaluate/check-expression.h"
1264ab3302SCarolineConcatto #include "flang/Evaluate/fold.h"
1364ab3302SCarolineConcatto #include "flang/Evaluate/tools.h"
1464ab3302SCarolineConcatto #include "flang/Parser/char-block.h"
1564ab3302SCarolineConcatto #include "flang/Parser/characters.h"
1664ab3302SCarolineConcatto #include "flang/Parser/message.h"
176f3d322fSpeter klausler #include "flang/Semantics/scope.h"
1864ab3302SCarolineConcatto #include "flang/Semantics/symbol.h"
1964ab3302SCarolineConcatto #include <type_traits>
2064ab3302SCarolineConcatto 
2164ab3302SCarolineConcatto using namespace Fortran::parser::literals;
2264ab3302SCarolineConcatto 
2364ab3302SCarolineConcatto namespace Fortran::evaluate {
2464ab3302SCarolineConcatto 
2564ab3302SCarolineConcatto // Constructors, accessors, mutators
2664ab3302SCarolineConcatto 
Triplet()2764ab3302SCarolineConcatto Triplet::Triplet() : stride_{Expr<SubscriptInteger>{1}} {}
2864ab3302SCarolineConcatto 
Triplet(std::optional<Expr<SubscriptInteger>> && l,std::optional<Expr<SubscriptInteger>> && u,std::optional<Expr<SubscriptInteger>> && s)2964ab3302SCarolineConcatto Triplet::Triplet(std::optional<Expr<SubscriptInteger>> &&l,
3064ab3302SCarolineConcatto     std::optional<Expr<SubscriptInteger>> &&u,
3164ab3302SCarolineConcatto     std::optional<Expr<SubscriptInteger>> &&s)
3264ab3302SCarolineConcatto     : stride_{s ? std::move(*s) : Expr<SubscriptInteger>{1}} {
3364ab3302SCarolineConcatto   if (l) {
3464ab3302SCarolineConcatto     lower_.emplace(std::move(*l));
3564ab3302SCarolineConcatto   }
3664ab3302SCarolineConcatto   if (u) {
3764ab3302SCarolineConcatto     upper_.emplace(std::move(*u));
3864ab3302SCarolineConcatto   }
3964ab3302SCarolineConcatto }
4064ab3302SCarolineConcatto 
lower() const4164ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> Triplet::lower() const {
4264ab3302SCarolineConcatto   if (lower_) {
4364ab3302SCarolineConcatto     return {lower_.value().value()};
4464ab3302SCarolineConcatto   }
4564ab3302SCarolineConcatto   return std::nullopt;
4664ab3302SCarolineConcatto }
4764ab3302SCarolineConcatto 
set_lower(Expr<SubscriptInteger> && expr)4864ab3302SCarolineConcatto Triplet &Triplet::set_lower(Expr<SubscriptInteger> &&expr) {
4964ab3302SCarolineConcatto   lower_.emplace(std::move(expr));
5064ab3302SCarolineConcatto   return *this;
5164ab3302SCarolineConcatto }
5264ab3302SCarolineConcatto 
upper() const5364ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> Triplet::upper() const {
5464ab3302SCarolineConcatto   if (upper_) {
5564ab3302SCarolineConcatto     return {upper_.value().value()};
5664ab3302SCarolineConcatto   }
5764ab3302SCarolineConcatto   return std::nullopt;
5864ab3302SCarolineConcatto }
5964ab3302SCarolineConcatto 
set_upper(Expr<SubscriptInteger> && expr)6064ab3302SCarolineConcatto Triplet &Triplet::set_upper(Expr<SubscriptInteger> &&expr) {
6164ab3302SCarolineConcatto   upper_.emplace(std::move(expr));
6264ab3302SCarolineConcatto   return *this;
6364ab3302SCarolineConcatto }
6464ab3302SCarolineConcatto 
stride() const6564ab3302SCarolineConcatto Expr<SubscriptInteger> Triplet::stride() const { return stride_.value(); }
6664ab3302SCarolineConcatto 
set_stride(Expr<SubscriptInteger> && expr)6764ab3302SCarolineConcatto Triplet &Triplet::set_stride(Expr<SubscriptInteger> &&expr) {
6864ab3302SCarolineConcatto   stride_.value() = std::move(expr);
6964ab3302SCarolineConcatto   return *this;
7064ab3302SCarolineConcatto }
7164ab3302SCarolineConcatto 
IsStrideOne() const7264ab3302SCarolineConcatto bool Triplet::IsStrideOne() const {
7364ab3302SCarolineConcatto   if (auto stride{ToInt64(stride_.value())}) {
7464ab3302SCarolineConcatto     return stride == 1;
7564ab3302SCarolineConcatto   } else {
7664ab3302SCarolineConcatto     return false;
7764ab3302SCarolineConcatto   }
7864ab3302SCarolineConcatto }
7964ab3302SCarolineConcatto 
CoarrayRef(SymbolVector && base,std::vector<Subscript> && ss,std::vector<Expr<SubscriptInteger>> && css)8064ab3302SCarolineConcatto CoarrayRef::CoarrayRef(SymbolVector &&base, std::vector<Subscript> &&ss,
8164ab3302SCarolineConcatto     std::vector<Expr<SubscriptInteger>> &&css)
8264ab3302SCarolineConcatto     : base_{std::move(base)}, subscript_(std::move(ss)),
8364ab3302SCarolineConcatto       cosubscript_(std::move(css)) {
8464ab3302SCarolineConcatto   CHECK(!base_.empty());
8564ab3302SCarolineConcatto   CHECK(!cosubscript_.empty());
8664ab3302SCarolineConcatto }
8764ab3302SCarolineConcatto 
stat() const8864ab3302SCarolineConcatto std::optional<Expr<SomeInteger>> CoarrayRef::stat() const {
8964ab3302SCarolineConcatto   if (stat_) {
9064ab3302SCarolineConcatto     return stat_.value().value();
9164ab3302SCarolineConcatto   } else {
9264ab3302SCarolineConcatto     return std::nullopt;
9364ab3302SCarolineConcatto   }
9464ab3302SCarolineConcatto }
9564ab3302SCarolineConcatto 
team() const9664ab3302SCarolineConcatto std::optional<Expr<SomeInteger>> CoarrayRef::team() const {
9764ab3302SCarolineConcatto   if (team_) {
9864ab3302SCarolineConcatto     return team_.value().value();
9964ab3302SCarolineConcatto   } else {
10064ab3302SCarolineConcatto     return std::nullopt;
10164ab3302SCarolineConcatto   }
10264ab3302SCarolineConcatto }
10364ab3302SCarolineConcatto 
set_stat(Expr<SomeInteger> && v)10464ab3302SCarolineConcatto CoarrayRef &CoarrayRef::set_stat(Expr<SomeInteger> &&v) {
10564ab3302SCarolineConcatto   CHECK(IsVariable(v));
10664ab3302SCarolineConcatto   stat_.emplace(std::move(v));
10764ab3302SCarolineConcatto   return *this;
10864ab3302SCarolineConcatto }
10964ab3302SCarolineConcatto 
set_team(Expr<SomeInteger> && v,bool isTeamNumber)11064ab3302SCarolineConcatto CoarrayRef &CoarrayRef::set_team(Expr<SomeInteger> &&v, bool isTeamNumber) {
11164ab3302SCarolineConcatto   CHECK(IsVariable(v));
11264ab3302SCarolineConcatto   team_.emplace(std::move(v));
11364ab3302SCarolineConcatto   teamIsTeamNumber_ = isTeamNumber;
11464ab3302SCarolineConcatto   return *this;
11564ab3302SCarolineConcatto }
11664ab3302SCarolineConcatto 
GetFirstSymbol() const11764ab3302SCarolineConcatto const Symbol &CoarrayRef::GetFirstSymbol() const { return base_.front(); }
11864ab3302SCarolineConcatto 
GetLastSymbol() const11964ab3302SCarolineConcatto const Symbol &CoarrayRef::GetLastSymbol() const { return base_.back(); }
12064ab3302SCarolineConcatto 
SetBounds(std::optional<Expr<SubscriptInteger>> & lower,std::optional<Expr<SubscriptInteger>> & upper)12164ab3302SCarolineConcatto void Substring::SetBounds(std::optional<Expr<SubscriptInteger>> &lower,
12264ab3302SCarolineConcatto     std::optional<Expr<SubscriptInteger>> &upper) {
12364ab3302SCarolineConcatto   if (lower) {
12464ab3302SCarolineConcatto     set_lower(std::move(lower.value()));
12564ab3302SCarolineConcatto   }
12664ab3302SCarolineConcatto   if (upper) {
12764ab3302SCarolineConcatto     set_upper(std::move(upper.value()));
12864ab3302SCarolineConcatto   }
12964ab3302SCarolineConcatto }
13064ab3302SCarolineConcatto 
lower() const13164ab3302SCarolineConcatto Expr<SubscriptInteger> Substring::lower() const {
13264ab3302SCarolineConcatto   if (lower_) {
13364ab3302SCarolineConcatto     return lower_.value().value();
13464ab3302SCarolineConcatto   } else {
13564ab3302SCarolineConcatto     return AsExpr(Constant<SubscriptInteger>{1});
13664ab3302SCarolineConcatto   }
13764ab3302SCarolineConcatto }
13864ab3302SCarolineConcatto 
set_lower(Expr<SubscriptInteger> && expr)13964ab3302SCarolineConcatto Substring &Substring::set_lower(Expr<SubscriptInteger> &&expr) {
14064ab3302SCarolineConcatto   lower_.emplace(std::move(expr));
14164ab3302SCarolineConcatto   return *this;
14264ab3302SCarolineConcatto }
14364ab3302SCarolineConcatto 
upper() const14464ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> Substring::upper() const {
14564ab3302SCarolineConcatto   if (upper_) {
14664ab3302SCarolineConcatto     return upper_.value().value();
14764ab3302SCarolineConcatto   } else {
148cd03e96fSPeter Klausler     return common::visit(
14964ab3302SCarolineConcatto         common::visitors{
15064ab3302SCarolineConcatto             [](const DataRef &dataRef) { return dataRef.LEN(); },
15164ab3302SCarolineConcatto             [](const StaticDataObject::Pointer &object)
15264ab3302SCarolineConcatto                 -> std::optional<Expr<SubscriptInteger>> {
15364ab3302SCarolineConcatto               return AsExpr(Constant<SubscriptInteger>{object->data().size()});
15464ab3302SCarolineConcatto             },
15564ab3302SCarolineConcatto         },
15664ab3302SCarolineConcatto         parent_);
15764ab3302SCarolineConcatto   }
15864ab3302SCarolineConcatto }
15964ab3302SCarolineConcatto 
set_upper(Expr<SubscriptInteger> && expr)16064ab3302SCarolineConcatto Substring &Substring::set_upper(Expr<SubscriptInteger> &&expr) {
16164ab3302SCarolineConcatto   upper_.emplace(std::move(expr));
16264ab3302SCarolineConcatto   return *this;
16364ab3302SCarolineConcatto }
16464ab3302SCarolineConcatto 
Fold(FoldingContext & context)16564ab3302SCarolineConcatto std::optional<Expr<SomeCharacter>> Substring::Fold(FoldingContext &context) {
16664ab3302SCarolineConcatto   if (!upper_) {
16764ab3302SCarolineConcatto     upper_ = upper();
16864ab3302SCarolineConcatto     if (!upper_) {
16964ab3302SCarolineConcatto       return std::nullopt;
17064ab3302SCarolineConcatto     }
17164ab3302SCarolineConcatto   }
17264ab3302SCarolineConcatto   upper_.value() = evaluate::Fold(context, std::move(upper_.value().value()));
173bd859cb4SPeter Klausler   std::optional<ConstantSubscript> ubi{ToInt64(upper_.value().value())};
174bd859cb4SPeter Klausler   if (!ubi) {
175bd859cb4SPeter Klausler     return std::nullopt;
17664ab3302SCarolineConcatto   }
177bd859cb4SPeter Klausler   if (!lower_) {
178bd859cb4SPeter Klausler     lower_ = AsExpr(Constant<SubscriptInteger>{1});
17964ab3302SCarolineConcatto   }
180bd859cb4SPeter Klausler   lower_.value() = evaluate::Fold(context, std::move(lower_.value().value()));
181bd859cb4SPeter Klausler   std::optional<ConstantSubscript> lbi{ToInt64(lower_.value().value())};
182bd859cb4SPeter Klausler   if (!lbi) {
183bd859cb4SPeter Klausler     return std::nullopt;
18464ab3302SCarolineConcatto   }
185bd859cb4SPeter Klausler   if (*lbi > *ubi) { // empty result; canonicalize
186bd859cb4SPeter Klausler     *lbi = 1;
187bd859cb4SPeter Klausler     *ubi = 0;
18864ab3302SCarolineConcatto     lower_ = AsExpr(Constant<SubscriptInteger>{*lbi});
18964ab3302SCarolineConcatto     upper_ = AsExpr(Constant<SubscriptInteger>{*ubi});
19064ab3302SCarolineConcatto   }
191bd859cb4SPeter Klausler   std::optional<ConstantSubscript> length;
192bd859cb4SPeter Klausler   std::optional<Expr<SomeCharacter>> strings; // a Constant<Character>
193bd859cb4SPeter Klausler   if (const auto *literal{std::get_if<StaticDataObject::Pointer>(&parent_)}) {
194bd859cb4SPeter Klausler     length = (*literal)->data().size();
195bd859cb4SPeter Klausler     if (auto str{(*literal)->AsString()}) {
196bd859cb4SPeter Klausler       strings =
197bd859cb4SPeter Klausler           Expr<SomeCharacter>(Expr<Ascii>(Constant<Ascii>{std::move(*str)}));
198dd3eb3f3SPeter Steinfeld     }
199bd859cb4SPeter Klausler   } else if (const auto *dataRef{std::get_if<DataRef>(&parent_)}) {
200bd859cb4SPeter Klausler     if (auto expr{AsGenericExpr(DataRef{*dataRef})}) {
201bd859cb4SPeter Klausler       auto folded{evaluate::Fold(context, std::move(*expr))};
202bd859cb4SPeter Klausler       if (IsActuallyConstant(folded)) {
203bd859cb4SPeter Klausler         if (const auto *value{UnwrapExpr<Expr<SomeCharacter>>(folded)}) {
204bd859cb4SPeter Klausler           strings = *value;
20564ab3302SCarolineConcatto         }
20664ab3302SCarolineConcatto       }
20764ab3302SCarolineConcatto     }
20864ab3302SCarolineConcatto   }
209bd859cb4SPeter Klausler   std::optional<Expr<SomeCharacter>> result;
210bd859cb4SPeter Klausler   if (strings) {
211cd03e96fSPeter Klausler     result = common::visit(
212bd859cb4SPeter Klausler         [&](const auto &expr) -> std::optional<Expr<SomeCharacter>> {
213bd859cb4SPeter Klausler           using Type = typename std::decay_t<decltype(expr)>::Result;
214bd859cb4SPeter Klausler           if (const auto *cc{std::get_if<Constant<Type>>(&expr.u)}) {
215bd859cb4SPeter Klausler             if (auto substr{cc->Substring(*lbi, *ubi)}) {
216bd859cb4SPeter Klausler               return Expr<SomeCharacter>{Expr<Type>{*substr}};
217bd859cb4SPeter Klausler             }
218bd859cb4SPeter Klausler           }
21964ab3302SCarolineConcatto           return std::nullopt;
220bd859cb4SPeter Klausler         },
221bd859cb4SPeter Klausler         strings->u);
222bd859cb4SPeter Klausler   }
223bd859cb4SPeter Klausler   if (!result) { // error cases
224bd859cb4SPeter Klausler     if (*lbi < 1) {
225bd859cb4SPeter Klausler       context.messages().Say(
226a53967cdSPeter Klausler           "Lower bound (%jd) on substring is less than one"_warn_en_US,
227bd859cb4SPeter Klausler           static_cast<std::intmax_t>(*lbi));
228bd859cb4SPeter Klausler       *lbi = 1;
229bd859cb4SPeter Klausler       lower_ = AsExpr(Constant<SubscriptInteger>{1});
230bd859cb4SPeter Klausler     }
231bd859cb4SPeter Klausler     if (length && *ubi > *length) {
232bd859cb4SPeter Klausler       context.messages().Say(
233a53967cdSPeter Klausler           "Upper bound (%jd) on substring is greater than character length (%jd)"_warn_en_US,
234bd859cb4SPeter Klausler           static_cast<std::intmax_t>(*ubi),
235bd859cb4SPeter Klausler           static_cast<std::intmax_t>(*length));
236bd859cb4SPeter Klausler       *ubi = *length;
237bd859cb4SPeter Klausler       upper_ = AsExpr(Constant<SubscriptInteger>{*ubi});
238bd859cb4SPeter Klausler     }
239bd859cb4SPeter Klausler   }
240bd859cb4SPeter Klausler   return result;
24164ab3302SCarolineConcatto }
24264ab3302SCarolineConcatto 
DescriptorInquiry(const NamedEntity & base,Field field,int dim)24364ab3302SCarolineConcatto DescriptorInquiry::DescriptorInquiry(
24464ab3302SCarolineConcatto     const NamedEntity &base, Field field, int dim)
24564ab3302SCarolineConcatto     : base_{base}, field_{field}, dimension_{dim} {
24664ab3302SCarolineConcatto   const Symbol &last{base_.GetLastSymbol()};
24764ab3302SCarolineConcatto   CHECK(IsDescriptor(last));
2489245f355Speter klausler   CHECK(((field == Field::Len || field == Field::Rank) && dim == 0) ||
24964ab3302SCarolineConcatto       (field != Field::Len && dim >= 0 && dim < last.Rank()));
25064ab3302SCarolineConcatto }
25164ab3302SCarolineConcatto 
DescriptorInquiry(NamedEntity && base,Field field,int dim)25264ab3302SCarolineConcatto DescriptorInquiry::DescriptorInquiry(NamedEntity &&base, Field field, int dim)
25364ab3302SCarolineConcatto     : base_{std::move(base)}, field_{field}, dimension_{dim} {
25464ab3302SCarolineConcatto   const Symbol &last{base_.GetLastSymbol()};
25564ab3302SCarolineConcatto   CHECK(IsDescriptor(last));
25664ab3302SCarolineConcatto   CHECK((field == Field::Len && dim == 0) ||
25764ab3302SCarolineConcatto       (field != Field::Len && dim >= 0 && dim < last.Rank()));
25864ab3302SCarolineConcatto }
25964ab3302SCarolineConcatto 
26064ab3302SCarolineConcatto // LEN()
SymbolLEN(const Symbol & symbol)2616f3d322fSpeter klausler static std::optional<Expr<SubscriptInteger>> SymbolLEN(const Symbol &symbol) {
2626f3d322fSpeter klausler   const Symbol &ultimate{symbol.GetUltimate()};
2636f3d322fSpeter klausler   if (const auto *assoc{ultimate.detailsIf<semantics::AssocEntityDetails>()}) {
2646f3d322fSpeter klausler     if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(assoc->expr())}) {
2656f3d322fSpeter klausler       return chExpr->LEN();
2666f3d322fSpeter klausler     }
2676f3d322fSpeter klausler   }
26878d60094SPeter Klausler   if (auto dyType{DynamicType::From(ultimate)}) {
26978d60094SPeter Klausler     if (auto len{dyType->GetCharLength()}) {
270*b70f507cSPeter Klausler       if (auto constLen{ToInt64(*len)}) {
271*b70f507cSPeter Klausler         return Expr<SubscriptInteger>{std::max<std::int64_t>(*constLen, 0)};
272*b70f507cSPeter Klausler       } else if (ultimate.owner().IsDerivedType() ||
273*b70f507cSPeter Klausler           IsScopeInvariantExpr(*len)) {
27478d60094SPeter Klausler         return AsExpr(Extremum<SubscriptInteger>{
27578d60094SPeter Klausler             Ordering::Greater, Expr<SubscriptInteger>{0}, std::move(*len)});
27678d60094SPeter Klausler       }
27778d60094SPeter Klausler     }
27878d60094SPeter Klausler   }
27978d60094SPeter Klausler   if (IsDescriptor(ultimate) && !ultimate.owner().IsDerivedType()) {
28078d60094SPeter Klausler     return Expr<SubscriptInteger>{
28178d60094SPeter Klausler         DescriptorInquiry{NamedEntity{symbol}, DescriptorInquiry::Field::Len}};
28264ab3302SCarolineConcatto   }
28364ab3302SCarolineConcatto   return std::nullopt;
28464ab3302SCarolineConcatto }
28564ab3302SCarolineConcatto 
LEN() const28664ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> BaseObject::LEN() const {
287cd03e96fSPeter Klausler   return common::visit(
28864ab3302SCarolineConcatto       common::visitors{
28964ab3302SCarolineConcatto           [](const Symbol &symbol) { return SymbolLEN(symbol); },
29064ab3302SCarolineConcatto           [](const StaticDataObject::Pointer &object)
29164ab3302SCarolineConcatto               -> std::optional<Expr<SubscriptInteger>> {
29264ab3302SCarolineConcatto             return AsExpr(Constant<SubscriptInteger>{object->data().size()});
29364ab3302SCarolineConcatto           },
29464ab3302SCarolineConcatto       },
29564ab3302SCarolineConcatto       u);
29664ab3302SCarolineConcatto }
29764ab3302SCarolineConcatto 
LEN() const29864ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> Component::LEN() const {
29964ab3302SCarolineConcatto   return SymbolLEN(GetLastSymbol());
30064ab3302SCarolineConcatto }
30164ab3302SCarolineConcatto 
LEN() const30264ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> NamedEntity::LEN() const {
30364ab3302SCarolineConcatto   return SymbolLEN(GetLastSymbol());
30464ab3302SCarolineConcatto }
30564ab3302SCarolineConcatto 
LEN() const30664ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> ArrayRef::LEN() const {
30764ab3302SCarolineConcatto   return base_.LEN();
30864ab3302SCarolineConcatto }
30964ab3302SCarolineConcatto 
LEN() const31064ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> CoarrayRef::LEN() const {
31164ab3302SCarolineConcatto   return SymbolLEN(GetLastSymbol());
31264ab3302SCarolineConcatto }
31364ab3302SCarolineConcatto 
LEN() const31464ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> DataRef::LEN() const {
315cd03e96fSPeter Klausler   return common::visit(common::visitors{
31664ab3302SCarolineConcatto                            [](SymbolRef symbol) { return SymbolLEN(symbol); },
31764ab3302SCarolineConcatto                            [](const auto &x) { return x.LEN(); },
31864ab3302SCarolineConcatto                        },
31964ab3302SCarolineConcatto       u);
32064ab3302SCarolineConcatto }
32164ab3302SCarolineConcatto 
LEN() const32264ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> Substring::LEN() const {
32364ab3302SCarolineConcatto   if (auto top{upper()}) {
32464ab3302SCarolineConcatto     return AsExpr(Extremum<SubscriptInteger>{Ordering::Greater,
32564ab3302SCarolineConcatto         AsExpr(Constant<SubscriptInteger>{0}),
32664ab3302SCarolineConcatto         *std::move(top) - lower() + AsExpr(Constant<SubscriptInteger>{1})});
32764ab3302SCarolineConcatto   } else {
32864ab3302SCarolineConcatto     return std::nullopt;
32964ab3302SCarolineConcatto   }
33064ab3302SCarolineConcatto }
33164ab3302SCarolineConcatto 
33264ab3302SCarolineConcatto template <typename T>
LEN() const33364ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> Designator<T>::LEN() const {
33464ab3302SCarolineConcatto   if constexpr (T::category == TypeCategory::Character) {
335cd03e96fSPeter Klausler     return common::visit(common::visitors{
33664ab3302SCarolineConcatto                              [](SymbolRef symbol) { return SymbolLEN(symbol); },
33764ab3302SCarolineConcatto                              [](const auto &x) { return x.LEN(); },
33864ab3302SCarolineConcatto                          },
33964ab3302SCarolineConcatto         u);
34064ab3302SCarolineConcatto   } else {
34164ab3302SCarolineConcatto     common::die("Designator<non-char>::LEN() called");
34264ab3302SCarolineConcatto     return std::nullopt;
34364ab3302SCarolineConcatto   }
34464ab3302SCarolineConcatto }
34564ab3302SCarolineConcatto 
LEN() const34664ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> ProcedureDesignator::LEN() const {
34764ab3302SCarolineConcatto   using T = std::optional<Expr<SubscriptInteger>>;
348cd03e96fSPeter Klausler   return common::visit(
34964ab3302SCarolineConcatto       common::visitors{
35064ab3302SCarolineConcatto           [](SymbolRef symbol) -> T { return SymbolLEN(symbol); },
35164ab3302SCarolineConcatto           [](const common::CopyableIndirection<Component> &c) -> T {
35264ab3302SCarolineConcatto             return c.value().LEN();
35364ab3302SCarolineConcatto           },
35464ab3302SCarolineConcatto           [](const SpecificIntrinsic &i) -> T {
355ac964175Speter klausler             // Some cases whose results' lengths can be determined
35664ab3302SCarolineConcatto             // from the lengths of their arguments are handled in
357ac964175Speter klausler             // ProcedureRef::LEN() before coming here.
358ac964175Speter klausler             if (const auto &result{i.characteristics.value().functionResult}) {
359ac964175Speter klausler               if (const auto *type{result->GetTypeAndShape()}) {
360ac964175Speter klausler                 if (auto length{type->type().GetCharLength()}) {
361ac964175Speter klausler                   return std::move(*length);
362ac964175Speter klausler                 }
363ac964175Speter klausler               }
364ac964175Speter klausler             }
36564ab3302SCarolineConcatto             return std::nullopt;
36664ab3302SCarolineConcatto           },
36764ab3302SCarolineConcatto       },
36864ab3302SCarolineConcatto       u);
36964ab3302SCarolineConcatto }
37064ab3302SCarolineConcatto 
37164ab3302SCarolineConcatto // Rank()
Rank() const37264ab3302SCarolineConcatto int BaseObject::Rank() const {
373cd03e96fSPeter Klausler   return common::visit(common::visitors{
37464ab3302SCarolineConcatto                            [](SymbolRef symbol) { return symbol->Rank(); },
37564ab3302SCarolineConcatto                            [](const StaticDataObject::Pointer &) { return 0; },
37664ab3302SCarolineConcatto                        },
37764ab3302SCarolineConcatto       u);
37864ab3302SCarolineConcatto }
37964ab3302SCarolineConcatto 
Rank() const38064ab3302SCarolineConcatto int Component::Rank() const {
38164ab3302SCarolineConcatto   if (int rank{symbol_->Rank()}; rank > 0) {
38264ab3302SCarolineConcatto     return rank;
38364ab3302SCarolineConcatto   }
38464ab3302SCarolineConcatto   return base().Rank();
38564ab3302SCarolineConcatto }
38664ab3302SCarolineConcatto 
Rank() const38764ab3302SCarolineConcatto int NamedEntity::Rank() const {
388cd03e96fSPeter Klausler   return common::visit(common::visitors{
38964ab3302SCarolineConcatto                            [](const SymbolRef s) { return s->Rank(); },
39064ab3302SCarolineConcatto                            [](const Component &c) { return c.Rank(); },
39164ab3302SCarolineConcatto                        },
39264ab3302SCarolineConcatto       u_);
39364ab3302SCarolineConcatto }
39464ab3302SCarolineConcatto 
Rank() const39564ab3302SCarolineConcatto int Subscript::Rank() const {
396cd03e96fSPeter Klausler   return common::visit(common::visitors{
39764ab3302SCarolineConcatto                            [](const IndirectSubscriptIntegerExpr &x) {
39864ab3302SCarolineConcatto                              return x.value().Rank();
39964ab3302SCarolineConcatto                            },
40064ab3302SCarolineConcatto                            [](const Triplet &) { return 1; },
40164ab3302SCarolineConcatto                        },
40264ab3302SCarolineConcatto       u);
40364ab3302SCarolineConcatto }
40464ab3302SCarolineConcatto 
Rank() const40564ab3302SCarolineConcatto int ArrayRef::Rank() const {
40664ab3302SCarolineConcatto   int rank{0};
40764ab3302SCarolineConcatto   for (const auto &expr : subscript_) {
40864ab3302SCarolineConcatto     rank += expr.Rank();
40964ab3302SCarolineConcatto   }
41064ab3302SCarolineConcatto   if (rank > 0) {
41164ab3302SCarolineConcatto     return rank;
41264ab3302SCarolineConcatto   } else if (const Component * component{base_.UnwrapComponent()}) {
41364ab3302SCarolineConcatto     return component->base().Rank();
41464ab3302SCarolineConcatto   } else {
41564ab3302SCarolineConcatto     return 0;
41664ab3302SCarolineConcatto   }
41764ab3302SCarolineConcatto }
41864ab3302SCarolineConcatto 
Rank() const41964ab3302SCarolineConcatto int CoarrayRef::Rank() const {
42064ab3302SCarolineConcatto   if (!subscript_.empty()) {
42164ab3302SCarolineConcatto     int rank{0};
42264ab3302SCarolineConcatto     for (const auto &expr : subscript_) {
42364ab3302SCarolineConcatto       rank += expr.Rank();
42464ab3302SCarolineConcatto     }
42564ab3302SCarolineConcatto     return rank;
42664ab3302SCarolineConcatto   } else {
42764ab3302SCarolineConcatto     return base_.back()->Rank();
42864ab3302SCarolineConcatto   }
42964ab3302SCarolineConcatto }
43064ab3302SCarolineConcatto 
Rank() const43164ab3302SCarolineConcatto int DataRef::Rank() const {
432cd03e96fSPeter Klausler   return common::visit(common::visitors{
43364ab3302SCarolineConcatto                            [](SymbolRef symbol) { return symbol->Rank(); },
43464ab3302SCarolineConcatto                            [](const auto &x) { return x.Rank(); },
43564ab3302SCarolineConcatto                        },
43664ab3302SCarolineConcatto       u);
43764ab3302SCarolineConcatto }
43864ab3302SCarolineConcatto 
Rank() const43964ab3302SCarolineConcatto int Substring::Rank() const {
440cd03e96fSPeter Klausler   return common::visit(
441cd03e96fSPeter Klausler       common::visitors{
44264ab3302SCarolineConcatto           [](const DataRef &dataRef) { return dataRef.Rank(); },
44364ab3302SCarolineConcatto           [](const StaticDataObject::Pointer &) { return 0; },
44464ab3302SCarolineConcatto       },
44564ab3302SCarolineConcatto       parent_);
44664ab3302SCarolineConcatto }
44764ab3302SCarolineConcatto 
Rank() const44864ab3302SCarolineConcatto int ComplexPart::Rank() const { return complex_.Rank(); }
44964ab3302SCarolineConcatto 
Rank() const45064ab3302SCarolineConcatto template <typename T> int Designator<T>::Rank() const {
451cd03e96fSPeter Klausler   return common::visit(common::visitors{
45264ab3302SCarolineConcatto                            [](SymbolRef symbol) { return symbol->Rank(); },
45364ab3302SCarolineConcatto                            [](const auto &x) { return x.Rank(); },
45464ab3302SCarolineConcatto                        },
45564ab3302SCarolineConcatto       u);
45664ab3302SCarolineConcatto }
45764ab3302SCarolineConcatto 
45864ab3302SCarolineConcatto // GetBaseObject(), GetFirstSymbol(), GetLastSymbol(), &c.
GetFirstSymbol() const45964ab3302SCarolineConcatto const Symbol &Component::GetFirstSymbol() const {
46064ab3302SCarolineConcatto   return base_.value().GetFirstSymbol();
46164ab3302SCarolineConcatto }
46264ab3302SCarolineConcatto 
GetFirstSymbol() const46364ab3302SCarolineConcatto const Symbol &NamedEntity::GetFirstSymbol() const {
464cd03e96fSPeter Klausler   return common::visit(common::visitors{
46564ab3302SCarolineConcatto                            [](SymbolRef s) -> const Symbol & { return s; },
46664ab3302SCarolineConcatto                            [](const Component &c) -> const Symbol & {
46764ab3302SCarolineConcatto                              return c.GetFirstSymbol();
46864ab3302SCarolineConcatto                            },
46964ab3302SCarolineConcatto                        },
47064ab3302SCarolineConcatto       u_);
47164ab3302SCarolineConcatto }
47264ab3302SCarolineConcatto 
GetLastSymbol() const47364ab3302SCarolineConcatto const Symbol &NamedEntity::GetLastSymbol() const {
474cd03e96fSPeter Klausler   return common::visit(common::visitors{
47564ab3302SCarolineConcatto                            [](SymbolRef s) -> const Symbol & { return s; },
47664ab3302SCarolineConcatto                            [](const Component &c) -> const Symbol & {
47764ab3302SCarolineConcatto                              return c.GetLastSymbol();
47864ab3302SCarolineConcatto                            },
47964ab3302SCarolineConcatto                        },
48064ab3302SCarolineConcatto       u_);
48164ab3302SCarolineConcatto }
48264ab3302SCarolineConcatto 
UnwrapComponent() const48364ab3302SCarolineConcatto const Component *NamedEntity::UnwrapComponent() const {
484cd03e96fSPeter Klausler   return common::visit(
485cd03e96fSPeter Klausler       common::visitors{
48664ab3302SCarolineConcatto           [](SymbolRef) -> const Component * { return nullptr; },
48764ab3302SCarolineConcatto           [](const Component &c) { return &c; },
48864ab3302SCarolineConcatto       },
48964ab3302SCarolineConcatto       u_);
49064ab3302SCarolineConcatto }
49164ab3302SCarolineConcatto 
UnwrapComponent()49264ab3302SCarolineConcatto Component *NamedEntity::UnwrapComponent() {
493cd03e96fSPeter Klausler   return common::visit(common::visitors{
49464ab3302SCarolineConcatto                            [](SymbolRef &) -> Component * { return nullptr; },
49564ab3302SCarolineConcatto                            [](Component &c) { return &c; },
49664ab3302SCarolineConcatto                        },
49764ab3302SCarolineConcatto       u_);
49864ab3302SCarolineConcatto }
49964ab3302SCarolineConcatto 
GetFirstSymbol() const50064ab3302SCarolineConcatto const Symbol &ArrayRef::GetFirstSymbol() const {
50164ab3302SCarolineConcatto   return base_.GetFirstSymbol();
50264ab3302SCarolineConcatto }
50364ab3302SCarolineConcatto 
GetLastSymbol() const50464ab3302SCarolineConcatto const Symbol &ArrayRef::GetLastSymbol() const { return base_.GetLastSymbol(); }
50564ab3302SCarolineConcatto 
GetFirstSymbol() const50664ab3302SCarolineConcatto const Symbol &DataRef::GetFirstSymbol() const {
507cd03e96fSPeter Klausler   return *common::visit(common::visitors{
50864ab3302SCarolineConcatto                             [](SymbolRef symbol) { return &*symbol; },
50964ab3302SCarolineConcatto                             [](const auto &x) { return &x.GetFirstSymbol(); },
51064ab3302SCarolineConcatto                         },
51164ab3302SCarolineConcatto       u);
51264ab3302SCarolineConcatto }
51364ab3302SCarolineConcatto 
GetLastSymbol() const51464ab3302SCarolineConcatto const Symbol &DataRef::GetLastSymbol() const {
515cd03e96fSPeter Klausler   return *common::visit(common::visitors{
51664ab3302SCarolineConcatto                             [](SymbolRef symbol) { return &*symbol; },
51764ab3302SCarolineConcatto                             [](const auto &x) { return &x.GetLastSymbol(); },
51864ab3302SCarolineConcatto                         },
51964ab3302SCarolineConcatto       u);
52064ab3302SCarolineConcatto }
52164ab3302SCarolineConcatto 
GetBaseObject() const52264ab3302SCarolineConcatto BaseObject Substring::GetBaseObject() const {
523cd03e96fSPeter Klausler   return common::visit(common::visitors{
52464ab3302SCarolineConcatto                            [](const DataRef &dataRef) {
52564ab3302SCarolineConcatto                              return BaseObject{dataRef.GetFirstSymbol()};
52664ab3302SCarolineConcatto                            },
52764ab3302SCarolineConcatto                            [](StaticDataObject::Pointer pointer) {
52864ab3302SCarolineConcatto                              return BaseObject{std::move(pointer)};
52964ab3302SCarolineConcatto                            },
53064ab3302SCarolineConcatto                        },
53164ab3302SCarolineConcatto       parent_);
53264ab3302SCarolineConcatto }
53364ab3302SCarolineConcatto 
GetLastSymbol() const53464ab3302SCarolineConcatto const Symbol *Substring::GetLastSymbol() const {
535cd03e96fSPeter Klausler   return common::visit(
53664ab3302SCarolineConcatto       common::visitors{
53764ab3302SCarolineConcatto           [](const DataRef &dataRef) { return &dataRef.GetLastSymbol(); },
53864ab3302SCarolineConcatto           [](const auto &) -> const Symbol * { return nullptr; },
53964ab3302SCarolineConcatto       },
54064ab3302SCarolineConcatto       parent_);
54164ab3302SCarolineConcatto }
54264ab3302SCarolineConcatto 
GetBaseObject() const54364ab3302SCarolineConcatto template <typename T> BaseObject Designator<T>::GetBaseObject() const {
544cd03e96fSPeter Klausler   return common::visit(
54564ab3302SCarolineConcatto       common::visitors{
54664ab3302SCarolineConcatto           [](SymbolRef symbol) { return BaseObject{symbol}; },
54764ab3302SCarolineConcatto           [](const Substring &sstring) { return sstring.GetBaseObject(); },
54864ab3302SCarolineConcatto           [](const auto &x) {
54964ab3302SCarolineConcatto #if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2
55064ab3302SCarolineConcatto             if constexpr (std::is_same_v<std::decay_t<decltype(x)>,
55164ab3302SCarolineConcatto                               Substring>) {
55264ab3302SCarolineConcatto               return x.GetBaseObject();
55364ab3302SCarolineConcatto             } else
55464ab3302SCarolineConcatto #endif
55564ab3302SCarolineConcatto               return BaseObject{x.GetFirstSymbol()};
55664ab3302SCarolineConcatto           },
55764ab3302SCarolineConcatto       },
55864ab3302SCarolineConcatto       u);
55964ab3302SCarolineConcatto }
56064ab3302SCarolineConcatto 
GetLastSymbol() const56164ab3302SCarolineConcatto template <typename T> const Symbol *Designator<T>::GetLastSymbol() const {
562cd03e96fSPeter Klausler   return common::visit(
56364ab3302SCarolineConcatto       common::visitors{
56464ab3302SCarolineConcatto           [](SymbolRef symbol) { return &*symbol; },
56564ab3302SCarolineConcatto           [](const Substring &sstring) { return sstring.GetLastSymbol(); },
56664ab3302SCarolineConcatto           [](const auto &x) {
56764ab3302SCarolineConcatto #if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2
56864ab3302SCarolineConcatto             if constexpr (std::is_same_v<std::decay_t<decltype(x)>,
56964ab3302SCarolineConcatto                               Substring>) {
57064ab3302SCarolineConcatto               return x.GetLastSymbol();
57164ab3302SCarolineConcatto             } else
57264ab3302SCarolineConcatto #endif
57364ab3302SCarolineConcatto               return &x.GetLastSymbol();
57464ab3302SCarolineConcatto           },
57564ab3302SCarolineConcatto       },
57664ab3302SCarolineConcatto       u);
57764ab3302SCarolineConcatto }
57864ab3302SCarolineConcatto 
5791f879005STim Keith template <typename T>
GetType() const5801f879005STim Keith std::optional<DynamicType> Designator<T>::GetType() const {
58164ab3302SCarolineConcatto   if constexpr (IsLengthlessIntrinsicType<Result>) {
58219d7cc2eSPeter Steinfeld     return Result::GetType();
58319d7cc2eSPeter Steinfeld   } else if (const Symbol * symbol{GetLastSymbol()}) {
58419d7cc2eSPeter Steinfeld     return DynamicType::From(*symbol);
58519d7cc2eSPeter Steinfeld   } else if constexpr (Result::category == TypeCategory::Character) {
58619d7cc2eSPeter Steinfeld     if (const Substring * substring{std::get_if<Substring>(&u)}) {
58719d7cc2eSPeter Steinfeld       const auto *parent{substring->GetParentIf<StaticDataObject::Pointer>()};
58819d7cc2eSPeter Steinfeld       CHECK(parent);
58919d7cc2eSPeter Steinfeld       return DynamicType{TypeCategory::Character, (*parent)->itemBytes()};
59064ab3302SCarolineConcatto     }
59164ab3302SCarolineConcatto   }
59219d7cc2eSPeter Steinfeld   return std::nullopt;
59319d7cc2eSPeter Steinfeld }
59464ab3302SCarolineConcatto 
AsNamedEntity(const SymbolVector & x)59564ab3302SCarolineConcatto static NamedEntity AsNamedEntity(const SymbolVector &x) {
59664ab3302SCarolineConcatto   CHECK(!x.empty());
59764ab3302SCarolineConcatto   NamedEntity result{x.front()};
59864ab3302SCarolineConcatto   int j{0};
59964ab3302SCarolineConcatto   for (const Symbol &symbol : x) {
60064ab3302SCarolineConcatto     if (j++ != 0) {
60164ab3302SCarolineConcatto       DataRef base{result.IsSymbol() ? DataRef{result.GetLastSymbol()}
60264ab3302SCarolineConcatto                                      : DataRef{result.GetComponent()}};
60364ab3302SCarolineConcatto       result = NamedEntity{Component{std::move(base), symbol}};
60464ab3302SCarolineConcatto     }
60564ab3302SCarolineConcatto   }
60664ab3302SCarolineConcatto   return result;
60764ab3302SCarolineConcatto }
60864ab3302SCarolineConcatto 
GetBase() const60964ab3302SCarolineConcatto NamedEntity CoarrayRef::GetBase() const { return AsNamedEntity(base_); }
61064ab3302SCarolineConcatto 
61164ab3302SCarolineConcatto // Equality testing
61264ab3302SCarolineConcatto 
61364ab3302SCarolineConcatto // For the purposes of comparing type parameter expressions while
61464ab3302SCarolineConcatto // testing the compatibility of procedure characteristics, two
61564ab3302SCarolineConcatto // object dummy arguments with the same name are considered equal.
AreSameSymbol(const Symbol & x,const Symbol & y)616e03b20e6Speter klausler static bool AreSameSymbol(const Symbol &x, const Symbol &y) {
61764ab3302SCarolineConcatto   if (&x == &y) {
61864ab3302SCarolineConcatto     return true;
61964ab3302SCarolineConcatto   }
62064ab3302SCarolineConcatto   if (x.name() == y.name()) {
62164ab3302SCarolineConcatto     if (const auto *xObject{x.detailsIf<semantics::ObjectEntityDetails>()}) {
62264ab3302SCarolineConcatto       if (const auto *yObject{y.detailsIf<semantics::ObjectEntityDetails>()}) {
62364ab3302SCarolineConcatto         return xObject->isDummy() && yObject->isDummy();
62464ab3302SCarolineConcatto       }
62564ab3302SCarolineConcatto     }
62664ab3302SCarolineConcatto   }
62764ab3302SCarolineConcatto   return false;
62864ab3302SCarolineConcatto }
62964ab3302SCarolineConcatto 
630e03b20e6Speter klausler // Implements operator==() for a union type, using special case handling
631e03b20e6Speter klausler // for Symbol references.
TestVariableEquality(const A & x,const A & y)632e03b20e6Speter klausler template <typename A> static bool TestVariableEquality(const A &x, const A &y) {
633e03b20e6Speter klausler   const SymbolRef *xSymbol{std::get_if<SymbolRef>(&x.u)};
634e03b20e6Speter klausler   if (const SymbolRef * ySymbol{std::get_if<SymbolRef>(&y.u)}) {
635e03b20e6Speter klausler     return xSymbol && AreSameSymbol(*xSymbol, *ySymbol);
636e03b20e6Speter klausler   } else {
637e03b20e6Speter klausler     return x.u == y.u;
638e03b20e6Speter klausler   }
639e03b20e6Speter klausler }
640e03b20e6Speter klausler 
operator ==(const BaseObject & that) const64164ab3302SCarolineConcatto bool BaseObject::operator==(const BaseObject &that) const {
64264ab3302SCarolineConcatto   return TestVariableEquality(*this, that);
64364ab3302SCarolineConcatto }
operator ==(const Component & that) const64464ab3302SCarolineConcatto bool Component::operator==(const Component &that) const {
64564ab3302SCarolineConcatto   return base_ == that.base_ && &*symbol_ == &*that.symbol_;
64664ab3302SCarolineConcatto }
operator ==(const NamedEntity & that) const64764ab3302SCarolineConcatto bool NamedEntity::operator==(const NamedEntity &that) const {
64864ab3302SCarolineConcatto   if (IsSymbol()) {
64964ab3302SCarolineConcatto     return that.IsSymbol() &&
65064ab3302SCarolineConcatto         AreSameSymbol(GetFirstSymbol(), that.GetFirstSymbol());
65164ab3302SCarolineConcatto   } else {
65264ab3302SCarolineConcatto     return !that.IsSymbol() && GetComponent() == that.GetComponent();
65364ab3302SCarolineConcatto   }
65464ab3302SCarolineConcatto }
operator ==(const TypeParamInquiry & that) const6554cbfd93aSpeter klausler bool TypeParamInquiry::operator==(const TypeParamInquiry &that) const {
65664ab3302SCarolineConcatto   return &*parameter_ == &*that.parameter_ && base_ == that.base_;
65764ab3302SCarolineConcatto }
operator ==(const Triplet & that) const65864ab3302SCarolineConcatto bool Triplet::operator==(const Triplet &that) const {
65964ab3302SCarolineConcatto   return lower_ == that.lower_ && upper_ == that.upper_ &&
66064ab3302SCarolineConcatto       stride_ == that.stride_;
66164ab3302SCarolineConcatto }
operator ==(const Subscript & that) const662e03b20e6Speter klausler bool Subscript::operator==(const Subscript &that) const { return u == that.u; }
operator ==(const ArrayRef & that) const66364ab3302SCarolineConcatto bool ArrayRef::operator==(const ArrayRef &that) const {
66464ab3302SCarolineConcatto   return base_ == that.base_ && subscript_ == that.subscript_;
66564ab3302SCarolineConcatto }
operator ==(const CoarrayRef & that) const66664ab3302SCarolineConcatto bool CoarrayRef::operator==(const CoarrayRef &that) const {
66764ab3302SCarolineConcatto   return base_ == that.base_ && subscript_ == that.subscript_ &&
66864ab3302SCarolineConcatto       cosubscript_ == that.cosubscript_ && stat_ == that.stat_ &&
66964ab3302SCarolineConcatto       team_ == that.team_ && teamIsTeamNumber_ == that.teamIsTeamNumber_;
67064ab3302SCarolineConcatto }
operator ==(const DataRef & that) const67164ab3302SCarolineConcatto bool DataRef::operator==(const DataRef &that) const {
67264ab3302SCarolineConcatto   return TestVariableEquality(*this, that);
67364ab3302SCarolineConcatto }
operator ==(const Substring & that) const67464ab3302SCarolineConcatto bool Substring::operator==(const Substring &that) const {
67564ab3302SCarolineConcatto   return parent_ == that.parent_ && lower_ == that.lower_ &&
67664ab3302SCarolineConcatto       upper_ == that.upper_;
67764ab3302SCarolineConcatto }
operator ==(const ComplexPart & that) const67864ab3302SCarolineConcatto bool ComplexPart::operator==(const ComplexPart &that) const {
67964ab3302SCarolineConcatto   return part_ == that.part_ && complex_ == that.complex_;
68064ab3302SCarolineConcatto }
operator ==(const ProcedureRef & that) const68164ab3302SCarolineConcatto bool ProcedureRef::operator==(const ProcedureRef &that) const {
68264ab3302SCarolineConcatto   return proc_ == that.proc_ && arguments_ == that.arguments_;
68364ab3302SCarolineConcatto }
684e03b20e6Speter klausler template <typename T>
operator ==(const Designator<T> & that) const685e03b20e6Speter klausler bool Designator<T>::operator==(const Designator<T> &that) const {
686e03b20e6Speter klausler   return TestVariableEquality(*this, that);
687e03b20e6Speter klausler }
operator ==(const DescriptorInquiry & that) const68864ab3302SCarolineConcatto bool DescriptorInquiry::operator==(const DescriptorInquiry &that) const {
68964ab3302SCarolineConcatto   return field_ == that.field_ && base_ == that.base_ &&
69064ab3302SCarolineConcatto       dimension_ == that.dimension_;
69164ab3302SCarolineConcatto }
69264ab3302SCarolineConcatto 
6935c5bde1bSPeter Klausler #ifdef _MSC_VER // disable bogus warning about missing definitions
6945c5bde1bSPeter Klausler #pragma warning(disable : 4661)
6955c5bde1bSPeter Klausler #endif
69664ab3302SCarolineConcatto INSTANTIATE_VARIABLE_TEMPLATES
6971f879005STim Keith } // namespace Fortran::evaluate
69864ab3302SCarolineConcatto 
69964ab3302SCarolineConcatto template class Fortran::common::Indirection<Fortran::evaluate::Component, true>;
700