Skip to content

Commit

Permalink
[flang][runtime] Handle conflicts for derived types with dynamic comp…
Browse files Browse the repository at this point in the history
…onents.

When creating a temporary for conflicting LHS and RHS we have to deep copy
the dynamic (allocatable, automatic) components from RHS to the temp.
Otherwise, the conflict may still be present between LHS and temp.

gfortran/regression/alloc_comp_assign_1.f90 is an example where the current
runtime code produces wrong result:
https://github.com/llvm/llvm-test-suite/blob/7b5b5dcbf9bdde729a14722eb67f9c3ab01647c7/Fortran/gfortran/regression/alloc_comp_assign_1.f90#L50

Reviewed By: klausler, tblah

Differential Revision: https://reviews.llvm.org/D156364
  • Loading branch information
vzakhari committed Jul 27, 2023
1 parent 32683b2 commit c78b528
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 9 deletions.
33 changes: 24 additions & 9 deletions flang/runtime/assign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<char>(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<char>(fromAt), fromElementBytes);
}
}
}
Assign(to, newFrom, terminator,
Expand Down
18 changes: 18 additions & 0 deletions flang/runtime/derived.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeInfo::Component>(k)};
if (comp.genre() == typeInfo::Component::Genre::Allocatable ||
comp.genre() == typeInfo::Component::Genre::Automatic) {
return true;
}
}
}
}
return false;
}

} // namespace Fortran::runtime
4 changes: 4 additions & 0 deletions flang/runtime/derived.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_

0 comments on commit c78b528

Please sign in to comment.