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 @@ -11,33 +11,19 @@ #include "flang/Runtime/descriptor.h" #include #include +#include namespace Fortran::runtime { -extern "C" { -void RTNAME(Transfer)(Descriptor &result, const Descriptor &source, - const Descriptor &mold, const char *sourceFile, int line) { - if (mold.rank() > 0) { - std::size_t moldElementBytes{mold.ElementBytes()}; - std::size_t elements{ - (source.Elements() * source.ElementBytes() + moldElementBytes - 1) / - moldElementBytes}; - return RTNAME(TransferSize)(result, source, mold, sourceFile, line, - static_cast(elements)); - } else { - return RTNAME(TransferSize)(result, source, mold, sourceFile, line, 1); - } -} - -void RTNAME(TransferSize)(Descriptor &result, const Descriptor &source, +static void TransferImpl(Descriptor &result, const Descriptor &source, const Descriptor &mold, const char *sourceFile, int line, - std::int64_t size) { - int rank{mold.rank() > 0 ? 1 : 0}; + std::optional resultExtent) { + int rank{resultExtent.has_value() ? 1 : 0}; std::size_t elementBytes{mold.ElementBytes()}; result.Establish(mold.type(), elementBytes, nullptr, rank, nullptr, CFI_attribute_allocatable, mold.Addendum() != nullptr); - if (rank > 0) { - result.GetDimension(0).SetBounds(1, size); + if (resultExtent) { + result.GetDimension(0).SetBounds(1, *resultExtent); } if (const DescriptorAddendum * addendum{mold.Addendum()}) { *result.Addendum() = *addendum; @@ -47,7 +33,7 @@ "TRANSFER: could not allocate memory for result; STAT=%d", stat); } char *to{result.OffsetElement()}; - std::size_t resultBytes{size * elementBytes}; + std::size_t resultBytes{result.Elements() * result.ElementBytes()}; const std::size_t sourceElementBytes{source.ElementBytes()}; std::size_t sourceElements{source.Elements()}; SubscriptValue sourceAt[maxRank]; @@ -65,5 +51,27 @@ } } +extern "C" { + +void RTNAME(Transfer)(Descriptor &result, const Descriptor &source, + const Descriptor &mold, const char *sourceFile, int line) { + 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, {}); + } +} + +void RTNAME(TransferSize)(Descriptor &result, const Descriptor &source, + const Descriptor &mold, const char *sourceFile, int line, + std::int64_t size) { + return TransferImpl(result, source, mold, sourceFile, line, size); +} + } // extern "C" } // namespace Fortran::runtime diff --git a/flang/unittests/Runtime/MiscIntrinsic.cpp b/flang/unittests/Runtime/MiscIntrinsic.cpp --- a/flang/unittests/Runtime/MiscIntrinsic.cpp +++ b/flang/unittests/Runtime/MiscIntrinsic.cpp @@ -68,3 +68,21 @@ EXPECT_EQ(result.OffsetElement()[1], 2.2F); result.Destroy(); } +TEST(MiscIntrinsic, TransferSizeScalarMold) { + StaticDescriptor<2, true, 2> staticDesc[2]; + auto &result{staticDesc[0].descriptor()}; + std::complex sourecStorage{1.1F, -2.2F}; + auto source{Descriptor::Create(TypeCategory::Complex, 4, + reinterpret_cast(&sourecStorage), 0, nullptr, + CFI_attribute_pointer)}; + auto &mold{staticDesc[1].descriptor()}; + mold.Establish(TypeCategory::Real, 4, nullptr, 0, nullptr); + RTNAME(TransferSize)(result, *source, mold, __FILE__, __LINE__, 2); + EXPECT_EQ(result.rank(), 1); + EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); + EXPECT_EQ(result.GetDimension(0).Extent(), 2); + EXPECT_EQ(result.type().raw(), (TypeCode{TypeCategory::Real, 4}.raw())); + EXPECT_EQ(result.OffsetElement()[0], 1.1F); + EXPECT_EQ(result.OffsetElement()[1], -2.2F); + result.Destroy(); +}