164ab3302SCarolineConcatto //===-- lib/Evaluate/expression.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/expression.h" 1064ab3302SCarolineConcatto #include "int-power.h" 1164ab3302SCarolineConcatto #include "flang/Common/idioms.h" 1264ab3302SCarolineConcatto #include "flang/Evaluate/common.h" 1364ab3302SCarolineConcatto #include "flang/Evaluate/tools.h" 1464ab3302SCarolineConcatto #include "flang/Evaluate/variable.h" 15b34f1168SPeter Steinfeld #include "flang/Parser/char-block.h" 1664ab3302SCarolineConcatto #include "flang/Parser/message.h" 17b34f1168SPeter Steinfeld #include "flang/Semantics/scope.h" 18b34f1168SPeter Steinfeld #include "flang/Semantics/symbol.h" 19b34f1168SPeter Steinfeld #include "flang/Semantics/tools.h" 20b34f1168SPeter Steinfeld #include "flang/Semantics/type.h" 218670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h" 2264ab3302SCarolineConcatto #include <string> 2364ab3302SCarolineConcatto #include <type_traits> 2464ab3302SCarolineConcatto 2564ab3302SCarolineConcatto using namespace Fortran::parser::literals; 2664ab3302SCarolineConcatto 2764ab3302SCarolineConcatto namespace Fortran::evaluate { 2864ab3302SCarolineConcatto 2964ab3302SCarolineConcatto template <int KIND> 3064ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> 3164ab3302SCarolineConcatto Expr<Type<TypeCategory::Character, KIND>>::LEN() const { 3264ab3302SCarolineConcatto using T = std::optional<Expr<SubscriptInteger>>; 33cd03e96fSPeter Klausler return common::visit( 3464ab3302SCarolineConcatto common::visitors{ 3564ab3302SCarolineConcatto [](const Constant<Result> &c) -> T { 3664ab3302SCarolineConcatto return AsExpr(Constant<SubscriptInteger>{c.LEN()}); 3764ab3302SCarolineConcatto }, 3801688ee9SPeter Klausler [](const ArrayConstructor<Result> &a) -> T { 3901688ee9SPeter Klausler if (const auto *len{a.LEN()}) { 4001688ee9SPeter Klausler return T{*len}; 4101688ee9SPeter Klausler } else { 4201688ee9SPeter Klausler return std::nullopt; 4301688ee9SPeter Klausler } 4401688ee9SPeter Klausler }, 4564ab3302SCarolineConcatto [](const Parentheses<Result> &x) { return x.left().LEN(); }, 4664ab3302SCarolineConcatto [](const Convert<Result> &x) { 47cd03e96fSPeter Klausler return common::visit( 4864ab3302SCarolineConcatto [&](const auto &kx) { return kx.LEN(); }, x.left().u); 4964ab3302SCarolineConcatto }, 5064ab3302SCarolineConcatto [](const Concat<KIND> &c) -> T { 5164ab3302SCarolineConcatto if (auto llen{c.left().LEN()}) { 5264ab3302SCarolineConcatto if (auto rlen{c.right().LEN()}) { 5364ab3302SCarolineConcatto return *std::move(llen) + *std::move(rlen); 5464ab3302SCarolineConcatto } 5564ab3302SCarolineConcatto } 5664ab3302SCarolineConcatto return std::nullopt; 5764ab3302SCarolineConcatto }, 5864ab3302SCarolineConcatto [](const Extremum<Result> &c) -> T { 5964ab3302SCarolineConcatto if (auto llen{c.left().LEN()}) { 6064ab3302SCarolineConcatto if (auto rlen{c.right().LEN()}) { 6164ab3302SCarolineConcatto return Expr<SubscriptInteger>{Extremum<SubscriptInteger>{ 6264ab3302SCarolineConcatto Ordering::Greater, *std::move(llen), *std::move(rlen)}}; 6364ab3302SCarolineConcatto } 6464ab3302SCarolineConcatto } 6564ab3302SCarolineConcatto return std::nullopt; 6664ab3302SCarolineConcatto }, 6764ab3302SCarolineConcatto [](const Designator<Result> &dr) { return dr.LEN(); }, 6864ab3302SCarolineConcatto [](const FunctionRef<Result> &fr) { return fr.LEN(); }, 6964ab3302SCarolineConcatto [](const SetLength<KIND> &x) -> T { return x.right(); }, 7064ab3302SCarolineConcatto }, 7164ab3302SCarolineConcatto u); 7264ab3302SCarolineConcatto } 7364ab3302SCarolineConcatto 7464ab3302SCarolineConcatto Expr<SomeType>::~Expr() = default; 7564ab3302SCarolineConcatto 7664ab3302SCarolineConcatto #if defined(__APPLE__) && defined(__GNUC__) 7764ab3302SCarolineConcatto template <typename A> 7864ab3302SCarolineConcatto typename ExpressionBase<A>::Derived &ExpressionBase<A>::derived() { 7964ab3302SCarolineConcatto return *static_cast<Derived *>(this); 8064ab3302SCarolineConcatto } 8164ab3302SCarolineConcatto 8264ab3302SCarolineConcatto template <typename A> 8364ab3302SCarolineConcatto const typename ExpressionBase<A>::Derived &ExpressionBase<A>::derived() const { 8464ab3302SCarolineConcatto return *static_cast<const Derived *>(this); 8564ab3302SCarolineConcatto } 8664ab3302SCarolineConcatto #endif 8764ab3302SCarolineConcatto 8864ab3302SCarolineConcatto template <typename A> 8964ab3302SCarolineConcatto std::optional<DynamicType> ExpressionBase<A>::GetType() const { 9064ab3302SCarolineConcatto if constexpr (IsLengthlessIntrinsicType<Result>) { 9164ab3302SCarolineConcatto return Result::GetType(); 9264ab3302SCarolineConcatto } else { 93cd03e96fSPeter Klausler return common::visit( 9464ab3302SCarolineConcatto [&](const auto &x) -> std::optional<DynamicType> { 9564ab3302SCarolineConcatto if constexpr (!common::HasMember<decltype(x), TypelessExpression>) { 9664ab3302SCarolineConcatto return x.GetType(); 9764ab3302SCarolineConcatto } 9864ab3302SCarolineConcatto return std::nullopt; // w/o "else" to dodge bogus g++ 8.1 warning 9964ab3302SCarolineConcatto }, 10064ab3302SCarolineConcatto derived().u); 10164ab3302SCarolineConcatto } 10264ab3302SCarolineConcatto } 10364ab3302SCarolineConcatto 10464ab3302SCarolineConcatto template <typename A> int ExpressionBase<A>::Rank() const { 105cd03e96fSPeter Klausler return common::visit( 10664ab3302SCarolineConcatto [](const auto &x) { 10764ab3302SCarolineConcatto if constexpr (common::HasMember<decltype(x), TypelessExpression>) { 10864ab3302SCarolineConcatto return 0; 10964ab3302SCarolineConcatto } else { 11064ab3302SCarolineConcatto return x.Rank(); 11164ab3302SCarolineConcatto } 11264ab3302SCarolineConcatto }, 11364ab3302SCarolineConcatto derived().u); 11464ab3302SCarolineConcatto } 11564ab3302SCarolineConcatto 116*3a8a52f4SPeter Klausler template <typename A> int ExpressionBase<A>::Corank() const { 117*3a8a52f4SPeter Klausler return common::visit( 118*3a8a52f4SPeter Klausler [](const auto &x) { 119*3a8a52f4SPeter Klausler if constexpr (common::HasMember<decltype(x), TypelessExpression>) { 120*3a8a52f4SPeter Klausler return 0; 121*3a8a52f4SPeter Klausler } else { 122*3a8a52f4SPeter Klausler return x.Corank(); 123*3a8a52f4SPeter Klausler } 124*3a8a52f4SPeter Klausler }, 125*3a8a52f4SPeter Klausler derived().u); 126*3a8a52f4SPeter Klausler } 127*3a8a52f4SPeter Klausler 128f6ecea1aSpeter klausler DynamicType Parentheses<SomeDerived>::GetType() const { 129f6ecea1aSpeter klausler return left().GetType().value(); 130f6ecea1aSpeter klausler } 131f6ecea1aSpeter klausler 132fdcbb540SJean Perier #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 133fdcbb540SJean Perier template <typename A> LLVM_DUMP_METHOD void ExpressionBase<A>::dump() const { 134fdcbb540SJean Perier llvm::errs() << "Expr is <{" << AsFortran() << "}>\n"; 135fdcbb540SJean Perier } 136fdcbb540SJean Perier #endif 137fdcbb540SJean Perier 138e03b20e6Speter klausler // Equality testing 13964ab3302SCarolineConcatto 140d2126ec1SPeter Klausler template <typename A> bool Extremum<A>::operator==(const Extremum &that) const { 141d2126ec1SPeter Klausler return ordering == that.ordering && Base::operator==(that); 142d2126ec1SPeter Klausler } 143d2126ec1SPeter Klausler 144d2126ec1SPeter Klausler template <int KIND> 145d2126ec1SPeter Klausler bool LogicalOperation<KIND>::operator==(const LogicalOperation &that) const { 146d2126ec1SPeter Klausler return logicalOperator == that.logicalOperator && Base::operator==(that); 147d2126ec1SPeter Klausler } 148d2126ec1SPeter Klausler 149d2126ec1SPeter Klausler template <typename A> 150d2126ec1SPeter Klausler bool Relational<A>::operator==(const Relational &that) const { 151d2126ec1SPeter Klausler return opr == that.opr && Base::operator==(that); 152d2126ec1SPeter Klausler } 153d2126ec1SPeter Klausler 154d2126ec1SPeter Klausler bool Relational<SomeType>::operator==(const Relational &that) const { 155d2126ec1SPeter Klausler return u == that.u; 156d2126ec1SPeter Klausler } 157d2126ec1SPeter Klausler 15864ab3302SCarolineConcatto bool ImpliedDoIndex::operator==(const ImpliedDoIndex &that) const { 15964ab3302SCarolineConcatto return name == that.name; 16064ab3302SCarolineConcatto } 16164ab3302SCarolineConcatto 16264ab3302SCarolineConcatto template <typename T> 16364ab3302SCarolineConcatto bool ImpliedDo<T>::operator==(const ImpliedDo<T> &that) const { 16464ab3302SCarolineConcatto return name_ == that.name_ && lower_ == that.lower_ && 16564ab3302SCarolineConcatto upper_ == that.upper_ && stride_ == that.stride_ && 16664ab3302SCarolineConcatto values_ == that.values_; 16764ab3302SCarolineConcatto } 16864ab3302SCarolineConcatto 169e03b20e6Speter klausler template <typename T> 170e03b20e6Speter klausler bool ArrayConstructorValue<T>::operator==( 171e03b20e6Speter klausler const ArrayConstructorValue<T> &that) const { 172e03b20e6Speter klausler return u == that.u; 173e03b20e6Speter klausler } 174e03b20e6Speter klausler 17564ab3302SCarolineConcatto template <typename R> 17664ab3302SCarolineConcatto bool ArrayConstructorValues<R>::operator==( 17764ab3302SCarolineConcatto const ArrayConstructorValues<R> &that) const { 17864ab3302SCarolineConcatto return values_ == that.values_; 17964ab3302SCarolineConcatto } 18064ab3302SCarolineConcatto 18164ab3302SCarolineConcatto template <int KIND> 18201688ee9SPeter Klausler auto ArrayConstructor<Type<TypeCategory::Character, KIND>>::set_LEN( 18301688ee9SPeter Klausler Expr<SubscriptInteger> &&len) -> ArrayConstructor & { 18401688ee9SPeter Klausler length_.emplace(std::move(len)); 18501688ee9SPeter Klausler return *this; 18601688ee9SPeter Klausler } 18701688ee9SPeter Klausler 18801688ee9SPeter Klausler template <int KIND> 18964ab3302SCarolineConcatto bool ArrayConstructor<Type<TypeCategory::Character, KIND>>::operator==( 19064ab3302SCarolineConcatto const ArrayConstructor &that) const { 19164ab3302SCarolineConcatto return length_ == that.length_ && 19264ab3302SCarolineConcatto static_cast<const Base &>(*this) == static_cast<const Base &>(that); 19364ab3302SCarolineConcatto } 19464ab3302SCarolineConcatto 19564ab3302SCarolineConcatto bool ArrayConstructor<SomeDerived>::operator==( 19664ab3302SCarolineConcatto const ArrayConstructor &that) const { 19764ab3302SCarolineConcatto return result_ == that.result_ && 19864ab3302SCarolineConcatto static_cast<const Base &>(*this) == static_cast<const Base &>(that); 19964ab3302SCarolineConcatto ; 20064ab3302SCarolineConcatto } 20164ab3302SCarolineConcatto 20264ab3302SCarolineConcatto StructureConstructor::StructureConstructor( 20364ab3302SCarolineConcatto const semantics::DerivedTypeSpec &spec, 20464ab3302SCarolineConcatto const StructureConstructorValues &values) 20564ab3302SCarolineConcatto : result_{spec}, values_{values} {} 20664ab3302SCarolineConcatto StructureConstructor::StructureConstructor( 20764ab3302SCarolineConcatto const semantics::DerivedTypeSpec &spec, StructureConstructorValues &&values) 20864ab3302SCarolineConcatto : result_{spec}, values_{std::move(values)} {} 20964ab3302SCarolineConcatto 21064ab3302SCarolineConcatto bool StructureConstructor::operator==(const StructureConstructor &that) const { 21164ab3302SCarolineConcatto return result_ == that.result_ && values_ == that.values_; 21264ab3302SCarolineConcatto } 21364ab3302SCarolineConcatto 214e03b20e6Speter klausler template <int KIND> 215e03b20e6Speter klausler bool Expr<Type<TypeCategory::Integer, KIND>>::operator==( 216e03b20e6Speter klausler const Expr<Type<TypeCategory::Integer, KIND>> &that) const { 217e03b20e6Speter klausler return u == that.u; 218e03b20e6Speter klausler } 219e03b20e6Speter klausler 220e03b20e6Speter klausler template <int KIND> 221e03b20e6Speter klausler bool Expr<Type<TypeCategory::Real, KIND>>::operator==( 222e03b20e6Speter klausler const Expr<Type<TypeCategory::Real, KIND>> &that) const { 223e03b20e6Speter klausler return u == that.u; 224e03b20e6Speter klausler } 225e03b20e6Speter klausler 226e03b20e6Speter klausler template <int KIND> 227e03b20e6Speter klausler bool Expr<Type<TypeCategory::Complex, KIND>>::operator==( 228e03b20e6Speter klausler const Expr<Type<TypeCategory::Complex, KIND>> &that) const { 229e03b20e6Speter klausler return u == that.u; 230e03b20e6Speter klausler } 231e03b20e6Speter klausler 232e03b20e6Speter klausler template <int KIND> 233e03b20e6Speter klausler bool Expr<Type<TypeCategory::Logical, KIND>>::operator==( 234e03b20e6Speter klausler const Expr<Type<TypeCategory::Logical, KIND>> &that) const { 235e03b20e6Speter klausler return u == that.u; 236e03b20e6Speter klausler } 237e03b20e6Speter klausler 238e03b20e6Speter klausler template <int KIND> 239e03b20e6Speter klausler bool Expr<Type<TypeCategory::Character, KIND>>::operator==( 240e03b20e6Speter klausler const Expr<Type<TypeCategory::Character, KIND>> &that) const { 241e03b20e6Speter klausler return u == that.u; 242e03b20e6Speter klausler } 243e03b20e6Speter klausler 244fc97d2e6SPeter Klausler template <int KIND> 245fc97d2e6SPeter Klausler bool Expr<Type<TypeCategory::Unsigned, KIND>>::operator==( 246fc97d2e6SPeter Klausler const Expr<Type<TypeCategory::Unsigned, KIND>> &that) const { 247fc97d2e6SPeter Klausler return u == that.u; 248fc97d2e6SPeter Klausler } 249fc97d2e6SPeter Klausler 250e03b20e6Speter klausler template <TypeCategory CAT> 251e03b20e6Speter klausler bool Expr<SomeKind<CAT>>::operator==(const Expr<SomeKind<CAT>> &that) const { 252e03b20e6Speter klausler return u == that.u; 253e03b20e6Speter klausler } 254e03b20e6Speter klausler 255e03b20e6Speter klausler bool Expr<SomeDerived>::operator==(const Expr<SomeDerived> &that) const { 256e03b20e6Speter klausler return u == that.u; 257e03b20e6Speter klausler } 258e03b20e6Speter klausler 259e03b20e6Speter klausler bool Expr<SomeCharacter>::operator==(const Expr<SomeCharacter> &that) const { 260e03b20e6Speter klausler return u == that.u; 261e03b20e6Speter klausler } 262e03b20e6Speter klausler 263e03b20e6Speter klausler bool Expr<SomeType>::operator==(const Expr<SomeType> &that) const { 264e03b20e6Speter klausler return u == that.u; 265e03b20e6Speter klausler } 266e03b20e6Speter klausler 26764ab3302SCarolineConcatto DynamicType StructureConstructor::GetType() const { return result_.GetType(); } 26864ab3302SCarolineConcatto 269b34f1168SPeter Steinfeld std::optional<Expr<SomeType>> StructureConstructor::CreateParentComponent( 27064ab3302SCarolineConcatto const Symbol &component) const { 271b34f1168SPeter Steinfeld if (const semantics::DerivedTypeSpec * 272b34f1168SPeter Steinfeld parentSpec{GetParentTypeSpec(derivedTypeSpec())}) { 273b34f1168SPeter Steinfeld StructureConstructor structureConstructor{*parentSpec}; 274b34f1168SPeter Steinfeld if (const auto *parentDetails{ 275b34f1168SPeter Steinfeld component.detailsIf<semantics::DerivedTypeDetails>()}) { 276b34f1168SPeter Steinfeld auto parentIter{parentDetails->componentNames().begin()}; 277b34f1168SPeter Steinfeld for (const auto &childIter : values_) { 278b34f1168SPeter Steinfeld if (parentIter == parentDetails->componentNames().end()) { 279b34f1168SPeter Steinfeld break; // There are more components in the child 280b34f1168SPeter Steinfeld } 281b34f1168SPeter Steinfeld SymbolRef componentSymbol{childIter.first}; 282b34f1168SPeter Steinfeld structureConstructor.Add( 283b34f1168SPeter Steinfeld *componentSymbol, common::Clone(childIter.second.value())); 284b34f1168SPeter Steinfeld ++parentIter; 285b34f1168SPeter Steinfeld } 286b34f1168SPeter Steinfeld Constant<SomeDerived> constResult{std::move(structureConstructor)}; 287b34f1168SPeter Steinfeld Expr<SomeDerived> result{std::move(constResult)}; 288b34f1168SPeter Steinfeld return std::optional<Expr<SomeType>>{result}; 289b34f1168SPeter Steinfeld } 290b34f1168SPeter Steinfeld } 291b34f1168SPeter Steinfeld return std::nullopt; 292b34f1168SPeter Steinfeld } 293b34f1168SPeter Steinfeld 294b34f1168SPeter Steinfeld static const Symbol *GetParentComponentSymbol(const Symbol &symbol) { 295b34f1168SPeter Steinfeld if (symbol.test(Symbol::Flag::ParentComp)) { 296b34f1168SPeter Steinfeld // we have a created parent component 297b34f1168SPeter Steinfeld const auto &compObject{symbol.get<semantics::ObjectEntityDetails>()}; 298b34f1168SPeter Steinfeld if (const semantics::DeclTypeSpec * compType{compObject.type()}) { 299b34f1168SPeter Steinfeld const semantics::DerivedTypeSpec &dtSpec{compType->derivedTypeSpec()}; 300b34f1168SPeter Steinfeld const semantics::Symbol &compTypeSymbol{dtSpec.typeSymbol()}; 301b34f1168SPeter Steinfeld return &compTypeSymbol; 302b34f1168SPeter Steinfeld } 303b34f1168SPeter Steinfeld } 304b34f1168SPeter Steinfeld if (symbol.detailsIf<semantics::DerivedTypeDetails>()) { 305b34f1168SPeter Steinfeld // we have an implicit parent type component 306b34f1168SPeter Steinfeld return &symbol; 307b34f1168SPeter Steinfeld } 30864ab3302SCarolineConcatto return nullptr; 30964ab3302SCarolineConcatto } 310b34f1168SPeter Steinfeld 311b34f1168SPeter Steinfeld std::optional<Expr<SomeType>> StructureConstructor::Find( 312b34f1168SPeter Steinfeld const Symbol &component) const { 313b34f1168SPeter Steinfeld if (auto iter{values_.find(component)}; iter != values_.end()) { 314b34f1168SPeter Steinfeld return iter->second.value(); 315b34f1168SPeter Steinfeld } 316b34f1168SPeter Steinfeld // The component wasn't there directly, see if we're looking for the parent 317b34f1168SPeter Steinfeld // component of an extended type 318b34f1168SPeter Steinfeld if (const Symbol * typeSymbol{GetParentComponentSymbol(component)}) { 319b34f1168SPeter Steinfeld return CreateParentComponent(*typeSymbol); 320b34f1168SPeter Steinfeld } 321b34f1168SPeter Steinfeld // Look for the component in the parent type component. The parent type 322b34f1168SPeter Steinfeld // component is always the first one 323b34f1168SPeter Steinfeld if (!values_.empty()) { 324b34f1168SPeter Steinfeld const Expr<SomeType> *parentExpr{&values_.begin()->second.value()}; 325b34f1168SPeter Steinfeld if (const Expr<SomeDerived> *derivedExpr{ 326b34f1168SPeter Steinfeld std::get_if<Expr<SomeDerived>>(&parentExpr->u)}) { 327b34f1168SPeter Steinfeld if (const Constant<SomeDerived> *constExpr{ 328b34f1168SPeter Steinfeld std::get_if<Constant<SomeDerived>>(&derivedExpr->u)}) { 329b34f1168SPeter Steinfeld if (std::optional<StructureConstructor> parentComponentValue{ 330b34f1168SPeter Steinfeld constExpr->GetScalarValue()}) { 331b34f1168SPeter Steinfeld // Try to find the component in the parent structure constructor 332b34f1168SPeter Steinfeld return parentComponentValue->Find(component); 333b34f1168SPeter Steinfeld } 334b34f1168SPeter Steinfeld } 335b34f1168SPeter Steinfeld } 336b34f1168SPeter Steinfeld } 337b34f1168SPeter Steinfeld return std::nullopt; 33864ab3302SCarolineConcatto } 33964ab3302SCarolineConcatto 34064ab3302SCarolineConcatto StructureConstructor &StructureConstructor::Add( 34164ab3302SCarolineConcatto const Symbol &symbol, Expr<SomeType> &&expr) { 34264ab3302SCarolineConcatto values_.emplace(symbol, std::move(expr)); 34364ab3302SCarolineConcatto return *this; 34464ab3302SCarolineConcatto } 34564ab3302SCarolineConcatto 34664ab3302SCarolineConcatto GenericExprWrapper::~GenericExprWrapper() {} 34764ab3302SCarolineConcatto 3488a8bb078Speter klausler void GenericExprWrapper::Deleter(GenericExprWrapper *p) { delete p; } 3498a8bb078Speter klausler 35064ab3302SCarolineConcatto GenericAssignmentWrapper::~GenericAssignmentWrapper() {} 35164ab3302SCarolineConcatto 3528a8bb078Speter klausler void GenericAssignmentWrapper::Deleter(GenericAssignmentWrapper *p) { 3538a8bb078Speter klausler delete p; 3548a8bb078Speter klausler } 3558a8bb078Speter klausler 35664ab3302SCarolineConcatto template <TypeCategory CAT> int Expr<SomeKind<CAT>>::GetKind() const { 357cd03e96fSPeter Klausler return common::visit( 35864ab3302SCarolineConcatto [](const auto &kx) { return std::decay_t<decltype(kx)>::Result::kind; }, 35964ab3302SCarolineConcatto u); 36064ab3302SCarolineConcatto } 36164ab3302SCarolineConcatto 36264ab3302SCarolineConcatto int Expr<SomeCharacter>::GetKind() const { 363cd03e96fSPeter Klausler return common::visit( 36464ab3302SCarolineConcatto [](const auto &kx) { return std::decay_t<decltype(kx)>::Result::kind; }, 36564ab3302SCarolineConcatto u); 36664ab3302SCarolineConcatto } 36764ab3302SCarolineConcatto 36864ab3302SCarolineConcatto std::optional<Expr<SubscriptInteger>> Expr<SomeCharacter>::LEN() const { 369cd03e96fSPeter Klausler return common::visit([](const auto &kx) { return kx.LEN(); }, u); 37064ab3302SCarolineConcatto } 37164ab3302SCarolineConcatto 3725c5bde1bSPeter Klausler #ifdef _MSC_VER // disable bogus warning about missing definitions 3735c5bde1bSPeter Klausler #pragma warning(disable : 4661) 3745c5bde1bSPeter Klausler #endif 37564ab3302SCarolineConcatto INSTANTIATE_EXPRESSION_TEMPLATES 3761f879005STim Keith } // namespace Fortran::evaluate 377