[flang-commits] [flang] [flang][semantic] parser node types and rewrite for assumed-shape-bounds-spec (PR #211690)

via flang-commits flang-commits at lists.llvm.org
Fri Jul 24 09:03:40 PDT 2026


https://github.com/ivanrodriguez3753 updated https://github.com/llvm/llvm-project/pull/211690

>From 7642999ff2670ab738aca88779c1071b668fa5ff Mon Sep 17 00:00:00 2001
From: Ivan Rodriguez <ivan.rodriguez at hpe.com>
Date: Thu, 23 Jul 2026 17:45:41 -0500
Subject: [PATCH 1/2] [flang][semantic] parser node types and rewrite for
 assumed-shape-bounds-spec

This commit lays the groundwork for semantic analysis of rank-1 integer array expressions being used as bounds in a declaration with assumed bounds.
This should strongly resemble the changes for explicit-shape-bounds-spec
in f5a4294.
---
 flang/include/flang/Parser/dump-parse-tree.h  |  1 +
 flang/include/flang/Parser/parse-tree.h       | 12 +++--
 flang/lib/Parser/unparse.cpp                  |  4 ++
 flang/lib/Semantics/resolve-names-utils.cpp   | 53 +++++++++++++++++++
 .../declaration-assumed-array-bounds.f90      | 44 +++++++++++++++
 5 files changed, 110 insertions(+), 4 deletions(-)
 create mode 100644 flang/test/Semantics/declaration-assumed-array-bounds.f90

diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 030b0cc6f5301..29797b7d088a7 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -172,6 +172,7 @@ class ParseTreeDumper {
   NODE(parser, AssumedImpliedSpec)
   NODE(parser, AssumedRankSpec)
   NODE(parser, AssumedShapeSpec)
+  NODE(parser, AssumedShapeBoundsSpec)
   NODE(parser, AssumedSizeSpec)
   NODE(parser, Asynchronous)
   NODE(parser, AsynchronousStmt)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index f1e483922eee4..ed605c4f1fc43 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -1359,10 +1359,14 @@ EMPTY_CLASS(AssumedRankSpec);
 
 // R815 array-spec ->
 //        explicit-shape-spec-list | explicit-shape-bounds-spec |
-//        assumed-shape-spec-list | deferred-shape-spec-list |
-//        assumed-size-spec | implied-shape-spec |
+//        assumed-shape-spec-list | assumed-shape-bounds-spec |
+//        deferred-shape-spec-list | assumed-size-spec | implied-shape-spec |
 //        implied-shape-or-assumed-size-spec | assumed-rank-spec
 
+using ExplicitBoundsExpr = IntExpr;
+
+WRAPPER_CLASS(AssumedShapeBoundsSpec, ExplicitBoundsExpr);
+
 struct ExplicitShapeBoundsSpec {
   TUPLE_CLASS_BOILERPLATE(ExplicitShapeBoundsSpec);
   std::tuple<std::optional<IntExpr>, IntExpr> t;
@@ -1371,8 +1375,8 @@ struct ExplicitShapeBoundsSpec {
 struct ArraySpec {
   UNION_CLASS_BOILERPLATE(ArraySpec);
   std::variant<std::list<ExplicitShapeSpec>, ExplicitShapeBoundsSpec,
-      std::list<AssumedShapeSpec>, DeferredShapeSpecList, AssumedSizeSpec,
-      ImpliedShapeSpec, AssumedRankSpec>
+      std::list<AssumedShapeSpec>, AssumedShapeBoundsSpec,
+      DeferredShapeSpecList, AssumedSizeSpec, ImpliedShapeSpec, AssumedRankSpec>
       u;
 };
 
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index c7fc6da4b8268..23d04f2e3ea42 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -596,6 +596,10 @@ class UnparseVisitor {
                   "Unparse for ExplicitShapeBoundsSpec should not be reached");
             },
             [&](const std::list<AssumedShapeSpec> &y) { Walk(y, ","); },
+            [&](const AssumedShapeBoundsSpec &y) {
+              llvm_unreachable(
+                  "Unparse for AssumedShapeBoundsSpec should not be reached");
+            },
             [&](const DeferredShapeSpecList &y) { Walk(y); },
             [&](const AssumedSizeSpec &y) { Walk(y); },
             [&](const ImpliedShapeSpec &y) { Walk(y); },
diff --git a/flang/lib/Semantics/resolve-names-utils.cpp b/flang/lib/Semantics/resolve-names-utils.cpp
index 817e73aeff6a1..5e982639750bb 100644
--- a/flang/lib/Semantics/resolve-names-utils.cpp
+++ b/flang/lib/Semantics/resolve-names-utils.cpp
@@ -202,6 +202,7 @@ class ArraySpecAnalyzer {
     }
   }
   void Analyze(const parser::AssumedShapeSpec &);
+  void Analyze(const parser::AssumedShapeBoundsSpec &);
   void Analyze(const parser::ExplicitShapeSpec &);
   void Analyze(const parser::ExplicitShapeBoundsSpec &);
   void Analyze(const parser::AssumedImpliedSpec &);
@@ -272,6 +273,32 @@ static bool shouldRewriteShapeSpecListToExplicitBounds(
   return foundArray;
 }
 
+static bool shouldRewriteAssumedShapeSpecListToAssumedBounds(
+    SemanticsContext &context, const parser::ArraySpec &x) {
+  auto &assumedShapeSpecList{std::get<std::list<parser::AssumedShapeSpec>>(
+      const_cast<parser::ArraySpec &>(x).u)};
+
+  if (assumedShapeSpecList.size() != 1) {
+    return false;
+  }
+
+  auto &assumedShapeSpec{assumedShapeSpecList.front()};
+  const auto &lowerBoundOpt{assumedShapeSpec.v};
+
+  bool foundArray{false};
+
+  if (lowerBoundOpt) {
+    const auto &lowerBound{*lowerBoundOpt};
+    if (MaybeExpr analyzedExpr =
+            AnalyzeExpr(context, lowerBound.v.thing.thing.value());
+        analyzedExpr && (analyzedExpr->Rank() > 0)) {
+      foundArray = true;
+    }
+  }
+
+  return foundArray;
+}
+
 static void rewriteShapeSpecListToExplicitBounds(const parser::ArraySpec &x) {
   auto &explicitShapeSpecList{std::get<std::list<parser::ExplicitShapeSpec>>(
       const_cast<parser::ArraySpec &>(x).u)};
@@ -292,6 +319,21 @@ static void rewriteShapeSpecListToExplicitBounds(const parser::ArraySpec &x) {
   mutableArraySpec.u = std::move(boundsSpec);
 }
 
+static void rewriteAssumedShapeSpecListToAssumedBounds(
+    const parser::ArraySpec &x) {
+  auto &assumedShapeSpecList{std::get<std::list<parser::AssumedShapeSpec>>(
+      const_cast<parser::ArraySpec &>(x).u)};
+  auto &mutableArraySpec{const_cast<parser::ArraySpec &>(x)};
+  auto &mutableAssumedShapeSpec{assumedShapeSpecList.front()};
+
+  auto &lowerBoundOpt{mutableAssumedShapeSpec.v};
+  CHECK(lowerBoundOpt.has_value());
+
+  parser::IntExpr lowerIntExpr{std::move(lowerBoundOpt->v.thing)};
+  parser::AssumedShapeBoundsSpec boundsSpec{std::move(lowerIntExpr)};
+  mutableArraySpec.u = std::move(boundsSpec);
+}
+
 ArraySpec ArraySpecAnalyzer::Analyze(const parser::ArraySpec &x) {
   // This node is rewritten manually here, as opposed to using RewriteParseTree,
   // because RewriteParseTree is called after ResolveNames in
@@ -301,6 +343,10 @@ ArraySpec ArraySpecAnalyzer::Analyze(const parser::ArraySpec &x) {
       shouldRewriteShapeSpecListToExplicitBounds(context_, x)) {
     rewriteShapeSpecListToExplicitBounds(x);
   }
+  if (std::get_if<std::list<parser::AssumedShapeSpec>>(&x.u) &&
+      shouldRewriteAssumedShapeSpecListToAssumedBounds(context_, x)) {
+    rewriteAssumedShapeSpecListToAssumedBounds(x);
+  }
   common::visit(common::visitors{
                     [&](const parser::AssumedSizeSpec &y) {
                       Analyze(
@@ -335,6 +381,13 @@ ArraySpec ArraySpecAnalyzer::Analyze(const parser::CoarraySpec &x) {
   return arraySpec_;
 }
 
+void ArraySpecAnalyzer::Analyze(const parser::AssumedShapeBoundsSpec &x) {
+  context_.Say("Analyze overload for AssumedShapeBoundsSpec"_todo_en_US);
+  // prevent CHECK abort in Analyze(ArraySpec), otherwise it'll abort before
+  // printing error message
+  arraySpec_.push_back(ShapeSpec::MakeAssumedShape(Bound{1}));
+}
+
 void ArraySpecAnalyzer::Analyze(const parser::AssumedShapeSpec &x) {
   arraySpec_.push_back(ShapeSpec::MakeAssumedShape(GetBound(x.v)));
 }
diff --git a/flang/test/Semantics/declaration-assumed-array-bounds.f90 b/flang/test/Semantics/declaration-assumed-array-bounds.f90
new file mode 100644
index 0000000000000..d9176e0f024d3
--- /dev/null
+++ b/flang/test/Semantics/declaration-assumed-array-bounds.f90
@@ -0,0 +1,44 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 
+program main  
+  implicit none 
+contains 
+  subroutine good(x, y, z, dim_a, scalar1, scalar2)
+    integer :: dim_a(1)
+    !valid cases
+    !simple rank-1 integer array reference
+    ! ERROR: not yet implemented: Analyze overload for AssumedShapeBoundsSpec
+    integer :: x(dim_a:) 
+    !rank-1 integer array + scalar = rank-1 integer array
+    ! ERROR: not yet implemented: Analyze overload for AssumedShapeBoundsSpec
+    integer :: y(dim_a + 2:)
+    !rank-1 integer array via array constructor literal, with some non-const values
+    ! ERROR: not yet implemented: Analyze overload for AssumedShapeBoundsSpec
+    integer :: z([1,2,dim_a(1) + x(dim_a(1))]:)
+    !rank-1 zero sized array is valid and should declare a scalar
+    ! ERROR: not yet implemented: Analyze overload for AssumedShapeBoundsSpec
+    integer :: scalar1([integer::]:)
+    integer :: empty_arr(0) = [integer::]
+    ! ERROR: not yet implemented: Analyze overload for AssumedShapeBoundsSpec
+    integer :: scalar2(empty_arr:)
+  end subroutine 
+
+  subroutine bad(x, y, z, dim1_assumed, dim2_assumed)
+    integer :: dim3(3, 3, 3)
+    integer :: dim1_assumed(:)
+    integer :: dim2_assumed(:,:)
+    ! invalid cases:
+    ! future_ERROR: Rank-1 integer array used as lower bounds in DECLARATION must have constant size
+    ! ERROR: not yet implemented: Analyze overload for AssumedShapeBoundsSpec
+    integer :: x(dim1_assumed:)
+    ! future_ERROR: Integer array used as lower bounds in DECLARATION must be rank-1 but is rank-3
+    ! ERROR: not yet implemented: Analyze overload for AssumedShapeBoundsSpec
+    integer :: y(dim3:)
+    ! Combining both errors in one declaration, plus integer-check from 
+    ! type wrapper 
+    ! future_ERROR: Integer array used as lower bounds in DECLARATION must be rank-1 but is rank-2
+    ! future_ERROR: Rank-1 integer array used as lower bounds in DECLARATION must have constant size
+    ! ERROR: not yet implemented: Analyze overload for AssumedShapeBoundsSpec
+    ! ERROR: Must have INTEGER type, but is REAL(4)
+    integer :: z(dim2_assumed + 3.7:)
+  end subroutine 
+end program 

>From 9512fe63c1edf2203f36dd1f2e04584677da7a41 Mon Sep 17 00:00:00 2001
From: Ivan Rodriguez <ivan.rodriguez at hpe.com>
Date: Fri, 24 Jul 2026 11:01:00 -0500
Subject: [PATCH 2/2] Address comments

---
 flang/include/flang/Parser/parse-tree.h       |  4 +---
 flang/lib/Semantics/resolve-names-utils.cpp   |  6 +++---
 .../declaration-assumed-array-bounds.f90      | 19 +++++++++----------
 3 files changed, 13 insertions(+), 16 deletions(-)

diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index ed605c4f1fc43..283d7f4aa7c26 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -1363,9 +1363,7 @@ EMPTY_CLASS(AssumedRankSpec);
 //        deferred-shape-spec-list | assumed-size-spec | implied-shape-spec |
 //        implied-shape-or-assumed-size-spec | assumed-rank-spec
 
-using ExplicitBoundsExpr = IntExpr;
-
-WRAPPER_CLASS(AssumedShapeBoundsSpec, ExplicitBoundsExpr);
+WRAPPER_CLASS(AssumedShapeBoundsSpec, IntExpr);
 
 struct ExplicitShapeBoundsSpec {
   TUPLE_CLASS_BOILERPLATE(ExplicitShapeBoundsSpec);
diff --git a/flang/lib/Semantics/resolve-names-utils.cpp b/flang/lib/Semantics/resolve-names-utils.cpp
index 5e982639750bb..d73a5bb1bfb4c 100644
--- a/flang/lib/Semantics/resolve-names-utils.cpp
+++ b/flang/lib/Semantics/resolve-names-utils.cpp
@@ -275,8 +275,8 @@ static bool shouldRewriteShapeSpecListToExplicitBounds(
 
 static bool shouldRewriteAssumedShapeSpecListToAssumedBounds(
     SemanticsContext &context, const parser::ArraySpec &x) {
-  auto &assumedShapeSpecList{std::get<std::list<parser::AssumedShapeSpec>>(
-      const_cast<parser::ArraySpec &>(x).u)};
+  auto &assumedShapeSpecList{
+      std::get<std::list<parser::AssumedShapeSpec>>(x.u)};
 
   if (assumedShapeSpecList.size() != 1) {
     return false;
@@ -290,7 +290,7 @@ static bool shouldRewriteAssumedShapeSpecListToAssumedBounds(
   if (lowerBoundOpt) {
     const auto &lowerBound{*lowerBoundOpt};
     if (MaybeExpr analyzedExpr =
-            AnalyzeExpr(context, lowerBound.v.thing.thing.value());
+            AnalyzeExpr(context, parser::UnwrapRef<parser::Expr>(lowerBound));
         analyzedExpr && (analyzedExpr->Rank() > 0)) {
       foundArray = true;
     }
diff --git a/flang/test/Semantics/declaration-assumed-array-bounds.f90 b/flang/test/Semantics/declaration-assumed-array-bounds.f90
index d9176e0f024d3..d2e283dec55fd 100644
--- a/flang/test/Semantics/declaration-assumed-array-bounds.f90
+++ b/flang/test/Semantics/declaration-assumed-array-bounds.f90
@@ -1,13 +1,13 @@
-! RUN: %python %S/test_errors.py %s %flang_fc1 
-program main  
-  implicit none 
-contains 
+! RUN: %python %S/test_errors.py %s %flang_fc1
+program main
+  implicit none
+contains
   subroutine good(x, y, z, dim_a, scalar1, scalar2)
     integer :: dim_a(1)
     !valid cases
     !simple rank-1 integer array reference
     ! ERROR: not yet implemented: Analyze overload for AssumedShapeBoundsSpec
-    integer :: x(dim_a:) 
+    integer :: x(dim_a:)
     !rank-1 integer array + scalar = rank-1 integer array
     ! ERROR: not yet implemented: Analyze overload for AssumedShapeBoundsSpec
     integer :: y(dim_a + 2:)
@@ -20,7 +20,7 @@ subroutine good(x, y, z, dim_a, scalar1, scalar2)
     integer :: empty_arr(0) = [integer::]
     ! ERROR: not yet implemented: Analyze overload for AssumedShapeBoundsSpec
     integer :: scalar2(empty_arr:)
-  end subroutine 
+  end subroutine
 
   subroutine bad(x, y, z, dim1_assumed, dim2_assumed)
     integer :: dim3(3, 3, 3)
@@ -33,12 +33,11 @@ subroutine bad(x, y, z, dim1_assumed, dim2_assumed)
     ! future_ERROR: Integer array used as lower bounds in DECLARATION must be rank-1 but is rank-3
     ! ERROR: not yet implemented: Analyze overload for AssumedShapeBoundsSpec
     integer :: y(dim3:)
-    ! Combining both errors in one declaration, plus integer-check from 
-    ! type wrapper 
+    ! Combining both errors in one declaration, plus integer-check from type wrapper
     ! future_ERROR: Integer array used as lower bounds in DECLARATION must be rank-1 but is rank-2
     ! future_ERROR: Rank-1 integer array used as lower bounds in DECLARATION must have constant size
     ! ERROR: not yet implemented: Analyze overload for AssumedShapeBoundsSpec
     ! ERROR: Must have INTEGER type, but is REAL(4)
     integer :: z(dim2_assumed + 3.7:)
-  end subroutine 
-end program 
+  end subroutine
+end program



More information about the flang-commits mailing list