From e798ab7d9148638d9db5022f37b9603ad681df1f Mon Sep 17 00:00:00 2001 From: peter klausler <pklausler@nvidia.com> Date: Thu, 16 Aug 2018 11:46:18 -0700 Subject: [PATCH] [flang] checkpoint with clang workaround Original-commit: flang-compiler/f18@c4a2aaf8b10adc2aec0d66f020d358e2a2ac417b Reviewed-on: https://github.com/flang-compiler/f18/pull/183 Tree-same-pre-rewrite: false --- flang/lib/common/idioms.h | 6 +- flang/lib/evaluate/expression.cc | 303 +++++++++------------------- flang/lib/evaluate/expression.h | 315 +++++++++++++++--------------- flang/lib/evaluate/type.h | 12 +- flang/lib/semantics/expression.cc | 14 +- 5 files changed, 263 insertions(+), 387 deletions(-) diff --git a/flang/lib/common/idioms.h b/flang/lib/common/idioms.h index 26044db3be88..1e58172af9b6 100644 --- a/flang/lib/common/idioms.h +++ b/flang/lib/common/idioms.h @@ -54,10 +54,10 @@ namespace Fortran::common { // Helper templates for combining a list of lambdas into an anonymous // struct for use with std::visit() on a std::variant<> sum type. // E.g.: std::visit(visitors{ -// [&](const UnaryExpr &x) { ... }, -// [&](const BinaryExpr &x) { ... }, +// [&](const firstType &x) { ... }, +// [&](const secondType &x) { ... }, // ... -// }, structure.unionMember); +// [&](const auto &catchAll) { ... }}, variantObject); template<typename... LAMBDAS> struct visitors : LAMBDAS... { using LAMBDAS::operator()...; diff --git a/flang/lib/evaluate/expression.cc b/flang/lib/evaluate/expression.cc index 7ffeefd4e73a..dd40567fa01f 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -33,9 +33,11 @@ std::ostream &Operation<D, R, O...>::Dump(std::ostream &o) const { if constexpr (operands() > 1) { operand<1>().Dump(o << infix_); } - return o << derived().postfix_; + return o << derived().suffix_; } +// TODO: dump Convert<Integer,x> as INT(x,KIND=), &c. + template<typename D, typename R, typename... O> auto Operation<D, R, O...>::Fold(FoldingContext &context) -> std::optional<Scalar<Result>> { @@ -58,42 +60,32 @@ auto Convert<TO, FROM>::FoldScalar(FoldingContext &context, const Scalar<Operand> &c) -> std::optional<Scalar<Result>> { if constexpr (std::is_same_v<Result, Operand>) { return {c}; - } - if constexpr (std::is_same_v<Result, SomeType>) { + } else if constexpr (std::is_same_v<Result, SomeType>) { using Generic = SomeKind<Operand::category>; if constexpr (std::is_same_v<Operand, Generic>) { return {Scalar<Result>{c}}; } else { return {Scalar<Result>{Generic{c}}}; } - } - if constexpr (std::is_same_v<Operand, SomeType>) { + } else if constexpr (std::is_same_v<Operand, SomeType>) { return std::visit( [&](const auto &x) -> std::optional<Scalar<Result>> { - return Convert<Result, std::decay_t<decltype(x)>>::FoldScalar( - context, x); + using Ty = std::decay_t<decltype(x)>; + return Convert<Result, Ty>::FoldScalar(context, x); }, c.u); - } - // Result and Operand are distinct types with known categories. - if constexpr (std::is_same_v<Result, SomeKind<Result::category>>) { + } else if constexpr (std::is_same_v<Result, SomeKind<Result::category>>) { if constexpr (Result::category == Operand::category) { return {Scalar<Result>{c}}; } - return std::nullopt; - } - // Result is a specific type. - if constexpr (std::is_same_v<Operand, SomeKind<Operand::category>>) { + } else if constexpr (std::is_same_v<Operand, SomeKind<Operand::category>>) { return std::visit( [&](const auto &x) -> std::optional<Scalar<Result>> { - return Convert<Result, - ScalarValueType<std::decay_t<decltype(x)>>>::FoldScalar(context, - x); + using Ty = ScalarValueType<std::decay_t<decltype(x)>>; + return Convert<Result, Ty>::FoldScalar(context, x); }, c.u); - } - // Result and Operand are distinct specific types. - if constexpr (Result::category == TypeCategory::Integer) { + } else if constexpr (Result::category == TypeCategory::Integer) { if constexpr (Operand::category == TypeCategory::Integer) { auto converted{Scalar<Result>::ConvertSigned(c)}; if (converted.overflow) { @@ -101,8 +93,7 @@ auto Convert<TO, FROM>::FoldScalar(FoldingContext &context, } else { return {std::move(converted.value)}; } - } - if constexpr (Operand::category == TypeCategory::Real) { + } else if constexpr (Operand::category == TypeCategory::Real) { auto converted{c.template ToInteger<Scalar<Result>>()}; if (converted.flags.test(RealFlag::InvalidArgument)) { context.messages.Say( @@ -113,14 +104,12 @@ auto Convert<TO, FROM>::FoldScalar(FoldingContext &context, return {std::move(converted.value)}; } } - } - if constexpr (Result::category == TypeCategory::Real) { + } else if constexpr (Result::category == TypeCategory::Real) { if constexpr (Operand::category == TypeCategory::Integer) { auto converted{Scalar<Result>::FromInteger(c)}; RealFlagWarnings(context, converted.flags, "INTEGER to REAL conversion"); return {std::move(converted.value)}; - } - if constexpr (Operand::category == TypeCategory::Real) { + } else if constexpr (Operand::category == TypeCategory::Real) { auto converted{Scalar<Result>::Convert(c)}; RealFlagWarnings(context, converted.flags, "REAL to REAL conversion"); return {std::move(converted.value)}; @@ -129,18 +118,35 @@ auto Convert<TO, FROM>::FoldScalar(FoldingContext &context, return std::nullopt; } -// Dumping -template<typename... A> -std::ostream &DumpExprWithType(std::ostream &o, const std::variant<A...> &u) { - std::visit( - [&](const auto &x) { - using Ty = typename std::remove_reference_t<decltype(x)>::Result; - x.Dump(o << '(' << Ty::Dump() << "::") << ')'; - }, - u); - return o; +template<typename A> +auto Negate<A>::FoldScalar(FoldingContext &context, const Scalar<Operand> &c) + -> std::optional<Scalar<Result>> { + if constexpr (Result::category == TypeCategory::Integer) { + auto negated{c.Negate()}; + if (negated.overflow) { + context.messages.Say("INTEGER negation overflowed"_en_US); + } else { + return {std::move(negated.value)}; + } + } else { + return {c.Negate()}; // REAL & COMPLEX: no exceptions possible + } + return std::nullopt; } +template<int KIND, bool R> +auto ComplexComponent<KIND, R>::FoldScalar(FoldingContext &context, + const Scalar<Operand> &z) -> std::optional<Scalar<Result>> { + return {isRealPart ? z.REAL() : z.AIMAG()}; +} + +template<int KIND> +auto Not<KIND>::FoldScalar(FoldingContext &context, const Scalar<Operand> &x) + -> std::optional<Scalar<Result>> { + return {Scalar<Result>{!x.IsTrue()}}; +} + +// Dumping template<typename... A> std::ostream &DumpExpr(std::ostream &o, const std::variant<A...> &u) { std::visit(common::visitors{[&](const BOZLiteralConstant &x) { @@ -165,12 +171,6 @@ std::ostream &Expr<SomeType>::Dump(std::ostream &o) const { return DumpExpr(o, u); } -template<typename CRTP, typename RESULT, typename A> -std::ostream &Unary<CRTP, RESULT, A>::Dump( - std::ostream &o, const char *opr) const { - return operand().Dump(o << opr) << ')'; -} - template<typename CRTP, typename RESULT, typename A, typename B> std::ostream &Binary<CRTP, RESULT, A, B>::Dump( std::ostream &o, const char *opr, const char *before) const { @@ -184,8 +184,6 @@ std::ostream &Expr<Type<TypeCategory::Integer, KIND>>::Dump( common::visitors{[&](const Scalar<Result> &n) { o << n.SignedDecimal(); }, [&](const CopyableIndirection<DataRef> &d) { d->Dump(o); }, [&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); }, - [&](const Parentheses<Result> &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, "*"); }, @@ -193,9 +191,7 @@ std::ostream &Expr<Type<TypeCategory::Integer, KIND>>::Dump( [&](const Power &p) { p.Dump(o, "**"); }, [&](const Max &m) { m.Dump(o, ",", "MAX("); }, [&](const Min &m) { m.Dump(o, ",", "MIN("); }, - [&](const auto &convert) { - DumpExprWithType(o, convert.operand().u); - }}, + [&](const auto &x) { x.Dump(o); }}, u_); return o; } @@ -209,8 +205,12 @@ std::ostream &Expr<Type<TypeCategory::Real, KIND>>::Dump( [&](const CopyableIndirection<DataRef> &d) { d->Dump(o); }, [&](const CopyableIndirection<ComplexPart> &d) { d->Dump(o); }, [&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); }, + [&](const Convert<Result, SomeInteger> &c) { c.Dump(o); }, + [&](const Convert<Result, SomeReal> &c) { c.Dump(o); }, + [&](const ComplexComponent<KIND, true> &z) { z.Dump(o); }, + [&](const ComplexComponent<KIND, false> &z) { z.Dump(o); }, [&](const Parentheses<Result> &p) { p.Dump(o); }, - [&](const Negate &n) { n.Dump(o, "(-"); }, + [&](const Negate<Result> &n) { n.Dump(o); }, [&](const Add &a) { a.Dump(o, "+"); }, [&](const Subtract &s) { s.Dump(o, "-"); }, [&](const Multiply &m) { m.Dump(o, "*"); }, @@ -218,12 +218,7 @@ std::ostream &Expr<Type<TypeCategory::Real, KIND>>::Dump( [&](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 RealPart &z) { z.Dump(o, "REAL("); }, - [&](const AIMAG &p) { p.Dump(o, "AIMAG("); }, - [&](const auto &convert) { - DumpExprWithType(o, convert.operand().u); - }}, + [&](const Min &m) { m.Dump(o, ",", "MIN("); }}, u_); return o; } @@ -236,15 +231,14 @@ std::ostream &Expr<Type<TypeCategory::Complex, KIND>>::Dump( }, [&](const CopyableIndirection<DataRef> &d) { d->Dump(o); }, [&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); }, - [&](const Parentheses<Result> &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 CMPLX &c) { c.Dump(o, ","); }}, + [&](const CMPLX &c) { c.Dump(o, ","); }, + [&](const auto &x) { x.Dump(o); }}, u_); return o; } @@ -280,7 +274,7 @@ std::ostream &Expr<Type<TypeCategory::Logical, KIND>>::Dump( [&](const CopyableIndirection<DataRef> &d) { d->Dump(o); }, [&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); }, // [&](const Parentheses<Result> &p) { p.Dump(o); }, - [&](const Not &n) { n.Dump(o, "(.NOT."); }, + [&](const Not<KIND> &n) { n.Dump(o); }, [&](const And &a) { a.Dump(o, ".AND."); }, [&](const Or &a) { a.Dump(o, ".OR."); }, [&](const Eqv &a) { a.Dump(o, ".EQV."); }, @@ -328,15 +322,6 @@ int Binary<CRTP, RESULT, A, B>::Rank() const { } // Folding -template<typename CRTP, typename RESULT, typename A> -auto Unary<CRTP, RESULT, A>::Fold(FoldingContext &context) - -> std::optional<Scalar<Result>> { - if (std::optional<Scalar<Operand>> c{operand_->Fold(context)}) { - return static_cast<CRTP *>(this)->FoldScalar(context, *c); - } - return std::nullopt; -} - template<typename CRTP, typename RESULT, typename A, typename B> auto Binary<CRTP, RESULT, A, B>::Fold(FoldingContext &context) -> std::optional<Scalar<Result>> { @@ -348,55 +333,6 @@ auto Binary<CRTP, RESULT, A, B>::Fold(FoldingContext &context) return std::nullopt; } -template<int KIND> -auto Expr<Type<TypeCategory::Integer, KIND>>::ConvertInteger::FoldScalar( - FoldingContext &context, const SomeKindScalar<TypeCategory::Integer> &c) - -> std::optional<Scalar<Result>> { - return std::visit( - [&](auto &x) -> std::optional<Scalar<Result>> { - auto converted{Scalar<Result>::ConvertSigned(x)}; - if (converted.overflow) { - context.messages.Say("integer conversion overflowed"_en_US); - return std::nullopt; - } - return {std::move(converted.value)}; - }, - c.u); -} - -template<int KIND> -auto Expr<Type<TypeCategory::Integer, KIND>>::ConvertReal::FoldScalar( - FoldingContext &context, const SomeKindScalar<TypeCategory::Real> &c) - -> std::optional<Scalar<Result>> { - return std::visit( - [&](auto &x) -> std::optional<Scalar<Result>> { - auto converted{x.template ToInteger<Scalar<Result>>()}; - if (converted.flags.test(RealFlag::Overflow)) { - context.messages.Say("real->integer conversion overflowed"_en_US); - return std::nullopt; - } - if (converted.flags.test(RealFlag::InvalidArgument)) { - context.messages.Say( - "real->integer conversion: invalid argument"_en_US); - return std::nullopt; - } - return {std::move(converted.value)}; - }, - c.u); -} - -template<int KIND> -auto Expr<Type<TypeCategory::Integer, KIND>>::Negate::FoldScalar( - FoldingContext &context, const Scalar<Result> &c) - -> std::optional<Scalar<Result>> { - auto negated{c.Negate()}; - if (negated.overflow) { - context.messages.Say("integer negation overflowed"_en_US); - return std::nullopt; - } - return {std::move(negated.value)}; -} - template<int KIND> auto Expr<Type<TypeCategory::Integer, KIND>>::Add::FoldScalar( FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b) @@ -492,12 +428,12 @@ auto Expr<Type<TypeCategory::Integer, KIND>>::Min::FoldScalar( template<int KIND> auto Expr<Type<TypeCategory::Integer, KIND>>::Fold(FoldingContext &context) -> std::optional<Scalar<Result>> { + if (auto c{ScalarValue()}) { + return c; + } return std::visit( [&](auto &x) -> std::optional<Scalar<Result>> { using Ty = std::decay_t<decltype(x)>; - if constexpr (std::is_same_v<Ty, Scalar<Result>>) { - return {x}; - } if constexpr (evaluate::FoldableTrait<Ty>) { if (auto c{x.Fold(context)}) { if constexpr (std::is_same_v<Ty, Parentheses<Result>>) { @@ -514,39 +450,6 @@ auto Expr<Type<TypeCategory::Integer, KIND>>::Fold(FoldingContext &context) u_); } -template<int KIND> -auto Expr<Type<TypeCategory::Real, KIND>>::ConvertInteger::FoldScalar( - FoldingContext &context, const SomeKindScalar<TypeCategory::Integer> &c) - -> std::optional<Scalar<Result>> { - return std::visit( - [&](auto &x) -> std::optional<Scalar<Result>> { - auto converted{Scalar<Result>::FromInteger(x)}; - RealFlagWarnings(context, converted.flags, "integer->real conversion"); - return {std::move(converted.value)}; - }, - c.u); -} - -template<int KIND> -auto Expr<Type<TypeCategory::Real, KIND>>::ConvertReal::FoldScalar( - FoldingContext &context, const SomeKindScalar<TypeCategory::Real> &c) - -> std::optional<Scalar<Result>> { - return std::visit( - [&](auto &x) -> std::optional<Scalar<Result>> { - auto converted{Scalar<Result>::Convert(x)}; - RealFlagWarnings(context, converted.flags, "real conversion"); - return {std::move(converted.value)}; - }, - c.u); -} - -template<int KIND> -auto Expr<Type<TypeCategory::Real, KIND>>::Negate::FoldScalar( - FoldingContext &context, const Scalar<Result> &c) - -> std::optional<Scalar<Result>> { - return {c.Negate()}; -} - template<int KIND> auto Expr<Type<TypeCategory::Real, KIND>>::Add::FoldScalar( FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b) @@ -624,37 +527,26 @@ auto Expr<Type<TypeCategory::Real, KIND>>::Min::FoldScalar( return {a}; } -template<int KIND> -auto Expr<Type<TypeCategory::Real, KIND>>::RealPart::FoldScalar( - FoldingContext &context, - const Scalar<SameKind<TypeCategory::Complex, Result>> &z) - -> std::optional<Scalar<Result>> { - return {z.REAL()}; -} - -template<int KIND> -auto Expr<Type<TypeCategory::Real, KIND>>::AIMAG::FoldScalar( - FoldingContext &context, - const Scalar<SameKind<TypeCategory::Complex, Result>> &z) - -> std::optional<Scalar<Result>> { - return {z.AIMAG()}; -} - template<int KIND> auto Expr<Type<TypeCategory::Real, KIND>>::Fold(FoldingContext &context) -> std::optional<Scalar<Result>> { + if (auto c{ScalarValue()}) { + return c; + } return std::visit( [&](auto &x) -> std::optional<Scalar<Result>> { using Ty = std::decay_t<decltype(x)>; - if constexpr (std::is_same_v<Ty, Scalar<Result>>) { - return {x}; - } if constexpr (evaluate::FoldableTrait<Ty>) { if (auto c{x.Fold(context)}) { if (context.flushDenormalsToZero) { *c = c->FlushDenormalToZero(); } - u_ = *c; + if constexpr (std::is_same_v<Ty, Parentheses<Result>>) { + // Preserve parentheses around constants. + u_ = Parentheses<Result>{Expr{*c}}; + } else { + u_ = *c; + } return c; } } @@ -663,13 +555,6 @@ auto Expr<Type<TypeCategory::Real, KIND>>::Fold(FoldingContext &context) u_); } -template<int KIND> -auto Expr<Type<TypeCategory::Complex, KIND>>::Negate::FoldScalar( - FoldingContext &context, const Scalar<Result> &c) - -> std::optional<Scalar<Result>> { - return {c.Negate()}; -} - template<int KIND> auto Expr<Type<TypeCategory::Complex, KIND>>::Add::FoldScalar( FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b) @@ -739,18 +624,23 @@ auto Expr<Type<TypeCategory::Complex, KIND>>::CMPLX::FoldScalar( template<int KIND> auto Expr<Type<TypeCategory::Complex, KIND>>::Fold(FoldingContext &context) -> std::optional<Scalar<Result>> { + if (auto c{ScalarValue()}) { + return c; + } return std::visit( [&](auto &x) -> std::optional<Scalar<Result>> { using Ty = std::decay_t<decltype(x)>; - if constexpr (std::is_same_v<Ty, Scalar<Result>>) { - return {x}; - } if constexpr (evaluate::FoldableTrait<Ty>) { if (auto c{x.Fold(context)}) { if (context.flushDenormalsToZero) { *c = c->FlushDenormalToZero(); } - u_ = *c; + if constexpr (std::is_same_v<Ty, Parentheses<Result>>) { + // Preserve parentheses around constants. + u_ = Parentheses<Result>{Expr{*c}}; + } else { + u_ = *c; + } return c; } } @@ -792,12 +682,12 @@ auto Expr<Type<TypeCategory::Character, KIND>>::Min::FoldScalar( template<int KIND> auto Expr<Type<TypeCategory::Character, KIND>>::Fold(FoldingContext &context) -> std::optional<Scalar<Result>> { + if (auto c{ScalarValue()}) { + return c; + } return std::visit( [&](auto &x) -> std::optional<Scalar<Result>> { using Ty = std::decay_t<decltype(x)>; - if constexpr (std::is_same_v<Ty, Scalar<Result>>) { - return {x}; - } if constexpr (evaluate::FoldableTrait<Ty>) { if (auto c{x.Fold(context)}) { u_ = *c; @@ -860,13 +750,6 @@ auto Comparison<A>::FoldScalar(FoldingContext &c, const Scalar<Operand> &a, return std::nullopt; } -template<int KIND> -auto Expr<Type<TypeCategory::Logical, KIND>>::Not::FoldScalar( - FoldingContext &context, const Scalar<Result> &x) - -> std::optional<Scalar<Result>> { - return {Scalar<Result>{!x.IsTrue()}}; -} - template<int KIND> auto Expr<Type<TypeCategory::Logical, KIND>>::And::FoldScalar( FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b) @@ -898,12 +781,12 @@ auto Expr<Type<TypeCategory::Logical, KIND>>::Neqv::FoldScalar( template<int KIND> auto Expr<Type<TypeCategory::Logical, KIND>>::Fold(FoldingContext &context) -> std::optional<Scalar<Result>> { + if (auto c{ScalarValue()}) { + return c; + } return std::visit( [&](auto &x) -> std::optional<Scalar<Result>> { using Ty = std::decay_t<decltype(x)>; - if constexpr (std::is_same_v<Ty, Scalar<Result>>) { - return {x}; - } if constexpr (evaluate::FoldableTrait<Ty>) { if (auto c{x.Fold(context)}) { u_ = *c; @@ -989,13 +872,6 @@ int Expr<SomeType>::Rank() const { u); } -template class Expr<SomeType>; -template class Expr<SomeKind<TypeCategory::Integer>>; -template class Expr<SomeKind<TypeCategory::Real>>; -template class Expr<SomeKind<TypeCategory::Complex>>; -template class Expr<SomeKind<TypeCategory::Character>>; -template class Expr<SomeKind<TypeCategory::Logical>>; - template class Expr<Type<TypeCategory::Integer, 1>>; template class Expr<Type<TypeCategory::Integer, 2>>; template class Expr<Type<TypeCategory::Integer, 4>>; @@ -1011,11 +887,7 @@ template class Expr<Type<TypeCategory::Complex, 4>>; template class Expr<Type<TypeCategory::Complex, 8>>; template class Expr<Type<TypeCategory::Complex, 10>>; template class Expr<Type<TypeCategory::Complex, 16>>; -template class Expr<Type<TypeCategory::Character, 1>>; -template class Expr<Type<TypeCategory::Logical, 1>>; -template class Expr<Type<TypeCategory::Logical, 2>>; -template class Expr<Type<TypeCategory::Logical, 4>>; -template class Expr<Type<TypeCategory::Logical, 8>>; +template class Expr<Type<TypeCategory::Character, 1>>; // TODO others template struct Comparison<Type<TypeCategory::Integer, 1>>; template struct Comparison<Type<TypeCategory::Integer, 2>>; @@ -1032,5 +904,18 @@ template struct Comparison<Type<TypeCategory::Complex, 4>>; template struct Comparison<Type<TypeCategory::Complex, 8>>; template struct Comparison<Type<TypeCategory::Complex, 10>>; template struct Comparison<Type<TypeCategory::Complex, 16>>; -template struct Comparison<Type<TypeCategory::Character, 1>>; +template struct Comparison<Type<TypeCategory::Character, 1>>; // TODO others + +template class Expr<Type<TypeCategory::Logical, 1>>; +template class Expr<Type<TypeCategory::Logical, 2>>; +template class Expr<Type<TypeCategory::Logical, 4>>; +template class Expr<Type<TypeCategory::Logical, 8>>; + +template class Expr<SomeInteger>; +template class Expr<SomeReal>; +template class Expr<SomeComplex>; +template class Expr<SomeCharacter>; +template class Expr<SomeLogical>; + +template class Expr<SomeType>; } // namespace Fortran::evaluate diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index a8e2beaaedb9..54c03bd450b6 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -46,7 +46,19 @@ public: template<int J> using Operand = std::tuple_element_t<J, OperandTypes>; 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<OPERAND> &&... x) : operand_{std::move(x)...} {} Operation(const Expr<OPERAND> &... x) : operand_{x...} {} @@ -63,16 +75,25 @@ public: protected: // Overridable strings for Dump() - static constexpr const char *prefix_{"("}, *infix_{""}, *postfix_{")"}; + static constexpr const char *prefix_{"("}, *infix_{""}, *suffix_{")"}; private: std::tuple<CopyableIndirection<Expr<OPERAND>>...> operand_; }; +template<typename TO, typename FROM> +struct Convert : public Operation<Convert<TO, FROM>, TO, FROM> { + using Base = Operation<Convert<TO, FROM>, TO, FROM>; + using Base::Base; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; + static std::optional<Scalar<Result>> FoldScalar( + FoldingContext &, const Scalar<Operand> &); +}; + template<typename A> -class Parentheses : public Operation<Parentheses<A>, A, A> { +struct Parentheses : public Operation<Parentheses<A>, A, A> { using Base = Operation<Parentheses, A, A>; - friend Base; using Base::Base; using typename Base::Result; using Operand = typename Base::template Operand<0>; @@ -82,34 +103,44 @@ class Parentheses : public Operation<Parentheses<A>, A, A> { } }; -template<typename TO, typename FROM> -class Convert : public Operation<Convert<TO, FROM>, TO, FROM> { - using Base = Operation<Convert<TO, FROM>, TO, FROM>; - friend Base; +template<typename A> struct Negate : public Operation<Negate<A>, A, A> { + using Base = Operation<Negate, A, A>; using Base::Base; using typename Base::Result; using Operand = typename Base::template Operand<0>; static std::optional<Scalar<Result>> FoldScalar( FoldingContext &, const Scalar<Operand> &); + static constexpr const char *prefix_{"(-"}; }; -// Helper base classes for packaging subexpressions. -template<typename CRTP, typename RESULT, typename A = RESULT> class Unary { -public: - using Result = RESULT; - using Operand = A; - using FoldableTrait = std::true_type; - CLASS_BOILERPLATE(Unary) - Unary(const Expr<Operand> &a) : operand_{a} {} - Unary(Expr<Operand> &&a) : operand_{std::move(a)} {} - Unary(CopyableIndirection<Expr<Operand>> &&a) : operand_{std::move(a)} {} - const Expr<Operand> &operand() const { return *operand_; } - Expr<Operand> &operand() { return *operand_; } - std::ostream &Dump(std::ostream &, const char *opr) const; - int Rank() const { return operand_.Rank(); } - std::optional<Scalar<Result>> Fold(FoldingContext &); // TODO: array result -private: - CopyableIndirection<Expr<Operand>> operand_; +// TODO: re vs. im can be dynamic +template<int KIND, bool realPart = true> +struct ComplexComponent + : public Operation<ComplexComponent<KIND, realPart>, + Type<TypeCategory::Real, KIND>, Type<TypeCategory::Complex, KIND>> { + using Base = Operation<ComplexComponent, Type<TypeCategory::Real, KIND>, + Type<TypeCategory::Complex, KIND>>; + static constexpr bool isRealPart{realPart}; + using Base::Base; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; + static std::optional<Scalar<Result>> FoldScalar( + FoldingContext &, const Scalar<Operand> &); + static constexpr const char *prefix_{"(("}; + static constexpr const char *suffix_{isRealPart ? ")%RE)" : ")%IM)"}; +}; + +template<int KIND> +struct Not : public Operation<Not<KIND>, Type<TypeCategory::Logical, KIND>, + Type<TypeCategory::Logical, KIND>> { + using Base = Operation<Not, Type<TypeCategory::Logical, KIND>, + Type<TypeCategory::Logical, KIND>>; + using Base::Base; + using typename Base::Result; + using Operand = typename Base::template Operand<0>; + static std::optional<Scalar<Result>> FoldScalar( + FoldingContext &, const Scalar<Operand> &); + static constexpr const char *prefix_{"(.NOT."}; }; template<typename CRTP, typename RESULT, typename A = RESULT, typename B = A> @@ -147,25 +178,7 @@ public: using Result = Type<TypeCategory::Integer, KIND>; using FoldableTrait = std::true_type; - struct ConvertInteger : public Unary<ConvertInteger, Result, SomeInteger> { - using Unary<ConvertInteger, Result, SomeInteger>::Unary; - static std::optional<Scalar<Result>> FoldScalar( - FoldingContext &, const SomeKindScalar<TypeCategory::Integer> &); - }; - - struct ConvertReal : public Unary<ConvertReal, Result, SomeReal> { - using Unary<ConvertReal, Result, SomeReal>::Unary; - static std::optional<Scalar<Result>> FoldScalar( - FoldingContext &, const SomeKindScalar<TypeCategory::Real> &); - }; - - template<typename CRTP> using Un = Unary<CRTP, Result>; template<typename CRTP> using Bin = Binary<CRTP, Result>; - struct Negate : public Un<Negate> { - using Un<Negate>::Un; - static std::optional<Scalar<Result>> FoldScalar( - FoldingContext &, const Scalar<Result> &); - }; struct Add : public Bin<Add> { using Bin<Add>::Bin; static std::optional<Scalar<Result>> FoldScalar( @@ -208,31 +221,30 @@ public: Expr(std::int64_t n) : u_{Scalar<Result>{n}} {} Expr(std::uint64_t n) : u_{Scalar<Result>{n}} {} Expr(int n) : u_{Scalar<Result>{n}} {} - Expr(const Expr<SomeInteger> &x) : u_{ConvertInteger{x}} {} - Expr(Expr<SomeInteger> &&x) : u_{ConvertInteger{std::move(x)}} {} + Expr(const Expr<SomeInteger> &x) : u_{Convert<Result, SomeInteger>{x}} {} + Expr(Expr<SomeInteger> &&x) + : u_{Convert<Result, SomeInteger>{std::move(x)}} {} template<int K> Expr(const Expr<Type<TypeCategory::Integer, K>> &x) - : u_{ConvertInteger{Expr<SomeInteger>{x}}} {} + : u_{Convert<Result, SomeInteger>{Expr<SomeInteger>{x}}} {} template<int K> Expr(Expr<Type<TypeCategory::Integer, K>> &&x) - : u_{ConvertInteger{Expr<SomeInteger>{std::move(x)}}} {} - Expr(const Expr<SomeReal> &x) : u_{ConvertReal{x}} {} - Expr(Expr<SomeReal> &&x) : u_{ConvertReal{std::move(x)}} {} + : u_{Convert<Result, SomeInteger>{Expr<SomeInteger>{std::move(x)}}} {} + Expr(const Expr<SomeReal> &x) : u_{Convert<Result, SomeReal>{x}} {} + Expr(Expr<SomeReal> &&x) : u_{Convert<Result, SomeReal>{std::move(x)}} {} template<int K> Expr(const Expr<Type<TypeCategory::Real, K>> &x) - : u_{ConvertReal{Expr<SomeReal>{x}}} {} + : u_{Convert<Result, SomeReal>{Expr<SomeReal>{x}}} {} template<int K> Expr(Expr<Type<TypeCategory::Real, K>> &&x) - : u_{ConvertReal{Expr<SomeReal>{std::move(x)}}} {} + : u_{Convert<Result, SomeReal>{Expr<SomeReal>{std::move(x)}}} {} template<typename A> Expr(const A &x) : u_{x} {} template<typename A> - Expr(std::enable_if_t<!std::is_reference_v<A> && - (std::is_base_of_v<Un, A> || std::is_base_of_v<Bin, A>), - A> &&x) - : u_(std::move(x)) {} + Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u_(std::move(x)) {} template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {} std::optional<Scalar<Result>> ScalarValue() const { + // TODO: Also succeed when parenthesized constant return common::GetIf<Scalar<Result>>(u_); } std::optional<Scalar<Result>> Fold(FoldingContext &c); @@ -240,9 +252,9 @@ public: private: std::variant<Scalar<Result>, CopyableIndirection<DataRef>, - CopyableIndirection<FunctionRef>, ConvertInteger, ConvertReal, - Parentheses<Result>, Negate, Add, Subtract, Multiply, Divide, Power, Max, - Min> + CopyableIndirection<FunctionRef>, Convert<Result, SomeInteger>, + Convert<Result, SomeReal>, Parentheses<Result>, Negate<Result>, Add, + Subtract, Multiply, Divide, Power, Max, Min> u_; }; @@ -254,23 +266,8 @@ public: // N.B. Real->Complex and Complex->Real conversions are done with CMPLX // and part access operations (resp.). Conversions between kinds of // Complex are done via decomposition to Real and reconstruction. - struct ConvertInteger : public Unary<ConvertInteger, Result, SomeInteger> { - using Unary<ConvertInteger, Result, SomeInteger>::Unary; - static std::optional<Scalar<Result>> FoldScalar( - FoldingContext &, const SomeKindScalar<TypeCategory::Integer> &); - }; - struct ConvertReal : public Unary<ConvertReal, Result, SomeReal> { - using Unary<ConvertReal, Result, SomeReal>::Unary; - static std::optional<Scalar<Result>> FoldScalar( - FoldingContext &, const SomeKindScalar<TypeCategory::Real> &); - }; - template<typename CRTP> using Un = Unary<CRTP, Result>; + template<typename CRTP> using Bin = Binary<CRTP, Result>; - struct Negate : public Un<Negate> { - using Un<Negate>::Un; - static std::optional<Scalar<Result>> FoldScalar( - FoldingContext &, const Scalar<Result> &); - }; struct Add : public Bin<Add> { using Bin<Add>::Bin; static std::optional<Scalar<Result>> FoldScalar( @@ -311,44 +308,33 @@ public: static std::optional<Scalar<Result>> FoldScalar( FoldingContext &, const Scalar<Result> &, const Scalar<Result> &); }; - template<typename CRTP> - using ComplexUn = - Unary<CRTP, Result, SameKind<TypeCategory::Complex, Result>>; - struct RealPart : public ComplexUn<RealPart> { - using ComplexUn<RealPart>::ComplexUn; - static std::optional<Scalar<Result>> FoldScalar(FoldingContext &, - const Scalar<SameKind<TypeCategory::Complex, Result>> &); - }; - struct AIMAG : public ComplexUn<AIMAG> { - using ComplexUn<AIMAG>::ComplexUn; - static std::optional<Scalar<Result>> FoldScalar(FoldingContext &, - const Scalar<SameKind<TypeCategory::Complex, Result>> &); - }; CLASS_BOILERPLATE(Expr) Expr(const Scalar<Result> &x) : u_{x} {} - Expr(const Expr<SomeInteger> &x) : u_{ConvertInteger{x}} {} - Expr(Expr<SomeInteger> &&x) : u_{ConvertInteger{std::move(x)}} {} + Expr(const Expr<SomeInteger> &x) : u_{Convert<Result, SomeInteger>{x}} {} + Expr(Expr<SomeInteger> &&x) + : u_{Convert<Result, SomeInteger>{std::move(x)}} {} template<int K> Expr(const Expr<Type<TypeCategory::Integer, K>> &x) - : u_{ConvertInteger{Expr<SomeInteger>{x}}} {} + : u_{Convert<Result, SomeInteger>{Expr<SomeInteger>{x}}} {} template<int K> Expr(Expr<Type<TypeCategory::Integer, K>> &&x) - : u_{ConvertInteger{Expr<SomeInteger>{std::move(x)}}} {} - Expr(const Expr<SomeReal> &x) : u_{ConvertReal{x}} {} - Expr(Expr<SomeReal> &&x) : u_{ConvertReal{std::move(x)}} {} + : u_{Convert<Result, SomeInteger>{Expr<SomeInteger>{std::move(x)}}} {} + Expr(const Expr<SomeReal> &x) : u_{Convert<Result, SomeReal>{x}} {} + Expr(Expr<SomeReal> &&x) : u_{Convert<Result, SomeReal>{std::move(x)}} {} template<int K> Expr(const Expr<Type<TypeCategory::Real, K>> &x) - : u_{ConvertReal{Expr<SomeReal>{x}}} {} + : u_{Convert<Result, SomeReal>{Expr<SomeReal>{x}}} {} template<int K> Expr(Expr<Type<TypeCategory::Real, K>> &&x) - : u_{ConvertReal{Expr<SomeReal>{std::move(x)}}} {} + : u_{Convert<Result, SomeReal>{Expr<SomeReal>{std::move(x)}}} {} template<typename A> Expr(const A &x) : u_{x} {} template<typename A> Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u_{std::move(x)} {} template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {} std::optional<Scalar<Result>> ScalarValue() const { + // TODO: parenthesized constants too return common::GetIf<Scalar<Result>>(u_); } std::optional<Scalar<Result>> Fold(FoldingContext &c); @@ -357,8 +343,10 @@ public: private: std::variant<Scalar<Result>, CopyableIndirection<DataRef>, CopyableIndirection<ComplexPart>, CopyableIndirection<FunctionRef>, - ConvertInteger, ConvertReal, Parentheses<Result>, Negate, Add, Subtract, - Multiply, Divide, Power, IntPower, Max, Min, RealPart, AIMAG> + Convert<Result, SomeInteger>, Convert<Result, SomeReal>, + ComplexComponent<KIND, true>, ComplexComponent<KIND, false>, + Parentheses<Result>, Negate<Result>, Add, Subtract, Multiply, Divide, + Power, IntPower, Max, Min> u_; }; @@ -367,13 +355,7 @@ public: using Result = Type<TypeCategory::Complex, KIND>; using FoldableTrait = std::true_type; - template<typename CRTP> using Un = Unary<CRTP, Result>; template<typename CRTP> using Bin = Binary<CRTP, Result>; - struct Negate : public Un<Negate> { - using Un<Negate>::Un; - static std::optional<Scalar<Result>> FoldScalar( - FoldingContext &, const Scalar<Result> &); - }; struct Add : public Bin<Add> { using Bin<Add>::Bin; static std::optional<Scalar<Result>> FoldScalar( @@ -420,6 +402,7 @@ public: template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {} std::optional<Scalar<Result>> ScalarValue() const { + // TODO: parenthesized constants too return common::GetIf<Scalar<Result>>(u_); } std::optional<Scalar<Result>> Fold(FoldingContext &c); @@ -427,11 +410,27 @@ public: private: std::variant<Scalar<Result>, CopyableIndirection<DataRef>, - CopyableIndirection<FunctionRef>, Parentheses<Result>, Negate, Add, - Subtract, Multiply, Divide, Power, IntPower, CMPLX> + CopyableIndirection<FunctionRef>, Parentheses<Result>, Negate<Result>, + Add, Subtract, Multiply, Divide, Power, IntPower, CMPLX> u_; }; +extern template class Expr<Type<TypeCategory::Integer, 1>>; +extern template class Expr<Type<TypeCategory::Integer, 2>>; +extern template class Expr<Type<TypeCategory::Integer, 4>>; +extern template class Expr<Type<TypeCategory::Integer, 8>>; +extern template class Expr<Type<TypeCategory::Integer, 16>>; +extern template class Expr<Type<TypeCategory::Real, 2>>; +extern template class Expr<Type<TypeCategory::Real, 4>>; +extern template class Expr<Type<TypeCategory::Real, 8>>; +extern template class Expr<Type<TypeCategory::Real, 10>>; +extern template class Expr<Type<TypeCategory::Real, 16>>; +extern template class Expr<Type<TypeCategory::Complex, 2>>; +extern template class Expr<Type<TypeCategory::Complex, 4>>; +extern template class Expr<Type<TypeCategory::Complex, 8>>; +extern template class Expr<Type<TypeCategory::Complex, 10>>; +extern template class Expr<Type<TypeCategory::Complex, 16>>; + template<int KIND> class Expr<Type<TypeCategory::Character, KIND>> { public: using Result = Type<TypeCategory::Character, KIND>; @@ -462,6 +461,7 @@ public: template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {} std::optional<Scalar<Result>> ScalarValue() const { + // TODO: parenthesized constants too return common::GetIf<Scalar<Result>>(u_); } std::optional<Scalar<Result>> Fold(FoldingContext &c); @@ -482,9 +482,8 @@ private: ENUM_CLASS(RelationalOperator, LT, LE, EQ, NE, GE, GT) template<typename A> -struct Comparison - : public Binary<Comparison<A>, Type<TypeCategory::Logical, 1>, A> { - using Result = Type<TypeCategory::Logical, 1>; +struct Comparison : public Binary<Comparison<A>, LogicalResult, A> { + using Result = LogicalResult; using Operand = A; using Base = Binary<Comparison, Result, Operand>; CLASS_BOILERPLATE(Comparison) @@ -498,27 +497,10 @@ struct Comparison RelationalOperator opr; }; -extern template struct Comparison<Type<TypeCategory::Integer, 1>>; -extern template struct Comparison<Type<TypeCategory::Integer, 2>>; -extern template struct Comparison<Type<TypeCategory::Integer, 4>>; -extern template struct Comparison<Type<TypeCategory::Integer, 8>>; -extern template struct Comparison<Type<TypeCategory::Integer, 16>>; -extern template struct Comparison<Type<TypeCategory::Real, 2>>; -extern template struct Comparison<Type<TypeCategory::Real, 4>>; -extern template struct Comparison<Type<TypeCategory::Real, 8>>; -extern template struct Comparison<Type<TypeCategory::Real, 10>>; -extern template struct Comparison<Type<TypeCategory::Real, 16>>; -extern template struct Comparison<Type<TypeCategory::Complex, 2>>; -extern template struct Comparison<Type<TypeCategory::Complex, 4>>; -extern template struct Comparison<Type<TypeCategory::Complex, 8>>; -extern template struct Comparison<Type<TypeCategory::Complex, 10>>; -extern template struct Comparison<Type<TypeCategory::Complex, 16>>; -extern template struct Comparison<Type<TypeCategory::Character, 1>>; - // Dynamically polymorphic comparisons whose operands are expressions of // the same supported kind of a particular type category. template<TypeCategory CAT> struct CategoryComparison { - using Result = Type<TypeCategory::Logical, 1>; + using Result = LogicalResult; CLASS_BOILERPLATE(CategoryComparison) template<int KIND> using KindComparison = Comparison<Type<CAT, KIND>>; template<int KIND> CategoryComparison(const KindComparison<KIND> &x) : u{x} {} @@ -526,18 +508,14 @@ template<TypeCategory CAT> struct CategoryComparison { CategoryComparison(KindComparison<KIND> &&x) : u{std::move(x)} {} std::optional<Scalar<Result>> Fold(FoldingContext &c); int Rank() const { return 1; } // TODO - typename KindsVariant<CAT, KindComparison>::type u; + + KindsVariant<CAT, KindComparison> u; }; template<int KIND> class Expr<Type<TypeCategory::Logical, KIND>> { public: using Result = Type<TypeCategory::Logical, KIND>; using FoldableTrait = std::true_type; - struct Not : Unary<Not, Result> { - using Unary<Not, Result>::Unary; - static std::optional<Scalar<Result>> FoldScalar( - FoldingContext &, const Scalar<Result> &); - }; template<typename CRTP> using Bin = Binary<CRTP, Result>; struct And : public Bin<And> { using Bin<And>::Bin; @@ -574,6 +552,7 @@ public: template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {} std::optional<Scalar<Result>> ScalarValue() const { + // TODO: parenthesized constants too return common::GetIf<Scalar<Result>>(u_); } std::optional<Scalar<Result>> Fold(FoldingContext &c); @@ -583,34 +562,13 @@ private: std::variant<Scalar<Result>, CopyableIndirection<DataRef>, CopyableIndirection<FunctionRef>, // Parentheses<Result>, - Not, And, Or, Eqv, Neqv, CategoryComparison<TypeCategory::Integer>, + Not<KIND>, And, Or, Eqv, Neqv, CategoryComparison<TypeCategory::Integer>, CategoryComparison<TypeCategory::Real>, CategoryComparison<TypeCategory::Complex>, CategoryComparison<TypeCategory::Character>> u_; }; -extern template class Expr<Type<TypeCategory::Integer, 1>>; -extern template class Expr<Type<TypeCategory::Integer, 2>>; -extern template class Expr<Type<TypeCategory::Integer, 4>>; -extern template class Expr<Type<TypeCategory::Integer, 8>>; -extern template class Expr<Type<TypeCategory::Integer, 16>>; -extern template class Expr<Type<TypeCategory::Real, 2>>; -extern template class Expr<Type<TypeCategory::Real, 4>>; -extern template class Expr<Type<TypeCategory::Real, 8>>; -extern template class Expr<Type<TypeCategory::Real, 10>>; -extern template class Expr<Type<TypeCategory::Real, 16>>; -extern template class Expr<Type<TypeCategory::Complex, 2>>; -extern template class Expr<Type<TypeCategory::Complex, 4>>; -extern template class Expr<Type<TypeCategory::Complex, 8>>; -extern template class Expr<Type<TypeCategory::Complex, 10>>; -extern template class Expr<Type<TypeCategory::Complex, 16>>; -extern template class Expr<Type<TypeCategory::Character, 1>>; -extern template class Expr<Type<TypeCategory::Logical, 1>>; -extern template class Expr<Type<TypeCategory::Logical, 2>>; -extern template class Expr<Type<TypeCategory::Logical, 4>>; -extern template class Expr<Type<TypeCategory::Logical, 8>>; - // Dynamically polymorphic expressions that can hold any supported kind // of a specific intrinsic type category. template<TypeCategory CAT> class Expr<SomeKind<CAT>> { @@ -618,20 +576,16 @@ public: using Result = SomeKind<CAT>; using FoldableTrait = std::true_type; CLASS_BOILERPLATE(Expr) + template<int KIND> using KindExpr = Expr<Type<CAT, KIND>>; template<int KIND> Expr(const KindExpr<KIND> &x) : u{x} {} template<int KIND> Expr(KindExpr<KIND> &&x) : u{std::move(x)} {} std::optional<Scalar<Result>> ScalarValue() const; std::optional<Scalar<Result>> Fold(FoldingContext &); int Rank() const; - typename KindsVariant<CAT, KindExpr>::type u; -}; -extern template class Expr<SomeInteger>; -extern template class Expr<SomeReal>; -extern template class Expr<SomeComplex>; -extern template class Expr<SomeCharacter>; -extern template class Expr<SomeLogical>; + KindsVariant<CAT, KindExpr> u; +}; // BOZ literal constants need to be wide enough to hold an integer or real // value of any supported kind. They also need to be distinguishable from @@ -666,7 +620,6 @@ public: u; }; -extern template class Expr<SomeType>; using GenericExpr = Expr<SomeType>; // TODO: delete name? template<typename A> using ResultType = typename std::decay_t<A>::Result; @@ -675,7 +628,15 @@ template<typename A> using ResultType = typename std::decay_t<A>::Result; // These definitions are created with temporary helper macros to reduce // C++ boilerplate. All combinations of lvalue and rvalue references are // allowed for operands. -template<typename A> A operator-(const A &x) { return {typename A::Negate{x}}; } +template<TypeCategory C, int K> +Expr<Type<C, K>> operator-(const Expr<Type<C, K>> &x) { + return {Negate<Type<C, K>>{x}}; +} +template<TypeCategory C> +Expr<SomeKind<C>> operator-(const Expr<SomeKind<C>> &x) { + return std::visit( + [](const auto &y) -> Expr<SomeKind<C>> { return {-y}; }, x.u); +} #define BINARY(FUNC, CONSTR) \ template<typename A> A FUNC(const A &x, const A &y) { \ @@ -728,5 +689,35 @@ BINARY(operator!=, RelationalOperator::NE) BINARY(operator>=, RelationalOperator::GE) BINARY(operator>, RelationalOperator::GT) #undef BINARY + +extern template class Expr<Type<TypeCategory::Character, 1>>; // TODO others +extern template struct Comparison<Type<TypeCategory::Integer, 1>>; +extern template struct Comparison<Type<TypeCategory::Integer, 2>>; +extern template struct Comparison<Type<TypeCategory::Integer, 4>>; +extern template struct Comparison<Type<TypeCategory::Integer, 8>>; +extern template struct Comparison<Type<TypeCategory::Integer, 16>>; +extern template struct Comparison<Type<TypeCategory::Real, 2>>; +extern template struct Comparison<Type<TypeCategory::Real, 4>>; +extern template struct Comparison<Type<TypeCategory::Real, 8>>; +extern template struct Comparison<Type<TypeCategory::Real, 10>>; +extern template struct Comparison<Type<TypeCategory::Real, 16>>; +extern template struct Comparison<Type<TypeCategory::Complex, 2>>; +extern template struct Comparison<Type<TypeCategory::Complex, 4>>; +extern template struct Comparison<Type<TypeCategory::Complex, 8>>; +extern template struct Comparison<Type<TypeCategory::Complex, 10>>; +extern template struct Comparison<Type<TypeCategory::Complex, 16>>; +extern template struct Comparison<Type<TypeCategory::Character, 1>>; // TODO + // more +extern template class Expr<Type<TypeCategory::Logical, 1>>; +extern template class Expr<Type<TypeCategory::Logical, 2>>; +extern template class Expr<Type<TypeCategory::Logical, 4>>; +extern template class Expr<Type<TypeCategory::Logical, 8>>; +extern template class Expr<SomeInteger>; +extern template class Expr<SomeReal>; +extern template class Expr<SomeComplex>; +extern template class Expr<SomeCharacter>; +extern template class Expr<SomeLogical>; +extern template class Expr<SomeType>; + } // namespace Fortran::evaluate #endif // FORTRAN_EVALUATE_EXPRESSION_H_ diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index a2bf59855e02..5e3d2c108e1c 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -149,16 +149,20 @@ using LogicalResult = Type<TypeCategory::Logical, 1>; // These macros and template create instances of std::variant<> that can contain // applications of some class template to all of the supported kinds of // a category of intrinsic type. -template<TypeCategory CAT, template<int> class T> struct KindsVariant; +template<TypeCategory CAT, template<int> class T> struct VariantOverKinds; #define TKIND(K) T<K> #define MAKE(Cat, CAT) \ - template<template<int> class T> struct KindsVariant<TypeCategory::Cat, T> { \ + template<template<int> class T> \ + struct VariantOverKinds<TypeCategory::Cat, T> { \ using type = std::variant<FOR_EACH_##CAT##_KIND(TKIND, COMMA)>; \ }; FOR_EACH_CATEGORY(MAKE) #undef MAKE #undef TKIND +template<TypeCategory CAT, template<int> class T> +using KindsVariant = typename VariantOverKinds<CAT, T>::type; + // Map scalar value types back to their Fortran types. // For every type T = Type<CAT, KIND>, TypeOfScalarValue<T>> == T. // E.g., TypeOfScalarValue<Integer<32>> is Type<TypeCategory::Integer, 4>. @@ -195,7 +199,6 @@ template<TypeCategory CAT> struct SomeKindScalar { static constexpr TypeCategory category{CAT}; CLASS_BOILERPLATE(SomeKindScalar) - template<int KIND> using KindScalar = Scalar<Type<CAT, KIND>>; template<typename A> SomeKindScalar(const A &x) : u{x} {} template<typename A> SomeKindScalar(std::enable_if_t<!std::is_reference_v<A>, A> &&x) @@ -213,7 +216,8 @@ template<TypeCategory CAT> struct SomeKindScalar { return common::GetIf<std::string>(u); } - typename KindsVariant<CAT, KindScalar>::type u; + template<int KIND> using KindScalar = Scalar<Type<CAT, KIND>>; + KindsVariant<CAT, KindScalar> u; }; // Holds a scalar constant of any intrinsic category and size. diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index 4fcce0cdb107..eb69ed8e4ccb 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -265,20 +265,16 @@ static std::optional<Expr<evaluate::SomeReal>> AnalyzeLiteral( static std::optional<Expr<evaluate::SomeReal>> AnalyzeLiteral( ExpressionAnalyzer &ea, const parser::SignedRealLiteralConstant &x) { - auto result{AnalyzeLiteral(ea, std::get<parser::RealLiteralConstant>(x.t))}; - if (result.has_value()) { + if (auto result{ + AnalyzeLiteral(ea, std::get<parser::RealLiteralConstant>(x.t))}) { if (auto sign{std::get<std::optional<parser::Sign>>(x.t)}) { if (sign == parser::Sign::Negative) { - std::visit( - [](auto &rk) { - using t = std::decay_t<decltype(rk)>; - rk = typename t::Negate{rk}; - }, - result->u); + return {-*result}; } } + return result; } - return result; + return std::nullopt; } template<>