Skip to content

Commit 65b06cd

Browse files
authored
[flang][runtime] Check SOURCE= conformability on ALLOCATE (#144113)
The SOURCE= expression of an ALLOCATE statement, when present and not scalar, must conform to the shape of the allocated objects. Check this at runtime, and return a recoverable error, or crash, when appropriate. Fixes #143900.
1 parent 9c25ca7 commit 65b06cd

File tree

3 files changed

+72
-0
lines changed

3 files changed

+72
-0
lines changed

flang-rt/lib/runtime/allocatable.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,26 @@ int RTDEF(AllocatableAllocateSource)(Descriptor &alloc,
165165
alloc, /*asyncObject=*/nullptr, hasStat, errMsg, sourceFile, sourceLine)};
166166
if (stat == StatOk) {
167167
Terminator terminator{sourceFile, sourceLine};
168+
if (alloc.rank() != source.rank() && source.rank() != 0) {
169+
terminator.Crash("ALLOCATE object has rank %d while SOURCE= has rank %d",
170+
alloc.rank(), source.rank());
171+
}
172+
if (int rank{source.rank()}; rank > 0) {
173+
SubscriptValue allocExtent[maxRank], sourceExtent[maxRank];
174+
alloc.GetShape(allocExtent);
175+
source.GetShape(sourceExtent);
176+
for (int j{0}; j < rank; ++j) {
177+
if (allocExtent[j] != sourceExtent[j]) {
178+
if (!hasStat) {
179+
terminator.Crash("ALLOCATE object has extent %jd on dimension %d, "
180+
"but SOURCE= has extent %jd",
181+
static_cast<std::intmax_t>(allocExtent[j]), j + 1,
182+
static_cast<std::intmax_t>(sourceExtent[j]));
183+
}
184+
return StatInvalidExtent;
185+
}
186+
}
187+
}
168188
DoFromSourceAssign(alloc, source, terminator);
169189
}
170190
return stat;

flang/lib/Semantics/check-allocate.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "assignment.h"
1111
#include "definable.h"
1212
#include "flang/Evaluate/fold.h"
13+
#include "flang/Evaluate/shape.h"
1314
#include "flang/Evaluate/type.h"
1415
#include "flang/Parser/parse-tree.h"
1516
#include "flang/Parser/tools.h"
@@ -33,6 +34,7 @@ struct AllocateCheckerInfo {
3334
bool gotMold{false};
3435
bool gotStream{false};
3536
bool gotPinned{false};
37+
std::optional<evaluate::ConstantSubscripts> sourceExprShape;
3638
};
3739

3840
class AllocationCheckerHelper {
@@ -259,6 +261,9 @@ static std::optional<AllocateCheckerInfo> CheckAllocateOptions(
259261
CheckCopyabilityInPureScope(messages, *expr, scope);
260262
}
261263
}
264+
auto maybeShape{evaluate::GetShape(context.foldingContext(), *expr)};
265+
info.sourceExprShape =
266+
evaluate::AsConstantExtents(context.foldingContext(), maybeShape);
262267
} else {
263268
// Error already reported on source expression.
264269
// Do not continue allocate checks.
@@ -581,6 +586,52 @@ bool AllocationCheckerHelper::RunChecks(SemanticsContext &context) {
581586
.Attach(
582587
ultimate_->name(), "Declared here with rank %d"_en_US, rank_);
583588
return false;
589+
} else if (allocateInfo_.gotSource && allocateInfo_.sourceExprShape &&
590+
allocateInfo_.sourceExprShape->size() ==
591+
static_cast<std::size_t>(allocateShapeSpecRank_)) {
592+
std::size_t j{0};
593+
for (const auto &shapeSpec :
594+
std::get<std::list<parser::AllocateShapeSpec>>(allocation_.t)) {
595+
if (j >= allocateInfo_.sourceExprShape->size()) {
596+
break;
597+
}
598+
std::optional<evaluate::ConstantSubscript> lbound;
599+
if (const auto &lb{std::get<0>(shapeSpec.t)}) {
600+
lbound.reset();
601+
const auto &lbExpr{lb->thing.thing.value()};
602+
if (const auto *expr{GetExpr(context, lbExpr)}) {
603+
auto folded{
604+
evaluate::Fold(context.foldingContext(), SomeExpr(*expr))};
605+
lbound = evaluate::ToInt64(folded);
606+
evaluate::SetExpr(lbExpr, std::move(folded));
607+
}
608+
} else {
609+
lbound = 1;
610+
}
611+
if (lbound) {
612+
const auto &ubExpr{std::get<1>(shapeSpec.t).thing.thing.value()};
613+
if (const auto *expr{GetExpr(context, ubExpr)}) {
614+
auto folded{
615+
evaluate::Fold(context.foldingContext(), SomeExpr(*expr))};
616+
auto ubound{evaluate::ToInt64(folded)};
617+
evaluate::SetExpr(ubExpr, std::move(folded));
618+
if (ubound) {
619+
auto extent{*ubound - *lbound + 1};
620+
if (extent < 0) {
621+
extent = 0;
622+
}
623+
if (extent != allocateInfo_.sourceExprShape->at(j)) {
624+
context.Say(name_.source,
625+
"Allocation has extent %jd on dimension %d, but SOURCE= has extent %jd"_err_en_US,
626+
static_cast<std::intmax_t>(extent), j + 1,
627+
static_cast<std::intmax_t>(
628+
allocateInfo_.sourceExprShape->at(j)));
629+
}
630+
}
631+
}
632+
}
633+
++j;
634+
}
584635
}
585636
}
586637
} else { // allocating a scalar object

flang/test/Semantics/allocate11.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ subroutine C938_C947(var2, ptr, ptr2, fptr, my_team, srca)
163163
allocate(var2(2)[5:*], MOLD=my_team)
164164
!ERROR: SOURCE or MOLD expression type must not be C_PTR or C_FUNPTR from ISO_C_BINDING when an allocatable object is a coarray
165165
allocate(var2(2)[5:*], MOLD=ptr)
166+
!ERROR: Allocation has extent 2 on dimension 1, but SOURCE= has extent 9
166167
!ERROR: SOURCE or MOLD expression type must not be C_PTR or C_FUNPTR from ISO_C_BINDING when an allocatable object is a coarray
167168
allocate(var2(2)[5:*], SOURCE=ptr2)
168169
!ERROR: SOURCE or MOLD expression type must not be C_PTR or C_FUNPTR from ISO_C_BINDING when an allocatable object is a coarray

0 commit comments

Comments
 (0)