[flang-commits] [flang] [flang] Support kind/index lookup inside of EQUIVALENCE (PR #170056)

Eugene Epshteyn via flang-commits flang-commits at lists.llvm.org
Tue Dec 2 12:46:29 PST 2025


https://github.com/eugeneepshteyn updated https://github.com/llvm/llvm-project/pull/170056

>From a9987b69b57eb6034a73bddcc6a1a92cc2bff770 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Sat, 29 Nov 2025 22:04:17 -0500
Subject: [PATCH 1/6] Fixed processing of kinds on parameters inside of
 equivalence statement

---
 flang/lib/Semantics/resolve-names.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 2a487a6d39d51..c17fd96fede50 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -6181,6 +6181,11 @@ bool DeclarationVisitor::Pre(const parser::KindParam &x) {
           parser::Scalar<parser::Integer<parser::Constant<parser::Name>>>>(
           &x.u)}) {
     const auto &name{parser::UnwrapRef<parser::Name>(kind)};
+    // For kind params scope resolution, temporarily turn off equivalence
+    // processing, because for equivalences the name resolution is confined
+    // to the current scope. For kind params that may be used for array
+    // indices, we don't want to limit the name resolution to the current scope.
+    auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
     if (!FindSymbol(name)) {
       Say(name, "Parameter '%s' not found"_err_en_US);
     }

>From f074da4637cb3aab8face411b4fc25a4edc27c50 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Sat, 29 Nov 2025 22:52:33 -0500
Subject: [PATCH 2/6] Experimentation: seems to work, but may be an overkill

---
 flang/lib/Semantics/resolve-names.cpp | 51 ++++++++++++++++++++++-----
 1 file changed, 43 insertions(+), 8 deletions(-)

diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index c17fd96fede50..277a97c7677de 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -2153,6 +2153,10 @@ class ResolveNamesVisitor : public virtual ScopeHandler,
   void Post(const parser::AssignedGotoStmt &);
   void Post(const parser::CompilerDirective &);
 
+  bool Pre(const parser::ArrayElement &);
+  bool Pre(const parser::Substring &);
+  bool Pre(const parser::CoindexedNamedObject &);
+
   // These nodes should never be reached: they are handled in ProgramUnit
   bool Pre(const parser::MainProgram &) {
     llvm_unreachable("This node is handled in ProgramUnit");
@@ -6181,11 +6185,6 @@ bool DeclarationVisitor::Pre(const parser::KindParam &x) {
           parser::Scalar<parser::Integer<parser::Constant<parser::Name>>>>(
           &x.u)}) {
     const auto &name{parser::UnwrapRef<parser::Name>(kind)};
-    // For kind params scope resolution, temporarily turn off equivalence
-    // processing, because for equivalences the name resolution is confined
-    // to the current scope. For kind params that may be used for array
-    // indices, we don't want to limit the name resolution to the current scope.
-    auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
     if (!FindSymbol(name)) {
       Say(name, "Parameter '%s' not found"_err_en_US);
     }
@@ -8757,7 +8756,10 @@ const parser::Name *DeclarationVisitor::ResolveDesignator(
       common::visitors{
           [&](const parser::DataRef &x) { return ResolveDataRef(x); },
           [&](const parser::Substring &x) {
-            Walk(std::get<parser::SubstringRange>(x.t).t);
+            {
+              auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
+              Walk(std::get<parser::SubstringRange>(x.t).t);
+            }
             return ResolveDataRef(std::get<parser::DataRef>(x.t));
           },
       },
@@ -8773,7 +8775,10 @@ const parser::Name *DeclarationVisitor::ResolveDataRef(
             return ResolveStructureComponent(y.value());
           },
           [&](const Indirection<parser::ArrayElement> &y) {
-            Walk(y.value().subscripts);
+            {
+              auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
+              Walk(y.value().subscripts);
+            }
             const parser::Name *name{ResolveDataRef(y.value().base)};
             if (name && name->symbol) {
               if (!IsProcedure(*name->symbol)) {
@@ -8787,7 +8792,10 @@ const parser::Name *DeclarationVisitor::ResolveDataRef(
             return name;
           },
           [&](const Indirection<parser::CoindexedNamedObject> &y) {
-            Walk(y.value().imageSelector);
+            {
+              auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
+              Walk(y.value().imageSelector);
+            }
             return ResolveDataRef(y.value().base);
           },
       },
@@ -10222,6 +10230,33 @@ template <typename A> std::set<SourceName> GetUses(const A &x) {
   return uses;
 }
 
+bool ResolveNamesVisitor::Pre(const parser::ArrayElement &x) {
+  Walk(x.base);
+  {
+    auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
+    Walk(x.subscripts);
+  }
+  return false;
+}
+
+bool ResolveNamesVisitor::Pre(const parser::Substring &x) {
+  {
+    auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
+    Walk(std::get<parser::SubstringRange>(x.t).t);
+  }
+  Walk(std::get<parser::DataRef>(x.t));
+  return false;
+}
+
+bool ResolveNamesVisitor::Pre(const parser::CoindexedNamedObject &x) {
+  Walk(x.base);
+  {
+    auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
+    Walk(x.imageSelector);
+  }
+  return false;
+}
+
 bool ResolveNamesVisitor::Pre(const parser::Program &x) {
   if (Scope * hermetic{context().currentHermeticModuleFileScope()}) {
     // Processing either the dependent modules or first module of a

>From 723c160f4114fc9b2c07d2713948750af946b3fe Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Sun, 30 Nov 2025 20:03:30 -0500
Subject: [PATCH 3/6] Removed unnecessary changes, added comments

---
 flang/lib/Semantics/resolve-names.cpp | 34 +++++----------------------
 1 file changed, 6 insertions(+), 28 deletions(-)

diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 277a97c7677de..ea00c97ad9187 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -2154,8 +2154,6 @@ class ResolveNamesVisitor : public virtual ScopeHandler,
   void Post(const parser::CompilerDirective &);
 
   bool Pre(const parser::ArrayElement &);
-  bool Pre(const parser::Substring &);
-  bool Pre(const parser::CoindexedNamedObject &);
 
   // These nodes should never be reached: they are handled in ProgramUnit
   bool Pre(const parser::MainProgram &) {
@@ -8756,10 +8754,7 @@ const parser::Name *DeclarationVisitor::ResolveDesignator(
       common::visitors{
           [&](const parser::DataRef &x) { return ResolveDataRef(x); },
           [&](const parser::Substring &x) {
-            {
-              auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
-              Walk(std::get<parser::SubstringRange>(x.t).t);
-            }
+            Walk(std::get<parser::SubstringRange>(x.t).t);
             return ResolveDataRef(std::get<parser::DataRef>(x.t));
           },
       },
@@ -8776,6 +8771,8 @@ const parser::Name *DeclarationVisitor::ResolveDataRef(
           },
           [&](const Indirection<parser::ArrayElement> &y) {
             {
+              // Turn off "in EQUIVALENCE" check for array indexing, because
+              // the indices themselves are not part of the EQUIVALENCE.
               auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
               Walk(y.value().subscripts);
             }
@@ -8792,10 +8789,7 @@ const parser::Name *DeclarationVisitor::ResolveDataRef(
             return name;
           },
           [&](const Indirection<parser::CoindexedNamedObject> &y) {
-            {
-              auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
-              Walk(y.value().imageSelector);
-            }
+            Walk(y.value().imageSelector);
             return ResolveDataRef(y.value().base);
           },
       },
@@ -10233,30 +10227,14 @@ template <typename A> std::set<SourceName> GetUses(const A &x) {
 bool ResolveNamesVisitor::Pre(const parser::ArrayElement &x) {
   Walk(x.base);
   {
+    // Turn off "in EQUIVALENCE" check for array indexing, because
+    // the indices themselves are not part of the EQUIVALENCE.
     auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
     Walk(x.subscripts);
   }
   return false;
 }
 
-bool ResolveNamesVisitor::Pre(const parser::Substring &x) {
-  {
-    auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
-    Walk(std::get<parser::SubstringRange>(x.t).t);
-  }
-  Walk(std::get<parser::DataRef>(x.t));
-  return false;
-}
-
-bool ResolveNamesVisitor::Pre(const parser::CoindexedNamedObject &x) {
-  Walk(x.base);
-  {
-    auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
-    Walk(x.imageSelector);
-  }
-  return false;
-}
-
 bool ResolveNamesVisitor::Pre(const parser::Program &x) {
   if (Scope * hermetic{context().currentHermeticModuleFileScope()}) {
     // Processing either the dependent modules or first module of a

>From 6acdbbc269abe63215440b005d4e65904c1fd833 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Tue, 2 Dec 2025 15:33:57 -0500
Subject: [PATCH 4/6] Implemented suggested changes to parser::SectionSubscript

---
 flang/lib/Semantics/resolve-names-utils.h |  1 +
 flang/lib/Semantics/resolve-names.cpp     | 22 +++++++---------------
 2 files changed, 8 insertions(+), 15 deletions(-)

diff --git a/flang/lib/Semantics/resolve-names-utils.h b/flang/lib/Semantics/resolve-names-utils.h
index ee8113a3fda5e..86c9c86152717 100644
--- a/flang/lib/Semantics/resolve-names-utils.h
+++ b/flang/lib/Semantics/resolve-names-utils.h
@@ -119,6 +119,7 @@ class EquivalenceSets {
   bool CheckDesignator(const parser::Designator &);
   bool CheckDataRef(const parser::CharBlock &, const parser::DataRef &);
   bool CheckObject(const parser::Name &);
+  bool CheckSectionSubscript(const parser::CharBlock &, const parser::SectionSubscript &);
   bool CheckArrayBound(const parser::Expr &);
   bool CheckSubstringBound(const parser::Expr &, bool);
   bool IsCharacterSequenceType(const DeclTypeSpec *);
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index ea00c97ad9187..4c8bffdef7d41 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -2153,7 +2153,7 @@ class ResolveNamesVisitor : public virtual ScopeHandler,
   void Post(const parser::AssignedGotoStmt &);
   void Post(const parser::CompilerDirective &);
 
-  bool Pre(const parser::ArrayElement &);
+  bool Pre(const parser::SectionSubscript &);
 
   // These nodes should never be reached: they are handled in ProgramUnit
   bool Pre(const parser::MainProgram &) {
@@ -8770,12 +8770,7 @@ const parser::Name *DeclarationVisitor::ResolveDataRef(
             return ResolveStructureComponent(y.value());
           },
           [&](const Indirection<parser::ArrayElement> &y) {
-            {
-              // Turn off "in EQUIVALENCE" check for array indexing, because
-              // the indices themselves are not part of the EQUIVALENCE.
-              auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
-              Walk(y.value().subscripts);
-            }
+            Walk(y.value().subscripts);
             const parser::Name *name{ResolveDataRef(y.value().base)};
             if (name && name->symbol) {
               if (!IsProcedure(*name->symbol)) {
@@ -10224,14 +10219,11 @@ template <typename A> std::set<SourceName> GetUses(const A &x) {
   return uses;
 }
 
-bool ResolveNamesVisitor::Pre(const parser::ArrayElement &x) {
-  Walk(x.base);
-  {
-    // Turn off "in EQUIVALENCE" check for array indexing, because
-    // the indices themselves are not part of the EQUIVALENCE.
-    auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
-    Walk(x.subscripts);
-  }
+bool ResolveNamesVisitor::Pre(const parser::SectionSubscript &x) {
+  // Turn off "in EQUIVALENCE" check for array indexing, because
+  // the indices themselves are not part of the EQUIVALENCE.
+  auto restorer{common::ScopedSet(inEquivalenceStmt_, false)};
+  Walk(x.u);
   return false;
 }
 

>From 3ff7538da11bb779924b6e921004663966962236 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Tue, 2 Dec 2025 15:44:12 -0500
Subject: [PATCH 5/6] LIT test

---
 flang/test/Semantics/equiv-kind.f90 | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
 create mode 100644 flang/test/Semantics/equiv-kind.f90

diff --git a/flang/test/Semantics/equiv-kind.f90 b/flang/test/Semantics/equiv-kind.f90
new file mode 100644
index 0000000000000..d54fe62ee77db
--- /dev/null
+++ b/flang/test/Semantics/equiv-kind.f90
@@ -0,0 +1,19 @@
+! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
+module equiv_kind_m
+  implicit none
+  integer, parameter :: knd = kind(42)
+  integer, parameter :: dim_2 = 1_knd
+  integer, parameter :: n = 3_knd
+  integer, parameter :: i_start = 1_knd
+contains
+subroutine test()
+  integer(knd) :: a(n),b(n,n)
+  character(len=5) :: small_ch
+  character(len=20) :: large_ch
+
+  equivalence (a(1_knd),b(1_knd,dim_2))
+  !CHECK: EQUIVALENCE (a(1_4), b(1_4,1_4))
+  equivalence (small_ch, large_ch(i_start:5_knd))
+  !CHECK: EQUIVALENCE (small_ch, large_ch(1_4:5_4))
+end subroutine test
+end module equiv_kind_m

>From 15f9b34b847229591d3c180b91fedc3a6c9d0499 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Tue, 2 Dec 2025 15:45:55 -0500
Subject: [PATCH 6/6] Removed unused declaration

---
 flang/lib/Semantics/resolve-names-utils.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/flang/lib/Semantics/resolve-names-utils.h b/flang/lib/Semantics/resolve-names-utils.h
index 86c9c86152717..ee8113a3fda5e 100644
--- a/flang/lib/Semantics/resolve-names-utils.h
+++ b/flang/lib/Semantics/resolve-names-utils.h
@@ -119,7 +119,6 @@ class EquivalenceSets {
   bool CheckDesignator(const parser::Designator &);
   bool CheckDataRef(const parser::CharBlock &, const parser::DataRef &);
   bool CheckObject(const parser::Name &);
-  bool CheckSectionSubscript(const parser::CharBlock &, const parser::SectionSubscript &);
   bool CheckArrayBound(const parser::Expr &);
   bool CheckSubstringBound(const parser::Expr &, bool);
   bool IsCharacterSequenceType(const DeclTypeSpec *);



More information about the flang-commits mailing list