[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 https://github.com/llvm/llvm-project/issues/143900.
This commit is contained in:
parent
9c25ca78f9
commit
65b06cd983
@ -165,6 +165,26 @@ int RTDEF(AllocatableAllocateSource)(Descriptor &alloc,
|
||||
alloc, /*asyncObject=*/nullptr, hasStat, errMsg, sourceFile, sourceLine)};
|
||||
if (stat == StatOk) {
|
||||
Terminator terminator{sourceFile, sourceLine};
|
||||
if (alloc.rank() != source.rank() && source.rank() != 0) {
|
||||
terminator.Crash("ALLOCATE object has rank %d while SOURCE= has rank %d",
|
||||
alloc.rank(), source.rank());
|
||||
}
|
||||
if (int rank{source.rank()}; rank > 0) {
|
||||
SubscriptValue allocExtent[maxRank], sourceExtent[maxRank];
|
||||
alloc.GetShape(allocExtent);
|
||||
source.GetShape(sourceExtent);
|
||||
for (int j{0}; j < rank; ++j) {
|
||||
if (allocExtent[j] != sourceExtent[j]) {
|
||||
if (!hasStat) {
|
||||
terminator.Crash("ALLOCATE object has extent %jd on dimension %d, "
|
||||
"but SOURCE= has extent %jd",
|
||||
static_cast<std::intmax_t>(allocExtent[j]), j + 1,
|
||||
static_cast<std::intmax_t>(sourceExtent[j]));
|
||||
}
|
||||
return StatInvalidExtent;
|
||||
}
|
||||
}
|
||||
}
|
||||
DoFromSourceAssign(alloc, source, terminator);
|
||||
}
|
||||
return stat;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "assignment.h"
|
||||
#include "definable.h"
|
||||
#include "flang/Evaluate/fold.h"
|
||||
#include "flang/Evaluate/shape.h"
|
||||
#include "flang/Evaluate/type.h"
|
||||
#include "flang/Parser/parse-tree.h"
|
||||
#include "flang/Parser/tools.h"
|
||||
@ -33,6 +34,7 @@ struct AllocateCheckerInfo {
|
||||
bool gotMold{false};
|
||||
bool gotStream{false};
|
||||
bool gotPinned{false};
|
||||
std::optional<evaluate::ConstantSubscripts> sourceExprShape;
|
||||
};
|
||||
|
||||
class AllocationCheckerHelper {
|
||||
@ -259,6 +261,9 @@ static std::optional<AllocateCheckerInfo> CheckAllocateOptions(
|
||||
CheckCopyabilityInPureScope(messages, *expr, scope);
|
||||
}
|
||||
}
|
||||
auto maybeShape{evaluate::GetShape(context.foldingContext(), *expr)};
|
||||
info.sourceExprShape =
|
||||
evaluate::AsConstantExtents(context.foldingContext(), maybeShape);
|
||||
} else {
|
||||
// Error already reported on source expression.
|
||||
// Do not continue allocate checks.
|
||||
@ -581,6 +586,52 @@ bool AllocationCheckerHelper::RunChecks(SemanticsContext &context) {
|
||||
.Attach(
|
||||
ultimate_->name(), "Declared here with rank %d"_en_US, rank_);
|
||||
return false;
|
||||
} else if (allocateInfo_.gotSource && allocateInfo_.sourceExprShape &&
|
||||
allocateInfo_.sourceExprShape->size() ==
|
||||
static_cast<std::size_t>(allocateShapeSpecRank_)) {
|
||||
std::size_t j{0};
|
||||
for (const auto &shapeSpec :
|
||||
std::get<std::list<parser::AllocateShapeSpec>>(allocation_.t)) {
|
||||
if (j >= allocateInfo_.sourceExprShape->size()) {
|
||||
break;
|
||||
}
|
||||
std::optional<evaluate::ConstantSubscript> lbound;
|
||||
if (const auto &lb{std::get<0>(shapeSpec.t)}) {
|
||||
lbound.reset();
|
||||
const auto &lbExpr{lb->thing.thing.value()};
|
||||
if (const auto *expr{GetExpr(context, lbExpr)}) {
|
||||
auto folded{
|
||||
evaluate::Fold(context.foldingContext(), SomeExpr(*expr))};
|
||||
lbound = evaluate::ToInt64(folded);
|
||||
evaluate::SetExpr(lbExpr, std::move(folded));
|
||||
}
|
||||
} else {
|
||||
lbound = 1;
|
||||
}
|
||||
if (lbound) {
|
||||
const auto &ubExpr{std::get<1>(shapeSpec.t).thing.thing.value()};
|
||||
if (const auto *expr{GetExpr(context, ubExpr)}) {
|
||||
auto folded{
|
||||
evaluate::Fold(context.foldingContext(), SomeExpr(*expr))};
|
||||
auto ubound{evaluate::ToInt64(folded)};
|
||||
evaluate::SetExpr(ubExpr, std::move(folded));
|
||||
if (ubound) {
|
||||
auto extent{*ubound - *lbound + 1};
|
||||
if (extent < 0) {
|
||||
extent = 0;
|
||||
}
|
||||
if (extent != allocateInfo_.sourceExprShape->at(j)) {
|
||||
context.Say(name_.source,
|
||||
"Allocation has extent %jd on dimension %d, but SOURCE= has extent %jd"_err_en_US,
|
||||
static_cast<std::intmax_t>(extent), j + 1,
|
||||
static_cast<std::intmax_t>(
|
||||
allocateInfo_.sourceExprShape->at(j)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // allocating a scalar object
|
||||
|
@ -163,6 +163,7 @@ subroutine C938_C947(var2, ptr, ptr2, fptr, my_team, srca)
|
||||
allocate(var2(2)[5:*], MOLD=my_team)
|
||||
!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
|
||||
allocate(var2(2)[5:*], MOLD=ptr)
|
||||
!ERROR: Allocation has extent 2 on dimension 1, but SOURCE= has extent 9
|
||||
!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
|
||||
allocate(var2(2)[5:*], SOURCE=ptr2)
|
||||
!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
|
||||
|
Loading…
x
Reference in New Issue
Block a user