Skip to content

Commit 75e5f22

Browse files
klauslerjeanPerier
authored andcommitted
[flang] Validate SIZE(x,DIM=n) dimension for assumed-size array x
Catch invalid attempts to extract the unknowable extent of the last dimension of an assumed-size array dummy argument, and clean up problems with assumed-rank arguments in similar circumstances exposed by testing the fix. Differential Revision: https://reviews.llvm.org/D109918
1 parent 5748bd1 commit 75e5f22

File tree

9 files changed

+55
-20
lines changed

9 files changed

+55
-20
lines changed

flang/include/flang/Evaluate/tools.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,9 @@ std::optional<DataRef> ExtractDataRef(const A *p, bool intoSubstring = false) {
298298
return std::nullopt;
299299
}
300300
}
301+
std::optional<DataRef> ExtractDataRef(
302+
const ActualArgument &, bool intoSubstring = false);
303+
301304
std::optional<DataRef> ExtractSubstringBase(const Substring &);
302305

303306
// Predicate: is an expression is an array element reference?

flang/include/flang/Semantics/tools.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,6 @@ inline bool IsAssumedSizeArray(const Symbol &symbol) {
179179
const auto *details{symbol.detailsIf<ObjectEntityDetails>()};
180180
return details && details->IsAssumedSize();
181181
}
182-
inline bool IsAssumedRankArray(const Symbol &symbol) {
183-
const auto *details{symbol.detailsIf<ObjectEntityDetails>()};
184-
return details && details->IsAssumedRank();
185-
}
186182
bool IsAssumedLengthCharacter(const Symbol &);
187183
bool IsExternal(const Symbol &);
188184
bool IsModuleProcedure(const Symbol &);

flang/lib/Evaluate/fold-integer.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
612612
if (const auto *array{UnwrapExpr<Expr<SomeType>>(args[0])}) {
613613
if (auto named{ExtractNamedEntity(*array)}) {
614614
const Symbol &symbol{named->GetLastSymbol()};
615-
if (semantics::IsAssumedRankArray(symbol)) {
615+
if (IsAssumedRank(symbol)) {
616616
// DescriptorInquiry can only be placed in expression of kind
617617
// DescriptorInquiry::Result::kind.
618618
return ConvertToType<T>(Expr<
@@ -667,7 +667,13 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
667667
if (auto dim{GetInt64Arg(args[1])}) {
668668
int rank{GetRank(*shape)};
669669
if (*dim >= 1 && *dim <= rank) {
670-
if (auto &extent{shape->at(*dim - 1)}) {
670+
const Symbol *symbol{UnwrapWholeSymbolDataRef(args[0])};
671+
if (symbol && IsAssumedSizeArray(*symbol) && *dim == rank) {
672+
context.messages().Say(
673+
"size(array,dim=%jd) of last dimension is not available for rank-%d assumed-size array dummy argument"_err_en_US,
674+
*dim, rank);
675+
return MakeInvalidIntrinsic<T>(std::move(funcRef));
676+
} else if (auto &extent{shape->at(*dim - 1)}) {
671677
return Fold(context, ConvertToType<T>(std::move(*extent)));
672678
}
673679
} else {
@@ -705,7 +711,7 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
705711
} else if (name == "ubound") {
706712
return UBOUND(context, std::move(funcRef));
707713
}
708-
// TODO: count(w/ dim), dot_product, findloc, ibits, image_status, ishftc,
714+
// TODO: dot_product, findloc, ibits, image_status, ishftc,
709715
// matmul, maxloc, minloc, sign, transfer
710716
return Expr<T>{std::move(funcRef)};
711717
}

flang/lib/Evaluate/formatting.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,7 @@ llvm::raw_ostream &DescriptorInquiry::AsFortran(llvm::raw_ostream &o) const {
739739
if (field_ == Field::Len) {
740740
return o << "%len";
741741
} else {
742-
if (dimension_ >= 0) {
742+
if (field_ != Field::Rank && dimension_ >= 0) {
743743
o << ",dim=" << (dimension_ + 1);
744744
}
745745
return o << ')';

flang/lib/Evaluate/shape.cpp

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,15 @@ auto GetLowerBoundHelper::operator()(const Symbol &symbol0) -> Result {
260260
}
261261
} else if (const auto *assoc{
262262
symbol.detailsIf<semantics::AssocEntityDetails>()}) {
263-
return (*this)(assoc->expr());
263+
if (assoc->rank()) { // SELECT RANK case
264+
const Symbol &resolved{ResolveAssociations(symbol)};
265+
if (IsDescriptor(resolved) && dimension_ < *assoc->rank()) {
266+
return ExtentExpr{DescriptorInquiry{NamedEntity{symbol0},
267+
DescriptorInquiry::Field::LowerBound, dimension_}};
268+
}
269+
} else {
270+
return (*this)(assoc->expr());
271+
}
264272
}
265273
return Default();
266274
}
@@ -338,7 +346,20 @@ static MaybeExtentExpr GetNonNegativeExtent(
338346

339347
MaybeExtentExpr GetExtent(const NamedEntity &base, int dimension) {
340348
CHECK(dimension >= 0);
341-
const Symbol &symbol{ResolveAssociations(base.GetLastSymbol())};
349+
const Symbol &last{base.GetLastSymbol()};
350+
const Symbol &symbol{ResolveAssociations(last)};
351+
if (const auto *assoc{last.detailsIf<semantics::AssocEntityDetails>()}) {
352+
if (assoc->rank()) { // SELECT RANK case
353+
if (semantics::IsDescriptor(symbol) && dimension < *assoc->rank()) {
354+
return ExtentExpr{DescriptorInquiry{
355+
NamedEntity{base}, DescriptorInquiry::Field::Extent, dimension}};
356+
}
357+
} else if (auto shape{GetShape(assoc->expr())}) {
358+
if (dimension < static_cast<int>(shape->size())) {
359+
return std::move(shape->at(dimension));
360+
}
361+
}
362+
}
342363
if (const auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
343364
if (IsImpliedShape(symbol) && details->init()) {
344365
if (auto shape{GetShape(symbol)}) {
@@ -369,13 +390,6 @@ MaybeExtentExpr GetExtent(const NamedEntity &base, int dimension) {
369390
}
370391
}
371392
}
372-
} else if (const auto *assoc{
373-
symbol.detailsIf<semantics::AssocEntityDetails>()}) {
374-
if (auto shape{GetShape(assoc->expr())}) {
375-
if (dimension < static_cast<int>(shape->size())) {
376-
return std::move(shape->at(dimension));
377-
}
378-
}
379393
}
380394
return std::nullopt;
381395
}

flang/lib/Evaluate/tools.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ Expr<SomeType> Parenthesize(Expr<SomeType> &&expr) {
5050
std::move(expr.u));
5151
}
5252

53+
std::optional<DataRef> ExtractDataRef(
54+
const ActualArgument &arg, bool intoSubstring) {
55+
if (const Expr<SomeType> *expr{arg.UnwrapExpr()}) {
56+
return ExtractDataRef(*expr, intoSubstring);
57+
} else {
58+
return std::nullopt;
59+
}
60+
}
61+
5362
std::optional<DataRef> ExtractSubstringBase(const Substring &substring) {
5463
return std::visit(
5564
common::visitors{
@@ -665,6 +674,11 @@ std::optional<Expr<SomeType>> ConvertToType(
665674
}
666675

667676
bool IsAssumedRank(const Symbol &original) {
677+
if (const auto *assoc{original.detailsIf<semantics::AssocEntityDetails>()}) {
678+
if (assoc->rank()) {
679+
return false; // in SELECT RANK case
680+
}
681+
}
668682
const Symbol &symbol{semantics::ResolveAssociations(original)};
669683
if (const auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
670684
return details->IsAssumedRank();

flang/lib/Evaluate/variable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ DescriptorInquiry::DescriptorInquiry(
245245
: base_{base}, field_{field}, dimension_{dim} {
246246
const Symbol &last{base_.GetLastSymbol()};
247247
CHECK(IsDescriptor(last));
248-
CHECK((field == Field::Len && dim == 0) ||
248+
CHECK(((field == Field::Len || field == Field::Rank) && dim == 0) ||
249249
(field != Field::Len && dim >= 0 && dim < last.Rank()));
250250
}
251251

flang/lib/Semantics/check-select-rank.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ void SelectRankConstructChecker::Leave(
3232
const Symbol *saveSelSymbol{nullptr};
3333
if (const auto selExpr{GetExprFromSelector(selectRankStmtSel)}) {
3434
if (const Symbol * sel{evaluate::UnwrapWholeSymbolDataRef(*selExpr)}) {
35-
if (!IsAssumedRankArray(*sel)) { // C1150
35+
if (!evaluate::IsAssumedRank(*sel)) { // C1150
3636
context_.Say(parser::FindSourceLocation(selectRankStmtSel),
3737
"Selector '%s' is not an assumed-rank array variable"_err_en_US,
3838
sel->name().ToString());

flang/test/Semantics/select-rank.f90

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,13 @@ subroutine CALL_ME8(x)
145145
Rank(2)
146146
print *, "Now it's rank 2 "
147147
RANK (*)
148-
print *, "Going for a other rank"
148+
print *, "Going for another rank"
149+
!ERROR: 'kind=' argument must be a constant scalar integer whose value is a supported kind for the intrinsic result type
149150
j = INT(0, KIND=MERGE(KIND(0), -1, RANK(x) == 1))
150151
!ERROR: Not more than one of the selectors of SELECT RANK statement may be '*'
151152
RANK (*)
152153
print *, "This is Wrong"
154+
!ERROR: 'kind=' argument must be a constant scalar integer whose value is a supported kind for the intrinsic result type
153155
j = INT(0, KIND=MERGE(KIND(0), -1, RANK(x) == 1))
154156
END SELECT
155157
end subroutine

0 commit comments

Comments
 (0)