Skip to content

Commit 4fed595

Browse files
authored
[flang] Correct semantic representation & handling of RANK(*) (llvm#66234)
A RANK(*) case in a SELECT RANK construct selects the case of an assumed-rank dummy argument whose effective actual argument is an assumed-size array. In this case, the attributes of the selector are those of a rank-1 assumed-size array, and the selector cannot be allocatable or a pointer. Ensure that the representation of a SELECT RANK construct's per-case AssocEntityDetails can distinguish RANK(n), RANK(*), and RANK DEFAULT, and clean up various code sites and tests where the distinctions matter.
1 parent 9a220dc commit 4fed595

File tree

13 files changed

+160
-85
lines changed

13 files changed

+160
-85
lines changed

flang/include/flang/Evaluate/tools.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,10 +1224,11 @@ bool IsEventTypeOrLockType(const DerivedTypeSpec *);
12241224
// of the construct entity.
12251225
// (E.g., for ASSOCIATE(x => y%z), ResolveAssociations(x) returns x,
12261226
// while GetAssociationRoot(x) returns y.)
1227-
// ResolveAssociationsExceptSelectRank() stops at a RANK case symbol.
1227+
// In a SELECT RANK construct, ResolveAssociations() stops at a
1228+
// RANK(n) or RANK(*) case symbol, but traverses the selector for
1229+
// RANK DEFAULT.
12281230
const Symbol &ResolveAssociations(const Symbol &);
12291231
const Symbol &GetAssociationRoot(const Symbol &);
1230-
const Symbol &ResolveAssociationsExceptSelectRank(const Symbol &);
12311232

12321233
const Symbol *FindCommonBlockContaining(const Symbol &);
12331234
int CountLenParameters(const DerivedTypeSpec &);

flang/include/flang/Semantics/symbol.h

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -278,12 +278,33 @@ class AssocEntityDetails : public EntityDetails {
278278
AssocEntityDetails &operator=(const AssocEntityDetails &) = default;
279279
AssocEntityDetails &operator=(AssocEntityDetails &&) = default;
280280
const MaybeExpr &expr() const { return expr_; }
281+
282+
// SELECT RANK's rank cases will return a populated result for
283+
// RANK(n) and RANK(*), and IsAssumedRank() will be true for
284+
// RANK DEFAULT.
285+
std::optional<int> rank() const {
286+
int r{rank_.value_or(0)};
287+
if (r == isAssumedSize) {
288+
return 1; // RANK(*)
289+
} else if (r == isAssumedRank) {
290+
return std::nullopt; // RANK DEFAULT
291+
} else {
292+
return rank_;
293+
}
294+
}
295+
bool IsAssumedSize() const { return rank_.value_or(0) == isAssumedSize; }
296+
bool IsAssumedRank() const { return rank_.value_or(0) == isAssumedRank; }
281297
void set_rank(int rank);
282-
std::optional<int> rank() const { return rank_; }
298+
void set_IsAssumedSize();
299+
void set_IsAssumedRank();
283300

284301
private:
285302
MaybeExpr expr_;
286-
std::optional<int> rank_; // for SELECT RANK
303+
// Populated for SELECT RANK with rank (n>=0) for RANK(n),
304+
// isAssumedSize for RANK(*), or isAssumedRank for RANK DEFAULT.
305+
static constexpr int isAssumedSize{-1}; // RANK(*)
306+
static constexpr int isAssumedRank{-2}; // RANK DEFAULT
307+
std::optional<int> rank_;
287308
};
288309
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const AssocEntityDetails &);
289310

@@ -862,12 +883,14 @@ class Symbol {
862883
return iface ? iface->RankImpl(depth) : 0;
863884
},
864885
[](const AssocEntityDetails &aed) {
865-
if (const auto &expr{aed.expr()}) {
866-
if (auto assocRank{aed.rank()}) {
867-
return *assocRank;
868-
} else {
869-
return expr->Rank();
870-
}
886+
if (auto assocRank{aed.rank()}) {
887+
// RANK(n) & RANK(*)
888+
return *assocRank;
889+
} else if (aed.IsAssumedRank()) {
890+
// RANK DEFAULT
891+
return 0;
892+
} else if (const auto &expr{aed.expr()}) {
893+
return expr->Rank();
871894
} else {
872895
return 0;
873896
}

flang/include/flang/Semantics/tools.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,13 @@ const Symbol *IsFinalizable(const DerivedTypeSpec &,
179179
const Symbol *HasImpureFinal(const Symbol &);
180180
bool IsInBlankCommon(const Symbol &);
181181
inline bool IsAssumedSizeArray(const Symbol &symbol) {
182-
const auto *details{symbol.detailsIf<ObjectEntityDetails>()};
183-
return details && details->IsAssumedSize();
182+
if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) {
183+
return object->IsAssumedSize();
184+
} else if (const auto *assoc{symbol.detailsIf<AssocEntityDetails>()}) {
185+
return assoc->IsAssumedSize();
186+
} else {
187+
return false;
188+
}
184189
}
185190
bool IsAssumedLengthCharacter(const Symbol &);
186191
bool IsExternal(const Symbol &);

flang/lib/Evaluate/shape.cpp

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -248,17 +248,17 @@ class GetLowerBoundHelper
248248

249249
Result GetLowerBound(const Symbol &symbol0, NamedEntity &&base) const {
250250
const Symbol &symbol{symbol0.GetUltimate()};
251-
if (const auto *details{
251+
if (const auto *object{
252252
symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
253-
int rank{details->shape().Rank()};
253+
int rank{object->shape().Rank()};
254254
if (dimension_ < rank) {
255-
const semantics::ShapeSpec &shapeSpec{details->shape()[dimension_]};
255+
const semantics::ShapeSpec &shapeSpec{object->shape()[dimension_]};
256256
if (shapeSpec.lbound().isExplicit()) {
257257
if (const auto &lbound{shapeSpec.lbound().GetExplicit()}) {
258258
if constexpr (LBOUND_SEMANTICS) {
259259
bool ok{false};
260260
auto lbValue{ToInt64(*lbound)};
261-
if (dimension_ == rank - 1 && details->IsAssumedSize()) {
261+
if (dimension_ == rank - 1 && object->IsAssumedSize()) {
262262
// last dimension of assumed-size dummy array: don't worry
263263
// about handling an empty dimension
264264
ok = !invariantOnly_ || IsScopeInvariantExpr(*lbound);
@@ -309,7 +309,10 @@ class GetLowerBoundHelper
309309
}
310310
} else if (const auto *assoc{
311311
symbol.detailsIf<semantics::AssocEntityDetails>()}) {
312-
if (assoc->rank()) { // SELECT RANK case
312+
if (assoc->IsAssumedSize()) { // RANK(*)
313+
return Result{1};
314+
} else if (assoc->IsAssumedRank()) { // RANK DEFAULT
315+
} else if (assoc->rank()) { // RANK(n)
313316
const Symbol &resolved{ResolveAssociations(symbol)};
314317
if (IsDescriptor(resolved) && dimension_ < *assoc->rank()) {
315318
return ExtentExpr{DescriptorInquiry{std::move(base),
@@ -497,9 +500,11 @@ MaybeExtentExpr GetExtent(
497500
const NamedEntity &base, int dimension, bool invariantOnly) {
498501
CHECK(dimension >= 0);
499502
const Symbol &last{base.GetLastSymbol()};
500-
const Symbol &symbol{ResolveAssociationsExceptSelectRank(last)};
503+
const Symbol &symbol{ResolveAssociations(last)};
501504
if (const auto *assoc{last.detailsIf<semantics::AssocEntityDetails>()}) {
502-
if (assoc->rank()) { // SELECT RANK case
505+
if (assoc->IsAssumedSize() || assoc->IsAssumedRank()) { // RANK(*)/DEFAULT
506+
return std::nullopt;
507+
} else if (assoc->rank()) { // RANK(n)
503508
if (semantics::IsDescriptor(symbol) && dimension < *assoc->rank()) {
504509
return ExtentExpr{DescriptorInquiry{
505510
NamedEntity{base}, DescriptorInquiry::Field::Extent, dimension}};
@@ -595,8 +600,7 @@ MaybeExtentExpr ComputeUpperBound(
595600

596601
MaybeExtentExpr GetRawUpperBound(
597602
const NamedEntity &base, int dimension, bool invariantOnly) {
598-
const Symbol &symbol{
599-
ResolveAssociationsExceptSelectRank(base.GetLastSymbol())};
603+
const Symbol &symbol{ResolveAssociations(base.GetLastSymbol())};
600604
if (const auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
601605
int rank{details->shape().Rank()};
602606
if (dimension < rank) {
@@ -612,7 +616,11 @@ MaybeExtentExpr GetRawUpperBound(
612616
}
613617
} else if (const auto *assoc{
614618
symbol.detailsIf<semantics::AssocEntityDetails>()}) {
615-
if (auto extent{GetAssociatedExtent(base, *assoc, dimension)}) {
619+
if (assoc->IsAssumedSize() || assoc->IsAssumedRank()) {
620+
return std::nullopt;
621+
} else if (assoc->rank() && dimension >= *assoc->rank()) {
622+
return std::nullopt;
623+
} else if (auto extent{GetAssociatedExtent(base, *assoc, dimension)}) {
616624
return ComputeUpperBound(
617625
GetRawLowerBound(base, dimension), std::move(extent));
618626
}
@@ -645,8 +653,7 @@ static MaybeExtentExpr GetExplicitUBOUND(FoldingContext *context,
645653

646654
static MaybeExtentExpr GetUBOUND(FoldingContext *context,
647655
const NamedEntity &base, int dimension, bool invariantOnly) {
648-
const Symbol &symbol{
649-
ResolveAssociationsExceptSelectRank(base.GetLastSymbol())};
656+
const Symbol &symbol{ResolveAssociations(base.GetLastSymbol())};
650657
if (const auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
651658
int rank{details->shape().Rank()};
652659
if (dimension < rank) {
@@ -662,7 +669,9 @@ static MaybeExtentExpr GetUBOUND(FoldingContext *context,
662669
}
663670
} else if (const auto *assoc{
664671
symbol.detailsIf<semantics::AssocEntityDetails>()}) {
665-
if (assoc->rank()) { // SELECT RANK case
672+
if (assoc->IsAssumedSize() || assoc->IsAssumedRank()) {
673+
return std::nullopt;
674+
} else if (assoc->rank()) { // RANK (n)
666675
const Symbol &resolved{ResolveAssociations(symbol)};
667676
if (IsDescriptor(resolved) && dimension < *assoc->rank()) {
668677
ExtentExpr lb{DescriptorInquiry{NamedEntity{base},

flang/lib/Evaluate/tools.cpp

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -702,15 +702,14 @@ std::optional<Expr<SomeType>> ConvertToType(
702702
bool IsAssumedRank(const Symbol &original) {
703703
if (const auto *assoc{original.detailsIf<semantics::AssocEntityDetails>()}) {
704704
if (assoc->rank()) {
705-
return false; // in SELECT RANK case
705+
return false; // in RANK(n) or RANK(*)
706+
} else if (assoc->IsAssumedRank()) {
707+
return true; // RANK DEFAULT
706708
}
707709
}
708710
const Symbol &symbol{semantics::ResolveAssociations(original)};
709-
if (const auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
710-
return details->IsAssumedRank();
711-
} else {
712-
return false;
713-
}
711+
const auto *object{symbol.detailsIf<semantics::ObjectEntityDetails>()};
712+
return object && object->IsAssumedRank();
714713
}
715714

716715
bool IsAssumedRank(const ActualArgument &arg) {
@@ -1209,17 +1208,7 @@ namespace Fortran::semantics {
12091208
const Symbol &ResolveAssociations(const Symbol &original) {
12101209
const Symbol &symbol{original.GetUltimate()};
12111210
if (const auto *details{symbol.detailsIf<AssocEntityDetails>()}) {
1212-
if (const Symbol * nested{UnwrapWholeSymbolDataRef(details->expr())}) {
1213-
return ResolveAssociations(*nested);
1214-
}
1215-
}
1216-
return symbol;
1217-
}
1218-
1219-
const Symbol &ResolveAssociationsExceptSelectRank(const Symbol &original) {
1220-
const Symbol &symbol{original.GetUltimate()};
1221-
if (const auto *details{symbol.detailsIf<AssocEntityDetails>()}) {
1222-
if (!details->rank()) {
1211+
if (!details->rank()) { // Not RANK(n) or RANK(*)
12231212
if (const Symbol * nested{UnwrapWholeSymbolDataRef(details->expr())}) {
12241213
return ResolveAssociations(*nested);
12251214
}

flang/lib/Semantics/check-allocate.cpp

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,11 @@ class AllocationCheckerHelper {
3939
public:
4040
AllocationCheckerHelper(
4141
const parser::Allocation &alloc, AllocateCheckerInfo &info)
42-
: allocateInfo_{info},
43-
allocateObject_{std::get<parser::AllocateObject>(alloc.t)},
44-
name_{parser::GetLastName(allocateObject_)},
45-
original_{name_.symbol ? &name_.symbol->GetUltimate() : nullptr},
46-
symbol_{original_ ? &ResolveAssociations(*original_) : nullptr},
47-
type_{symbol_ ? symbol_->GetType() : nullptr},
48-
allocateShapeSpecRank_{ShapeSpecRank(alloc)},
49-
rank_{original_ ? original_->Rank() : 0},
50-
allocateCoarraySpecRank_{CoarraySpecRank(alloc)},
51-
corank_{symbol_ ? symbol_->Corank() : 0} {}
42+
: allocateInfo_{info}, allocateObject_{std::get<parser::AllocateObject>(
43+
alloc.t)},
44+
allocateShapeSpecRank_{ShapeSpecRank(alloc)}, allocateCoarraySpecRank_{
45+
CoarraySpecRank(
46+
alloc)} {}
5247

5348
bool RunChecks(SemanticsContext &context);
5449

@@ -90,14 +85,17 @@ class AllocationCheckerHelper {
9085

9186
AllocateCheckerInfo &allocateInfo_;
9287
const parser::AllocateObject &allocateObject_;
93-
const parser::Name &name_;
94-
const Symbol *original_{nullptr}; // no USE or host association
95-
const Symbol *symbol_{nullptr}; // no USE, host, or construct association
96-
const DeclTypeSpec *type_{nullptr};
97-
const int allocateShapeSpecRank_;
98-
const int rank_{0};
99-
const int allocateCoarraySpecRank_;
100-
const int corank_{0};
88+
const int allocateShapeSpecRank_{0};
89+
const int allocateCoarraySpecRank_{0};
90+
const parser::Name &name_{parser::GetLastName(allocateObject_)};
91+
// no USE or host association
92+
const Symbol *original_{
93+
name_.symbol ? &name_.symbol->GetUltimate() : nullptr};
94+
// no USE, host, or construct association
95+
const Symbol *symbol_{original_ ? &ResolveAssociations(*original_) : nullptr};
96+
const DeclTypeSpec *type_{symbol_ ? symbol_->GetType() : nullptr};
97+
const int rank_{original_ ? original_->Rank() : 0};
98+
const int corank_{symbol_ ? symbol_->Corank() : 0};
10199
bool hasDeferredTypeParameter_{false};
102100
bool isUnlimitedPolymorphic_{false};
103101
bool isAbstract_{false};
@@ -539,6 +537,11 @@ bool AllocationCheckerHelper::RunChecks(SemanticsContext &context) {
539537
}
540538
}
541539
// Shape related checks
540+
if (symbol_ && evaluate::IsAssumedRank(*symbol_)) {
541+
context.Say(name_.source,
542+
"An assumed-rank object may not appear in an ALLOCATE statement"_err_en_US);
543+
return false;
544+
}
542545
if (rank_ > 0) {
543546
if (!hasAllocateShapeSpecList()) {
544547
// C939

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ void SelectRankConstructChecker::Leave(
8787
}
8888
if (saveSelSymbol &&
8989
IsAllocatableOrPointer(*saveSelSymbol)) { // F'2023 C1160
90-
context_.Say(parser::FindSourceLocation(selectRankStmtSel),
90+
context_.Say(rankCaseStmt.source,
9191
"RANK (*) cannot be used when selector is "
9292
"POINTER or ALLOCATABLE"_err_en_US);
9393
}

flang/lib/Semantics/expression.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,11 +260,11 @@ MaybeExpr ExpressionAnalyzer::CompleteSubscripts(ArrayRef &&ref) {
260260
symbolRank, symbol.name(), subscripts);
261261
}
262262
return std::nullopt;
263-
} else if (const auto *object{
264-
symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
263+
} else if (symbol.has<semantics::ObjectEntityDetails>() ||
264+
symbol.has<semantics::AssocEntityDetails>()) {
265265
// C928 & C1002
266266
if (Triplet *last{std::get_if<Triplet>(&ref.subscript().back().u)}) {
267-
if (!last->upper() && object->IsAssumedSize()) {
267+
if (!last->upper() && IsAssumedSizeArray(symbol)) {
268268
Say("Assumed-size array '%s' must have explicit final "
269269
"subscript upper bound value"_err_en_US,
270270
symbol.name());

flang/lib/Semantics/resolve-names.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6942,17 +6942,32 @@ void ConstructVisitor::Post(const parser::TypeGuardStmt::Guard &x) {
69426942
void ConstructVisitor::Post(const parser::SelectRankCaseStmt::Rank &x) {
69436943
if (auto *symbol{MakeAssocEntity()}) {
69446944
SetTypeFromAssociation(*symbol);
6945+
auto &details{symbol->get<AssocEntityDetails>()};
69456946
// Don't call SetAttrsFromAssociation() for SELECT RANK.
6946-
symbol->attrs() |=
6947-
evaluate::GetAttrs(GetCurrentAssociation().selector.expr) &
6948-
Attrs{Attr::ALLOCATABLE, Attr::ASYNCHRONOUS, Attr::POINTER,
6949-
Attr::TARGET, Attr::VOLATILE};
6950-
if (const auto *init{std::get_if<parser::ScalarIntConstantExpr>(&x.u)}) {
6951-
if (auto val{EvaluateInt64(context(), *init)}) {
6952-
auto &details{symbol->get<AssocEntityDetails>()};
6953-
details.set_rank(*val);
6947+
Attrs selectorAttrs{
6948+
evaluate::GetAttrs(GetCurrentAssociation().selector.expr)};
6949+
Attrs attrsToKeep{Attr::ASYNCHRONOUS, Attr::TARGET, Attr::VOLATILE};
6950+
if (const auto *rankValue{
6951+
std::get_if<parser::ScalarIntConstantExpr>(&x.u)}) {
6952+
// RANK(n)
6953+
if (auto expr{EvaluateIntExpr(*rankValue)}) {
6954+
if (auto val{evaluate::ToInt64(*expr)}) {
6955+
details.set_rank(*val);
6956+
attrsToKeep |= Attrs{Attr::ALLOCATABLE, Attr::POINTER};
6957+
} else {
6958+
Say("RANK() expression must be constant"_err_en_US);
6959+
}
69546960
}
6961+
} else if (std::holds_alternative<parser::Star>(x.u)) {
6962+
// RANK(*): assumed-size
6963+
details.set_IsAssumedSize();
6964+
} else {
6965+
CHECK(std::holds_alternative<parser::Default>(x.u));
6966+
// RANK DEFAULT: assumed-rank
6967+
details.set_IsAssumedRank();
6968+
attrsToKeep |= Attrs{Attr::ALLOCATABLE, Attr::POINTER};
69556969
}
6970+
symbol->attrs() |= selectorAttrs & attrsToKeep;
69566971
}
69576972
}
69586973

flang/lib/Semantics/symbol.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ void EntityDetails::set_type(const DeclTypeSpec &type) {
153153
}
154154

155155
void AssocEntityDetails::set_rank(int rank) { rank_ = rank; }
156+
void AssocEntityDetails::set_IsAssumedSize() { rank_ = isAssumedSize; }
157+
void AssocEntityDetails::set_IsAssumedRank() { rank_ = isAssumedRank; }
156158
void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; }
157159

158160
ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d)
@@ -438,8 +440,12 @@ llvm::raw_ostream &operator<<(
438440
llvm::raw_ostream &operator<<(
439441
llvm::raw_ostream &os, const AssocEntityDetails &x) {
440442
os << *static_cast<const EntityDetails *>(&x);
441-
if (auto assocRank{x.rank()}) {
442-
os << " rank: " << *assocRank;
443+
if (x.IsAssumedSize()) {
444+
os << " RANK(*)";
445+
} else if (x.IsAssumedRank()) {
446+
os << " RANK DEFAULT";
447+
} else if (auto assocRank{x.rank()}) {
448+
os << " RANK(" << *assocRank << ')';
443449
}
444450
DumpExpr(os, "expr", x.expr());
445451
return os;

0 commit comments

Comments
 (0)