[flang-commits] [flang] [flang] Add traits to several AST nodes (PR #175065)

Krzysztof Parzyszek via flang-commits flang-commits at lists.llvm.org
Thu Jan 8 13:09:18 PST 2026


https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/175065

>From 539ae71c5e92a885aa3869f87d7d16489eb76f4e Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 7 Jan 2026 14:08:03 -0600
Subject: [PATCH 1/3] [flang] Add traits to several AST nodes, NFC

There are quite a few AST nodes that don't have any of the standard
traits (Wrapper/Tuple/etc). Because of that they require special
handling in the parse tree visitor.

Convert a subset of these nodes to the typical format, and remove
the special cases from the parse tree visitor.
---
 flang/include/flang/Parser/dump-parse-tree.h  |   1 +
 .../include/flang/Parser/parse-tree-visitor.h | 153 ------------------
 flang/include/flang/Parser/parse-tree.h       |  64 +++-----
 flang/lib/Lower/Bridge.cpp                    |  13 +-
 flang/lib/Parser/parse-tree.cpp               |   7 +-
 flang/lib/Parser/unparse.cpp                  |  26 +--
 flang/lib/Semantics/check-case.cpp            |  11 +-
 flang/lib/Semantics/expression.cpp            |   5 +-
 flang/lib/Semantics/resolve-names.cpp         |  44 ++---
 9 files changed, 81 insertions(+), 243 deletions(-)

diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 466cec9003038..f6e4cce241ad3 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -64,6 +64,7 @@ class ParseTreeDumper {
   NODE(std, uint64_t)
   NODE_ENUM(common, CUDADataAttr)
   NODE_ENUM(common, CUDASubprogramAttrs)
+  NODE_ENUM(common, ImportKind)
   NODE_ENUM(common, OmpDependenceKind)
   NODE_ENUM(common, OmpMemoryOrderType)
   NODE_ENUM(common, OpenACCDeviceType)
diff --git a/flang/include/flang/Parser/parse-tree-visitor.h b/flang/include/flang/Parser/parse-tree-visitor.h
index 7ebce671c5fd1..67f5481144c52 100644
--- a/flang/include/flang/Parser/parse-tree-visitor.h
+++ b/flang/include/flang/Parser/parse-tree-visitor.h
@@ -296,20 +296,6 @@ struct ParseTreeVisitorLookupScope {
     }
   }
 
-  template <typename V> static void Walk(const AcSpec &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.type, visitor);
-      Walk(x.values, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M> static void Walk(AcSpec &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.type, mutator);
-      Walk(x.values, mutator);
-      mutator.Post(x);
-    }
-  }
   template <typename V> static void Walk(const ArrayElement &x, V &visitor) {
     if (visitor.Pre(x)) {
       Walk(x.base, visitor);
@@ -325,37 +311,6 @@ struct ParseTreeVisitorLookupScope {
     }
   }
   template <typename V>
-  static void Walk(const CharSelector::LengthAndKind &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.length, visitor);
-      Walk(x.kind, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M>
-  static void Walk(CharSelector::LengthAndKind &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.length, mutator);
-      Walk(x.kind, mutator);
-      mutator.Post(x);
-    }
-  }
-  template <typename V>
-  static void Walk(const CaseValueRange::Range &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.lower, visitor);
-      Walk(x.upper, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M> static void Walk(CaseValueRange::Range &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.lower, mutator);
-      Walk(x.upper, mutator);
-      mutator.Post(x);
-    }
-  }
-  template <typename V>
   static void Walk(const CoindexedNamedObject &x, V &visitor) {
     if (visitor.Pre(x)) {
       Walk(x.base, visitor);
@@ -370,102 +325,6 @@ struct ParseTreeVisitorLookupScope {
       mutator.Post(x);
     }
   }
-  template <typename V>
-  static void Walk(const DeclarationTypeSpec::Class &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.derived, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M>
-  static void Walk(DeclarationTypeSpec::Class &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.derived, mutator);
-      mutator.Post(x);
-    }
-  }
-  template <typename V>
-  static void Walk(const DeclarationTypeSpec::Type &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.derived, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M>
-  static void Walk(DeclarationTypeSpec::Type &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.derived, mutator);
-      mutator.Post(x);
-    }
-  }
-  template <typename V> static void Walk(const ImportStmt &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.names, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M> static void Walk(ImportStmt &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.names, mutator);
-      mutator.Post(x);
-    }
-  }
-  template <typename V>
-  static void Walk(const IntrinsicTypeSpec::Character &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.selector, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M>
-  static void Walk(IntrinsicTypeSpec::Character &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.selector, mutator);
-      mutator.Post(x);
-    }
-  }
-  template <typename V>
-  static void Walk(const IntrinsicTypeSpec::Complex &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.kind, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M>
-  static void Walk(IntrinsicTypeSpec::Complex &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.kind, mutator);
-      mutator.Post(x);
-    }
-  }
-  template <typename V>
-  static void Walk(const IntrinsicTypeSpec::Logical &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.kind, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M>
-  static void Walk(IntrinsicTypeSpec::Logical &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.kind, mutator);
-      mutator.Post(x);
-    }
-  }
-  template <typename V>
-  static void Walk(const IntrinsicTypeSpec::Real &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.kind, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M>
-  static void Walk(IntrinsicTypeSpec::Real &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.kind, mutator);
-      mutator.Post(x);
-    }
-  }
   template <typename A, typename B, typename V>
   static void Walk(const LoopBounds<A, B> &x, V &visitor) {
     if (visitor.Pre(x)) {
@@ -486,18 +345,6 @@ struct ParseTreeVisitorLookupScope {
       mutator.Post(x);
     }
   }
-  template <typename V> static void Walk(const CommonStmt &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.blocks, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M> static void Walk(CommonStmt &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.blocks, mutator);
-      mutator.Post(x);
-    }
-  }
 
   // Expr traversal uses iteration rather than recursion to avoid
   // blowing out the stack on very deep expression parse trees.
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 2ab640ed351d8..37c0f699361eb 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -623,12 +623,12 @@ using ObjectName = Name;
 //        IMPORT [[::] import-name-list] |
 //        IMPORT , ONLY : import-name-list | IMPORT , NONE | IMPORT , ALL
 struct ImportStmt {
-  BOILERPLATE(ImportStmt);
-  ImportStmt(common::ImportKind &&k) : kind{k} {}
-  ImportStmt(std::list<Name> &&n) : names(std::move(n)) {}
+  TUPLE_CLASS_BOILERPLATE(ImportStmt);
+  ImportStmt(common::ImportKind &&k) : t(k, std::list<Name>{}) {}
+  ImportStmt(std::list<Name> &&n)
+      : t(common::ImportKind::Default, std::move(n)) {}
   ImportStmt(common::ImportKind &&, std::list<Name> &&);
-  common::ImportKind kind{common::ImportKind::Default};
-  std::list<Name> names;
+  std::tuple<common::ImportKind, std::list<Name>> t;
 };
 
 // R868 namelist-stmt ->
@@ -686,11 +686,8 @@ struct LengthSelector {
 struct CharSelector {
   UNION_CLASS_BOILERPLATE(CharSelector);
   struct LengthAndKind {
-    BOILERPLATE(LengthAndKind);
-    LengthAndKind(std::optional<TypeParamValue> &&l, ScalarIntConstantExpr &&k)
-        : length(std::move(l)), kind(std::move(k)) {}
-    std::optional<TypeParamValue> length;
-    ScalarIntConstantExpr kind;
+    TUPLE_CLASS_BOILERPLATE(LengthAndKind);
+    std::tuple<std::optional<TypeParamValue>, ScalarIntConstantExpr> t;
   };
   CharSelector(TypeParamValue &&l, ScalarIntConstantExpr &&k)
       : u{LengthAndKind{std::make_optional(std::move(l)), std::move(k)}} {}
@@ -707,25 +704,17 @@ struct CharSelector {
 struct IntrinsicTypeSpec {
   UNION_CLASS_BOILERPLATE(IntrinsicTypeSpec);
   struct Real {
-    BOILERPLATE(Real);
-    Real(std::optional<KindSelector> &&k) : kind{std::move(k)} {}
-    std::optional<KindSelector> kind;
+    WRAPPER_CLASS_BOILERPLATE(Real, std::optional<KindSelector>);
   };
   EMPTY_CLASS(DoublePrecision);
   struct Complex {
-    BOILERPLATE(Complex);
-    Complex(std::optional<KindSelector> &&k) : kind{std::move(k)} {}
-    std::optional<KindSelector> kind;
+    WRAPPER_CLASS_BOILERPLATE(Complex, std::optional<KindSelector>);
   };
   struct Character {
-    BOILERPLATE(Character);
-    Character(std::optional<CharSelector> &&s) : selector{std::move(s)} {}
-    std::optional<CharSelector> selector;
+    WRAPPER_CLASS_BOILERPLATE(Character, std::optional<CharSelector>);
   };
   struct Logical {
-    BOILERPLATE(Logical);
-    Logical(std::optional<KindSelector> &&k) : kind{std::move(k)} {}
-    std::optional<KindSelector> kind;
+    WRAPPER_CLASS_BOILERPLATE(Logical, std::optional<KindSelector>);
   };
   EMPTY_CLASS(DoubleComplex);
   std::variant<IntegerTypeSpec, UnsignedTypeSpec, Real, DoublePrecision,
@@ -774,16 +763,8 @@ struct TypeSpec {
 // Legacy extension: RECORD /struct/
 struct DeclarationTypeSpec {
   UNION_CLASS_BOILERPLATE(DeclarationTypeSpec);
-  struct Type {
-    BOILERPLATE(Type);
-    Type(DerivedTypeSpec &&dt) : derived(std::move(dt)) {}
-    DerivedTypeSpec derived;
-  };
-  struct Class {
-    BOILERPLATE(Class);
-    Class(DerivedTypeSpec &&dt) : derived(std::move(dt)) {}
-    DerivedTypeSpec derived;
-  };
+  WRAPPER_CLASS(Type, DerivedTypeSpec);
+  WRAPPER_CLASS(Class, DerivedTypeSpec);
   EMPTY_CLASS(ClassStar);
   EMPTY_CLASS(TypeStar);
   WRAPPER_CLASS(Record, Name);
@@ -1274,12 +1255,9 @@ struct AcValue {
 
 // R770 ac-spec -> type-spec :: | [type-spec ::] ac-value-list
 struct AcSpec {
-  BOILERPLATE(AcSpec);
-  AcSpec(std::optional<TypeSpec> &&ts, std::list<AcValue> &&xs)
-      : type(std::move(ts)), values(std::move(xs)) {}
-  explicit AcSpec(TypeSpec &&ts) : type{std::move(ts)} {}
-  std::optional<TypeSpec> type;
-  std::list<AcValue> values;
+  TUPLE_CLASS_BOILERPLATE(AcSpec);
+  explicit AcSpec(TypeSpec &&ts) : t(std::move(ts), std::list<AcValue>()) {}
+  std::tuple<std::optional<TypeSpec>, std::list<AcValue>> t;
 };
 
 // R769 array-constructor -> (/ ac-spec /) | lbracket ac-spec rbracket
@@ -1646,11 +1624,10 @@ struct CommonStmt {
     TUPLE_CLASS_BOILERPLATE(Block);
     std::tuple<std::optional<Name>, std::list<CommonBlockObject>> t;
   };
-  BOILERPLATE(CommonStmt);
+  WRAPPER_CLASS_BOILERPLATE(CommonStmt, std::list<Block>);
   CommonStmt(std::optional<Name> &&, std::list<CommonBlockObject> &&,
       std::list<Block> &&);
   CharBlock source;
-  std::list<Block> blocks;
 };
 
 // R872 equivalence-object -> variable-name | array-element | substring
@@ -2416,10 +2393,9 @@ using CaseValue = Scalar<ConstantExpr>;
 struct CaseValueRange {
   UNION_CLASS_BOILERPLATE(CaseValueRange);
   struct Range {
-    BOILERPLATE(Range);
-    Range(std::optional<CaseValue> &&l, std::optional<CaseValue> &&u)
-        : lower{std::move(l)}, upper{std::move(u)} {}
-    std::optional<CaseValue> lower, upper; // not both missing
+    TUPLE_CLASS_BOILERPLATE(Range);
+    std::tuple<std::optional<CaseValue>, std::optional<CaseValue>>
+        t; // not both missing
   };
   std::variant<CaseValue, Range> u;
 };
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 6c3631438a596..5570e07501ee9 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -4011,16 +4011,17 @@ class FirConverter : public Fortran::lower::AbstractConverter {
         }
         const auto &caseRange =
             std::get<Fortran::parser::CaseValueRange::Range>(caseValueRange.u);
-        if (caseRange.lower && caseRange.upper) {
+        auto &[lower, upper]{caseRange.t};
+        if (lower && upper) {
           attrList.push_back(fir::ClosedIntervalAttr::get(context));
-          addValue(*caseRange.lower);
-          addValue(*caseRange.upper);
-        } else if (caseRange.lower) {
+          addValue(*lower);
+          addValue(*upper);
+        } else if (lower) {
           attrList.push_back(fir::LowerBoundAttr::get(context));
-          addValue(*caseRange.lower);
+          addValue(*lower);
         } else {
           attrList.push_back(fir::UpperBoundAttr::get(context));
-          addValue(*caseRange.upper);
+          addValue(*upper);
         }
       }
     }
diff --git a/flang/lib/Parser/parse-tree.cpp b/flang/lib/Parser/parse-tree.cpp
index 53d4e4e680caa..4783a4e3b635e 100644
--- a/flang/lib/Parser/parse-tree.cpp
+++ b/flang/lib/Parser/parse-tree.cpp
@@ -22,7 +22,8 @@ namespace Fortran::parser {
 
 // R867
 ImportStmt::ImportStmt(common::ImportKind &&k, std::list<Name> &&n)
-    : kind{k}, names(std::move(n)) {
+    : t(k, std::move(n)) {
+  auto &[kind, names]{t};
   CHECK(kind == common::ImportKind::Default ||
       kind == common::ImportKind::Only || names.empty());
 }
@@ -30,8 +31,8 @@ ImportStmt::ImportStmt(common::ImportKind &&k, std::list<Name> &&n)
 // R873
 CommonStmt::CommonStmt(std::optional<Name> &&name,
     std::list<CommonBlockObject> &&objects, std::list<Block> &&others) {
-  blocks.emplace_front(std::move(name), std::move(objects));
-  blocks.splice(blocks.end(), std::move(others));
+  v.emplace_front(std::move(name), std::move(objects));
+  v.splice(v.end(), std::move(others));
 }
 
 // R901 designator
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 0a6b0cdf88efa..812ed9ac58e6f 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -142,10 +142,10 @@ class UnparseVisitor {
   void Post(const Star &) { Put('*'); } // R701 &c.
   void Post(const TypeParamValue::Deferred &) { Put(':'); } // R701
   void Unparse(const DeclarationTypeSpec::Type &x) { // R703
-    Word("TYPE("), Walk(x.derived), Put(')');
+    Word("TYPE("), Walk(x.v), Put(')');
   }
   void Unparse(const DeclarationTypeSpec::Class &x) {
-    Word("CLASS("), Walk(x.derived), Put(')');
+    Word("CLASS("), Walk(x.v), Put(')');
   }
   void Post(const DeclarationTypeSpec::ClassStar &) { Word("CLASS(*)"); }
   void Post(const DeclarationTypeSpec::TypeStar &) { Word("TYPE(*)"); }
@@ -204,8 +204,11 @@ class UnparseVisitor {
     Put('('), Walk(x.t, ","), Put(')');
   }
   void Unparse(const CharSelector::LengthAndKind &x) { // R721
-    Put('('), Word("KIND="), Walk(x.kind);
-    Walk(", LEN=", x.length), Put(')');
+    Put('(');
+    Word("KIND=");
+    Walk(std::get<ScalarIntConstantExpr>(x.t));
+    Walk(", LEN=", std::get<std::optional<TypeParamValue>>(x.t));
+    Put(')');
   }
   void Unparse(const LengthSelector &x) { // R722
     common::visit(common::visitors{
@@ -430,7 +433,8 @@ class UnparseVisitor {
     Put('['), Walk(x.v), Put(']');
   }
   void Unparse(const AcSpec &x) { // R770
-    Walk(x.type, "::"), Walk(x.values, ", ");
+    Walk(std::get<std::optional<TypeSpec>>(x.t), "::");
+    Walk(std::get<std::list<AcValue>>(x.t), ", ");
   }
   template <typename A, typename B> void Unparse(const LoopBounds<A, B> &x) {
     Walk(x.name), Put('='), Walk(x.lower), Put(','), Walk(x.upper);
@@ -723,14 +727,15 @@ class UnparseVisitor {
     }
   }
   void Unparse(const ImportStmt &x) { // R867
+    auto &[kind, names]{x.t};
     Word("IMPORT");
-    switch (x.kind) {
+    switch (kind) {
     case common::ImportKind::Default:
-      Walk(" :: ", x.names, ", ");
+      Walk(" :: ", names, ", ");
       break;
     case common::ImportKind::Only:
       Put(", "), Word("ONLY: ");
-      Walk(x.names, ", ");
+      Walk(names, ", ");
       break;
     case common::ImportKind::None:
       Word(", NONE");
@@ -757,7 +762,7 @@ class UnparseVisitor {
   }
   void Unparse(const CommonStmt &x) { // R873
     Word("COMMON ");
-    Walk(x.blocks);
+    Walk(x.v);
   }
   void Unparse(const CommonBlockObject &x) { // R874
     Walk(std::get<Name>(x.t));
@@ -1103,7 +1108,8 @@ class UnparseVisitor {
         x.u);
   }
   void Unparse(const CaseValueRange::Range &x) { // R1146
-    Walk(x.lower), Put(':'), Walk(x.upper);
+    auto &[lower, upper]{x.t};
+    Walk(lower), Put(':'), Walk(upper);
   }
   void Unparse(const SelectRankStmt &x) { // R1149
     Walk(std::get<0>(x.t), ": ");
diff --git a/flang/lib/Semantics/check-case.cpp b/flang/lib/Semantics/check-case.cpp
index 7593154b84c4c..1b00db91b83f2 100644
--- a/flang/lib/Semantics/check-case.cpp
+++ b/flang/lib/Semantics/check-case.cpp
@@ -124,14 +124,15 @@ template <typename T> class CaseValues {
               return PairOfValues{value, value};
             },
             [&](const parser::CaseValueRange::Range &x) {
+              auto &[lower, upper]{x.t};
               std::optional<Value> lo, hi;
-              if (x.lower) {
-                lo = GetValue(*x.lower);
+              if (lower) {
+                lo = GetValue(*lower);
               }
-              if (x.upper) {
-                hi = GetValue(*x.upper);
+              if (upper) {
+                hi = GetValue(*upper);
               }
-              if ((x.lower && !lo) || (x.upper && !hi)) {
+              if ((lower && !lo) || (upper && !hi)) {
                 return PairOfValues{}; // error case
               }
               return PairOfValues{std::move(lo), std::move(hi)};
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 6e301e6ba752a..1a6b3956dacd6 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -2076,10 +2076,11 @@ MaybeExpr ArrayConstructorContext::ToExpr() {
 
 MaybeExpr ExpressionAnalyzer::Analyze(const parser::ArrayConstructor &array) {
   const parser::AcSpec &acSpec{array.v};
+  auto &[type, values]{acSpec.t};
   bool hadAnyFatalError{context_.AnyFatalError()};
   ArrayConstructorContext acContext{
-      *this, AnalyzeTypeSpec(acSpec.type, GetFoldingContext())};
-  for (const parser::AcValue &value : acSpec.values) {
+      *this, AnalyzeTypeSpec(type, GetFoldingContext())};
+  for (const parser::AcValue &value : values) {
     acContext.Add(value);
   }
   if (!hadAnyFatalError && context_.AnyFatalError()) {
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index ae251476ed591..6d1f87f2eb0cc 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -6138,14 +6138,14 @@ void DeclarationVisitor::Post(const parser::UnsignedTypeSpec &x) {
 }
 void DeclarationVisitor::Post(const parser::IntrinsicTypeSpec::Real &x) {
   if (!isVectorType_) {
-    SetDeclTypeSpec(MakeNumericType(TypeCategory::Real, x.kind));
+    SetDeclTypeSpec(MakeNumericType(TypeCategory::Real, x.v));
   }
 }
 void DeclarationVisitor::Post(const parser::IntrinsicTypeSpec::Complex &x) {
-  SetDeclTypeSpec(MakeNumericType(TypeCategory::Complex, x.kind));
+  SetDeclTypeSpec(MakeNumericType(TypeCategory::Complex, x.v));
 }
 void DeclarationVisitor::Post(const parser::IntrinsicTypeSpec::Logical &x) {
-  SetDeclTypeSpec(MakeLogicalType(x.kind));
+  SetDeclTypeSpec(MakeLogicalType(x.v));
 }
 void DeclarationVisitor::Post(const parser::IntrinsicTypeSpec::Character &) {
   if (!charInfo_.length) {
@@ -6160,7 +6160,8 @@ void DeclarationVisitor::Post(const parser::IntrinsicTypeSpec::Character &) {
   charInfo_ = {};
 }
 void DeclarationVisitor::Post(const parser::CharSelector::LengthAndKind &x) {
-  charInfo_.kind = EvaluateSubscriptIntExpr(x.kind);
+  auto &[length, kind]{x.t};
+  charInfo_.kind = EvaluateSubscriptIntExpr(kind);
   std::optional<std::int64_t> intKind{ToInt64(charInfo_.kind)};
   if (intKind &&
       !context().targetCharacteristics().IsTypeEnabled(
@@ -6169,8 +6170,8 @@ void DeclarationVisitor::Post(const parser::CharSelector::LengthAndKind &x) {
         "KIND value (%jd) not valid for CHARACTER"_err_en_US, *intKind);
     charInfo_.kind = std::nullopt; // prevent further errors
   }
-  if (x.length) {
-    charInfo_.length = GetParamValue(*x.length, common::TypeParamAttr::Len);
+  if (length) {
+    charInfo_.length = GetParamValue(*length, common::TypeParamAttr::Len);
   }
 }
 void DeclarationVisitor::Post(const parser::CharLength &x) {
@@ -6245,7 +6246,7 @@ void DeclarationVisitor::Post(const parser::VectorTypeSpec &x) {
                     },
                     [&](const parser::IntrinsicTypeSpec::Real &z) {
                       vecElemKind = GetVectorElementKind(
-                          TypeCategory::Real, std::move(z.kind));
+                          TypeCategory::Real, std::move(z.v));
                       typeParams.push_back(
                           ParamValue(static_cast<common::ConstantSubscript>(
                                          common::VectorElementCategory::Real),
@@ -6321,7 +6322,7 @@ bool DeclarationVisitor::Pre(const parser::DeclarationTypeSpec::Type &) {
 }
 
 void DeclarationVisitor::Post(const parser::DeclarationTypeSpec::Type &type) {
-  const parser::Name &derivedName{std::get<parser::Name>(type.derived.t)};
+  const parser::Name &derivedName{std::get<parser::Name>(type.v.t)};
   if (const Symbol * derivedSymbol{derivedName.symbol}) {
     CheckForAbstractType(*derivedSymbol); // C706
   }
@@ -6334,7 +6335,7 @@ bool DeclarationVisitor::Pre(const parser::DeclarationTypeSpec::Class &) {
 
 void DeclarationVisitor::Post(
     const parser::DeclarationTypeSpec::Class &parsedClass) {
-  const auto &typeName{std::get<parser::Name>(parsedClass.derived.t)};
+  const auto &typeName{std::get<parser::Name>(parsedClass.v.t)};
   if (auto spec{ResolveDerivedType(typeName)};
       spec && !IsExtensibleType(&*spec)) { // C705
     SayWithDecl(typeName, *typeName.symbol,
@@ -7893,8 +7894,9 @@ bool ConstructVisitor::Pre(const parser::LocalitySpec::Shared &x) {
 }
 
 bool ConstructVisitor::Pre(const parser::AcSpec &x) {
-  ProcessTypeSpec(x.type);
-  Walk(x.values);
+  auto &[type, values]{x.t};
+  ProcessTypeSpec(type);
+  Walk(values);
   return false;
 }
 
@@ -8492,12 +8494,13 @@ class ExecutionPartSkimmerBase {
     return true;
   }
   void Post(const parser::ImportStmt &x) {
-    if (x.kind == common::ImportKind::None ||
-        x.kind == common::ImportKind::Only) {
+    auto &[kind, names]{x.t};
+    if (kind == common::ImportKind::None ||
+        kind == common::ImportKind::Only) {
       if (!nestedScopes_.front().importOnly.has_value()) {
         nestedScopes_.front().importOnly.emplace();
       }
-      for (const auto &name : x.names) {
+      for (const auto &name : names) {
         nestedScopes_.front().importOnly->emplace(name.source);
       }
     } else {
@@ -8709,6 +8712,7 @@ bool ResolveNamesVisitor::Pre(const parser::CallStmt &x) {
 }
 
 bool ResolveNamesVisitor::Pre(const parser::ImportStmt &x) {
+  auto &[kind, names]{x.t};
   auto &scope{currScope()};
   // Check C896 and C899: where IMPORT statements are allowed
   switch (scope.kind()) {
@@ -8716,7 +8720,7 @@ bool ResolveNamesVisitor::Pre(const parser::ImportStmt &x) {
     if (scope.IsModule()) {
       Say("IMPORT is not allowed in a module scoping unit"_err_en_US);
       return false;
-    } else if (x.kind == common::ImportKind::None) {
+    } else if (kind == common::ImportKind::None) {
       Say("IMPORT,NONE is not allowed in a submodule scoping unit"_err_en_US);
       return false;
     }
@@ -8735,10 +8739,10 @@ bool ResolveNamesVisitor::Pre(const parser::ImportStmt &x) {
     return false;
   default:;
   }
-  if (auto error{scope.SetImportKind(x.kind)}) {
+  if (auto error{scope.SetImportKind(kind)}) {
     Say(std::move(*error));
   }
-  for (auto &name : x.names) {
+  for (auto &name : names) {
     if (Symbol * outer{FindSymbol(scope.parent(), name)}) {
       scope.add_importName(name.source);
       if (Symbol * symbol{FindInScope(name)}) {
@@ -9613,10 +9617,10 @@ void ResolveNamesVisitor::HandleDerivedTypesInImplicitStmts(
           if (const auto *dtSpec{common::visit(
                   common::visitors{
                       [](const parser::DeclarationTypeSpec::Type &x) {
-                        return &x.derived;
+                        return &x.v;
                       },
                       [](const parser::DeclarationTypeSpec::Class &x) {
-                        return &x.derived;
+                        return &x.v;
                       },
                       [](const auto &) -> const parser::DerivedTypeSpec * {
                         return nullptr;
@@ -9783,7 +9787,7 @@ void ResolveNamesVisitor::EarlyDummyTypeDeclaration(
 
 void ResolveNamesVisitor::CreateCommonBlockSymbols(
     const parser::CommonStmt &commonStmt) {
-  for (const parser::CommonStmt::Block &block : commonStmt.blocks) {
+  for (const parser::CommonStmt::Block &block : commonStmt.v) {
     const auto &[name, objects] = block.t;
     Symbol &commonBlock{MakeCommonBlockSymbol(name, commonStmt.source)};
     for (const auto &object : objects) {

>From 2a5bdc63ac479fb7f39e5472186ee7cab1d4e7d5 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Thu, 8 Jan 2026 14:46:16 -0600
Subject: [PATCH 2/3] format

---
 flang/lib/Semantics/check-case.cpp    | 42 +++++++++++++--------------
 flang/lib/Semantics/resolve-names.cpp |  3 +-
 2 files changed, 22 insertions(+), 23 deletions(-)

diff --git a/flang/lib/Semantics/check-case.cpp b/flang/lib/Semantics/check-case.cpp
index 1b00db91b83f2..e102257e83211 100644
--- a/flang/lib/Semantics/check-case.cpp
+++ b/flang/lib/Semantics/check-case.cpp
@@ -117,27 +117,27 @@ template <typename T> class CaseValues {
 
   using PairOfValues = std::pair<std::optional<Value>, std::optional<Value>>;
   PairOfValues ComputeBounds(const parser::CaseValueRange &range) {
-    return common::visit(
-        common::visitors{
-            [&](const parser::CaseValue &x) {
-              auto value{GetValue(x)};
-              return PairOfValues{value, value};
-            },
-            [&](const parser::CaseValueRange::Range &x) {
-              auto &[lower, upper]{x.t};
-              std::optional<Value> lo, hi;
-              if (lower) {
-                lo = GetValue(*lower);
-              }
-              if (upper) {
-                hi = GetValue(*upper);
-              }
-              if ((lower && !lo) || (upper && !hi)) {
-                return PairOfValues{}; // error case
-              }
-              return PairOfValues{std::move(lo), std::move(hi)};
-            },
-        },
+    return common::visit(common::visitors{
+                             [&](const parser::CaseValue &x) {
+                               auto value{GetValue(x)};
+                               return PairOfValues{value, value};
+                             },
+                             [&](const parser::CaseValueRange::Range &x) {
+                               auto &[lower, upper]{x.t};
+                               std::optional<Value> lo, hi;
+                               if (lower) {
+                                 lo = GetValue(*lower);
+                               }
+                               if (upper) {
+                                 hi = GetValue(*upper);
+                               }
+                               if ((lower && !lo) || (upper && !hi)) {
+                                 return PairOfValues{}; // error case
+                               }
+                               return PairOfValues{
+                                   std::move(lo), std::move(hi)};
+                             },
+                         },
         range.u);
   }
 
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 6d1f87f2eb0cc..e7f1eb1f41891 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -8495,8 +8495,7 @@ class ExecutionPartSkimmerBase {
   }
   void Post(const parser::ImportStmt &x) {
     auto &[kind, names]{x.t};
-    if (kind == common::ImportKind::None ||
-        kind == common::ImportKind::Only) {
+    if (kind == common::ImportKind::None || kind == common::ImportKind::Only) {
       if (!nestedScopes_.front().importOnly.has_value()) {
         nestedScopes_.front().importOnly.emplace();
       }

>From 36824e29df9415373b122e08c8cc70ba82aceab0 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Thu, 8 Jan 2026 15:07:54 -0600
Subject: [PATCH 3/3] Use "const auto &"

---
 flang/lib/Lower/Bridge.cpp            | 2 +-
 flang/lib/Parser/parse-tree.cpp       | 2 +-
 flang/lib/Parser/unparse.cpp          | 4 ++--
 flang/lib/Semantics/check-case.cpp    | 2 +-
 flang/lib/Semantics/expression.cpp    | 2 +-
 flang/lib/Semantics/resolve-names.cpp | 8 ++++----
 6 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 5570e07501ee9..9224bc2be1028 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -4011,7 +4011,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
         }
         const auto &caseRange =
             std::get<Fortran::parser::CaseValueRange::Range>(caseValueRange.u);
-        auto &[lower, upper]{caseRange.t};
+        const auto &[lower, upper]{caseRange.t};
         if (lower && upper) {
           attrList.push_back(fir::ClosedIntervalAttr::get(context));
           addValue(*lower);
diff --git a/flang/lib/Parser/parse-tree.cpp b/flang/lib/Parser/parse-tree.cpp
index 4783a4e3b635e..dae1912afa99e 100644
--- a/flang/lib/Parser/parse-tree.cpp
+++ b/flang/lib/Parser/parse-tree.cpp
@@ -23,7 +23,7 @@ namespace Fortran::parser {
 // R867
 ImportStmt::ImportStmt(common::ImportKind &&k, std::list<Name> &&n)
     : t(k, std::move(n)) {
-  auto &[kind, names]{t};
+  const auto &[kind, names]{t};
   CHECK(kind == common::ImportKind::Default ||
       kind == common::ImportKind::Only || names.empty());
 }
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 812ed9ac58e6f..9b31454537df5 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -727,7 +727,7 @@ class UnparseVisitor {
     }
   }
   void Unparse(const ImportStmt &x) { // R867
-    auto &[kind, names]{x.t};
+    const auto &[kind, names]{x.t};
     Word("IMPORT");
     switch (kind) {
     case common::ImportKind::Default:
@@ -1108,7 +1108,7 @@ class UnparseVisitor {
         x.u);
   }
   void Unparse(const CaseValueRange::Range &x) { // R1146
-    auto &[lower, upper]{x.t};
+    const auto &[lower, upper]{x.t};
     Walk(lower), Put(':'), Walk(upper);
   }
   void Unparse(const SelectRankStmt &x) { // R1149
diff --git a/flang/lib/Semantics/check-case.cpp b/flang/lib/Semantics/check-case.cpp
index e102257e83211..9004d8b3a28f9 100644
--- a/flang/lib/Semantics/check-case.cpp
+++ b/flang/lib/Semantics/check-case.cpp
@@ -123,7 +123,7 @@ template <typename T> class CaseValues {
                                return PairOfValues{value, value};
                              },
                              [&](const parser::CaseValueRange::Range &x) {
-                               auto &[lower, upper]{x.t};
+                               const auto &[lower, upper]{x.t};
                                std::optional<Value> lo, hi;
                                if (lower) {
                                  lo = GetValue(*lower);
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 1a6b3956dacd6..b3643e0d35d5f 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -2076,7 +2076,7 @@ MaybeExpr ArrayConstructorContext::ToExpr() {
 
 MaybeExpr ExpressionAnalyzer::Analyze(const parser::ArrayConstructor &array) {
   const parser::AcSpec &acSpec{array.v};
-  auto &[type, values]{acSpec.t};
+  const auto &[type, values]{acSpec.t};
   bool hadAnyFatalError{context_.AnyFatalError()};
   ArrayConstructorContext acContext{
       *this, AnalyzeTypeSpec(type, GetFoldingContext())};
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index e7f1eb1f41891..8086e43b90f20 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -6160,7 +6160,7 @@ void DeclarationVisitor::Post(const parser::IntrinsicTypeSpec::Character &) {
   charInfo_ = {};
 }
 void DeclarationVisitor::Post(const parser::CharSelector::LengthAndKind &x) {
-  auto &[length, kind]{x.t};
+  const auto &[length, kind]{x.t};
   charInfo_.kind = EvaluateSubscriptIntExpr(kind);
   std::optional<std::int64_t> intKind{ToInt64(charInfo_.kind)};
   if (intKind &&
@@ -7894,7 +7894,7 @@ bool ConstructVisitor::Pre(const parser::LocalitySpec::Shared &x) {
 }
 
 bool ConstructVisitor::Pre(const parser::AcSpec &x) {
-  auto &[type, values]{x.t};
+  const auto &[type, values]{x.t};
   ProcessTypeSpec(type);
   Walk(values);
   return false;
@@ -8494,7 +8494,7 @@ class ExecutionPartSkimmerBase {
     return true;
   }
   void Post(const parser::ImportStmt &x) {
-    auto &[kind, names]{x.t};
+    const auto &[kind, names]{x.t};
     if (kind == common::ImportKind::None || kind == common::ImportKind::Only) {
       if (!nestedScopes_.front().importOnly.has_value()) {
         nestedScopes_.front().importOnly.emplace();
@@ -8711,7 +8711,7 @@ bool ResolveNamesVisitor::Pre(const parser::CallStmt &x) {
 }
 
 bool ResolveNamesVisitor::Pre(const parser::ImportStmt &x) {
-  auto &[kind, names]{x.t};
+  const auto &[kind, names]{x.t};
   auto &scope{currScope()};
   // Check C896 and C899: where IMPORT statements are allowed
   switch (scope.kind()) {



More information about the flang-commits mailing list