[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