Index: flang/lib/Lower/Allocatable.cpp =================================================================== --- flang/lib/Lower/Allocatable.cpp +++ flang/lib/Lower/Allocatable.cpp @@ -558,8 +558,6 @@ genAllocateObjectInit(box); if (alloc.hasCoarraySpec()) TODO(loc, "coarray allocation"); - if (alloc.getShapeSpecs().size() > 0 && sourceExv.rank() == 0) - TODO(loc, "allocate array object with scalar SOURCE specifier"); // Set length of the allocate object if it has. Otherwise, get the length // from source for the deferred length parameter. if (lenParams.empty() && box.isCharacter() && Index: flang/runtime/allocatable.cpp =================================================================== --- flang/runtime/allocatable.cpp +++ flang/runtime/allocatable.cpp @@ -126,8 +126,7 @@ alloc, hasStat, errMsg, sourceFile, sourceLine)}; if (stat == StatOk) { Terminator terminator{sourceFile, sourceLine}; - // 9.7.1.2(7) - Assign(alloc, source, terminator, /*skipRealloc=*/true); + DoFromSourceAssign(alloc, source, terminator); } return stat; } Index: flang/runtime/assign.h =================================================================== --- flang/runtime/assign.h +++ flang/runtime/assign.h @@ -6,9 +6,6 @@ // //===----------------------------------------------------------------------===// -// Internal APIs for data assignment (both intrinsic assignment and TBP defined -// generic ASSIGNMENT(=)). - #ifndef FORTRAN_RUNTIME_ASSIGN_INTERNAL_H_ #define FORTRAN_RUNTIME_ASSIGN_INTERNAL_H_ @@ -16,15 +13,11 @@ class Descriptor; class Terminator; -// Assigns one object to another via intrinsic assignment (F'2018 10.2.1.3) or -// type-bound (only!) defined assignment (10.2.1.4), as appropriate. Performs -// finalization, scalar expansion, & allocatable (re)allocation as needed. -// Does not perform intrinsic assignment implicit type conversion. Both -// descriptors must be initialized. Recurses as needed to handle components. -// Do not perform allocatable reallocation if \p skipRealloc is true, which is -// used for allocate statement with source specifier. -void Assign( - Descriptor &, const Descriptor &, Terminator &, bool skipRealloc = false); +// Assign one object to another via allocate statement from source specifier. +// Note that if allocate object and source expression have the same rank, the +// value of the allocate object becomes the value provided; otherwise the value +// of each element of allocate object becomes the value provided (9.7.1.2(7)). +void DoFromSourceAssign(Descriptor &, const Descriptor &, Terminator &); } // namespace Fortran::runtime #endif // FORTRAN_RUNTIME_ASSIGN_INTERNAL_H_ Index: flang/runtime/assign.cpp =================================================================== --- flang/runtime/assign.cpp +++ flang/runtime/assign.cpp @@ -60,8 +60,15 @@ } } -void Assign(Descriptor &to, const Descriptor &from, Terminator &terminator, - bool skipRealloc) { +// Assigns one object to another via intrinsic assignment (F'2018 10.2.1.3) or +// type-bound (only!) defined assignment (10.2.1.4), as appropriate. Performs +// finalization, scalar expansion, & allocatable (re)allocation as needed. +// Does not perform intrinsic assignment implicit type conversion. Both +// descriptors must be initialized. Recurses as needed to handle components. +// Do not perform allocatable reallocation if \p skipRealloc is true, which is +// used for allocate statement with source specifier. +static void Assign(Descriptor &to, const Descriptor &from, + Terminator &terminator, bool skipRealloc = false) { DescriptorAddendum *toAddendum{to.Addendum()}; const typeInfo::DerivedType *toDerived{ toAddendum ? toAddendum->derivedType() : nullptr}; @@ -276,6 +283,33 @@ } } +void DoFromSourceAssign( + Descriptor &alloc, const Descriptor &source, Terminator &terminator) { + if (alloc.rank() > 0 && source.rank() == 0) { + // The value of each element of allocate object becomes the value of source. + DescriptorAddendum *allocAddendum{alloc.Addendum()}; + SubscriptValue allocAt[maxRank]; + alloc.GetLowerBounds(allocAt); + if (allocAddendum) { + const typeInfo::DerivedType *allocDerived{allocAddendum->derivedType()}; + for (std::size_t n{alloc.Elements()}; n-- > 0; + alloc.IncrementSubscripts(allocAt)) { + Descriptor allocElement{*Descriptor::Create(*allocDerived, + reinterpret_cast(alloc.Element(allocAt)), 0)}; + Assign(allocElement, source, terminator, /*skipRealloc=*/true); + } + } else { // intrinsic type + for (std::size_t n{alloc.Elements()}; n-- > 0; + alloc.IncrementSubscripts(allocAt)) { + std::memmove(alloc.Element(allocAt), source.raw().base_addr, + alloc.ElementBytes()); + } + } + } else { + Assign(alloc, source, terminator, /*skipRealloc=*/true); + } +} + extern "C" { void RTNAME(Assign)(Descriptor &to, const Descriptor &from, const char *sourceFile, int sourceLine) { Index: flang/runtime/pointer.cpp =================================================================== --- flang/runtime/pointer.cpp +++ flang/runtime/pointer.cpp @@ -143,8 +143,7 @@ pointer, hasStat, errMsg, sourceFile, sourceLine)}; if (stat == StatOk) { Terminator terminator{sourceFile, sourceLine}; - // 9.7.1.2(7) - Assign(pointer, source, terminator, /*skipRealloc=*/true); + DoFromSourceAssign(pointer, source, terminator); } return stat; }