//===-- lib/Evaluate/tools.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "flang/Evaluate/tools.h" #include "flang/Common/idioms.h" #include "flang/Evaluate/characteristics.h" #include "flang/Evaluate/traverse.h" #include "flang/Parser/message.h" #include "flang/Semantics/tools.h" #include #include using namespace Fortran::parser::literals; namespace Fortran::evaluate { Expr Parenthesize(Expr &&expr) { return std::visit( [&](auto &&x) { using T = std::decay_t; if constexpr (common::HasMember || std::is_same_v>) { return expr; // no parentheses around typeless or derived type } else { return std::visit( [](auto &&y) { using T = ResultType; return AsGenericExpr(Parentheses{std::move(y)}); }, std::move(x.u)); } }, std::move(expr.u)); } std::optional ExtractSubstringBase(const Substring &substring) { return std::visit( common::visitors{ [&](const DataRef &x) -> std::optional { return x; }, [&](const StaticDataObject::Pointer &) -> std::optional { return std::nullopt; }, }, substring.parent()); } // IsVariable() auto IsVariableHelper::operator()(const Symbol &symbol) const -> Result { return !symbol.attrs().test(semantics::Attr::PARAMETER); } auto IsVariableHelper::operator()(const Component &x) const -> Result { return (*this)(x.base()); } auto IsVariableHelper::operator()(const ArrayRef &x) const -> Result { return (*this)(x.base()); } auto IsVariableHelper::operator()(const Substring &x) const -> Result { return (*this)(x.GetBaseObject()); } auto IsVariableHelper::operator()(const ProcedureDesignator &x) const -> Result { const Symbol *symbol{x.GetSymbol()}; return symbol && symbol->attrs().test(semantics::Attr::POINTER); } // Conversions of COMPLEX component expressions to REAL. ConvertRealOperandsResult ConvertRealOperands( parser::ContextualMessages &messages, Expr &&x, Expr &&y, int defaultRealKind) { return std::visit( common::visitors{ [&](Expr &&ix, Expr &&iy) -> ConvertRealOperandsResult { // Can happen in a CMPLX() constructor. Per F'2018, // both integer operands are converted to default REAL. return {AsSameKindExprs( ConvertToKind( defaultRealKind, std::move(ix)), ConvertToKind( defaultRealKind, std::move(iy)))}; }, [&](Expr &&ix, Expr &&ry) -> ConvertRealOperandsResult { return {AsSameKindExprs( ConvertTo(ry, std::move(ix)), std::move(ry))}; }, [&](Expr &&rx, Expr &&iy) -> ConvertRealOperandsResult { return {AsSameKindExprs( std::move(rx), ConvertTo(rx, std::move(iy)))}; }, [&](Expr &&rx, Expr &&ry) -> ConvertRealOperandsResult { return {AsSameKindExprs( std::move(rx), std::move(ry))}; }, [&](Expr &&ix, BOZLiteralConstant &&by) -> ConvertRealOperandsResult { return {AsSameKindExprs( ConvertToKind( defaultRealKind, std::move(ix)), ConvertToKind( defaultRealKind, std::move(by)))}; }, [&](BOZLiteralConstant &&bx, Expr &&iy) -> ConvertRealOperandsResult { return {AsSameKindExprs( ConvertToKind( defaultRealKind, std::move(bx)), ConvertToKind( defaultRealKind, std::move(iy)))}; }, [&](Expr &&rx, BOZLiteralConstant &&by) -> ConvertRealOperandsResult { return {AsSameKindExprs( std::move(rx), ConvertTo(rx, std::move(by)))}; }, [&](BOZLiteralConstant &&bx, Expr &&ry) -> ConvertRealOperandsResult { return {AsSameKindExprs( ConvertTo(ry, std::move(bx)), std::move(ry))}; }, [&](auto &&, auto &&) -> ConvertRealOperandsResult { // C718 messages.Say("operands must be INTEGER or REAL"_err_en_US); return std::nullopt; }, }, std::move(x.u), std::move(y.u)); } // Helpers for NumericOperation and its subroutines below. static std::optional> NoExpr() { return std::nullopt; } template std::optional> Package(Expr> &&catExpr) { return {AsGenericExpr(std::move(catExpr))}; } template std::optional> Package( std::optional>> &&catExpr) { if (catExpr) { return {AsGenericExpr(std::move(*catExpr))}; } return NoExpr(); } // Mixed REAL+INTEGER operations. REAL**INTEGER is a special case that // does not require conversion of the exponent expression. template