diff --git a/flang/lib/common/fortran.h b/flang/lib/common/fortran.h index 39ef486587f8..695d04be59b1 100644 --- a/flang/lib/common/fortran.h +++ b/flang/lib/common/fortran.h @@ -31,5 +31,7 @@ ENUM_CLASS(ImportKind, Default, Only, None, All) // The attribute on a type parameter can be KIND or LEN. ENUM_CLASS(TypeParamAttr, Kind, Len) +ENUM_CLASS(RelationalOperator, LT, LE, EQ, NE, GE, GT) + } // namespace Fortran::common #endif // FORTRAN_COMMON_FORTRAN_H_ diff --git a/flang/lib/evaluate/common.h b/flang/lib/evaluate/common.h index 9b09dffea7f1..0fe6ba0ba5c3 100644 --- a/flang/lib/evaluate/common.h +++ b/flang/lib/evaluate/common.h @@ -116,14 +116,12 @@ using HostUnsignedInt = // - There is no default constructor (Class() {}), usually to prevent the // need for std::monostate as a default constituent in a std::variant<>. // - There are full copy and move semantics for construction and assignment. -// - There's a Dump(std::ostream &) member function. #define CLASS_BOILERPLATE(t) \ t() = delete; \ t(const t &) = default; \ t(t &&) = default; \ t &operator=(const t &) = default; \ - t &operator=(t &&) = default; \ - std::ostream &Dump(std::ostream &) const; + t &operator=(t &&) = default; // Force availability of copy construction and assignment template using CopyableIndirection = common::Indirection; diff --git a/flang/lib/evaluate/expression.cc b/flang/lib/evaluate/expression.cc index dd40567fa01f..8fbaeec34b99 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -27,16 +27,7 @@ using namespace Fortran::parser::literals; namespace Fortran::evaluate { -template -std::ostream &Operation::Dump(std::ostream &o) const { - operand<0>().Dump(o << derived().prefix_); - if constexpr (operands() > 1) { - operand<1>().Dump(o << infix_); - } - return o << derived().suffix_; -} - -// TODO: dump Convert as INT(x,KIND=), &c. +// Folding template auto Operation::Fold(FoldingContext &context) @@ -134,9 +125,9 @@ auto Negate::FoldScalar(FoldingContext &context, const Scalar &c) return std::nullopt; } -template -auto ComplexComponent::FoldScalar(FoldingContext &context, - const Scalar &z) -> std::optional> { +template +auto ComplexComponent::FoldScalar(FoldingContext &context, + const Scalar &z) const -> std::optional> { return {isRealPart ? z.REAL() : z.AIMAG()}; } @@ -146,7 +137,39 @@ auto Not::FoldScalar(FoldingContext &context, const Scalar &x) return {Scalar{!x.IsTrue()}}; } +template +auto Add::FoldScalar(FoldingContext &context, const Scalar &x, + const Scalar &y) -> std::optional> { + if constexpr (Result::category == TypeCategory::Integer) { + auto sum{x.AddSigned(y)}; + if (sum.overflow) { + context.messages.Say("INTEGER addition overflowed"_en_US); + } else { + return {std::move(sum.value)}; + } + } else { + auto sum{x.Add(y, context.rounding)}; + RealFlagWarnings(context, sum.flags, "addition"); + return {std::move(sum.value)}; + } + return std::nullopt; +} + // Dumping + +template +std::ostream &Operation::Dump(std::ostream &o) const { + operand<0>().Dump(o << derived().prefix()); + if constexpr (operands() > 1) { + operand<1>().Dump(o << derived().infix()); + } + return o << derived().suffix(); +} + +template std::string Comparison::infix() const { + return "."s + EnumToString(opr) + '.'; +} + template std::ostream &DumpExpr(std::ostream &o, const std::variant &u) { std::visit(common::visitors{[&](const BOZLiteralConstant &x) { @@ -180,18 +203,18 @@ std::ostream &Binary::Dump( template std::ostream &Expr>::Dump( std::ostream &o) const { - std::visit( - common::visitors{[&](const Scalar &n) { o << n.SignedDecimal(); }, - [&](const CopyableIndirection &d) { d->Dump(o); }, - [&](const CopyableIndirection &d) { d->Dump(o); }, - [&](const Add &a) { a.Dump(o, "+"); }, - [&](const Subtract &s) { s.Dump(o, "-"); }, - [&](const Multiply &m) { m.Dump(o, "*"); }, - [&](const Divide &d) { d.Dump(o, "/"); }, - [&](const Power &p) { p.Dump(o, "**"); }, - [&](const Max &m) { m.Dump(o, ",", "MAX("); }, - [&](const Min &m) { m.Dump(o, ",", "MIN("); }, - [&](const auto &x) { x.Dump(o); }}, + std::visit(common::visitors{[&](const Scalar &n) { + o << n.SignedDecimal() << '_' << KIND; + }, + [&](const CopyableIndirection &d) { d->Dump(o); }, + [&](const CopyableIndirection &d) { d->Dump(o); }, + [&](const Subtract &s) { s.Dump(o, "-"); }, + [&](const Multiply &m) { m.Dump(o, "*"); }, + [&](const Divide &d) { d.Dump(o, "/"); }, + [&](const Power &p) { p.Dump(o, "**"); }, + [&](const Max &m) { m.Dump(o, ",", "MAX("); }, + [&](const Min &m) { m.Dump(o, ",", "MIN("); }, + [&](const auto &x) { x.Dump(o); }}, u_); return o; } @@ -205,20 +228,14 @@ std::ostream &Expr>::Dump( [&](const CopyableIndirection &d) { d->Dump(o); }, [&](const CopyableIndirection &d) { d->Dump(o); }, [&](const CopyableIndirection &d) { d->Dump(o); }, - [&](const Convert &c) { c.Dump(o); }, - [&](const Convert &c) { c.Dump(o); }, - [&](const ComplexComponent &z) { z.Dump(o); }, - [&](const ComplexComponent &z) { z.Dump(o); }, - [&](const Parentheses &p) { p.Dump(o); }, - [&](const Negate &n) { n.Dump(o); }, - [&](const Add &a) { a.Dump(o, "+"); }, [&](const Subtract &s) { s.Dump(o, "-"); }, [&](const Multiply &m) { m.Dump(o, "*"); }, [&](const Divide &d) { d.Dump(o, "/"); }, [&](const Power &p) { p.Dump(o, "**"); }, [&](const IntPower &p) { p.Dump(o, "**"); }, [&](const Max &m) { m.Dump(o, ",", "MAX("); }, - [&](const Min &m) { m.Dump(o, ",", "MIN("); }}, + [&](const Min &m) { m.Dump(o, ",", "MIN("); }, + [&](const auto &x) { x.Dump(o); }}, u_); return o; } @@ -231,7 +248,6 @@ std::ostream &Expr>::Dump( }, [&](const CopyableIndirection &d) { d->Dump(o); }, [&](const CopyableIndirection &d) { d->Dump(o); }, - [&](const Add &a) { a.Dump(o, "+"); }, [&](const Subtract &s) { s.Dump(o, "-"); }, [&](const Multiply &m) { m.Dump(o, "*"); }, [&](const Divide &d) { d.Dump(o, "/"); }, @@ -247,7 +263,8 @@ template std::ostream &Expr>::Dump( std::ostream &o) const { std::visit(common::visitors{[&](const Scalar &s) { - o << parser::QuoteCharacterLiteral(s); + o << KIND << '_' + << parser::QuoteCharacterLiteral(s); }, // [&](const Parentheses &p) { p.Dump(o); }, [&](const Concat &concat) { concat.Dump(o, "//"); }, @@ -258,18 +275,12 @@ std::ostream &Expr>::Dump( return o; } -template std::ostream &Comparison::Dump(std::ostream &o) const { - o << '(' << A::Dump() << "::"; - this->left().Dump(o); - o << '.' << EnumToString(this->opr) << '.'; - return this->right().Dump(o) << ')'; -} - template std::ostream &Expr>::Dump( std::ostream &o) const { std::visit(common::visitors{[&](const Scalar &tf) { - o << (tf.IsTrue() ? ".TRUE." : ".FALSE."); + o << (tf.IsTrue() ? ".TRUE." : ".FALSE.") << '_' + << KIND; }, [&](const CopyableIndirection &d) { d->Dump(o); }, [&](const CopyableIndirection &d) { d->Dump(o); }, @@ -333,18 +344,6 @@ auto Binary::Fold(FoldingContext &context) return std::nullopt; } -template -auto Expr>::Add::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - auto sum{a.AddSigned(b)}; - if (sum.overflow) { - context.messages.Say("integer addition overflowed"_en_US); - return std::nullopt; - } - return {std::move(sum.value)}; -} - template auto Expr>::Subtract::FoldScalar( FoldingContext &context, const Scalar &a, const Scalar &b) @@ -450,15 +449,6 @@ auto Expr>::Fold(FoldingContext &context) u_); } -template -auto Expr>::Add::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - auto sum{a.Add(b, context.rounding)}; - RealFlagWarnings(context, sum.flags, "real addition"); - return {std::move(sum.value)}; -} - template auto Expr>::Subtract::FoldScalar( FoldingContext &context, const Scalar &a, const Scalar &b) @@ -555,15 +545,6 @@ auto Expr>::Fold(FoldingContext &context) u_); } -template -auto Expr>::Add::FoldScalar( - FoldingContext &context, const Scalar &a, const Scalar &b) - -> std::optional> { - auto sum{a.Add(b, context.rounding)}; - RealFlagWarnings(context, sum.flags, "complex addition"); - return {std::move(sum.value)}; -} - template auto Expr>::Subtract::FoldScalar( FoldingContext &context, const Scalar &a, const Scalar &b) diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index 54c03bd450b6..d805b3f73bfa 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -24,6 +24,7 @@ #include "common.h" #include "type.h" #include "variable.h" +#include "../lib/common/fortran.h" #include "../lib/common/idioms.h" #include "../lib/parser/char-block.h" #include "../lib/parser/message.h" @@ -33,54 +34,51 @@ namespace Fortran::evaluate { +using common::RelationalOperator; + template class Expr; template class Operation { -private: - using OperandTypes = std::tuple; - public: using Derived = DERIVED; using Result = RESULT; + using OperandTypes = std::tuple; + using OperandTuple = std::tuple...>; template using Operand = std::tuple_element_t; using FoldableTrait = std::true_type; static_assert(Result::kind > 0); // Operations have specific Result types -#if !__clang__ CLASS_BOILERPLATE(Operation) -#else // clang 6.0 erroneously deletes the "=default" copy constructor - Operation() = delete; - Operation(const Operation &that) : operand_{that.operand_} {} - Operation(Operation &&) = default; - Operation &operator=(const Operation &) = default; - Operation &operator=(Operation &&) = default; - std::ostream &Dump(std::ostream &) const; -#endif - - Operation(Expr &&... x) : operand_{std::move(x)...} {} - Operation(const Expr &... x) : operand_{x...} {} + Operation(const Expr &... x) : operand_{OperandTuple{x...}} {} + Operation(Expr &&... x) + : operand_{OperandTuple{std::forward>(x)...}} {} DERIVED &derived() { return *static_cast(this); } const DERIVED &derived() const { return *static_cast(this); } - static constexpr auto operands() { return sizeof...(OPERAND); } - template Expr> &operand() { return *std::get(operand_); } + static constexpr auto operands() { return std::tuple_size_v; } + template Expr> &operand() { return std::get(*operand_); } template const Expr> &operand() const { - return *std::get(operand_); + return std::get(*operand_); } + std::ostream &Dump(std::ostream &) const; std::optional> Fold(FoldingContext &); // TODO rank > 0 protected: - // Overridable strings for Dump() - static constexpr const char *prefix_{"("}, *infix_{""}, *suffix_{")"}; + // Overridable string functions for Dump() + static const char *prefix() { return "("; } + static const char *infix() { return ","; } + static const char *suffix() { return ")"; } private: - std::tuple>...> operand_; + CopyableIndirection operand_; }; +// Unary operations + template struct Convert : public Operation, TO, FROM> { using Base = Operation, TO, FROM>; @@ -110,24 +108,29 @@ template struct Negate : public Operation, A, A> { using Operand = typename Base::template Operand<0>; static std::optional> FoldScalar( FoldingContext &, const Scalar &); - static constexpr const char *prefix_{"(-"}; + static const char *prefix() { return "(-"; } }; -// TODO: re vs. im can be dynamic -template +template struct ComplexComponent - : public Operation, - Type, Type> { + : public Operation, Type, + Type> { using Base = Operation, Type>; - static constexpr bool isRealPart{realPart}; - using Base::Base; using typename Base::Result; using Operand = typename Base::template Operand<0>; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &); - static constexpr const char *prefix_{"(("}; - static constexpr const char *suffix_{isRealPart ? ")%RE)" : ")%IM)"}; + CLASS_BOILERPLATE(ComplexComponent) + ComplexComponent(bool isReal, const Expr &x) + : Base{x}, isRealPart{isReal} {} + ComplexComponent(bool isReal, Expr &&x) + : Base{std::move(x)}, isRealPart{isReal} {} + + std::optional> FoldScalar( + FoldingContext &, const Scalar &) const; + static const char *prefix() { return "(("; } + const char *suffix() const { return isRealPart ? "%RE)" : "%IM)"; } + + bool isRealPart{true}; }; template @@ -140,7 +143,19 @@ struct Not : public Operation, Type, using Operand = typename Base::template Operand<0>; static std::optional> FoldScalar( FoldingContext &, const Scalar &); - static constexpr const char *prefix_{"(.NOT."}; + static const char *prefix() { return "(.NOT."; } +}; + +// Binary operations + +template struct Add : public Operation, A, A, A> { + using Base = Operation; + using Base::Base; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; + static std::optional> FoldScalar( + FoldingContext &, const Scalar &, const Scalar &); + static const char *infix() { return "+"; } }; template @@ -179,11 +194,6 @@ public: using FoldableTrait = std::true_type; template using Bin = Binary; - struct Add : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; struct Subtract : public Bin { using Bin::Bin; static std::optional> FoldScalar( @@ -247,14 +257,15 @@ public: // TODO: Also succeed when parenthesized constant return common::GetIf>(u_); } + std::ostream &Dump(std::ostream &) const; std::optional> Fold(FoldingContext &c); int Rank() const { return 1; } // TODO private: std::variant, CopyableIndirection, CopyableIndirection, Convert, - Convert, Parentheses, Negate, Add, - Subtract, Multiply, Divide, Power, Max, Min> + Convert, Parentheses, Negate, + Add, Subtract, Multiply, Divide, Power, Max, Min> u_; }; @@ -268,11 +279,6 @@ public: // Complex are done via decomposition to Real and reconstruction. template using Bin = Binary; - struct Add : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; struct Subtract : public Bin { using Bin::Bin; static std::optional> FoldScalar( @@ -337,6 +343,7 @@ public: // TODO: parenthesized constants too return common::GetIf>(u_); } + std::ostream &Dump(std::ostream &) const; std::optional> Fold(FoldingContext &c); int Rank() const { return 1; } // TODO @@ -344,9 +351,8 @@ private: std::variant, CopyableIndirection, CopyableIndirection, CopyableIndirection, Convert, Convert, - ComplexComponent, ComplexComponent, - Parentheses, Negate, Add, Subtract, Multiply, Divide, - Power, IntPower, Max, Min> + ComplexComponent, Parentheses, Negate, Add, + Subtract, Multiply, Divide, Power, IntPower, Max, Min> u_; }; @@ -356,11 +362,6 @@ public: using FoldableTrait = std::true_type; template using Bin = Binary; - struct Add : public Bin { - using Bin::Bin; - static std::optional> FoldScalar( - FoldingContext &, const Scalar &, const Scalar &); - }; struct Subtract : public Bin { using Bin::Bin; static std::optional> FoldScalar( @@ -405,13 +406,14 @@ public: // TODO: parenthesized constants too return common::GetIf>(u_); } + std::ostream &Dump(std::ostream &) const; std::optional> Fold(FoldingContext &c); int Rank() const { return 1; } // TODO private: std::variant, CopyableIndirection, CopyableIndirection, Parentheses, Negate, - Add, Subtract, Multiply, Divide, Power, IntPower, CMPLX> + Add, Subtract, Multiply, Divide, Power, IntPower, CMPLX> u_; }; @@ -464,6 +466,7 @@ public: // TODO: parenthesized constants too return common::GetIf>(u_); } + std::ostream &Dump(std::ostream &) const; std::optional> Fold(FoldingContext &c); int Rank() const { return 1; } // TODO Expr LEN() const; @@ -479,21 +482,23 @@ private: // The Comparison class template is a helper for constructing logical // expressions with polymorphism over the cross product of the possible // categories and kinds of comparable operands. -ENUM_CLASS(RelationalOperator, LT, LE, EQ, NE, GE, GT) template -struct Comparison : public Binary, LogicalResult, A> { - using Result = LogicalResult; - using Operand = A; - using Base = Binary; +struct Comparison : public Operation, LogicalResult, A, A> { + using Base = Operation; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; CLASS_BOILERPLATE(Comparison) Comparison( RelationalOperator r, const Expr &a, const Expr &b) : Base{a, b}, opr{r} {} Comparison(RelationalOperator r, Expr &&a, Expr &&b) : Base{std::move(a), std::move(b)}, opr{r} {} + std::optional> FoldScalar( FoldingContext &c, const Scalar &, const Scalar &); + std::string infix() const; + RelationalOperator opr; }; @@ -506,6 +511,7 @@ template struct CategoryComparison { template CategoryComparison(const KindComparison &x) : u{x} {} template CategoryComparison(KindComparison &&x) : u{std::move(x)} {} + std::ostream &Dump(std::ostream &) const; std::optional> Fold(FoldingContext &c); int Rank() const { return 1; } // TODO @@ -555,6 +561,7 @@ public: // TODO: parenthesized constants too return common::GetIf>(u_); } + std::ostream &Dump(std::ostream &) const; std::optional> Fold(FoldingContext &c); int Rank() const { return 1; } // TODO @@ -581,6 +588,7 @@ public: template Expr(const KindExpr &x) : u{x} {} template Expr(KindExpr &&x) : u{std::move(x)} {} std::optional> ScalarValue() const; + std::ostream &Dump(std::ostream &) const; std::optional> Fold(FoldingContext &); int Rank() const; @@ -612,6 +620,7 @@ public: Expr(Expr> &&x) : u{Expr>{std::move(x)}} {} std::optional> ScalarValue() const; + std::ostream &Dump(std::ostream &) const; std::optional> Fold(FoldingContext &); int Rank() const; @@ -625,9 +634,7 @@ using GenericExpr = Expr; // TODO: delete name? template using ResultType = typename std::decay_t::Result; // Convenience functions and operator overloadings for expression construction. -// These definitions are created with temporary helper macros to reduce -// C++ boilerplate. All combinations of lvalue and rvalue references are -// allowed for operands. + template Expr> operator-(const Expr> &x) { return {Negate>{x}}; @@ -638,7 +645,26 @@ Expr> operator-(const Expr> &x) { [](const auto &y) -> Expr> { return {-y}; }, x.u); } -#define BINARY(FUNC, CONSTR) \ +#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) +#undef BINARY + +#define OLDBINARY(FUNC, CONSTR) \ template A FUNC(const A &x, const A &y) { \ return {typename A::CONSTR{x, y}}; \ } \ @@ -655,12 +681,11 @@ Expr> operator-(const Expr> &x) { return {typename A::CONSTR{std::move(x), std::move(y)}}; \ } -BINARY(operator+, Add) -BINARY(operator-, Subtract) -BINARY(operator*, Multiply) -BINARY(operator/, Divide) -BINARY(Power, Power) -#undef BINARY +OLDBINARY(operator-, Subtract) +OLDBINARY(operator*, Multiply) +OLDBINARY(operator/, Divide) +OLDBINARY(Power, Power) +#undef OLDBINARY #define BINARY(FUNC, OP) \ template Expr FUNC(const A &x, const A &y) { \ diff --git a/flang/lib/evaluate/variable.h b/flang/lib/evaluate/variable.h index fa9396fd2c8f..9ce5bf9bdbf3 100644 --- a/flang/lib/evaluate/variable.h +++ b/flang/lib/evaluate/variable.h @@ -62,6 +62,7 @@ public: DataRef &base() { return *base_; } const Symbol &symbol() const { return *symbol_; } Expr LEN() const; + std::ostream &Dump(std::ostream &) const; private: CopyableIndirection base_; @@ -78,6 +79,7 @@ public: std::optional> lower() const; std::optional> upper() const; std::optional> stride() const; + std::ostream &Dump(std::ostream &) const; private: std::optional lower_, upper_, stride_; @@ -93,6 +95,7 @@ public: : u_{IndirectSubscriptIntegerExpr::Make(std::move(s))} {} explicit Subscript(const Triplet &t) : u_{t} {} explicit Subscript(Triplet &&t) : u_{std::move(t)} {} + std::ostream &Dump(std::ostream &) const; private: std::variant u_; @@ -111,6 +114,7 @@ public: ArrayRef(Component &&c, std::vector &&ss) : u_{std::move(c)}, subscript_(std::move(ss)) {} Expr LEN() const; + std::ostream &Dump(std::ostream &) const; private: std::variant u_; @@ -133,6 +137,7 @@ public: CoarrayRef &setStat(Variable &&); CoarrayRef &setTeam(Variable &&, bool isTeamNumber = false); Expr LEN() const; + std::ostream &Dump(std::ostream &) const; private: std::vector base_; @@ -154,6 +159,7 @@ public: explicit DataRef(ArrayRef &&a) : u_{std::move(a)} {} explicit DataRef(CoarrayRef &&a) : u_{std::move(a)} {} Expr LEN() const; + std::ostream &Dump(std::ostream &) const; private: std::variant u_; @@ -176,6 +182,7 @@ public: Expr last() const; Expr LEN() const; std::optional Fold(FoldingContext &); + std::ostream &Dump(std::ostream &) const; private: std::variant u_; @@ -192,6 +199,7 @@ public: ComplexPart(DataRef &&z, Part p) : complex_{std::move(z)}, part_{p} {} const DataRef &complex() const { return complex_; } Part part() const { return part_; } + std::ostream &Dump(std::ostream &) const; private: DataRef complex_; @@ -206,6 +214,7 @@ public: explicit Designator(DataRef &&d) : u_{std::move(d)} {} explicit Designator(Substring &&s) : u_{std::move(s)} {} explicit Designator(ComplexPart &&c) : u_{std::move(c)} {} + std::ostream &Dump(std::ostream &) const; private: std::variant u_; @@ -219,6 +228,7 @@ public: explicit ProcedureDesignator(const Component &c) : u_{c} {} explicit ProcedureDesignator(Component &&c) : u_{std::move(c)} {} Expr LEN() const; + std::ostream &Dump(std::ostream &) const; private: std::variant u_; @@ -232,6 +242,7 @@ public: : proc_{std::move(p)}, argument_(std::move(a)) {} const ProcedureDesignator &proc() const { return proc_; } const std::vector &argument() const { return argument_; } + std::ostream &Dump(std::ostream &) const; private: ProcedureDesignator proc_; @@ -245,6 +256,7 @@ public: CLASS_BOILERPLATE(Variable) explicit Variable(Designator &&d) : u_{std::move(d)} {} explicit Variable(FunctionRef &&p) : u_{std::move(p)} {} + std::ostream &Dump(std::ostream &) const; private: std::variant u_; @@ -255,6 +267,7 @@ public: CLASS_BOILERPLATE(ActualFunctionArg) explicit ActualFunctionArg(Expr &&x) : u_{std::move(x)} {} explicit ActualFunctionArg(Variable &&x) : u_{std::move(x)} {} + std::ostream &Dump(std::ostream &) const; private: std::variant>, Variable> u_; @@ -264,6 +277,7 @@ struct Label { // TODO: this is a placeholder CLASS_BOILERPLATE(Label) explicit Label(int lab) : label{lab} {} int label; + std::ostream &Dump(std::ostream &) const; }; class ActualSubroutineArg { @@ -272,6 +286,7 @@ public: explicit ActualSubroutineArg(Expr &&x) : u_{std::move(x)} {} explicit ActualSubroutineArg(Variable &&x) : u_{std::move(x)} {} explicit ActualSubroutineArg(const Label &l) : u_{&l} {} + std::ostream &Dump(std::ostream &) const; private: std::variant>, Variable, const Label *> u_; diff --git a/flang/test/evaluate/expression.cc b/flang/test/evaluate/expression.cc index d4d727f2646b..5c7ba2a8b75e 100644 --- a/flang/test/evaluate/expression.cc +++ b/flang/test/evaluate/expression.cc @@ -31,24 +31,24 @@ template std::string Dump(const A &x) { int main() { using DefaultIntegerExpr = Expr; TEST(DefaultIntegerExpr::Result::Dump() == "Integer(4)"); - MATCH("666", Dump(DefaultIntegerExpr{666})); - MATCH("(-1)", Dump(-DefaultIntegerExpr{1})); + MATCH("666_4", Dump(DefaultIntegerExpr{666})); + MATCH("(-1_4)", Dump(-DefaultIntegerExpr{1})); auto ex1{ DefaultIntegerExpr{2} + DefaultIntegerExpr{3} * -DefaultIntegerExpr{4}}; - MATCH("(2+(3*(-4)))", Dump(ex1)); + MATCH("(2_4+(3_4*(-4_4)))", Dump(ex1)); Fortran::parser::CharBlock src; Fortran::parser::ContextualMessages messages{src, nullptr}; FoldingContext context{messages}; ex1.Fold(context); - MATCH("-10", Dump(ex1)); - MATCH("(Integer(4)::6.LE.7)", + MATCH("-10_4", Dump(ex1)); + MATCH("(6_4.LE.7_4)", Dump(DefaultIntegerExpr{6} <= DefaultIntegerExpr{7})); DefaultIntegerExpr a{1}; DefaultIntegerExpr b{2}; - MATCH("(1/2)", Dump(a / b)); - MATCH("1", Dump(a)); + MATCH("(1_4/2_4)", Dump(a / b)); + MATCH("1_4", Dump(a)); a = b; - MATCH("2", Dump(a)); - MATCH("2", Dump(b)); + MATCH("2_4", Dump(a)); + MATCH("2_4", Dump(b)); return testing::Complete(); }