Skip to content

[flang] Correct semantic representation & handling of RANK(*) #66234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 13, 2023

Conversation

klausler
Copy link
Contributor

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.

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.

Pull request: llvm#66234
@klausler klausler requested a review from psteinfeld September 13, 2023 16:40
@klausler klausler requested a review from a team as a code owner September 13, 2023 16:40
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:semantics labels Sep 13, 2023
@llvmbot
Copy link
Member

llvmbot commented Sep 13, 2023

@llvm/pr-subscribers-flang-semantics

Changes 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.

Patch is 25.75 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/66234.diff

13 Files Affected:

  • (modified) flang/include/flang/Evaluate/tools.h (+3-2)
  • (modified) flang/include/flang/Semantics/symbol.h (+31-8)
  • (modified) flang/include/flang/Semantics/tools.h (+7-2)
  • (modified) flang/lib/Evaluate/shape.cpp (+22-13)
  • (modified) flang/lib/Evaluate/tools.cpp (+6-17)
  • (modified) flang/lib/Semantics/check-allocate.cpp (+21-18)
  • (modified) flang/lib/Semantics/check-select-rank.cpp (+1-1)
  • (modified) flang/lib/Semantics/expression.cpp (+3-3)
  • (modified) flang/lib/Semantics/resolve-names.cpp (+23-8)
  • (modified) flang/lib/Semantics/symbol.cpp (+8-2)
  • (modified) flang/test/Semantics/misc-intrinsics.f90 (+21)
  • (modified) flang/test/Semantics/select-rank.f90 (+3-5)
  • (modified) flang/test/Semantics/select-rank03.f90 (+11-6)

<pre>
diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index b3f8f4a67a7b5dd..71fe1237efdde7c 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -1224,10 +1224,11 @@ bool IsEventTypeOrLockType(const DerivedTypeSpec );
// of the construct entity.
// (E.g., for ASSOCIATE(x =&gt; y%z), ResolveAssociations(x) returns x,
// while GetAssociationRoot(x) returns y.)
-// ResolveAssociationsExceptSelectRank() stops at a RANK case symbol.
+// In a SELECT RANK construct, ResolveAssociations() stops at a
+// RANK(n) or RANK(
) case symbol, but traverses the selector for
+// RANK DEFAULT.
const Symbol &amp;ResolveAssociations(const Symbol &amp;);
const Symbol &amp;GetAssociationRoot(const Symbol &amp;);
-const Symbol &amp;ResolveAssociationsExceptSelectRank(const Symbol &amp;);

const Symbol *FindCommonBlockContaining(const Symbol &amp;);
int CountLenParameters(const DerivedTypeSpec &amp;);
diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index aada3bf94cc1213..a5f4ad76c26b784 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -278,12 +278,33 @@ class AssocEntityDetails : public EntityDetails {
AssocEntityDetails &amp;operator=(const AssocEntityDetails &amp;) = default;
AssocEntityDetails &amp;operator=(AssocEntityDetails &amp;&amp;) = default;
const MaybeExpr &amp;expr() const { return expr_; }
+

  • // SELECT RANK&#x27;s rank cases will return a populated result for
  • // RANK(n) and RANK(*), and IsAssumedRank() will be true for
  • // RANK DEFAULT.
  • std::optional&lt;int&gt; rank() const {
  • int r{rank_.value_or(0)};
  • if (r == isAssumedSize) {
  •  return 1; // RANK(*)
    
  • } else if (r == isAssumedRank) {
  •  return std::nullopt; // RANK DEFAULT
    
  • } else {
  •  return rank_;
    
  • }
  • }
  • bool IsAssumedSize() const { return rank_.value_or(0) == isAssumedSize; }
  • bool IsAssumedRank() const { return rank_.value_or(0) == isAssumedRank; }
    void set_rank(int rank);
  • std::optional&lt;int&gt; rank() const { return rank_; }
  • void set_IsAssumedSize();
  • void set_IsAssumedRank();

private:
MaybeExpr expr_;

  • std::optional&lt;int&gt; rank_; // for SELECT RANK
  • // Populated for SELECT RANK with rank (n&gt;=0) for RANK(n),
  • // isAssumedSize for RANK(*), or isAssumedRank for RANK DEFAULT.
  • static constexpr int isAssumedSize{-1}; // RANK(*)
  • static constexpr int isAssumedRank{-2}; // RANK DEFAULT
  • std::optional&lt;int&gt; rank_;
    };
    llvm::raw_ostream &amp;operator&lt;&lt;(llvm::raw_ostream &amp;, const AssocEntityDetails &amp;);

@@ -862,12 +883,14 @@ class Symbol {
return iface ? iface-&gt;RankImpl(depth) : 0;
},
[](const AssocEntityDetails &amp;aed) {

  •          if (const auto &amp;amp;expr{aed.expr()}) {
    
  •            if (auto assocRank{aed.rank()}) {
    
  •              return *assocRank;
    
  •            } else {
    
  •              return expr-&amp;gt;Rank();
    
  •            }
    
  •          if (auto assocRank{aed.rank()}) {
    
  •            // RANK(n) &amp;amp; RANK(*)
    
  •            return *assocRank;
    
  •          } else if (aed.IsAssumedRank()) {
    
  •            // RANK DEFAULT
    
  •            return 0;
    
  •          } else if (const auto &amp;amp;expr{aed.expr()}) {
    
  •            return expr-&amp;gt;Rank();
             } else {
               return 0;
             }
    

diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h
index 5bcb96e6050fa08..12649da6adbe21a 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -179,8 +179,13 @@ const Symbol *IsFinalizable(const DerivedTypeSpec &amp;,
const Symbol *HasImpureFinal(const Symbol &amp;);
bool IsInBlankCommon(const Symbol &amp;);
inline bool IsAssumedSizeArray(const Symbol &amp;symbol) {

  • const auto *details{symbol.detailsIf&lt;ObjectEntityDetails&gt;()};
  • return details &amp;&amp; details-&gt;IsAssumedSize();
  • if (const auto *object{symbol.detailsIf&lt;ObjectEntityDetails&gt;()}) {

  • return object-&gt;IsAssumedSize();

  • } else if (const auto *assoc{symbol.detailsIf&lt;AssocEntityDetails&gt;()}) {

  • return assoc-&gt;IsAssumedSize();

  • } else {

  • return false;

  • }
    }
    bool IsAssumedLengthCharacter(const Symbol &amp;);
    bool IsExternal(const Symbol &amp;);
    diff --git a/flang/lib/Evaluate/shape.cpp b/flang/lib/Evaluate/shape.cpp
    index 8f4923ff96a94b0..e26479cc1f055fb 100644
    --- a/flang/lib/Evaluate/shape.cpp
    +++ b/flang/lib/Evaluate/shape.cpp
    @@ -248,17 +248,17 @@ class GetLowerBoundHelper

    Result GetLowerBound(const Symbol &amp;symbol0, NamedEntity &amp;&amp;base) const {
    const Symbol &amp;symbol{symbol0.GetUltimate()};

  • if (const auto *details{
  • if (const auto *object{
    symbol.detailsIf&lt;semantics::ObjectEntityDetails&gt;()}) {
  •  int rank{details-&amp;gt;shape().Rank()};
    
  •  int rank{object-&amp;gt;shape().Rank()};
     if (dimension_ &amp;lt; rank) {
    
  •    const semantics::ShapeSpec &amp;amp;shapeSpec{details-&amp;gt;shape()[dimension_]};
    
  •    const semantics::ShapeSpec &amp;amp;shapeSpec{object-&amp;gt;shape()[dimension_]};
       if (shapeSpec.lbound().isExplicit()) {
         if (const auto &amp;amp;lbound{shapeSpec.lbound().GetExplicit()}) {
           if constexpr (LBOUND_SEMANTICS) {
             bool ok{false};
             auto lbValue{ToInt64(*lbound)};
    
  •          if (dimension_ == rank - 1 &amp;amp;&amp;amp; details-&amp;gt;IsAssumedSize()) {
    
  •          if (dimension_ == rank - 1 &amp;amp;&amp;amp; object-&amp;gt;IsAssumedSize()) {
               // last dimension of assumed-size dummy array: don&amp;#x27;t worry
               // about handling an empty dimension
               ok = !invariantOnly_ || IsScopeInvariantExpr(*lbound);
    

@@ -309,7 +309,10 @@ class GetLowerBoundHelper
}
} else if (const auto *assoc{
symbol.detailsIf&lt;semantics::AssocEntityDetails&gt;()}) {

  •  if (assoc-&amp;gt;rank()) { // SELECT RANK case
    
  •  if (assoc-&amp;gt;IsAssumedSize()) { // RANK(*)
    
  •    return Result{1};
    
  •  } else if (assoc-&amp;gt;IsAssumedRank()) { // RANK DEFAULT
    
  •  } else if (assoc-&amp;gt;rank()) { // RANK(n)
       const Symbol &amp;amp;resolved{ResolveAssociations(symbol)};
       if (IsDescriptor(resolved) &amp;amp;&amp;amp; dimension_ &amp;lt; *assoc-&amp;gt;rank()) {
         return ExtentExpr{DescriptorInquiry{std::move(base),
    

@@ -497,9 +500,11 @@ MaybeExtentExpr GetExtent(
const NamedEntity &amp;base, int dimension, bool invariantOnly) {
CHECK(dimension &gt;= 0);
const Symbol &amp;last{base.GetLastSymbol()};

  • const Symbol &amp;symbol{ResolveAssociationsExceptSelectRank(last)};
  • const Symbol &amp;symbol{ResolveAssociations(last)};
    if (const auto *assoc{last.detailsIf&lt;semantics::AssocEntityDetails&gt;()}) {
  • if (assoc-&gt;rank()) { // SELECT RANK case
  • if (assoc-&gt;IsAssumedSize() || assoc-&gt;IsAssumedRank()) { // RANK(*)/DEFAULT
  •  return std::nullopt;
    
  • } else if (assoc-&gt;rank()) { // RANK(n)
    if (semantics::IsDescriptor(symbol) &amp;&amp; dimension &lt; *assoc-&gt;rank()) {
    return ExtentExpr{DescriptorInquiry{
    NamedEntity{base}, DescriptorInquiry::Field::Extent, dimension}};
    @@ -595,8 +600,7 @@ MaybeExtentExpr ComputeUpperBound(

MaybeExtentExpr GetRawUpperBound(
const NamedEntity &amp;base, int dimension, bool invariantOnly) {

  • const Symbol &amp;symbol{
  •  ResolveAssociationsExceptSelectRank(base.GetLastSymbol())};
    
  • const Symbol &amp;symbol{ResolveAssociations(base.GetLastSymbol())};
    if (const auto *details{symbol.detailsIf&lt;semantics::ObjectEntityDetails&gt;()}) {
    int rank{details-&gt;shape().Rank()};
    if (dimension &lt; rank) {
    @@ -612,7 +616,11 @@ MaybeExtentExpr GetRawUpperBound(
    }
    } else if (const auto *assoc{
    symbol.detailsIf&lt;semantics::AssocEntityDetails&gt;()}) {
  • if (auto extent{GetAssociatedExtent(base, *assoc, dimension)}) {
  • if (assoc-&gt;IsAssumedSize() || assoc-&gt;IsAssumedRank()) {
  •  return std::nullopt;
    
  • } else if (assoc-&gt;rank() &amp;&amp; dimension &gt;= *assoc-&gt;rank()) {
  •  return std::nullopt;
    
  • } else if (auto extent{GetAssociatedExtent(base, *assoc, dimension)}) {
    return ComputeUpperBound(
    GetRawLowerBound(base, dimension), std::move(extent));
    }
    @@ -645,8 +653,7 @@ static MaybeExtentExpr GetExplicitUBOUND(FoldingContext *context,

static MaybeExtentExpr GetUBOUND(FoldingContext *context,
const NamedEntity &amp;base, int dimension, bool invariantOnly) {

  • const Symbol &amp;symbol{
  •  ResolveAssociationsExceptSelectRank(base.GetLastSymbol())};
    
  • const Symbol &amp;symbol{ResolveAssociations(base.GetLastSymbol())};
    if (const auto *details{symbol.detailsIf&lt;semantics::ObjectEntityDetails&gt;()}) {
    int rank{details-&gt;shape().Rank()};
    if (dimension &lt; rank) {
    @@ -662,7 +669,9 @@ static MaybeExtentExpr GetUBOUND(FoldingContext *context,
    }
    } else if (const auto *assoc{
    symbol.detailsIf&lt;semantics::AssocEntityDetails&gt;()}) {
  • if (assoc-&gt;rank()) { // SELECT RANK case
  • if (assoc-&gt;IsAssumedSize() || assoc-&gt;IsAssumedRank()) {
  •  return std::nullopt;
    
  • } else if (assoc-&gt;rank()) { // RANK (n)
    const Symbol &amp;resolved{ResolveAssociations(symbol)};
    if (IsDescriptor(resolved) &amp;&amp; dimension &lt; *assoc-&gt;rank()) {
    ExtentExpr lb{DescriptorInquiry{NamedEntity{base},
    diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
    index d2fa5c9b5f36be6..aadbc0804b342a7 100644
    --- a/flang/lib/Evaluate/tools.cpp
    +++ b/flang/lib/Evaluate/tools.cpp
    @@ -702,15 +702,14 @@ std::optional&lt;Expr&lt;SomeType&gt;&gt; ConvertToType(
    bool IsAssumedRank(const Symbol &amp;original) {
    if (const auto *assoc{original.detailsIf&lt;semantics::AssocEntityDetails&gt;()}) {
    if (assoc-&gt;rank()) {
  •  return false; // in SELECT RANK case
    
  •  return false; // in RANK(n) or RANK(*)
    
  • } else if (assoc-&gt;IsAssumedRank()) {
  •  return true; // RANK DEFAULT
    
    }
    }
    const Symbol &amp;symbol{semantics::ResolveAssociations(original)};
  • if (const auto *details{symbol.detailsIf&lt;semantics::ObjectEntityDetails&gt;()}) {
  • return details-&gt;IsAssumedRank();
  • } else {
  • return false;
  • }
  • const auto *object{symbol.detailsIf&lt;semantics::ObjectEntityDetails&gt;()};
  • return object &amp;&amp; object-&gt;IsAssumedRank();
    }

bool IsAssumedRank(const ActualArgument &amp;arg) {
@@ -1209,17 +1208,7 @@ namespace Fortran::semantics {
const Symbol &amp;ResolveAssociations(const Symbol &amp;original) {
const Symbol &amp;symbol{original.GetUltimate()};
if (const auto *details{symbol.detailsIf&lt;AssocEntityDetails&gt;()}) {

  • if (const Symbol * nested{UnwrapWholeSymbolDataRef(details-&gt;expr())}) {
  •  return ResolveAssociations(*nested);
    
  • }
  • }
  • return symbol;
    -}

-const Symbol &amp;ResolveAssociationsExceptSelectRank(const Symbol &amp;original) {

  • const Symbol &amp;symbol{original.GetUltimate()};
  • if (const auto *details{symbol.detailsIf&lt;AssocEntityDetails&gt;()}) {
  • if (!details-&gt;rank()) {
  • if (!details-&gt;rank()) { // Not RANK(n) or RANK(*)
    if (const Symbol * nested{UnwrapWholeSymbolDataRef(details-&gt;expr())}) {
    return ResolveAssociations(*nested);
    }
    diff --git a/flang/lib/Semantics/check-allocate.cpp b/flang/lib/Semantics/check-allocate.cpp
    index 12d795290d927ad..2edb8e59fd08406 100644
    --- a/flang/lib/Semantics/check-allocate.cpp
    +++ b/flang/lib/Semantics/check-allocate.cpp
    @@ -39,16 +39,11 @@ class AllocationCheckerHelper {
    public:
    AllocationCheckerHelper(
    const parser::Allocation &amp;alloc, AllocateCheckerInfo &amp;info)
  •  : allocateInfo_{info},
    
  •    allocateObject_{std::get&amp;lt;parser::AllocateObject&amp;gt;(alloc.t)},
    
  •    name_{parser::GetLastName(allocateObject_)},
    
  •    original_{name_.symbol ? &amp;amp;name_.symbol-&amp;gt;GetUltimate() : nullptr},
    
  •    symbol_{original_ ? &amp;amp;ResolveAssociations(*original_) : nullptr},
    
  •    type_{symbol_ ? symbol_-&amp;gt;GetType() : nullptr},
    
  •    allocateShapeSpecRank_{ShapeSpecRank(alloc)},
    
  •    rank_{original_ ? original_-&amp;gt;Rank() : 0},
    
  •    allocateCoarraySpecRank_{CoarraySpecRank(alloc)},
    
  •    corank_{symbol_ ? symbol_-&amp;gt;Corank() : 0} {}
    
  •  : allocateInfo_{info}, allocateObject_{std::get&amp;lt;parser::AllocateObject&amp;gt;(
    
  •                             alloc.t)},
    
  •    allocateShapeSpecRank_{ShapeSpecRank(alloc)}, allocateCoarraySpecRank_{
    
  •                                                      CoarraySpecRank(
    
  •                                                          alloc)} {}
    

    bool RunChecks(SemanticsContext &amp;context);

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

AllocateCheckerInfo &amp;allocateInfo_;
const parser::AllocateObject &amp;allocateObject_;

  • const parser::Name &amp;name_;
  • const Symbol *original_{nullptr}; // no USE or host association
  • const Symbol *symbol_{nullptr}; // no USE, host, or construct association
  • const DeclTypeSpec *type_{nullptr};
  • const int allocateShapeSpecRank_;
  • const int rank_{0};
  • const int allocateCoarraySpecRank_;
  • const int corank_{0};
  • const int allocateShapeSpecRank_{0};
  • const int allocateCoarraySpecRank_{0};
  • const parser::Name &amp;name_{parser::GetLastName(allocateObject_)};
  • // no USE or host association
  • const Symbol *original_{
  •  name_.symbol ? &amp;amp;name_.symbol-&amp;gt;GetUltimate() : nullptr};
    
  • // no USE, host, or construct association
  • const Symbol *symbol_{original_ ? &amp;ResolveAssociations(*original_) : nullptr};
  • const DeclTypeSpec *type_{symbol_ ? symbol_-&gt;GetType() : nullptr};
  • const int rank_{original_ ? original_-&gt;Rank() : 0};
  • const int corank_{symbol_ ? symbol_-&gt;Corank() : 0};
    bool hasDeferredTypeParameter_{false};
    bool isUnlimitedPolymorphic_{false};
    bool isAbstract_{false};
    @@ -539,6 +537,11 @@ bool AllocationCheckerHelper::RunChecks(SemanticsContext &amp;context) {
    }
    }
    // Shape related checks
  • if (symbol_ &amp;&amp; evaluate::IsAssumedRank(*symbol_)) {
  • context.Say(name_.source,
  •    &amp;quot;An assumed-rank object may not appear in an ALLOCATE statement&amp;quot;_err_en_US);
    
  • return false;
  • }
    if (rank_ &gt; 0) {
    if (!hasAllocateShapeSpecList()) {
    // C939
    diff --git a/flang/lib/Semantics/check-select-rank.cpp b/flang/lib/Semantics/check-select-rank.cpp
    index 424f9b45d64cdfd..2e602d307013c1e 100644
    --- a/flang/lib/Semantics/check-select-rank.cpp
    +++ b/flang/lib/Semantics/check-select-rank.cpp
    @@ -87,7 +87,7 @@ void SelectRankConstructChecker::Leave(
    }
    if (saveSelSymbol &amp;&amp;
    IsAllocatableOrPointer(*saveSelSymbol)) { // F&#x27;2023 C1160
  •            context_.Say(parser::FindSourceLocation(selectRankStmtSel),
    
  •            context_.Say(rankCaseStmt.source,
                   &amp;quot;RANK (*) cannot be used when selector is &amp;quot;
                   &amp;quot;POINTER or ALLOCATABLE&amp;quot;_err_en_US);
             }
    

diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index d690f3da6820dbb..4ccb2c3ef5d0121 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -260,11 +260,11 @@ MaybeExpr ExpressionAnalyzer::CompleteSubscripts(ArrayRef &amp;&amp;ref) {
symbolRank, symbol.name(), subscripts);
}
return std::nullopt;

  • } else if (const auto *object{
  •             symbol.detailsIf&amp;lt;semantics::ObjectEntityDetails&amp;gt;()}) {
    
  • } else if (symbol.has&lt;semantics::ObjectEntityDetails&gt;() ||
  •  symbol.has&amp;lt;semantics::AssocEntityDetails&amp;gt;()) {
    
    // C928 &amp; C1002
    if (Triplet *last{std::get_if&lt;Triplet&gt;(&amp;ref.subscript().back().u)}) {
  •  if (!last-&amp;gt;upper() &amp;amp;&amp;amp; object-&amp;gt;IsAssumedSize()) {
    
  •  if (!last-&amp;gt;upper() &amp;amp;&amp;amp; IsAssumedSizeArray(symbol)) {
       Say(&amp;quot;Assumed-size array &amp;#x27;%s&amp;#x27; must have explicit final &amp;quot;
           &amp;quot;subscript upper bound value&amp;quot;_err_en_US,
           symbol.name());
    

diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 865c198424696a9..edf2d1e1d4749b7 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -6942,17 +6942,32 @@ void ConstructVisitor::Post(const parser::TypeGuardStmt::Guard &amp;x) {
void ConstructVisitor::Post(const parser::SelectRankCaseStmt::Rank &amp;x) {
if (auto *symbol{MakeAssocEntity()}) {
SetTypeFromAssociation(*symbol);

  • auto &amp;details{symbol-&gt;get&lt;AssocEntityDetails&gt;()};
    // Don&#x27;t call SetAttrsFromAssociation() for SELECT RANK.
  • symbol-&gt;attrs() |=
  •    evaluate::GetAttrs(GetCurrentAssociation().selector.expr) &amp;amp;
    
  •    Attrs{Attr::ALLOCATABLE, Attr::ASYNCHRONOUS, Attr::POINTER,
    
  •        Attr::TARGET, Attr::VOLATILE};
    
  • if (const auto *init{std::get_if&lt;parser::ScalarIntConstantExpr&gt;(&amp;x.u)}) {
  •  if (auto val{EvaluateInt64(context(), *init)}) {
    
  •    auto &amp;amp;details{symbol-&amp;gt;get&amp;lt;AssocEntityDetails&amp;gt;()};
    
  •    details.set_rank(*val);
    
  • Attrs selectorAttrs{
  •    evaluate::GetAttrs(GetCurrentAssociation().selector.expr)};
    
  • Attrs attrsToKeep{Attr::ASYNCHRONOUS, Attr::TARGET, Attr::VOLATILE};
  • if (const auto *rankValue{
  •        std::get_if&amp;lt;parser::ScalarIntConstantExpr&amp;gt;(&amp;amp;x.u)}) {
    
  •  // RANK(n)
    
  •  if (auto expr{EvaluateIntExpr(*rankValue)}) {
    
  •    if (auto val{evaluate::ToInt64(*expr)}) {
    
  •      details.set_rank(*val);
    
  •      attrsToKeep |= Attrs{Attr::ALLOCATABLE, Attr::POINTER};
    
  •    } else {
    
  •      Say(&amp;quot;RANK() expression must be constant&amp;quot;_err_en_US);
    
  •    }
     }
    
  • } else if (std::holds_alternative&lt;parser::Star&gt;(x.u)) {
  •  // RANK(*): assumed-size
    
  •  details.set_IsAssumedSize();
    
  • } else {
  •  CHECK(std::holds_alternative&amp;lt;parser::Default&amp;gt;(x.u));
    
  •  // RANK DEFAULT: assumed-rank
    
  •  details.set_IsAssumedRank();
    
  •  attrsToKeep |= Attrs{Attr::ALLOCATABLE, Attr::POINTER};
    
    }
  • symbol-&gt;attrs() |= selectorAttrs &amp; attrsToKeep;
    }
    }

diff --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp
index 2e14b2e8a19559c..f4edc8a08fe699d 100644
--- a/flang/lib/Semantics/symbol.cpp
+++ b/flang/lib/Semantics/symbol.cpp
@@ -153,6 +153,8 @@ void EntityDetails::set_type(const DeclTypeSpec &amp;type) {
}

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

ObjectEntityDetails::ObjectEntityDetails(EntityDetails &amp;&amp;d)
@@ -438,8 +440,12 @@ llvm::raw_ostream &amp;operator&lt;&lt;(
llvm::raw_ostream &amp;operator&lt;&lt;(
llvm::raw_ostream &amp;os, const AssocEntityDetails &amp;x) {
os &lt;&lt; *static_cast&lt;const EntityDetails *&gt;(&amp;x);

  • if (auto assocRank{x.rank()}) {
  • os &lt;&lt; &quot; rank: &quot; &lt;&lt; *assocRank;
  • if (x.IsAssumedSize()) {
  • os &lt;&lt; &quot; RANK(*)&quot;;
  • } else if (x.IsAssumedRank()) {
  • os &lt;&lt; &quot; RANK DEFAULT&quot;;
  • } else if (auto assocRank{x.rank()}) {
  • os &lt;&lt; &quot; RANK(&quot; &lt;&lt; *assocRank &lt;&lt; &#x27;)&#x27;;
    ...

Copy link
Contributor

@psteinfeld psteinfeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All builds and tests correctly and looks good.

@klausler klausler merged commit 4fed595 into llvm:main Sep 13, 2023
@klausler klausler deleted the s5 branch September 13, 2023 23:13
ZijunZhaoCCK pushed a commit to ZijunZhaoCCK/llvm-project that referenced this pull request Sep 19, 2023
…6234)

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants