diff --git a/flang/include/flang/Runtime/allocatable.h b/flang/include/flang/Runtime/allocatable.h --- a/flang/include/flang/Runtime/allocatable.h +++ b/flang/include/flang/Runtime/allocatable.h @@ -33,6 +33,17 @@ void RTNAME(AllocatableInitDerived)( Descriptor &, const typeInfo::DerivedType &, int rank = 0, int corank = 0); +// Initializes the descriptor for an allocatable of intrinsic or derived type. +// These functions are meant to be used in the allocate statement lowering. If +// the descriptor is allocated, the initialization is skiped so the error +// handling can be done by AllocatableAllocate. +void RTNAME(AllocatableInitIntrinsicForAllocate)( + Descriptor &, TypeCategory, int kind, int rank = 0, int corank = 0); +void RTNAME(AllocatableInitCharacterForAllocate)(Descriptor &, + SubscriptValue length = 0, int kind = 1, int rank = 0, int corank = 0); +void RTNAME(AllocatableInitDerivedForAllocate)( + Descriptor &, const typeInfo::DerivedType &, int rank = 0, int corank = 0); + // Checks that an allocatable is not already allocated in statements // with STAT=. Use this on a value descriptor before setting bounds or // type parameters. Not necessary on a freshly initialized descriptor. diff --git a/flang/runtime/allocatable.cpp b/flang/runtime/allocatable.cpp --- a/flang/runtime/allocatable.cpp +++ b/flang/runtime/allocatable.cpp @@ -41,6 +41,30 @@ derivedType, nullptr, rank, nullptr, CFI_attribute_allocatable); } +void RTNAME(AllocatableInitIntrinsicForAllocate)(Descriptor &descriptor, + TypeCategory category, int kind, int rank, int corank) { + if (descriptor.IsAllocated()) { + return; + } + RTNAME(AllocatableInitIntrinsic)(descriptor, category, kind, rank, corank); +} + +void RTNAME(AllocatableInitCharacterForAllocate)(Descriptor &descriptor, + SubscriptValue length, int kind, int rank, int corank) { + if (descriptor.IsAllocated()) { + return; + } + RTNAME(AllocatableInitCharacter)(descriptor, length, kind, rank, corank); +} + +void RTNAME(AllocatableInitDerivedForAllocate)(Descriptor &descriptor, + const typeInfo::DerivedType &derivedType, int rank, int corank) { + if (descriptor.IsAllocated()) { + return; + } + RTNAME(AllocatableInitDerived)(descriptor, derivedType, rank, corank); +} + std::int32_t RTNAME(MoveAlloc)(Descriptor &to, Descriptor &from, const typeInfo::DerivedType *derivedType, bool hasStat, const Descriptor *errMsg, const char *sourceFile, int sourceLine) { diff --git a/flang/unittests/Runtime/Allocatable.cpp b/flang/unittests/Runtime/Allocatable.cpp --- a/flang/unittests/Runtime/Allocatable.cpp +++ b/flang/unittests/Runtime/Allocatable.cpp @@ -94,3 +94,20 @@ EXPECT_EQ(*a->OffsetElement(), 3.4F); a->Destroy(); } + +TEST(AllocatableTest, DoubleAllocation) { + // CLASS(*), ALLOCATABLE :: r + // ALLOCATE(REAL::r) + auto r{createAllocatable(TypeCategory::Real, 4, 0)}; + EXPECT_FALSE(r->IsAllocated()); + EXPECT_TRUE(r->IsAllocatable()); + RTNAME(AllocatableAllocate)(*r); + EXPECT_TRUE(r->IsAllocated()); + + // Make sure AllocatableInitIntrinsicForAllocate doesn't reset the decsriptor + // if it is allocated. + // ALLOCATE(INTEGER::r) + RTNAME(AllocatableInitIntrinsicForAllocate) + (*r, Fortran::common::TypeCategory::Integer, 4); + EXPECT_TRUE(r->IsAllocated()); +}