brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.7 KiB · b257dad Raw
775 lines · cpp
1//===-- lib/Evaluate/variable.cpp -----------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "flang/Evaluate/variable.h"10#include "flang/Common/idioms.h"11#include "flang/Evaluate/check-expression.h"12#include "flang/Evaluate/fold.h"13#include "flang/Evaluate/tools.h"14#include "flang/Parser/char-block.h"15#include "flang/Parser/characters.h"16#include "flang/Parser/message.h"17#include "flang/Semantics/scope.h"18#include "flang/Semantics/symbol.h"19#include <type_traits>20 21using namespace Fortran::parser::literals;22 23namespace Fortran::evaluate {24 25// Constructors, accessors, mutators26 27Triplet::Triplet() : stride_{Expr<SubscriptInteger>{1}} {}28 29Triplet::Triplet(std::optional<Expr<SubscriptInteger>> &&l,30    std::optional<Expr<SubscriptInteger>> &&u,31    std::optional<Expr<SubscriptInteger>> &&s)32    : stride_{s ? std::move(*s) : Expr<SubscriptInteger>{1}} {33  if (l) {34    lower_.emplace(std::move(*l));35  }36  if (u) {37    upper_.emplace(std::move(*u));38  }39}40 41std::optional<Expr<SubscriptInteger>> Triplet::lower() const {42  if (lower_) {43    return {lower_.value().value()};44  }45  return std::nullopt;46}47 48Triplet &Triplet::set_lower(Expr<SubscriptInteger> &&expr) {49  lower_.emplace(std::move(expr));50  return *this;51}52 53std::optional<Expr<SubscriptInteger>> Triplet::upper() const {54  if (upper_) {55    return {upper_.value().value()};56  }57  return std::nullopt;58}59 60Triplet &Triplet::set_upper(Expr<SubscriptInteger> &&expr) {61  upper_.emplace(std::move(expr));62  return *this;63}64 65Expr<SubscriptInteger> Triplet::stride() const { return stride_.value(); }66 67Triplet &Triplet::set_stride(Expr<SubscriptInteger> &&expr) {68  stride_.value() = std::move(expr);69  return *this;70}71 72CoarrayRef::CoarrayRef(73    DataRef &&base, std::vector<Expr<SubscriptInteger>> &&css)74    : base_{std::move(base)}, cosubscript_(std::move(css)) {}75 76std::optional<Expr<SomeInteger>> CoarrayRef::stat() const {77  if (stat_) {78    return stat_.value().value();79  } else {80    return std::nullopt;81  }82}83 84std::optional<Expr<SomeType>> CoarrayRef::team() const {85  if (team_) {86    return team_.value().value();87  } else {88    return std::nullopt;89  }90}91 92std::optional<Expr<SomeType>> CoarrayRef::notify() const {93  if (notify_) {94    return notify_.value().value();95  } else {96    return std::nullopt;97  }98}99 100CoarrayRef &CoarrayRef::set_stat(Expr<SomeInteger> &&v) {101  CHECK(IsVariable(v));102  stat_.emplace(std::move(v));103  return *this;104}105 106CoarrayRef &CoarrayRef::set_team(Expr<SomeType> &&v) {107  team_.emplace(std::move(v));108  return *this;109}110 111CoarrayRef &CoarrayRef::set_notify(Expr<SomeType> &&v) {112  notify_.emplace(std::move(v));113  return *this;114}115 116const Symbol &CoarrayRef::GetFirstSymbol() const {117  return base().GetFirstSymbol();118}119 120const Symbol &CoarrayRef::GetLastSymbol() const {121  return base().GetLastSymbol();122}123 124void Substring::SetBounds(std::optional<Expr<SubscriptInteger>> &lower,125    std::optional<Expr<SubscriptInteger>> &upper) {126  if (lower) {127    set_lower(std::move(lower.value()));128  }129  if (upper) {130    set_upper(std::move(upper.value()));131  }132}133 134Expr<SubscriptInteger> Substring::lower() const {135  if (lower_) {136    return lower_.value().value();137  } else {138    return AsExpr(Constant<SubscriptInteger>{1});139  }140}141 142Substring &Substring::set_lower(Expr<SubscriptInteger> &&expr) {143  lower_.emplace(std::move(expr));144  return *this;145}146 147std::optional<Expr<SubscriptInteger>> Substring::upper() const {148  if (upper_) {149    return upper_.value().value();150  } else {151    return common::visit(152        common::visitors{153            [](const DataRef &dataRef) { return dataRef.LEN(); },154            [](const StaticDataObject::Pointer &object)155                -> std::optional<Expr<SubscriptInteger>> {156              return AsExpr(Constant<SubscriptInteger>{object->data().size()});157            },158        },159        parent_);160  }161}162 163Substring &Substring::set_upper(Expr<SubscriptInteger> &&expr) {164  upper_.emplace(std::move(expr));165  return *this;166}167 168std::optional<Expr<SomeCharacter>> Substring::Fold(FoldingContext &context) {169  if (!upper_) {170    upper_ = upper();171    if (!upper_) {172      return std::nullopt;173    }174  }175  upper_.value() = evaluate::Fold(context, std::move(upper_.value().value()));176  std::optional<ConstantSubscript> ubi{ToInt64(upper_.value().value())};177  if (!ubi) {178    return std::nullopt;179  }180  if (!lower_) {181    lower_ = AsExpr(Constant<SubscriptInteger>{1});182  }183  lower_.value() = evaluate::Fold(context, std::move(lower_.value().value()));184  std::optional<ConstantSubscript> lbi{ToInt64(lower_.value().value())};185  if (!lbi) {186    return std::nullopt;187  }188  if (*lbi > *ubi) { // empty result; canonicalize189    *lbi = 1;190    *ubi = 0;191    lower_ = AsExpr(Constant<SubscriptInteger>{*lbi});192    upper_ = AsExpr(Constant<SubscriptInteger>{*ubi});193  }194  std::optional<ConstantSubscript> length;195  std::optional<Expr<SomeCharacter>> strings; // a Constant<Character>196  if (const auto *literal{std::get_if<StaticDataObject::Pointer>(&parent_)}) {197    length = (*literal)->data().size();198    if (auto str{(*literal)->AsString()}) {199      strings =200          Expr<SomeCharacter>(Expr<Ascii>(Constant<Ascii>{std::move(*str)}));201    }202  } else if (const auto *dataRef{std::get_if<DataRef>(&parent_)}) {203    if (auto expr{AsGenericExpr(DataRef{*dataRef})}) {204      auto folded{evaluate::Fold(context, std::move(*expr))};205      if (IsActuallyConstant(folded)) {206        if (const auto *value{UnwrapExpr<Expr<SomeCharacter>>(folded)}) {207          strings = *value;208        }209      }210    }211  }212  std::optional<Expr<SomeCharacter>> result;213  if (strings) {214    result = common::visit(215        [&](const auto &expr) -> std::optional<Expr<SomeCharacter>> {216          using Type = typename std::decay_t<decltype(expr)>::Result;217          if (const auto *cc{std::get_if<Constant<Type>>(&expr.u)}) {218            if (auto substr{cc->Substring(*lbi, *ubi)}) {219              return Expr<SomeCharacter>{Expr<Type>{*substr}};220            }221          }222          return std::nullopt;223        },224        strings->u);225  }226  if (!result) { // error cases227    if (*lbi < 1) {228      context.Warn(common::UsageWarning::Bounds,229          "Lower bound (%jd) on substring is less than one"_warn_en_US,230          static_cast<std::intmax_t>(*lbi));231      *lbi = 1;232      lower_ = AsExpr(Constant<SubscriptInteger>{1});233    }234    if (length && *ubi > *length) {235      context.Warn(common::UsageWarning::Bounds,236          "Upper bound (%jd) on substring is greater than character length (%jd)"_warn_en_US,237          static_cast<std::intmax_t>(*ubi),238          static_cast<std::intmax_t>(*length));239      *ubi = *length;240      upper_ = AsExpr(Constant<SubscriptInteger>{*ubi});241    }242  }243  return result;244}245 246DescriptorInquiry::DescriptorInquiry(247    const NamedEntity &base, Field field, int dim)248    : base_{base}, field_{field}, dimension_{dim} {249  const Symbol &last{base_.GetLastSymbol()};250  CHECK(IsDescriptor(last));251  CHECK(((field == Field::Len || field == Field::Rank) && dim == 0) ||252      (field != Field::Len && dim >= 0 && dim < last.Rank()));253}254 255DescriptorInquiry::DescriptorInquiry(NamedEntity &&base, Field field, int dim)256    : base_{std::move(base)}, field_{field}, dimension_{dim} {257  const Symbol &last{base_.GetLastSymbol()};258  CHECK(IsDescriptor(last));259  CHECK((field == Field::Len && dim == 0) ||260      (field != Field::Len && dim >= 0 &&261          (dim < last.Rank() || IsAssumedRank(last))));262}263 264// LEN()265static std::optional<Expr<SubscriptInteger>> SymbolLEN(const Symbol &symbol) {266  const Symbol &ultimate{symbol.GetUltimate()};267  if (const auto *assoc{ultimate.detailsIf<semantics::AssocEntityDetails>()}) {268    if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(assoc->expr())}) {269      return chExpr->LEN();270    }271  }272  if (auto dyType{DynamicType::From(ultimate)}) {273    auto len{dyType->GetCharLength()};274    if (!len && ultimate.attrs().test(semantics::Attr::PARAMETER)) {275      // Its initializer determines the length of an implied-length named276      // constant.277      if (const auto *object{278              ultimate.detailsIf<semantics::ObjectEntityDetails>()}) {279        if (object->init()) {280          if (auto dyType2{DynamicType::From(*object->init())}) {281            len = dyType2->GetCharLength();282          }283        }284      }285    }286    if (len) {287      if (auto constLen{ToInt64(*len)}) {288        return Expr<SubscriptInteger>{std::max<std::int64_t>(*constLen, 0)};289      } else if (ultimate.owner().IsDerivedType() ||290          IsScopeInvariantExpr(*len)) {291        return AsExpr(Extremum<SubscriptInteger>{292            Ordering::Greater, Expr<SubscriptInteger>{0}, std::move(*len)});293      }294    }295  }296  if (IsDescriptor(ultimate) && !ultimate.owner().IsDerivedType()) {297    return Expr<SubscriptInteger>{298        DescriptorInquiry{NamedEntity{symbol}, DescriptorInquiry::Field::Len}};299  }300  return std::nullopt;301}302 303std::optional<Expr<SubscriptInteger>> BaseObject::LEN() const {304  return common::visit(305      common::visitors{306          [](const Symbol &symbol) { return SymbolLEN(symbol); },307          [](const StaticDataObject::Pointer &object)308              -> std::optional<Expr<SubscriptInteger>> {309            return AsExpr(Constant<SubscriptInteger>{object->data().size()});310          },311      },312      u);313}314 315std::optional<Expr<SubscriptInteger>> Component::LEN() const {316  return SymbolLEN(GetLastSymbol());317}318 319std::optional<Expr<SubscriptInteger>> NamedEntity::LEN() const {320  return SymbolLEN(GetLastSymbol());321}322 323std::optional<Expr<SubscriptInteger>> ArrayRef::LEN() const {324  return base_.LEN();325}326 327std::optional<Expr<SubscriptInteger>> CoarrayRef::LEN() const {328  return SymbolLEN(GetLastSymbol());329}330 331std::optional<Expr<SubscriptInteger>> DataRef::LEN() const {332  return common::visit(common::visitors{333                           [](SymbolRef symbol) { return SymbolLEN(symbol); },334                           [](const auto &x) { return x.LEN(); },335                       },336      u);337}338 339std::optional<Expr<SubscriptInteger>> Substring::LEN() const {340  if (auto top{upper()}) {341    return AsExpr(Extremum<SubscriptInteger>{Ordering::Greater,342        AsExpr(Constant<SubscriptInteger>{0}),343        *std::move(top) - lower() + AsExpr(Constant<SubscriptInteger>{1})});344  } else {345    return std::nullopt;346  }347}348 349template <typename T>350std::optional<Expr<SubscriptInteger>> Designator<T>::LEN() const {351  if constexpr (T::category == TypeCategory::Character) {352    return common::visit(common::visitors{353                             [](SymbolRef symbol) { return SymbolLEN(symbol); },354                             [](const auto &x) { return x.LEN(); },355                         },356        u);357  } else {358    common::die("Designator<non-char>::LEN() called");359    return std::nullopt;360  }361}362 363std::optional<Expr<SubscriptInteger>> ProcedureDesignator::LEN() const {364  using T = std::optional<Expr<SubscriptInteger>>;365  return common::visit(366      common::visitors{367          [](SymbolRef symbol) -> T { return SymbolLEN(symbol); },368          [](const common::CopyableIndirection<Component> &c) -> T {369            return c.value().LEN();370          },371          [](const SpecificIntrinsic &i) -> T {372            // Some cases whose results' lengths can be determined373            // from the lengths of their arguments are handled in374            // ProcedureRef::LEN() before coming here.375            if (const auto &result{i.characteristics.value().functionResult}) {376              if (const auto *type{result->GetTypeAndShape()}) {377                if (auto length{type->type().GetCharLength()}) {378                  return std::move(*length);379                }380              }381            }382            return std::nullopt;383          },384      },385      u);386}387 388// Rank()389int BaseObject::Rank() const {390  return common::visit(common::visitors{391                           [](SymbolRef symbol) { return symbol->Rank(); },392                           [](const StaticDataObject::Pointer &) { return 0; },393                       },394      u);395}396 397int Component::Rank() const {398  if (int rank{symbol_->Rank()}; rank > 0) {399    return rank;400  }401  return base().Rank();402}403 404int NamedEntity::Rank() const {405  return common::visit(common::visitors{406                           [](const SymbolRef s) { return s->Rank(); },407                           [](const Component &c) { return c.Rank(); },408                       },409      u_);410}411 412int Subscript::Rank() const {413  return common::visit(common::visitors{414                           [](const IndirectSubscriptIntegerExpr &x) {415                             return x.value().Rank();416                           },417                           [](const Triplet &) { return 1; },418                       },419      u);420}421 422int ArrayRef::Rank() const {423  int rank{0};424  for (const auto &expr : subscript_) {425    rank += expr.Rank();426  }427  if (rank > 0) {428    return rank;429  } else if (const Component * component{base_.UnwrapComponent()}) {430    return component->base().Rank();431  } else {432    return 0;433  }434}435 436int CoarrayRef::Rank() const { return base().Rank(); }437 438int DataRef::Rank() const {439  return common::visit(common::visitors{440                           [](SymbolRef symbol) { return symbol->Rank(); },441                           [](const auto &x) { return x.Rank(); },442                       },443      u);444}445 446int Substring::Rank() const {447  return common::visit(448      common::visitors{449          [](const DataRef &dataRef) { return dataRef.Rank(); },450          [](const StaticDataObject::Pointer &) { return 0; },451      },452      parent_);453}454 455int ComplexPart::Rank() const { return complex_.Rank(); }456 457template <typename T> int Designator<T>::Rank() const {458  return common::visit(common::visitors{459                           [](SymbolRef symbol) { return symbol->Rank(); },460                           [](const auto &x) { return x.Rank(); },461                       },462      u);463}464 465// Corank()466int BaseObject::Corank() const {467  return common::visit(common::visitors{468                           [](SymbolRef symbol) { return symbol->Corank(); },469                           [](const StaticDataObject::Pointer &) { return 0; },470                       },471      u);472}473 474int Component::Corank() const {475  if (int corank{symbol_->Corank()}; corank > 0) {476    return corank;477  } else if (semantics::IsAllocatableOrObjectPointer(&*symbol_)) {478    return 0; // coarray subobjects ca%a or ca%p are not coarrays479  } else {480    return base().Corank();481  }482}483 484int NamedEntity::Corank() const {485  return common::visit(common::visitors{486                           [](const SymbolRef s) { return s->Corank(); },487                           [](const Component &c) { return c.Corank(); },488                       },489      u_);490}491 492int ArrayRef::Corank() const {493  for (const Subscript &subs : subscript_) {494    if (!std::holds_alternative<Triplet>(subs.u) && subs.Rank() > 0) {495      return 0; // vector-valued subscript - subobject is not a coarray496    }497  }498  return base().Corank();499}500 501int DataRef::Corank() const {502  return common::visit(common::visitors{503                           [](SymbolRef symbol) { return symbol->Corank(); },504                           [](const auto &x) { return x.Corank(); },505                       },506      u);507}508 509int Substring::Corank() const {510  return common::visit(511      common::visitors{512          [](const DataRef &dataRef) { return dataRef.Corank(); },513          [](const StaticDataObject::Pointer &) { return 0; },514      },515      parent_);516}517 518int ComplexPart::Corank() const { return complex_.Corank(); }519 520template <typename T> int Designator<T>::Corank() const {521  return common::visit(common::visitors{522                           [](SymbolRef symbol) { return symbol->Corank(); },523                           [](const auto &x) { return x.Corank(); },524                       },525      u);526}527 528// GetBaseObject(), GetFirstSymbol(), GetLastSymbol(), &c.529const Symbol &Component::GetFirstSymbol() const {530  return base_.value().GetFirstSymbol();531}532 533const Symbol &NamedEntity::GetFirstSymbol() const {534  return common::visit(common::visitors{535                           [](SymbolRef s) -> const Symbol & { return s; },536                           [](const Component &c) -> const Symbol & {537                             return c.GetFirstSymbol();538                           },539                       },540      u_);541}542 543const Symbol &NamedEntity::GetLastSymbol() const {544  return common::visit(common::visitors{545                           [](SymbolRef s) -> const Symbol & { return s; },546                           [](const Component &c) -> const Symbol & {547                             return c.GetLastSymbol();548                           },549                       },550      u_);551}552 553const SymbolRef *NamedEntity::UnwrapSymbolRef() const {554  return common::visit(555      common::visitors{556          [](const SymbolRef &s) { return &s; },557          [](const Component &) -> const SymbolRef * { return nullptr; },558      },559      u_);560}561 562SymbolRef *NamedEntity::UnwrapSymbolRef() {563  return common::visit(common::visitors{564                           [](SymbolRef &s) { return &s; },565                           [](Component &) -> SymbolRef * { return nullptr; },566                       },567      u_);568}569 570const Component *NamedEntity::UnwrapComponent() const {571  return common::visit(572      common::visitors{573          [](SymbolRef) -> const Component * { return nullptr; },574          [](const Component &c) { return &c; },575      },576      u_);577}578 579Component *NamedEntity::UnwrapComponent() {580  return common::visit(common::visitors{581                           [](SymbolRef &) -> Component * { return nullptr; },582                           [](Component &c) { return &c; },583                       },584      u_);585}586 587const Symbol &ArrayRef::GetFirstSymbol() const {588  return base_.GetFirstSymbol();589}590 591const Symbol &ArrayRef::GetLastSymbol() const { return base_.GetLastSymbol(); }592 593const Symbol &DataRef::GetFirstSymbol() const {594  return *common::visit(common::visitors{595                            [](SymbolRef symbol) { return &*symbol; },596                            [](const auto &x) { return &x.GetFirstSymbol(); },597                        },598      u);599}600 601const Symbol &DataRef::GetLastSymbol() const {602  return *common::visit(common::visitors{603                            [](SymbolRef symbol) { return &*symbol; },604                            [](const auto &x) { return &x.GetLastSymbol(); },605                        },606      u);607}608 609BaseObject Substring::GetBaseObject() const {610  return common::visit(common::visitors{611                           [](const DataRef &dataRef) {612                             return BaseObject{dataRef.GetFirstSymbol()};613                           },614                           [](StaticDataObject::Pointer pointer) {615                             return BaseObject{std::move(pointer)};616                           },617                       },618      parent_);619}620 621const Symbol *Substring::GetLastSymbol() const {622  return common::visit(623      common::visitors{624          [](const DataRef &dataRef) { return &dataRef.GetLastSymbol(); },625          [](const auto &) -> const Symbol * { return nullptr; },626      },627      parent_);628}629 630template <typename T> BaseObject Designator<T>::GetBaseObject() const {631  return common::visit(632      common::visitors{633          [](SymbolRef symbol) { return BaseObject{symbol}; },634          [](const Substring &sstring) { return sstring.GetBaseObject(); },635          [](const auto &x) { return BaseObject{x.GetFirstSymbol()}; },636      },637      u);638}639 640template <typename T> const Symbol *Designator<T>::GetLastSymbol() const {641  return common::visit(642      common::visitors{643          [](SymbolRef symbol) { return &*symbol; },644          [](const Substring &sstring) { return sstring.GetLastSymbol(); },645          [](const auto &x) { return &x.GetLastSymbol(); },646      },647      u);648}649 650template <typename T>651std::optional<DynamicType> Designator<T>::GetType() const {652  if constexpr (IsLengthlessIntrinsicType<Result>) {653    return Result::GetType();654  }655  if constexpr (Result::category == TypeCategory::Character) {656    if (std::holds_alternative<Substring>(u)) {657      if (auto len{LEN()}) {658        if (auto n{ToInt64(*len)}) {659          return DynamicType{T::kind, *n};660        }661      }662      return DynamicType{TypeCategory::Character, T::kind};663    }664  }665  if (const Symbol * symbol{GetLastSymbol()}) {666    return DynamicType::From(*symbol);667  }668  return std::nullopt;669}670 671// Equality testing672 673// For the purposes of comparing type parameter expressions while674// testing the compatibility of procedure characteristics, two675// dummy arguments with the same position are considered equal.676static std::optional<int> GetDummyArgPosition(const Symbol &original) {677  const Symbol &symbol(original.GetUltimate());678  if (IsDummy(symbol)) {679    if (const Symbol * proc{symbol.owner().symbol()}) {680      if (const auto *subp{proc->detailsIf<semantics::SubprogramDetails>()}) {681        int j{0};682        for (const Symbol *arg : subp->dummyArgs()) {683          if (arg == &symbol) {684            return j;685          }686          ++j;687        }688      }689    }690  }691  return std::nullopt;692}693 694static bool AreSameSymbol(const Symbol &x, const Symbol &y) {695  if (&x == &y) {696    return true;697  }698  if (auto xPos{GetDummyArgPosition(x)}) {699    if (auto yPos{GetDummyArgPosition(y)}) {700      return *xPos == *yPos;701    }702  }703  return false;704}705 706// Implements operator==() for a union type, using special case handling707// for Symbol references.708template <typename A> static bool TestVariableEquality(const A &x, const A &y) {709  const SymbolRef *xSymbol{std::get_if<SymbolRef>(&x.u)};710  if (const SymbolRef * ySymbol{std::get_if<SymbolRef>(&y.u)}) {711    return xSymbol && AreSameSymbol(*xSymbol, *ySymbol);712  } else {713    return x.u == y.u;714  }715}716 717bool BaseObject::operator==(const BaseObject &that) const {718  return TestVariableEquality(*this, that);719}720bool Component::operator==(const Component &that) const {721  return base_ == that.base_ && &*symbol_ == &*that.symbol_;722}723bool NamedEntity::operator==(const NamedEntity &that) const {724  if (IsSymbol()) {725    return that.IsSymbol() &&726        AreSameSymbol(GetFirstSymbol(), that.GetFirstSymbol());727  } else {728    return !that.IsSymbol() && GetComponent() == that.GetComponent();729  }730}731bool TypeParamInquiry::operator==(const TypeParamInquiry &that) const {732  return &*parameter_ == &*that.parameter_ && base_ == that.base_;733}734bool Triplet::operator==(const Triplet &that) const {735  return lower_ == that.lower_ && upper_ == that.upper_ &&736      stride_ == that.stride_;737}738bool Subscript::operator==(const Subscript &that) const { return u == that.u; }739bool ArrayRef::operator==(const ArrayRef &that) const {740  return base_ == that.base_ && subscript_ == that.subscript_;741}742bool CoarrayRef::operator==(const CoarrayRef &that) const {743  return base_ == that.base_ && cosubscript_ == that.cosubscript_ &&744      stat_ == that.stat_ && team_ == that.team_;745}746bool DataRef::operator==(const DataRef &that) const {747  return TestVariableEquality(*this, that);748}749bool Substring::operator==(const Substring &that) const {750  return parent_ == that.parent_ && lower_ == that.lower_ &&751      upper_ == that.upper_;752}753bool ComplexPart::operator==(const ComplexPart &that) const {754  return part_ == that.part_ && complex_ == that.complex_;755}756bool ProcedureRef::operator==(const ProcedureRef &that) const {757  return proc_ == that.proc_ && arguments_ == that.arguments_;758}759template <typename T>760bool Designator<T>::operator==(const Designator<T> &that) const {761  return TestVariableEquality(*this, that);762}763bool DescriptorInquiry::operator==(const DescriptorInquiry &that) const {764  return field_ == that.field_ && base_ == that.base_ &&765      dimension_ == that.dimension_;766}767 768#ifdef _MSC_VER // disable bogus warning about missing definitions769#pragma warning(disable : 4661)770#endif771INSTANTIATE_VARIABLE_TEMPLATES772} // namespace Fortran::evaluate773 774template class Fortran::common::Indirection<Fortran::evaluate::Component, true>;775