diff --git a/flang/lib/evaluate/expression.cc b/flang/lib/evaluate/expression.cc index 13186a59d9c1..2e493ecc5eca 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -15,6 +15,7 @@ #include "expression.h" #include "common.h" #include "int-power.h" +#include "tools.h" #include "variable.h" #include "../common/idioms.h" #include "../parser/characters.h" diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index 9d692a4c28f6..e00f5ff41ca8 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -42,6 +42,8 @@ using common::RelationalOperator; // wrap discriminated unions. template class Expr; +template using ResultType = typename std::decay_t::Result; + template class Operation { public: @@ -597,92 +599,6 @@ public: u; }; -using GenericExpr = Expr; // TODO: delete name? - -template using ResultType = typename std::decay_t::Result; - -// Convenience functions and operator overloadings for expression construction. - -template -Expr> operator-(const Expr> &x) { - return {Negate>{x}}; -} -template -Expr> operator-(const Expr> &x) { - return std::visit( - [](const auto &y) -> Expr> { return {-y}; }, x.u); -} - -#define BINARY(op, CONSTR) \ - template \ - Expr> operator op( \ - const Expr> &x, const Expr> &y) { \ - return {CONSTR>{x, y}}; \ - } \ - template \ - Expr> operator op( \ - const Expr> &x, const Expr> &y) { \ - return std::visit( \ - [](const auto &xk, const auto &yk) -> Expr> { \ - return {xk op yk}; \ - }, \ - x.u, y.u); \ - } - -BINARY(+, Add) -BINARY(-, Subtract) -BINARY(*, Multiply) -BINARY(/, Divide) -#undef BINARY - -#if 0 -#define OLDBINARY(FUNC, CONSTR) \ - template A FUNC(const A &x, const A &y) { \ - return {CONSTR{x, y}}; \ - } \ - template \ - std::enable_if_t, A> FUNC(const A &x, A &&y) { \ - return {CONSTR{A{x}, std::move(y)}}; \ - } \ - template \ - std::enable_if_t, A> FUNC(A &&x, const A &y) { \ - return {CONSTR{std::move(x), A{y}}}; \ - } \ - template \ - std::enable_if_t, A> FUNC(A &&x, A &&y) { \ - return {CONSTR{std::move(x), std::move(y)}}; \ - } -#undef OLDBINARY -#endif - -#define BINARY(FUNC, OP) \ - template Expr FUNC(const A &x, const A &y) { \ - return {Relational>{OP, x, y}}; \ - } \ - template \ - std::enable_if_t, Expr> FUNC( \ - const A &x, A &&y) { \ - return {Relational>{OP, x, std::move(y)}}; \ - } \ - template \ - std::enable_if_t, Expr> FUNC( \ - A &&x, const A &y) { \ - return {Relational>{OP, std::move(x), y}}; \ - } \ - template \ - std::enable_if_t, Expr> FUNC( \ - A &&x, A &&y) { \ - return {Relational>{OP, std::move(x), std::move(y)}}; \ - } - -BINARY(operator<, RelationalOperator::LT) -BINARY(operator<=, RelationalOperator::LE) -BINARY(operator==, RelationalOperator::EQ) -BINARY(operator!=, RelationalOperator::NE) -BINARY(operator>=, RelationalOperator::GE) -BINARY(operator>, RelationalOperator::GT) -#undef BINARY - extern template class Expr>; // TODO others extern template struct Relational>; extern template struct Relational>; diff --git a/flang/lib/evaluate/tools.cc b/flang/lib/evaluate/tools.cc index d22d71e57854..c49028983eaa 100644 --- a/flang/lib/evaluate/tools.cc +++ b/flang/lib/evaluate/tools.cc @@ -20,20 +20,9 @@ using namespace Fortran::parser::literals; namespace Fortran::evaluate { -Expr ConvertToTypeOf( - const Expr &to, const Expr &from) { - return std::visit( - [&](const auto &rk) { return Expr{decltype(rk){to}}; }, to.u); -} - -Expr ConvertToTypeOf( - const Expr &to, const Expr &from) { - return std::visit( - [&](const auto &rk) { return Expr{decltype(rk){to}}; }, to.u); -} - std::optional, Expr>> ConvertRealOperands( - parser::ContextualMessages &messages, GenericExpr &&x, GenericExpr &&y) { + parser::ContextualMessages &messages, Expr &&x, + Expr &&y) { return std::visit( common::visitors{[&](Expr &&ix, Expr &&iy) { // Can happen in a CMPLX() constructor. Per F'2018, @@ -43,11 +32,11 @@ std::optional, Expr>> ConvertRealOperands( Expr{Expr{std::move(iy)}})}; }, [&](Expr &&ix, Expr &&ry) { - auto rx{ConvertToTypeOf(ry, std::move(ix))}; + auto rx{ConvertToTypeAndKindOf(ry, std::move(ix))}; return std::optional{std::make_pair(std::move(rx), std::move(ry))}; }, [&](Expr &&rx, Expr &&iy) { - auto ry{ConvertToTypeOf(rx, std::move(iy))}; + auto ry{ConvertToTypeAndKindOf(rx, std::move(iy))}; return std::optional{std::make_pair(std::move(rx), std::move(ry))}; }, [&](Expr &&rx, Expr &&ry) { @@ -63,8 +52,8 @@ std::optional, Expr>> ConvertRealOperands( } std::optional, Expr>> ConvertRealOperands( - parser::ContextualMessages &messages, std::optional &&x, - std::optional &&y) { + parser::ContextualMessages &messages, std::optional> &&x, + std::optional> &&y) { if (x.has_value() && y.has_value()) { return ConvertRealOperands(messages, std::move(*x), std::move(*y)); } diff --git a/flang/lib/evaluate/tools.h b/flang/lib/evaluate/tools.h index 6b437cbd019b..f1bc983b601e 100644 --- a/flang/lib/evaluate/tools.h +++ b/flang/lib/evaluate/tools.h @@ -23,18 +23,92 @@ namespace Fortran::evaluate { -// Convert the second argument to the same type and kind of the first. -Expr ConvertToTypeOf( - const Expr &to, const Expr &from); -Expr ConvertToTypeOf( - const Expr &to, const Expr &from); +// Convenience functions and operator overloadings for expression construction. +template +Expr> operator-(Expr> &&x) { + return {Negate>{std::move(x)}}; +} + +template +Expr> operator+(Expr> &&x, Expr> &&y) { + return {Add>{std::move(x), std::move(y)}}; +} + +template +Expr> operator-(Expr> &&x, Expr> &&y) { + return {Subtract>{std::move(x), std::move(y)}}; +} + +template +Expr> operator*(Expr> &&x, Expr> &&y) { + return {Multiply>{std::move(x), std::move(y)}}; +} + +template +Expr> operator/(Expr> &&x, Expr> &&y) { + return {Divide>{std::move(x), std::move(y)}}; +} + +template Expr> operator-(Expr> &&x) { + return std::visit( + [](auto &xk) { return Expr>{-std::move(xk)}; }, x.u); +} + +template +Expr> operator+(Expr> &&x, Expr> &&y) { + return std::visit( + [](auto &xk, auto &yk) { + return Expr>{std::move(xk) + std::move(yk)}; + }, + x.u, y.u); +} + +template +Expr> operator-(Expr> &&x, Expr> &&y) { + return std::visit( + [](auto &xk, auto &yk) { + return Expr>{std::move(xk) - std::move(yk)}; + }, + x.u, y.u); +} + +template +Expr> operator*(Expr> &&x, Expr> &&y) { + return std::visit( + [](auto &xk, auto &yk) { + return Expr>{std::move(xk) * std::move(yk)}; + }, + x.u, y.u); +} + +template +Expr> operator/(Expr> &&x, Expr> &&y) { + return std::visit( + [](auto &xk, auto &yk) { + return Expr>{std::move(xk) / std::move(yk)}; + }, + x.u, y.u); +} + +// Convert the second argument expression to an expression of the same type +// and kind as that of the first. +template +Expr> ConvertToTypeAndKindOf( + const Expr> &to, Expr &&from) { + return std::visit( + [&](const auto &tk) -> Expr> { + using SpecificExpr = std::decay_t; + return {SpecificExpr{std::move(from)}}; + }, + to.u); +} // Ensure that both operands of an intrinsic REAL operation or CMPLX() // are INTEGER or REAL, and convert them as necessary to the same REAL type. using ConvertRealOperandsResult = std::optional, Expr>>; ConvertRealOperandsResult ConvertRealOperands( - parser::ContextualMessages &, GenericExpr &&, GenericExpr &&); + parser::ContextualMessages &, Expr &&, Expr &&); template void ConvertToSameKind(Expr> &x, Expr> &y) { diff --git a/flang/lib/evaluate/variable.cc b/flang/lib/evaluate/variable.cc index 7bca1a374d55..0dde964db7c7 100644 --- a/flang/lib/evaluate/variable.cc +++ b/flang/lib/evaluate/variable.cc @@ -13,6 +13,7 @@ // limitations under the License. #include "variable.h" +#include "tools.h" #include "../common/idioms.h" #include "../parser/char-block.h" #include "../parser/characters.h" diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index 99f941f9948f..722d4885cfd3 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -25,7 +25,7 @@ namespace Fortran::semantics { using common::TypeCategory; using evaluate::Expr; -using evaluate::GenericExpr; +using evaluate::SomeType; using evaluate::Type; using MaybeIntExpr = std::optional>; @@ -117,8 +117,8 @@ static std::optional> AnalyzeLiteral( } template MaybeExpr PackageGeneric(std::optional &&x) { - std::function f{ - [](A &&y) { return GenericExpr{std::move(y)}; }}; + std::function(A &&)> f{ + [](A &&y) { return Expr{std::move(y)}; }}; return common::MapOptional(f, std::move(x)); } @@ -153,7 +153,7 @@ MaybeExpr AnalyzeHelper( evaluate::CopyableIndirection ind{std::move(substring)}; Expr chExpr{std::move(ind)}; chExpr.Fold(ea.context()); - return {GenericExpr{Expr{std::move(chExpr)}}}; + return {Expr{Expr{std::move(chExpr)}}}; } // Common handling of parser::IntLiteralConstant and SignedIntLiteralConstant @@ -269,7 +269,7 @@ static std::optional> AnalyzeLiteral( AnalyzeLiteral(ea, std::get(x.t))}) { if (auto sign{std::get>(x.t)}) { if (sign == parser::Sign::Negative) { - return {-*result}; + return {-std::move(*result)}; } } return result; @@ -577,12 +577,12 @@ ExpressionAnalyzer::KindParam ExpressionAnalyzer::Analyze( std::optional> ExpressionAnalyzer::ConstructComplex( MaybeExpr &&real, MaybeExpr &&imaginary) { // TODO: pmk abstract further, this will be a common pattern - auto partial{[&](GenericExpr &&x, GenericExpr &&y) { + auto partial{[&](Expr &&x, Expr &&y) { return evaluate::ConvertRealOperands( context_.messages, std::move(x), std::move(y)); }}; using fType = - evaluate::ConvertRealOperandsResult(GenericExpr &&, GenericExpr &&); + evaluate::ConvertRealOperandsResult(Expr &&, Expr &&); std::function f{partial}; auto converted{common::MapOptional(f, std::move(real), std::move(imaginary))}; if (auto joined{common::JoinOptionals(std::move(converted))}) { diff --git a/flang/lib/semantics/expression.h b/flang/lib/semantics/expression.h index 9faea6833807..43fc5f471d06 100644 --- a/flang/lib/semantics/expression.h +++ b/flang/lib/semantics/expression.h @@ -23,7 +23,7 @@ namespace Fortran::semantics { -using MaybeExpr = std::optional; +using MaybeExpr = std::optional>; class ExpressionAnalyzer { public: diff --git a/flang/test/evaluate/expression.cc b/flang/test/evaluate/expression.cc index 5c7ba2a8b75e..c51dbc2637f6 100644 --- a/flang/test/evaluate/expression.cc +++ b/flang/test/evaluate/expression.cc @@ -13,6 +13,7 @@ // limitations under the License. #include "../../lib/evaluate/expression.h" +#include "../../lib/evaluate/tools.h" #include "testing.h" #include "../../lib/parser/message.h" #include @@ -41,11 +42,9 @@ int main() { FoldingContext context{messages}; ex1.Fold(context); MATCH("-10_4", Dump(ex1)); - MATCH("(6_4.LE.7_4)", - Dump(DefaultIntegerExpr{6} <= DefaultIntegerExpr{7})); + MATCH("(1_4/2_4)", Dump(DefaultIntegerExpr{1} / DefaultIntegerExpr{2})); DefaultIntegerExpr a{1}; DefaultIntegerExpr b{2}; - MATCH("(1_4/2_4)", Dump(a / b)); MATCH("1_4", Dump(a)); a = b; MATCH("2_4", Dump(a));