diff --git a/flang/runtime/assign.cpp b/flang/runtime/assign.cpp index 8c1ee296c02ac..c0d50e4e7ead4 100644 --- a/flang/runtime/assign.cpp +++ b/flang/runtime/assign.cpp @@ -285,16 +285,31 @@ static void Assign( newFrom.raw().attribute = CFI_attribute_allocatable; auto stat{ReturnError(terminator, newFrom.Allocate())}; if (stat == StatOk) { - char *toAt{newFrom.OffsetElement()}; - std::size_t fromElements{from.Elements()}; - if (from.IsContiguous()) { - std::memcpy( - toAt, from.OffsetElement(), fromElements * fromElementBytes); + if (HasDynamicComponent(from)) { + // If 'from' has allocatable/automatic component, we cannot + // just make a shallow copy of the descriptor member. + // This will still leave data overlap in 'to' and 'newFrom'. + // For example: + // type t + // character, allocatable :: c(:) + // end type t + // type(t) :: x(3) + // x(2:3) = x(1:2) + // We have to make a deep copy into 'newFrom' in this case. + RTNAME(AssignTemporary) + (newFrom, from, terminator.sourceFileName(), terminator.sourceLine()); } else { - SubscriptValue fromAt[maxRank]; - for (from.GetLowerBounds(fromAt); fromElements-- > 0; - toAt += fromElementBytes, from.IncrementSubscripts(fromAt)) { - std::memcpy(toAt, from.Element(fromAt), fromElementBytes); + char *toAt{newFrom.OffsetElement()}; + std::size_t fromElements{from.Elements()}; + if (from.IsContiguous()) { + std::memcpy( + toAt, from.OffsetElement(), fromElements * fromElementBytes); + } else { + SubscriptValue fromAt[maxRank]; + for (from.GetLowerBounds(fromAt); fromElements-- > 0; + toAt += fromElementBytes, from.IncrementSubscripts(fromAt)) { + std::memcpy(toAt, from.Element(fromAt), fromElementBytes); + } } } Assign(to, newFrom, terminator, diff --git a/flang/runtime/derived.cpp b/flang/runtime/derived.cpp index 814fcfa1e1e7d..ac9b1c5906f42 100644 --- a/flang/runtime/derived.cpp +++ b/flang/runtime/derived.cpp @@ -258,4 +258,22 @@ void Destroy(const Descriptor &descriptor, bool finalize, } } +bool HasDynamicComponent(const Descriptor &descriptor) { + if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { + if (const auto *derived = addendum->derivedType()) { + const Descriptor &componentDesc{derived->component()}; + std::size_t myComponents{componentDesc.Elements()}; + for (std::size_t k{0}; k < myComponents; ++k) { + const auto &comp{ + *componentDesc.ZeroBasedIndexedElement(k)}; + if (comp.genre() == typeInfo::Component::Genre::Allocatable || + comp.genre() == typeInfo::Component::Genre::Automatic) { + return true; + } + } + } + } + return false; +} + } // namespace Fortran::runtime diff --git a/flang/runtime/derived.h b/flang/runtime/derived.h index d655a672a84d4..894cdfd9a598c 100644 --- a/flang/runtime/derived.h +++ b/flang/runtime/derived.h @@ -31,5 +31,9 @@ void Finalize(const Descriptor &, const typeInfo::DerivedType &derived); // Does not deallocate the original descriptor. void Destroy(const Descriptor &, bool finalize, const typeInfo::DerivedType &); +// Return true if the passed descriptor is for a derived type +// entity that has a dynamic (allocatable, automatic) component. +bool HasDynamicComponent(const Descriptor &); + } // namespace Fortran::runtime #endif // FORTRAN_RUNTIME_DERIVED_H_