diff --git a/flang/lib/Evaluate/shape.cpp b/flang/lib/Evaluate/shape.cpp --- a/flang/lib/Evaluate/shape.cpp +++ b/flang/lib/Evaluate/shape.cpp @@ -931,19 +931,34 @@ } else { // SIZE= is absent and MOLD= is array: result is vector whose // length is determined by sizes of types. See 16.9.193p4 case(ii). + // Note that if sourceBytes is not known to be empty, we + // can fold only when moldElementBytes is known to not be zero; + // the most general case risks a division by zero otherwise. if (auto sourceTypeAndShape{ characteristics::TypeAndShape::Characterize( call.arguments().at(0), *context_)}) { - auto sourceBytes{ - sourceTypeAndShape->MeasureSizeInBytes(*context_)}; - auto moldElementBytes{ - moldTypeAndShape->MeasureElementSizeInBytes(*context_, true)}; - if (sourceBytes && moldElementBytes) { - ExtentExpr extent{Fold(*context_, - (std::move(*sourceBytes) + - common::Clone(*moldElementBytes) - ExtentExpr{1}) / - common::Clone(*moldElementBytes))}; - return Shape{MaybeExtentExpr{std::move(extent)}}; + if (auto sourceBytes{ + sourceTypeAndShape->MeasureSizeInBytes(*context_)}) { + *sourceBytes = Fold(*context_, std::move(*sourceBytes)); + if (auto sourceBytesConst{ToInt64(*sourceBytes)}) { + if (*sourceBytesConst == 0) { + return Shape{ExtentExpr{0}}; + } + } + if (auto moldElementBytes{ + moldTypeAndShape->MeasureElementSizeInBytes( + *context_, true)}) { + *moldElementBytes = + Fold(*context_, std::move(*moldElementBytes)); + auto moldElementBytesConst{ToInt64(*moldElementBytes)}; + if (moldElementBytesConst && *moldElementBytesConst != 0) { + ExtentExpr extent{Fold(*context_, + (std::move(*sourceBytes) + + common::Clone(*moldElementBytes) - ExtentExpr{1}) / + common::Clone(*moldElementBytes))}; + return Shape{MaybeExtentExpr{std::move(extent)}}; + } + } } } } diff --git a/flang/runtime/misc-intrinsic.cpp b/flang/runtime/misc-intrinsic.cpp --- a/flang/runtime/misc-intrinsic.cpp +++ b/flang/runtime/misc-intrinsic.cpp @@ -55,16 +55,23 @@ void RTNAME(Transfer)(Descriptor &result, const Descriptor &source, const Descriptor &mold, const char *sourceFile, int line) { + std::optional elements; if (mold.rank() > 0) { - std::size_t moldElementBytes{mold.ElementBytes()}; - std::size_t elements{ - (source.Elements() * source.ElementBytes() + moldElementBytes - 1) / - moldElementBytes}; - return TransferImpl(result, source, mold, sourceFile, line, - static_cast(elements)); - } else { - return TransferImpl(result, source, mold, sourceFile, line, {}); + if (std::size_t sourceElementBytes{ + source.Elements() * source.ElementBytes()}) { + if (std::size_t moldElementBytes{mold.ElementBytes()}) { + elements = static_cast( + (sourceElementBytes + moldElementBytes - 1) / moldElementBytes); + } else { + Terminator{sourceFile, line}.Crash("TRANSFER: zero-sized type of MOLD= " + "when SOURCE= is not zero-sized"); + } + } else { + elements = 0; + } } + return TransferImpl( + result, source, mold, sourceFile, line, std::move(elements)); } void RTNAME(TransferSize)(Descriptor &result, const Descriptor &source,