@@ -215,6 +215,115 @@ Expr<Type<TypeCategory::Logical, KIND>> FoldIntrinsicFunction(
215215 if (auto *expr{UnwrapExpr<Expr<SomeLogical>>(args[0 ])}) {
216216 return Fold (context, ConvertToType<T>(std::move (*expr)));
217217 }
218+ } else if (name == " out_of_range" ) {
219+ if (Expr<SomeType> * cx{UnwrapExpr<Expr<SomeType>>(args[0 ])}) {
220+ auto restorer{context.messages ().DiscardMessages ()};
221+ *args[0 ] = Fold (context, std::move (*cx));
222+ if (Expr<SomeType> & folded{DEREF (args[0 ].value ().UnwrapExpr ())};
223+ IsActuallyConstant (folded)) {
224+ std::optional<std::vector<typename T::Scalar>> result;
225+ if (Expr<SomeReal> * realMold{UnwrapExpr<Expr<SomeReal>>(args[1 ])}) {
226+ if (const auto *xInt{UnwrapExpr<Expr<SomeInteger>>(folded)}) {
227+ result.emplace ();
228+ std::visit (
229+ [&](const auto &mold, const auto &x) {
230+ using RealType =
231+ typename std::decay_t <decltype (mold)>::Result;
232+ static_assert (RealType::category == TypeCategory::Real);
233+ using Scalar = typename RealType::Scalar;
234+ using xType = typename std::decay_t <decltype (x)>::Result;
235+ const auto &xConst{DEREF (UnwrapExpr<Constant<xType>>(x))};
236+ for (const auto &elt : xConst.values ()) {
237+ result->emplace_back (
238+ Scalar::template FromInteger (elt).flags .test (
239+ RealFlag::Overflow));
240+ }
241+ },
242+ realMold->u , xInt->u );
243+ } else if (const auto *xReal{UnwrapExpr<Expr<SomeReal>>(folded)}) {
244+ result.emplace ();
245+ std::visit (
246+ [&](const auto &mold, const auto &x) {
247+ using RealType =
248+ typename std::decay_t <decltype (mold)>::Result;
249+ static_assert (RealType::category == TypeCategory::Real);
250+ using Scalar = typename RealType::Scalar;
251+ using xType = typename std::decay_t <decltype (x)>::Result;
252+ const auto &xConst{DEREF (UnwrapExpr<Constant<xType>>(x))};
253+ for (const auto &elt : xConst.values ()) {
254+ result->emplace_back (elt.IsFinite () &&
255+ Scalar::template Convert (elt).flags .test (
256+ RealFlag::Overflow));
257+ }
258+ },
259+ realMold->u , xReal->u );
260+ }
261+ } else if (Expr<SomeInteger> *
262+ intMold{UnwrapExpr<Expr<SomeInteger>>(args[1 ])}) {
263+ if (const auto *xInt{UnwrapExpr<Expr<SomeInteger>>(folded)}) {
264+ result.emplace ();
265+ std::visit (
266+ [&](const auto &mold, const auto &x) {
267+ using IntType = typename std::decay_t <decltype (mold)>::Result;
268+ static_assert (IntType::category == TypeCategory::Integer);
269+ using Scalar = typename IntType::Scalar;
270+ using xType = typename std::decay_t <decltype (x)>::Result;
271+ const auto &xConst{DEREF (UnwrapExpr<Constant<xType>>(x))};
272+ for (const auto &elt : xConst.values ()) {
273+ result->emplace_back (
274+ Scalar::template ConvertSigned (elt).overflow );
275+ }
276+ },
277+ intMold->u , xInt->u );
278+ } else if (Expr<SomeLogical> *
279+ cRound{args.size () >= 3
280+ ? UnwrapExpr<Expr<SomeLogical>>(args[2 ])
281+ : nullptr };
282+ !cRound || IsActuallyConstant (*args[2 ]->UnwrapExpr ())) {
283+ if (const auto *xReal{UnwrapExpr<Expr<SomeReal>>(folded)}) {
284+ common::RoundingMode roundingMode{common::RoundingMode::ToZero};
285+ if (cRound &&
286+ common::visit (
287+ [](const auto &x) {
288+ using xType =
289+ typename std::decay_t <decltype (x)>::Result;
290+ return GetScalarConstantValue<xType>(x)
291+ .value ()
292+ .IsTrue ();
293+ },
294+ cRound->u )) {
295+ // ROUND=.TRUE. - convert with NINT()
296+ roundingMode = common::RoundingMode::TiesAwayFromZero;
297+ }
298+ result.emplace ();
299+ std::visit (
300+ [&](const auto &mold, const auto &x) {
301+ using IntType =
302+ typename std::decay_t <decltype (mold)>::Result;
303+ static_assert (IntType::category == TypeCategory::Integer);
304+ using Scalar = typename IntType::Scalar;
305+ using xType = typename std::decay_t <decltype (x)>::Result;
306+ const auto &xConst{DEREF (UnwrapExpr<Constant<xType>>(x))};
307+ for (const auto &elt : xConst.values ()) {
308+ // Note that OUT_OF_RANGE(Inf/NaN) is .TRUE. for the
309+ // real->integer case, but not for real->real.
310+ result->emplace_back (!elt.IsFinite () ||
311+ elt.template ToInteger <Scalar>(roundingMode)
312+ .flags .test (RealFlag::Overflow));
313+ }
314+ },
315+ intMold->u , xReal->u );
316+ }
317+ }
318+ }
319+ if (result) {
320+ if (auto extents{GetConstantExtents (context, folded)}) {
321+ return Expr<T>{
322+ Constant<T>{std::move (*result), std::move (*extents)}};
323+ }
324+ }
325+ }
326+ }
218327 } else if (name == " parity" ) {
219328 return FoldAllAnyParity (
220329 context, std::move (funcRef), &Scalar<T>::NEQV, Scalar<T>{false });
@@ -242,9 +351,7 @@ Expr<Type<TypeCategory::Logical, KIND>> FoldIntrinsicFunction(
242351 name == " __builtin_ieee_support_underflow_control" ) {
243352 return Expr<T>{true };
244353 }
245- // TODO: is_iostat_end,
246- // is_iostat_eor, logical, matmul, out_of_range,
247- // parity
354+ // TODO: is_iostat_end, is_iostat_eor, logical, matmul, parity
248355 return Expr<T>{std::move (funcRef)};
249356}
250357
0 commit comments