[flang-commits] [flang] d542fac - [flang] Add traits to more AST nodes (#175578)

via flang-commits flang-commits at lists.llvm.org
Tue Jan 20 07:57:40 PST 2026


Author: Krzysztof Parzyszek
Date: 2026-01-20T09:57:35-06:00
New Revision: d542fac6b16406ec0ed0e168e6c3f4c6be28cff8

URL: https://github.com/llvm/llvm-project/commit/d542fac6b16406ec0ed0e168e6c3f4c6be28cff8
DIFF: https://github.com/llvm/llvm-project/commit/d542fac6b16406ec0ed0e168e6c3f4c6be28cff8.diff

LOG: [flang] Add traits to more AST nodes (#175578)

Follow-up to PR175211.

There are still 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.

The members of these nodes were frequently used, so instead of
extracting them by hand each time use helper member functions to access
them.

Added: 
    

Modified: 
    flang/include/flang/Parser/parse-tree-visitor.h
    flang/include/flang/Parser/parse-tree.h
    flang/lib/Lower/Bridge.cpp
    flang/lib/Lower/IO.cpp
    flang/lib/Lower/OpenACC.cpp
    flang/lib/Lower/OpenMP/OpenMP.cpp
    flang/lib/Lower/OpenMP/Utils.cpp
    flang/lib/Lower/PFTBuilder.cpp
    flang/lib/Parser/parse-tree.cpp
    flang/lib/Parser/tools.cpp
    flang/lib/Parser/unparse.cpp
    flang/lib/Semantics/check-acc-structure.cpp
    flang/lib/Semantics/check-cuda.cpp
    flang/lib/Semantics/check-data.cpp
    flang/lib/Semantics/check-deallocate.cpp
    flang/lib/Semantics/check-do-forall.cpp
    flang/lib/Semantics/check-nullify.cpp
    flang/lib/Semantics/check-omp-loop.cpp
    flang/lib/Semantics/check-omp-structure.cpp
    flang/lib/Semantics/data-to-inits.cpp
    flang/lib/Semantics/expression.cpp
    flang/lib/Semantics/resolve-directives.cpp
    flang/lib/Semantics/resolve-names-utils.cpp
    flang/lib/Semantics/resolve-names.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Parser/parse-tree-visitor.h b/flang/include/flang/Parser/parse-tree-visitor.h
index 191e74ee89f1c..5aff5152a3793 100644
--- a/flang/include/flang/Parser/parse-tree-visitor.h
+++ b/flang/include/flang/Parser/parse-tree-visitor.h
@@ -314,56 +314,6 @@ struct ParseTreeVisitorLookupScope {
     }
   }
 
-  template <typename V> static void Walk(const ArrayElement &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.base, visitor);
-      Walk(x.subscripts, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M> static void Walk(ArrayElement &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.base, mutator);
-      Walk(x.subscripts, mutator);
-      mutator.Post(x);
-    }
-  }
-  template <typename V>
-  static void Walk(const CoindexedNamedObject &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.base, visitor);
-      Walk(x.imageSelector, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M> static void Walk(CoindexedNamedObject &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.base, mutator);
-      Walk(x.imageSelector, 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)) {
-      Walk(x.name, visitor);
-      Walk(x.lower, visitor);
-      Walk(x.upper, visitor);
-      Walk(x.step, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename A, typename B, typename M>
-  static void Walk(LoopBounds<A, B> &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.name, mutator);
-      Walk(x.lower, mutator);
-      Walk(x.upper, mutator);
-      Walk(x.step, mutator);
-      mutator.Post(x);
-    }
-  }
-
   // Expr traversal uses iteration rather than recursion to avoid
   // blowing out the stack on very deep expression parse trees.
   // It replaces implementations that looked like:
@@ -451,21 +401,6 @@ struct ParseTreeVisitorLookupScope {
       mutator.Post(x);
     }
   }
-  template <typename V>
-  static void Walk(const StructureComponent &x, V &visitor) {
-    if (visitor.Pre(x)) {
-      Walk(x.base, visitor);
-      Walk(x.component, visitor);
-      visitor.Post(x);
-    }
-  }
-  template <typename M> static void Walk(StructureComponent &x, M &mutator) {
-    if (mutator.Pre(x)) {
-      Walk(x.base, mutator);
-      Walk(x.component, mutator);
-      mutator.Post(x);
-    }
-  }
   template <typename V> static void Walk(const UseStmt &x, V &visitor) {
     if (visitor.Pre(x)) {
       Walk(x.nature, visitor);

diff  --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index c03823b60f0de..6c1aace66275f 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -1256,15 +1256,13 @@ WRAPPER_CLASS(ArrayConstructor, AcSpec);
 using DoVariable = Scalar<Integer<Name>>;
 
 template <typename VAR, typename BOUND> struct LoopBounds {
-  LoopBounds(LoopBounds &&that) = default;
-  LoopBounds(
-      VAR &&name, BOUND &&lower, BOUND &&upper, std::optional<BOUND> &&step)
-      : name{std::move(name)}, lower{std::move(lower)}, upper{std::move(upper)},
-        step{std::move(step)} {}
-  LoopBounds &operator=(LoopBounds &&) = default;
-  VAR name;
-  BOUND lower, upper;
-  std::optional<BOUND> step;
+  TUPLE_CLASS_BOILERPLATE(LoopBounds);
+  std::tuple<VAR, BOUND, BOUND, std::optional<BOUND>> t;
+
+  const VAR &Name() const { return std::get<0>(t); }
+  const BOUND &Lower() const { return std::get<1>(t); }
+  const BOUND &Upper() const { return std::get<2>(t); }
+  const std::optional<BOUND> &Step() const { return std::get<3>(t); }
 };
 
 using ScalarName = Scalar<Name>;
@@ -1858,11 +1856,11 @@ using ScalarIntVariable = Scalar<Integer<Variable>>;
 
 // R913 structure-component -> data-ref
 struct StructureComponent {
-  BOILERPLATE(StructureComponent);
-  StructureComponent(DataRef &&dr, Name &&n)
-      : base{std::move(dr)}, component(std::move(n)) {}
-  DataRef base;
-  Name component;
+  TUPLE_CLASS_BOILERPLATE(StructureComponent);
+  std::tuple<DataRef, Name> t;
+
+  const DataRef &Base() const { return std::get<DataRef>(t); }
+  const Name &Component() const { return std::get<Name>(t); }
 };
 
 // R1039 proc-component-ref -> scalar-variable % procedure-component-name
@@ -1873,23 +1871,22 @@ struct ProcComponentRef {
 
 // R914 coindexed-named-object -> data-ref
 struct CoindexedNamedObject {
-  BOILERPLATE(CoindexedNamedObject);
-  CoindexedNamedObject(DataRef &&dr, ImageSelector &&is)
-      : base{std::move(dr)}, imageSelector{std::move(is)} {}
-  DataRef base;
-  ImageSelector imageSelector;
+  TUPLE_CLASS_BOILERPLATE(CoindexedNamedObject);
+  std::tuple<DataRef, ImageSelector> t;
 };
 
 // R917 array-element -> data-ref
 struct ArrayElement {
-  BOILERPLATE(ArrayElement);
-  ArrayElement(DataRef &&dr, std::list<SectionSubscript> &&ss)
-      : base{std::move(dr)}, subscripts(std::move(ss)) {}
+  TUPLE_CLASS_BOILERPLATE(ArrayElement);
   Substring ConvertToSubstring();
   StructureConstructor ConvertToStructureConstructor(
       const semantics::DerivedTypeSpec &);
-  DataRef base;
-  std::list<SectionSubscript> subscripts;
+  std::tuple<DataRef, std::list<SectionSubscript>> t;
+
+  const DataRef &Base() const { return std::get<DataRef>(t); }
+  const std::list<SectionSubscript> &Subscripts() const {
+    return std::get<std::list<SectionSubscript>>(t);
+  }
 };
 
 // R933 allocate-object -> variable-name | structure-component

diff  --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index eba232fa1e9f3..251e8d9ca9e14 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2491,8 +2491,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
                        &loopControl->u)) {
       // Non-concurrent increment loop.
       IncrementLoopInfo &info = incrementLoopNestInfo.emplace_back(
-          *bounds->name.thing.symbol, bounds->lower, bounds->upper,
-          bounds->step);
+          *bounds->Name().thing.symbol, bounds->Lower(), bounds->Upper(),
+          bounds->Step());
       if (unstructuredContext) {
         maybeStartBlock(preheaderBlock);
         info.hasRealControl = info.loopVariableSym->GetType()->IsNumeric(
@@ -3850,22 +3850,22 @@ class FirConverter : public Fortran::lower::AbstractConverter {
         assert(bounds && "Expected bounds on the loop construct");
 
         Fortran::semantics::Symbol &ivSym =
-            bounds->name.thing.symbol->GetUltimate();
+            bounds->Name().thing.symbol->GetUltimate();
         ivValues.push_back(getSymbolAddress(ivSym));
 
         lbs.push_back(builder->createConvert(
             crtLoc, idxTy,
             fir::getBase(genExprValue(
-                *Fortran::semantics::GetExpr(bounds->lower), stmtCtx))));
+                *Fortran::semantics::GetExpr(bounds->Lower()), stmtCtx))));
         ubs.push_back(builder->createConvert(
             crtLoc, idxTy,
             fir::getBase(genExprValue(
-                *Fortran::semantics::GetExpr(bounds->upper), stmtCtx))));
-        if (bounds->step)
+                *Fortran::semantics::GetExpr(bounds->Upper()), stmtCtx))));
+        if (auto &step = bounds->Step())
           steps.push_back(builder->createConvert(
               crtLoc, idxTy,
-              fir::getBase(genExprValue(
-                  *Fortran::semantics::GetExpr(bounds->step), stmtCtx))));
+              fir::getBase(
+                  genExprValue(*Fortran::semantics::GetExpr(step), stmtCtx))));
         else // If `step` is not present, assume it is `1`.
           steps.push_back(builder->createIntegerConstant(loc, idxTy, 1));
 

diff  --git a/flang/lib/Lower/IO.cpp b/flang/lib/Lower/IO.cpp
index c3f9c1a882423..de2afb70636d5 100644
--- a/flang/lib/Lower/IO.cpp
+++ b/flang/lib/Lower/IO.cpp
@@ -951,7 +951,7 @@ static void genIoLoop(Fortran::lower::AbstractConverter &converter,
   const auto &itemList = std::get<0>(ioImpliedDo.t);
   const auto &control = std::get<1>(ioImpliedDo.t);
   const auto &loopSym =
-      *Fortran::parser::UnwrapRef<Fortran::parser::Name>(control.name).symbol;
+      *Fortran::parser::UnwrapRef<Fortran::parser::Name>(control.Name()).symbol;
   mlir::Value loopVar = fir::getBase(converter.genExprAddr(
       Fortran::evaluate::AsGenericExpr(loopSym).value(), stmtCtx));
   auto genControlValue = [&](const Fortran::parser::ScalarIntExpr &expr) {
@@ -959,11 +959,11 @@ static void genIoLoop(Fortran::lower::AbstractConverter &converter,
         converter.genExprValue(*Fortran::semantics::GetExpr(expr), stmtCtx));
     return builder.createConvert(loc, builder.getIndexType(), v);
   };
-  mlir::Value lowerValue = genControlValue(control.lower);
-  mlir::Value upperValue = genControlValue(control.upper);
+  mlir::Value lowerValue = genControlValue(control.Lower());
+  mlir::Value upperValue = genControlValue(control.Upper());
   mlir::Value stepValue =
-      control.step.has_value()
-          ? genControlValue(*control.step)
+      control.Step().has_value()
+          ? genControlValue(*control.Step())
           : mlir::arith::ConstantIndexOp::create(builder, loc, 1);
   auto genItemList = [&](const D &ioImpliedDo) {
     if constexpr (std::is_same_v<D, Fortran::parser::InputImpliedDo>)

diff  --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index 1e313b20d464c..f0f671e8e524d 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -311,13 +311,13 @@ getSymbolFromAccObject(const Fortran::parser::AccObject &accObject) {
             Fortran::parser::Unwrap<Fortran::parser::ArrayElement>(
                 *designator)) {
       const Fortran::parser::Name &name =
-          Fortran::parser::GetLastName(arrayElement->base);
+          Fortran::parser::GetLastName(arrayElement->Base());
       return *name.symbol;
     }
     if (const auto *component =
             Fortran::parser::Unwrap<Fortran::parser::StructureComponent>(
                 *designator)) {
-      return *component->component.symbol;
+      return *component->Component().symbol;
     }
   } else if (const auto *name =
                  std::get_if<Fortran::parser::Name>(&accObject.u)) {
@@ -1996,18 +1996,18 @@ static void processDoLoopBounds(
             mlir::Location loc) {
           locs.push_back(loc);
           lowerbounds.push_back(fir::getBase(converter.genExprValue(
-              *Fortran::semantics::GetExpr(bounds.lower), stmtCtx)));
+              *Fortran::semantics::GetExpr(bounds.Lower()), stmtCtx)));
           upperbounds.push_back(fir::getBase(converter.genExprValue(
-              *Fortran::semantics::GetExpr(bounds.upper), stmtCtx)));
-          if (bounds.step)
+              *Fortran::semantics::GetExpr(bounds.Upper()), stmtCtx)));
+          if (auto &step = bounds.Step())
             steps.push_back(fir::getBase(converter.genExprValue(
-                *Fortran::semantics::GetExpr(bounds.step), stmtCtx)));
+                *Fortran::semantics::GetExpr(step), stmtCtx)));
           else // If `step` is not present, assume it is `1`.
             steps.push_back(builder.createIntegerConstant(
                 currentLocation, upperbounds[upperbounds.size() - 1].getType(),
                 1));
           Fortran::semantics::Symbol &ivSym =
-              bounds.name.thing.symbol->GetUltimate();
+              bounds.Name().thing.symbol->GetUltimate();
           privatizeIv(converter, ivSym, currentLocation, ivTypes, ivLocs,
                       privateOperands, ivPrivate);
 
@@ -2178,7 +2178,7 @@ static void privatizeInductionVariables(
                        mlir::Location loc) {
                      locs.push_back(loc);
                      Fortran::semantics::Symbol &ivSym =
-                         bounds.name.thing.symbol->GetUltimate();
+                         bounds.Name().thing.symbol->GetUltimate();
                      privatizeIv(converter, ivSym, currentLocation, ivTypes,
                                  ivLocs, privateOperands, ivPrivate);
                    });

diff  --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 0764693f748a5..9d12a8c4dc847 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2090,13 +2090,13 @@ static void genCanonicalLoopNest(
     assert(bounds && "Expected bounds for canonical loop");
     lower::StatementContext stmtCtx;
     mlir::Value loopLBVar = fir::getBase(
-        converter.genExprValue(*semantics::GetExpr(bounds->lower), stmtCtx));
+        converter.genExprValue(*semantics::GetExpr(bounds->Lower()), stmtCtx));
     mlir::Value loopUBVar = fir::getBase(
-        converter.genExprValue(*semantics::GetExpr(bounds->upper), stmtCtx));
+        converter.genExprValue(*semantics::GetExpr(bounds->Upper()), stmtCtx));
     mlir::Value loopStepVar = [&]() {
-      if (bounds->step) {
+      if (auto &step = bounds->Step()) {
         return fir::getBase(
-            converter.genExprValue(*semantics::GetExpr(bounds->step), stmtCtx));
+            converter.genExprValue(*semantics::GetExpr(step), stmtCtx));
       }
 
       // If `step` is not present, assume it is `1`.
@@ -2105,7 +2105,7 @@ static void genCanonicalLoopNest(
     }();
 
     // Get the integer kind for the loop variable and cast the loop bounds
-    size_t loopVarTypeSize = bounds->name.thing.symbol->GetUltimate().size();
+    size_t loopVarTypeSize = bounds->Name().thing.symbol->GetUltimate().size();
     mlir::Type loopVarType = getLoopVarType(converter, loopVarTypeSize);
     loopVarTypes.push_back(loopVarType);
     loopLBVar = firOpBuilder.createConvert(loc, loopVarType, loopLBVar);

diff  --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index a818d635668de..dce8580856664 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -31,6 +31,7 @@
 #include <flang/Semantics/tools.h>
 #include <flang/Semantics/type.h>
 #include <flang/Utils/OpenMP.h>
+#include <llvm/ADT/STLExtras.h>
 #include <llvm/ADT/SmallPtrSet.h>
 #include <llvm/ADT/StringRef.h>
 #include <llvm/Support/CommandLine.h>
@@ -255,9 +256,10 @@ getIterationVariableSymbol(const lower::pft::Evaluation &eval) {
         if (const auto &maybeCtrl = doLoop.GetLoopControl()) {
           using LoopControl = parser::LoopControl;
           if (auto *bounds = std::get_if<LoopControl::Bounds>(&maybeCtrl->u)) {
-            static_assert(std::is_same_v<decltype(bounds->name),
-                                         parser::Scalar<parser::Name>>);
-            return bounds->name.thing.symbol;
+            using NameType = llvm::remove_cvref_t<decltype(bounds->Name())>;
+            static_assert(
+                std::is_same_v<NameType, parser::Scalar<parser::Name>>);
+            return bounds->Name().thing.symbol;
           }
         }
         return static_cast<semantics::Symbol *>(nullptr);
@@ -894,19 +896,19 @@ void collectLoopRelatedInfo(
     assert(bounds && "Expected bounds for worksharing do loop");
     lower::StatementContext stmtCtx;
     result.loopLowerBounds.push_back(fir::getBase(
-        converter.genExprValue(*semantics::GetExpr(bounds->lower), stmtCtx)));
+        converter.genExprValue(*semantics::GetExpr(bounds->Lower()), stmtCtx)));
     result.loopUpperBounds.push_back(fir::getBase(
-        converter.genExprValue(*semantics::GetExpr(bounds->upper), stmtCtx)));
-    if (bounds->step) {
+        converter.genExprValue(*semantics::GetExpr(bounds->Upper()), stmtCtx)));
+    if (auto &step = bounds->Step()) {
       result.loopSteps.push_back(fir::getBase(
-          converter.genExprValue(*semantics::GetExpr(bounds->step), stmtCtx)));
+          converter.genExprValue(*semantics::GetExpr(step), stmtCtx)));
     } else { // If `step` is not present, assume it as `1`.
       result.loopSteps.push_back(firOpBuilder.createIntegerConstant(
           currentLocation, firOpBuilder.getIntegerType(32), 1));
     }
-    iv.push_back(bounds->name.thing.symbol);
-    loopVarTypeSize = std::max(loopVarTypeSize,
-                               bounds->name.thing.symbol->GetUltimate().size());
+    iv.push_back(bounds->Name().thing.symbol);
+    loopVarTypeSize = std::max(
+        loopVarTypeSize, bounds->Name().thing.symbol->GetUltimate().size());
     if (--collapseValue)
       doConstructEval = getNestedDoConstruct(*doConstructEval);
   } while (collapseValue > 0);

diff  --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp
index 1a7fb41f3273c..308db726f073c 100644
--- a/flang/lib/Lower/PFTBuilder.cpp
+++ b/flang/lib/Lower/PFTBuilder.cpp
@@ -1055,7 +1055,7 @@ class PFTBuilder {
             eval.controlSuccessor = &evaluationList.back();
             if (const auto *bounds =
                     std::get_if<parser::LoopControl::Bounds>(&loopControl->u)) {
-              if (bounds->name.thing.symbol->GetType()->IsNumeric(
+              if (bounds->Name().thing.symbol->GetType()->IsNumeric(
                       common::TypeCategory::Real))
                 eval.isUnstructured = true; // real-valued loop control
             } else if (std::get_if<parser::ScalarLogicalExpr>(

diff  --git a/flang/lib/Parser/parse-tree.cpp b/flang/lib/Parser/parse-tree.cpp
index e0c668ddc328b..afe28182f8627 100644
--- a/flang/lib/Parser/parse-tree.cpp
+++ b/flang/lib/Parser/parse-tree.cpp
@@ -102,8 +102,9 @@ static Designator MakeArrayElementRef(
     const Name &name, std::list<Expr> &&subscripts) {
   ArrayElement arrayElement{DataRef{Name{name}}, std::list<SectionSubscript>{}};
   for (Expr &expr : subscripts) {
-    arrayElement.subscripts.push_back(
-        SectionSubscript{Integer{common::Indirection{std::move(expr)}}});
+    std::get<std::list<SectionSubscript>>(arrayElement.t)
+        .push_back(
+            SectionSubscript{Integer{common::Indirection{std::move(expr)}}});
   }
   return Designator{DataRef{common::Indirection{std::move(arrayElement)}}};
 }
@@ -113,8 +114,9 @@ static Designator MakeArrayElementRef(
   ArrayElement arrayElement{DataRef{common::Indirection{std::move(sc)}},
       std::list<SectionSubscript>{}};
   for (Expr &expr : subscripts) {
-    arrayElement.subscripts.push_back(
-        SectionSubscript{Integer{common::Indirection{std::move(expr)}}});
+    std::get<std::list<SectionSubscript>>(arrayElement.t)
+        .push_back(
+            SectionSubscript{Integer{common::Indirection{std::move(expr)}}});
   }
   return Designator{DataRef{common::Indirection{std::move(arrayElement)}}};
 }
@@ -186,6 +188,7 @@ StructureConstructor FunctionReference::ConvertToStructureConstructor(
 
 StructureConstructor ArrayElement::ConvertToStructureConstructor(
     const semantics::DerivedTypeSpec &derived) {
+  auto &[base, subscripts]{t};
   Name name{std::get<parser::Name>(base.u)};
   std::list<ComponentSpec> components;
   for (auto &subscript : subscripts) {
@@ -198,6 +201,7 @@ StructureConstructor ArrayElement::ConvertToStructureConstructor(
 }
 
 Substring ArrayElement::ConvertToSubstring() {
+  auto &[base, subscripts]{t};
   auto iter{subscripts.begin()};
   CHECK(iter != subscripts.end());
   auto &triplet{std::get<SubscriptTriplet>(iter->u)};

diff  --git a/flang/lib/Parser/tools.cpp b/flang/lib/Parser/tools.cpp
index ed6d194c17dc3..ff0538ae565b2 100644
--- a/flang/lib/Parser/tools.cpp
+++ b/flang/lib/Parser/tools.cpp
@@ -13,7 +13,7 @@ namespace Fortran::parser {
 const Name &GetLastName(const Name &x) { return x; }
 
 const Name &GetLastName(const StructureComponent &x) {
-  return GetLastName(x.component);
+  return GetLastName(x.Component());
 }
 
 const Name &GetLastName(const DataRef &x) {
@@ -23,10 +23,12 @@ const Name &GetLastName(const DataRef &x) {
           [](const common::Indirection<StructureComponent> &sc)
               -> const Name & { return GetLastName(sc.value()); },
           [](const common::Indirection<ArrayElement> &sc) -> const Name & {
-            return GetLastName(sc.value().base);
+            return GetLastName(sc.value().Base());
           },
           [](const common::Indirection<CoindexedNamedObject> &ci)
-              -> const Name & { return GetLastName(ci.value().base); },
+              -> const Name & {
+            return GetLastName(std::get<DataRef>(ci.value().t));
+          },
       },
       x.u);
 }
@@ -71,7 +73,7 @@ const Name &GetLastName(const AllocateObject &x) {
 const Name &GetFirstName(const Name &x) { return x; }
 
 const Name &GetFirstName(const StructureComponent &x) {
-  return GetFirstName(x.base);
+  return GetFirstName(x.Base());
 }
 
 const Name &GetFirstName(const DataRef &x) {
@@ -81,10 +83,12 @@ const Name &GetFirstName(const DataRef &x) {
           [](const common::Indirection<StructureComponent> &sc)
               -> const Name & { return GetFirstName(sc.value()); },
           [](const common::Indirection<ArrayElement> &sc) -> const Name & {
-            return GetFirstName(sc.value().base);
+            return GetFirstName(sc.value().Base());
           },
           [](const common::Indirection<CoindexedNamedObject> &ci)
-              -> const Name & { return GetFirstName(ci.value().base); },
+              -> const Name & {
+            return GetFirstName(std::get<DataRef>(ci.value().t));
+          },
       },
       x.u);
 }
@@ -134,7 +138,7 @@ const CoindexedNamedObject *GetCoindexedNamedObject(const DataRef &base) {
           [](const common::Indirection<CoindexedNamedObject> &x)
               -> const CoindexedNamedObject * { return &x.value(); },
           [](const auto &x) -> const CoindexedNamedObject * {
-            return GetCoindexedNamedObject(x.value().base);
+            return GetCoindexedNamedObject(x.value().Base());
           },
       },
       base.u);
@@ -168,7 +172,7 @@ const CoindexedNamedObject *GetCoindexedNamedObject(
   return common::visit(
       common::visitors{
           [](const StructureComponent &x) -> const CoindexedNamedObject * {
-            return GetCoindexedNamedObject(x.base);
+            return GetCoindexedNamedObject(x.Base());
           },
           [](const auto &) -> const CoindexedNamedObject * { return nullptr; },
       },

diff  --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 0465b67aed08d..fb7a7ec8517f4 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -440,8 +440,8 @@ class UnparseVisitor {
     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);
-    Walk(",", x.step);
+    Walk(x.Name()), Put('='), Walk(x.Lower()), Put(','), Walk(x.Upper());
+    Walk(",", x.Step());
   }
   void Unparse(const AcImpliedDo &x) { // R774
     Put('('), Walk(std::get<std::list<AcValue>>(x.t), ", ");
@@ -798,18 +798,18 @@ class UnparseVisitor {
     Walk(imageSelector);
   }
   void Unparse(const StructureComponent &x) { // R913
-    Walk(x.base);
-    if (structureComponents_.find(x.component.source) !=
+    Walk(x.Base());
+    if (structureComponents_.find(x.Component().source) !=
         structureComponents_.end()) {
       Put('.');
     } else {
       Put('%');
     }
-    Walk(x.component);
+    Walk(x.Component());
   }
   void Unparse(const ArrayElement &x) { // R917
-    Walk(x.base);
-    Put('('), Walk(x.subscripts, ","), Put(')');
+    Walk(x.Base());
+    Put('('), Walk(x.Subscripts(), ","), Put(')');
   }
   void Unparse(const SubscriptTriplet &x) { // R921
     Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t));

diff  --git a/flang/lib/Semantics/check-acc-structure.cpp b/flang/lib/Semantics/check-acc-structure.cpp
index 519f9b1fcf348..24fdc7c048e5d 100644
--- a/flang/lib/Semantics/check-acc-structure.cpp
+++ b/flang/lib/Semantics/check-acc-structure.cpp
@@ -688,7 +688,8 @@ void AccStructureChecker::Enter(const parser::OpenACCCacheConstruct &x) {
                 if (const auto *arrayElem =
                         std::get_if<common::Indirection<parser::ArrayElement>>(
                             &dataRef->u)) {
-                  for (const auto &subscript : arrayElem->value().subscripts) {
+                  for (const auto &subscript :
+                      arrayElem->value().Subscripts()) {
                     if (const auto *triplet =
                             std::get_if<parser::SubscriptTriplet>(
                                 &subscript.u)) {

diff  --git a/flang/lib/Semantics/check-cuda.cpp b/flang/lib/Semantics/check-cuda.cpp
index caa9bdd28f1f4..13c523da13c25 100644
--- a/flang/lib/Semantics/check-cuda.cpp
+++ b/flang/lib/Semantics/check-cuda.cpp
@@ -514,10 +514,10 @@ template <bool IsCUFKernelDo> class DeviceContextChecker {
     Check(uS.statement, uS.source);
   }
   void Check(const parser::LoopControl::Bounds &bounds) {
-    Check(bounds.lower);
-    Check(bounds.upper);
-    if (bounds.step) {
-      Check(*bounds.step);
+    Check(bounds.Lower());
+    Check(bounds.Upper());
+    if (auto &step{bounds.Step()}) {
+      Check(*step);
     }
   }
   void Check(const parser::LoopControl::Concurrent &x) {

diff  --git a/flang/lib/Semantics/check-data.cpp b/flang/lib/Semantics/check-data.cpp
index 9b41a879ad700..adbcc3776b763 100644
--- a/flang/lib/Semantics/check-data.cpp
+++ b/flang/lib/Semantics/check-data.cpp
@@ -26,7 +26,7 @@ namespace Fortran::semantics {
 // represented as such in the "body" of the implied DO loop.
 void DataChecker::Enter(const parser::DataImpliedDo &x) {
   const auto &name{parser::UnwrapRef<parser::Name>(
-      std::get<parser::DataImpliedDo::Bounds>(x.t).name)};
+      std::get<parser::DataImpliedDo::Bounds>(x.t).Name())};
   int kind{evaluate::ResultType<evaluate::ImpliedDoIndex>::kind};
   if (const auto dynamicType{evaluate::DynamicType::From(DEREF(name.symbol))}) {
     if (dynamicType->category() == TypeCategory::Integer) {
@@ -38,7 +38,7 @@ void DataChecker::Enter(const parser::DataImpliedDo &x) {
 
 void DataChecker::Leave(const parser::DataImpliedDo &x) {
   const auto &name{parser::UnwrapRef<parser::Name>(
-      std::get<parser::DataImpliedDo::Bounds>(x.t).name)};
+      std::get<parser::DataImpliedDo::Bounds>(x.t).Name())};
   exprAnalyzer_.RemoveImpliedDo(name.source);
 }
 

diff  --git a/flang/lib/Semantics/check-deallocate.cpp b/flang/lib/Semantics/check-deallocate.cpp
index e6ce1b30a59f5..729e92aefc04c 100644
--- a/flang/lib/Semantics/check-deallocate.cpp
+++ b/flang/lib/Semantics/check-deallocate.cpp
@@ -98,11 +98,11 @@ void DeallocateChecker::Leave(const parser::DeallocateStmt &deallocateStmt) {
             [&](const parser::StructureComponent &structureComponent) {
               // Only perform structureComponent checks if it was successfully
               // analyzed by expression analysis.
-              source = structureComponent.component.source;
+              source = structureComponent.Component().source;
               if (const auto *expr{GetExpr(context_, allocateObject)}) {
-                if (const Symbol *symbol{structureComponent.component.symbol
-                            ? &structureComponent.component.symbol
-                                  ->GetUltimate()
+                if (const Symbol *symbol{structureComponent.Component().symbol
+                            ? &structureComponent.Component()
+                                  .symbol->GetUltimate()
                             : nullptr};
                     !IsAllocatableOrObjectPointer(symbol)) { // F'2023 C936
                   context_.Say(source,

diff  --git a/flang/lib/Semantics/check-do-forall.cpp b/flang/lib/Semantics/check-do-forall.cpp
index c90479d9e352e..bf92d920f282e 100644
--- a/flang/lib/Semantics/check-do-forall.cpp
+++ b/flang/lib/Semantics/check-do-forall.cpp
@@ -71,7 +71,7 @@ static const Bounds &GetBounds(const parser::DoConstruct &doConstruct) {
 static const parser::Name &GetDoVariable(
     const parser::DoConstruct &doConstruct) {
   const Bounds &bounds{GetBounds(doConstruct)};
-  return bounds.name.thing;
+  return bounds.Name().thing;
 }
 
 static parser::MessageFixedText GetEnclosingDoMsg() {
@@ -546,14 +546,14 @@ class DoContext {
     // C1120 -- types of DO variables must be INTEGER, extended by allowing
     // REAL and DOUBLE PRECISION
     const Bounds &bounds{GetBounds(doConstruct)};
-    CheckDoVariable(bounds.name);
-    CheckDoExpression(bounds.lower);
-    CheckDoExpression(bounds.upper);
-    if (bounds.step) {
-      CheckDoExpression(*bounds.step);
-      if (IsZero(*bounds.step)) {
+    CheckDoVariable(bounds.Name());
+    CheckDoExpression(bounds.Lower());
+    CheckDoExpression(bounds.Upper());
+    if (auto &step{bounds.Step()}) {
+      CheckDoExpression(*step);
+      if (IsZero(*step)) {
         context_.Warn(common::UsageWarning::ZeroDoStep,
-            parser::UnwrapRef<parser::Expr>(bounds.step).source,
+            parser::UnwrapRef<parser::Expr>(step).source,
             "DO step expression should not be zero"_warn_en_US);
       }
     }
@@ -1194,13 +1194,13 @@ static void CheckIoImpliedDoIndex(
 void DoForallChecker::Leave(const parser::OutputImpliedDo &outputImpliedDo) {
   CheckIoImpliedDoIndex(context_,
       parser::UnwrapRef<parser::Name>(
-          std::get<parser::IoImpliedDoControl>(outputImpliedDo.t).name));
+          std::get<parser::IoImpliedDoControl>(outputImpliedDo.t).Name()));
 }
 
 void DoForallChecker::Leave(const parser::InputImpliedDo &inputImpliedDo) {
   CheckIoImpliedDoIndex(context_,
       parser::UnwrapRef<parser::Name>(
-          std::get<parser::IoImpliedDoControl>(inputImpliedDo.t).name));
+          std::get<parser::IoImpliedDoControl>(inputImpliedDo.t).Name()));
 }
 
 void DoForallChecker::Leave(const parser::StatVariable &statVariable) {

diff  --git a/flang/lib/Semantics/check-nullify.cpp b/flang/lib/Semantics/check-nullify.cpp
index 452a891fe9bd8..db9738a452d2e 100644
--- a/flang/lib/Semantics/check-nullify.cpp
+++ b/flang/lib/Semantics/check-nullify.cpp
@@ -37,7 +37,7 @@ void NullifyChecker::Leave(const parser::NullifyStmt &nullifyStmt) {
               }
             },
             [&](const parser::StructureComponent &structureComponent) {
-              const auto &component{structureComponent.component};
+              const auto &component{structureComponent.Component()};
               SourceName at{component.source};
               if (const auto *checkedExpr{GetExpr(context_, pointerObject)}) {
                 if (auto whyNot{WhyNotDefinable(at, scope,

diff  --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp
index a801d526af0ae..24d9103793948 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -489,7 +489,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
 const parser::Name OmpStructureChecker::GetLoopIndex(
     const parser::DoConstruct *x) {
   using Bounds = parser::LoopControl::Bounds;
-  return std::get<Bounds>(x->GetLoopControl()->u).name.thing;
+  return std::get<Bounds>(x->GetLoopControl()->u).Name().thing;
 }
 
 void OmpStructureChecker::SetLoopInfo(const parser::OpenMPLoopConstruct &x) {

diff  --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index cc8d968f7db83..b19a59fe06f68 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -3638,7 +3638,7 @@ void OmpStructureChecker::CheckReductionObjects(
     // a language identifier.
     for (const parser::OmpObject &object : objects.v) {
       if (auto *elem{GetArrayElementFromObj(object)}) {
-        const parser::DataRef &base = elem->base;
+        const parser::DataRef &base = elem->Base();
         if (!std::holds_alternative<parser::Name>(base.u)) {
           auto source{GetObjectSource(object)};
           context_.Say(source ? *source : GetContext().clauseSource,
@@ -3955,7 +3955,7 @@ bool OmpStructureChecker::IsDataRefTypeParamInquiry(
   bool dataRefIsTypeParamInquiry{false};
   if (const auto *structComp{
           parser::Unwrap<parser::StructureComponent>(dataRef)}) {
-    if (const auto *compSymbol{structComp->component.symbol}) {
+    if (const auto *compSymbol{structComp->Component().symbol}) {
       if (const auto *compSymbolMiscDetails{
               std::get_if<MiscDetails>(&compSymbol->details())}) {
         const auto detailsKind = compSymbolMiscDetails->kind();
@@ -4627,7 +4627,7 @@ void OmpStructureChecker::CheckDoacross(const parser::OmpDoacross &doa) {
       // Do-construct, collect the induction variable.
       if (auto &control{(*doc)->GetLoopControl()}) {
         if (auto *b{std::get_if<parser::LoopControl::Bounds>(&control->u)}) {
-          inductionVars.insert(b->name.thing.symbol);
+          inductionVars.insert(b->Name().thing.symbol);
         }
       }
     } else {
@@ -5033,10 +5033,10 @@ void OmpStructureChecker::CheckDependList(const parser::DataRef &d) {
       common::visitors{
           [&](const common::Indirection<parser::ArrayElement> &elem) {
             // Check if the base element is valid on Depend Clause
-            CheckDependList(elem.value().base);
+            CheckDependList(elem.value().Base());
           },
           [&](const common::Indirection<parser::StructureComponent> &comp) {
-            CheckDependList(comp.value().base);
+            CheckDependList(comp.value().Base());
           },
           [&](const common::Indirection<parser::CoindexedNamedObject> &) {
             context_.Say(GetContext().clauseSource,
@@ -5060,7 +5060,7 @@ void OmpStructureChecker::CheckArraySection(
   // looking for strings.
   if (!IsAssumedSizeArray(*name.symbol)) {
     evaluate::ExpressionAnalyzer ea{context_};
-    if (MaybeExpr expr = ea.Analyze(arrayElement.base)) {
+    if (MaybeExpr expr = ea.Analyze(arrayElement.Base())) {
       if (expr->Rank() == 0) {
         // Not an array: rank 0
         if (std::optional<evaluate::DynamicType> type = expr->GetType()) {
@@ -5079,8 +5079,8 @@ void OmpStructureChecker::CheckArraySection(
       }
     }
   }
-  if (!arrayElement.subscripts.empty()) {
-    for (const auto &subscript : arrayElement.subscripts) {
+  if (!arrayElement.Subscripts().empty()) {
+    for (const auto &subscript : arrayElement.Subscripts()) {
       if (const auto *triplet{
               std::get_if<parser::SubscriptTriplet>(&subscript.u)}) {
         if (std::get<0>(triplet->t) && std::get<1>(triplet->t)) {
@@ -5373,7 +5373,7 @@ struct NameHelper {
     return Visit(std::get<parser::DataRef>(x.t));
   }
   static const parser::Name *Visit(const parser::ArrayElement &x) {
-    return Visit(x.base);
+    return Visit(x.Base());
   }
   static const parser::Name *Visit(const parser::Designator &x) {
     return common::visit([](auto &&s) { return Visit(s); }, x.u);

diff  --git a/flang/lib/Semantics/data-to-inits.cpp b/flang/lib/Semantics/data-to-inits.cpp
index 9012396ebf3b3..d9e79340a6d91 100644
--- a/flang/lib/Semantics/data-to-inits.cpp
+++ b/flang/lib/Semantics/data-to-inits.cpp
@@ -179,14 +179,14 @@ bool DataInitializationCompiler<DSV>::Scan(
 template <typename DSV>
 bool DataInitializationCompiler<DSV>::Scan(const parser::DataImpliedDo &ido) {
   const auto &bounds{std::get<parser::DataImpliedDo::Bounds>(ido.t)};
-  const auto &name{parser::UnwrapRef<parser::Name>(bounds.name)};
-  const auto *lowerExpr{GetExpr(
-      exprAnalyzer_.context(), parser::UnwrapRef<parser::Expr>(bounds.lower))};
-  const auto *upperExpr{GetExpr(
-      exprAnalyzer_.context(), parser::UnwrapRef<parser::Expr>(bounds.upper))};
-  const auto *stepExpr{bounds.step
+  const auto &name{parser::UnwrapRef<parser::Name>(bounds.Name())};
+  const auto *lowerExpr{GetExpr(exprAnalyzer_.context(),
+      parser::UnwrapRef<parser::Expr>(bounds.Lower()))};
+  const auto *upperExpr{GetExpr(exprAnalyzer_.context(),
+      parser::UnwrapRef<parser::Expr>(bounds.Upper()))};
+  const auto *stepExpr{bounds.Step()
           ? GetExpr(exprAnalyzer_.context(),
-                parser::UnwrapRef<parser::Expr>(bounds.step))
+                parser::UnwrapRef<parser::Expr>(bounds.Step()))
           : nullptr};
   if (lowerExpr && upperExpr) {
     // Fold the bounds expressions (again) in case any of them depend

diff  --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index c6433b15886e2..e07d2ccd4f16b 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -587,12 +587,12 @@ static std::optional<parser::Substring> FixMisparsedSubstringDataRef(
           std::get_if<common::Indirection<parser::ArrayElement>>(&dataRef.u)}) {
     // ...%a(j:k) and "a" is a character scalar
     parser::ArrayElement &arrElement{ae->value()};
-    if (arrElement.subscripts.size() == 1) {
+    if (arrElement.Subscripts().size() == 1) {
       if (auto *triplet{std::get_if<parser::SubscriptTriplet>(
-              &arrElement.subscripts.front().u)}) {
+              &arrElement.Subscripts().front().u)}) {
         if (!std::get<2 /*stride*/>(triplet->t).has_value()) {
           if (const Symbol *symbol{
-                  parser::GetLastName(arrElement.base).symbol}) {
+                  parser::GetLastName(arrElement.Base()).symbol}) {
             const Symbol &ultimate{symbol->GetUltimate()};
             if (const semantics::DeclTypeSpec *type{ultimate.GetType()}) {
               if (ultimate.Rank() == 0 &&
@@ -623,10 +623,10 @@ MaybeExpr ExpressionAnalyzer::FixMisparsedSubstring(
     if (auto *sc{std::get_if<common::Indirection<parser::StructureComponent>>(
             &dataRef->u)}) {
       parser::StructureComponent &structComponent{sc->value()};
-      parser::CharBlock which{structComponent.component.source};
+      parser::CharBlock which{structComponent.Component().source};
       if (which == "kind" || which == "len") {
-        if (auto substring{
-                FixMisparsedSubstringDataRef(structComponent.base)}) {
+        if (auto substring{FixMisparsedSubstringDataRef(
+                std::get<parser::DataRef>(structComponent.t))}) {
           // ...%a(j:k)%kind or %len and "a" is a character scalar
           mutate.u = std::move(*substring);
           if (MaybeExpr substringExpr{Analyze(d)}) {
@@ -1378,10 +1378,10 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::ArrayElement &ae) {
   MaybeExpr baseExpr;
   {
     auto restorer{AllowWholeAssumedSizeArray()};
-    baseExpr = Analyze(ae.base);
+    baseExpr = Analyze(ae.Base());
   }
   if (baseExpr) {
-    if (ae.subscripts.empty()) {
+    if (ae.Subscripts().empty()) {
       // will be converted to function call later or error reported
     } else if (baseExpr->Rank() == 0) {
       if (const Symbol *symbol{GetLastSymbol(*baseExpr)}) {
@@ -1399,14 +1399,14 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::ArrayElement &ae) {
     } else if (std::optional<DataRef> dataRef{
                    ExtractDataRef(std::move(*baseExpr))}) {
       return ApplySubscripts(
-          std::move(*dataRef), AnalyzeSectionSubscripts(ae.subscripts));
+          std::move(*dataRef), AnalyzeSectionSubscripts(ae.Subscripts()));
     } else {
       Say("Subscripts may be applied only to an object, component, or array constant"_err_en_US);
     }
   }
   // error was reported: analyze subscripts without reporting more errors
   auto restorer{GetContextualMessages().DiscardMessages()};
-  AnalyzeSectionSubscripts(ae.subscripts);
+  AnalyzeSectionSubscripts(ae.Subscripts());
   return std::nullopt;
 }
 
@@ -1460,7 +1460,7 @@ std::optional<Component> ExpressionAnalyzer::CreateComponent(DataRef &&base,
 
 // Derived type component references and type parameter inquiries
 MaybeExpr ExpressionAnalyzer::Analyze(const parser::StructureComponent &sc) {
-  Symbol *sym{sc.component.symbol};
+  Symbol *sym{sc.Component().symbol};
   if (context_.HasError(sym)) {
     return std::nullopt;
   }
@@ -1472,14 +1472,14 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::StructureComponent &sc) {
   MaybeExpr base;
   if (isTypeParamInquiry) {
     auto restorer{AllowWholeAssumedSizeArray()};
-    base = Analyze(sc.base);
+    base = Analyze(sc.Base());
   } else {
-    base = Analyze(sc.base);
+    base = Analyze(sc.Base());
   }
   if (!base) {
     return std::nullopt;
   }
-  const auto &name{sc.component.source};
+  const auto &name{sc.Component().source};
   if (auto *dtExpr{UnwrapExpr<Expr<SomeDerived>>(*base)}) {
     const auto *dtSpec{GetDerivedTypeSpec(dtExpr->GetType())};
     if (isTypeParamInquiry) {
@@ -1551,7 +1551,8 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::StructureComponent &sc) {
 }
 
 MaybeExpr ExpressionAnalyzer::Analyze(const parser::CoindexedNamedObject &x) {
-  if (auto dataRef{ExtractDataRef(Analyze(x.base))}) {
+  const auto &[base, selector]{x.t};
+  if (auto dataRef{ExtractDataRef(Analyze(base))}) {
     if (!std::holds_alternative<ArrayRef>(dataRef->u) &&
         dataRef->GetLastSymbol().Rank() > 0) { // F'2023 C916
       Say("Subscripts must appear in a coindexed reference when its base is an array"_err_en_US);
@@ -1559,7 +1560,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::CoindexedNamedObject &x) {
     std::vector<Expr<SubscriptInteger>> cosubscripts;
     bool cosubsOk{true};
     for (const auto &cosub :
-        std::get<std::list<parser::Cosubscript>>(x.imageSelector.t)) {
+        std::get<std::list<parser::Cosubscript>>(selector.t)) {
       MaybeExpr coex{Analyze(cosub)};
       if (auto *intExpr{UnwrapExpr<Expr<SomeInteger>>(coex)}) {
         cosubscripts.push_back(
@@ -1578,7 +1579,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::CoindexedNamedObject &x) {
     }
     CoarrayRef coarrayRef{std::move(*dataRef), std::move(cosubscripts)};
     for (const auto &imageSelSpec :
-        std::get<std::list<parser::ImageSelectorSpec>>(x.imageSelector.t)) {
+        std::get<std::list<parser::ImageSelectorSpec>>(selector.t)) {
       common::visit(
           common::visitors{
               [&](const parser::ImageSelectorSpec::Notify &x) {
@@ -1969,8 +1970,8 @@ void ArrayConstructorContext::Add(const parser::Expr &expr) {
 void ArrayConstructorContext::Add(const parser::AcImpliedDo &impliedDo) {
   const auto &control{std::get<parser::AcImpliedDoControl>(impliedDo.t)};
   const auto &bounds{std::get<parser::AcImpliedDoControl::Bounds>(control.t)};
-  exprAnalyzer_.Analyze(bounds.name);
-  const auto &parsedName{parser::UnwrapRef<parser::Name>(bounds.name)};
+  exprAnalyzer_.Analyze(bounds.Name());
+  const auto &parsedName{parser::UnwrapRef<parser::Name>(bounds.Name())};
   parser::CharBlock name{parsedName.source};
   int kind{ImpliedDoIntType::kind};
   if (const Symbol *symbol{parsedName.symbol}) {
@@ -1981,12 +1982,12 @@ void ArrayConstructorContext::Add(const parser::AcImpliedDo &impliedDo) {
     }
   }
   std::optional<Expr<ImpliedDoIntType>> lower{
-      GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.lower)};
+      GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.Lower())};
   std::optional<Expr<ImpliedDoIntType>> upper{
-      GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.upper)};
+      GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.Upper())};
   if (lower && upper) {
     std::optional<Expr<ImpliedDoIntType>> stride{
-        GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.step)};
+        GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.Step())};
     if (!stride) {
       stride = Expr<ImpliedDoIntType>{1};
     }
@@ -1998,7 +1999,8 @@ void ArrayConstructorContext::Add(const parser::AcImpliedDo &impliedDo) {
       auto cUpper{ToInt64(upper)};
       auto cStride{ToInt64(stride)};
       if (!(messageDisplayedSet_ & 0x10) && cStride && *cStride == 0) {
-        exprAnalyzer_.SayAt(parser::UnwrapRef<parser::Expr>(bounds.step).source,
+        exprAnalyzer_.SayAt(
+            parser::UnwrapRef<parser::Expr>(bounds.Step()).source,
             "The stride of an implied DO loop must not be zero"_err_en_US);
         messageDisplayedSet_ |= 0x10;
       }
@@ -2565,15 +2567,15 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
     const parser::ProcComponentRef &pcr, ActualArguments &&arguments,
     bool isSubroutine) -> std::optional<CalleeAndArguments> {
   const auto &sc{parser::UnwrapRef<parser::StructureComponent>(pcr)};
-  if (MaybeExpr base{Analyze(sc.base)}) {
-    if (const Symbol *sym{sc.component.symbol}) {
+  if (MaybeExpr base{Analyze(sc.Base())}) {
+    if (const Symbol *sym{sc.Component().symbol}) {
       if (context_.HasError(sym)) {
         return std::nullopt;
       }
       if (!IsProcedure(*sym)) {
         AttachDeclaration(
-            Say(sc.component.source, "'%s' is not a procedure"_err_en_US,
-                sc.component.source),
+            Say(sc.Component().source, "'%s' is not a procedure"_err_en_US,
+                sc.Component().source),
             *sym);
         return std::nullopt;
       }
@@ -2628,7 +2630,7 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
               sym = latest;
             }
           }
-          sc.component.symbol = const_cast<Symbol *>(sym);
+          sc.Component().symbol = const_cast<Symbol *>(sym);
         }
         std::optional<DataRef> dataRef{ExtractDataRef(std::move(*dtExpr))};
         if (dataRef && !CheckDataRef(*dataRef)) {
@@ -2641,11 +2643,11 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
             // enforce it.
             AttachDeclaration(
                 Warn(common::LanguageFeature::NopassScalarBase,
-                    sc.component.source,
+                    sc.Component().source,
                     "Base of NOPASS type-bound procedure reference should be scalar"_port_en_US),
                 *sym);
           } else if (IsProcedurePointer(*sym)) { // C919
-            Say(sc.component.source,
+            Say(sc.Component().source,
                 "Base of procedure component reference must be scalar"_err_en_US);
           }
         }
@@ -2657,10 +2659,10 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
         } else if (dataRef.has_value()) {
           if (ExtractCoarrayRef(*dataRef)) {
             if (IsProcedurePointer(*sym)) {
-              Say(sc.component.source,
+              Say(sc.Component().source,
                   "Base of procedure component reference may not be coindexed"_err_en_US);
             } else {
-              Say(sc.component.source,
+              Say(sc.Component().source,
                   "A procedure binding may not be coindexed unless it can be resolved at compilation time"_err_en_US);
             }
           }
@@ -2674,7 +2676,7 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
                     std::move(arguments)};
               }
             }
-            Say(sc.component.source,
+            Say(sc.Component().source,
                 "Component is not in scope of base derived type"_err_en_US);
             return std::nullopt;
           } else {
@@ -2686,7 +2688,7 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
           }
         }
       }
-      Say(sc.component.source,
+      Say(sc.Component().source,
           "Base of procedure component reference is not a derived-type object"_err_en_US);
     }
   }
@@ -3369,7 +3371,7 @@ static const Symbol *AssumedTypePointerOrAllocatableDummy(const A &object) {
   return common::visit(
       common::visitors{
           [&](const parser::StructureComponent &x) {
-            return AssumedTypeDummy(x.component);
+            return AssumedTypeDummy(x.Component());
           },
           [&](const parser::Name &x) { return AssumedTypeDummy(x); },
       },
@@ -4081,7 +4083,7 @@ static bool CheckFuncRefToArrayElement(semantics::SemanticsContext &context,
   if (!name) {
     name = &parser::UnwrapRef<parser::StructureComponent>(
         std::get<parser::ProcComponentRef>(proc.u))
-                .component;
+                .Component();
   }
   if (!name->symbol) {
     return false;
@@ -4137,7 +4139,8 @@ static void FixMisparsedFunctionReference(
                 [&](parser::Name &name) { return name.symbol; },
                 [&](parser::ProcComponentRef &pcr) {
                   return parser::UnwrapRef<parser::StructureComponent>(pcr)
-                      .component.symbol;
+                      .Component()
+                      .symbol;
                 },
             },
             proc.u)}) {
@@ -5467,7 +5470,7 @@ void ExprChecker::Post(const parser::DataStmtObject &obj) {
 bool ExprChecker::Pre(const parser::DataImpliedDo &ido) {
   parser::Walk(std::get<parser::DataImpliedDo::Bounds>(ido.t), *this);
   const auto &bounds{std::get<parser::DataImpliedDo::Bounds>(ido.t)};
-  const auto &name{parser::UnwrapRef<parser::Name>(bounds.name)};
+  const auto &name{parser::UnwrapRef<parser::Name>(bounds.Name())};
   int kind{evaluate::ResultType<evaluate::ImpliedDoIndex>::kind};
   if (const auto dynamicType{evaluate::DynamicType::From(DEREF(name.symbol))}) {
     if (dynamicType->category() == TypeCategory::Integer) {

diff  --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 0ca84d84b97b6..13cce518aae94 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -226,7 +226,7 @@ class AccAttributeVisitor : DirectiveAttributeVisitor<llvm::acc::Directive> {
   bool Pre(const parser::LoopBounds<parser::ScalarName, A> &x) {
     if (!dirContext_.empty() && GetContext().withinConstruct) {
       if (auto *symbol{ResolveAcc(
-              x.name.thing, Symbol::Flag::AccPrivate, currScope())}) {
+              x.Name().thing, Symbol::Flag::AccPrivate, currScope())}) {
         AddToContextObjectWithDSA(*symbol, Symbol::Flag::AccPrivate);
       }
     }
@@ -807,9 +807,9 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
           }
           if (auto *procRef{
                   parser::Unwrap<parser::ProcComponentRef>(procD->u)}) {
-            if (!procRef->v.thing.component.symbol) {
-              if (!ResolveName(&procRef->v.thing.component)) {
-                createDummyProcSymbol(&procRef->v.thing.component);
+            if (!procRef->v.thing.Component().symbol) {
+              if (!ResolveName(&procRef->v.thing.Component())) {
+                createDummyProcSymbol(&procRef->v.thing.Component());
               }
             }
           }
@@ -1130,9 +1130,9 @@ std::tuple<const parser::Name *, const parser::ScalarExpr *,
 DirectiveAttributeVisitor<T>::GetLoopBounds(const parser::DoConstruct &x) {
   using Bounds = parser::LoopControl::Bounds;
   if (x.GetLoopControl()) {
-    if (const Bounds * b{std::get_if<Bounds>(&x.GetLoopControl()->u)}) {
-      auto &step = b->step;
-      return {&b->name.thing, &b->lower, &b->upper,
+    if (const Bounds *b{std::get_if<Bounds>(&x.GetLoopControl()->u)}) {
+      const auto &step = b->Step();
+      return {&b->Name().thing, &b->Lower(), &b->Upper(),
           step.has_value() ? &step.value() : nullptr};
     }
   } else {
@@ -1677,12 +1677,12 @@ void AccAttributeVisitor::CheckAssociatedLoop(
       if (auto *symbol{ResolveAcc(*ivName, flag, currScope())}) {
         if (auto &control{loop->GetLoopControl()}) {
           if (const Bounds * b{std::get_if<Bounds>(&control->u)}) {
-            if (auto lowerExpr{semantics::AnalyzeExpr(context_, b->lower)}) {
+            if (auto lowerExpr{semantics::AnalyzeExpr(context_, b->Lower())}) {
               semantics::UnorderedSymbolSet lowerSyms =
                   evaluate::CollectSymbols(*lowerExpr);
               checkExprHasSymbols(ivs, lowerSyms);
             }
-            if (auto upperExpr{semantics::AnalyzeExpr(context_, b->upper)}) {
+            if (auto upperExpr{semantics::AnalyzeExpr(context_, b->Upper())}) {
               semantics::UnorderedSymbolSet upperSyms =
                   evaluate::CollectSymbols(*upperExpr);
               checkExprHasSymbols(ivs, upperSyms);

diff  --git a/flang/lib/Semantics/resolve-names-utils.cpp b/flang/lib/Semantics/resolve-names-utils.cpp
index ac67799938013..ef34c89182f7f 100644
--- a/flang/lib/Semantics/resolve-names-utils.cpp
+++ b/flang/lib/Semantics/resolve-names-utils.cpp
@@ -519,8 +519,8 @@ bool EquivalenceSets::CheckDataRef(
             return false;
           },
           [&](const common::Indirection<parser::ArrayElement> &elem) {
-            bool ok{CheckDataRef(source, elem.value().base)};
-            for (const auto &subscript : elem.value().subscripts) {
+            bool ok{CheckDataRef(source, elem.value().Base())};
+            for (const auto &subscript : elem.value().Subscripts()) {
               ok &= common::visit(
                   common::visitors{
                       [&](const parser::SubscriptTriplet &) {

diff  --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 8db6cef8ef5ee..9919fc248e260 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1532,7 +1532,7 @@ bool AccVisitor::Pre(const parser::AccClause::UseDevice &x) {
                       common::Indirection<parser::ArrayElement>;
                   if (auto *ind{std::get_if<ElementIndirection>(&dataRef->u)}) {
                     const parser::ArrayElement &arrayElement{ind->value()};
-                    const parser::DataRef &base{arrayElement.base};
+                    const parser::DataRef &base{arrayElement.Base()};
                     if (auto *name{std::get_if<parser::Name>(&base.u)}) {
                       CopySymbolWithDevice(name);
                     }
@@ -2142,7 +2142,7 @@ class ResolveNamesVisitor : public virtual ScopeHandler,
   void Post(const parser::SubstringInquiry &);
   template <typename A, typename B>
   void Post(const parser::LoopBounds<A, B> &x) {
-    ResolveName(parser::UnwrapRef<parser::Name>(x.name));
+    ResolveName(parser::UnwrapRef<parser::Name>(x.Name()));
   }
   void Post(const parser::ProcComponentRef &);
   bool Pre(const parser::FunctionReference &);
@@ -7936,13 +7936,13 @@ bool ConstructVisitor::Pre(const parser::AcImpliedDo &x) {
   // of the implied DO variable appears in one of the bound expressions. Thus
   // this extension, which shrinks the scope of the variable to exclude the
   // expressions in the bounds.
-  auto restore{BeginCheckOnIndexUseInOwnBounds(bounds.name)};
-  Walk(bounds.lower);
-  Walk(bounds.upper);
-  Walk(bounds.step);
+  auto restore{BeginCheckOnIndexUseInOwnBounds(bounds.Name())};
+  Walk(bounds.Lower());
+  Walk(bounds.Upper());
+  Walk(bounds.Step());
   EndCheckOnIndexUseInOwnBounds(restore);
   PushScope(Scope::Kind::ImpliedDos, nullptr);
-  DeclareStatementEntity(bounds.name, type);
+  DeclareStatementEntity(bounds.Name(), type);
   Walk(values);
   PopScope();
   return false;
@@ -7953,13 +7953,13 @@ bool ConstructVisitor::Pre(const parser::DataImpliedDo &x) {
   auto &type{std::get<std::optional<parser::IntegerTypeSpec>>(x.t)};
   auto &bounds{std::get<parser::DataImpliedDo::Bounds>(x.t)};
   // See comment in Pre(AcImpliedDo) above.
-  auto restore{BeginCheckOnIndexUseInOwnBounds(bounds.name)};
-  Walk(bounds.lower);
-  Walk(bounds.upper);
-  Walk(bounds.step);
+  auto restore{BeginCheckOnIndexUseInOwnBounds(bounds.Name())};
+  Walk(bounds.Lower());
+  Walk(bounds.Upper());
+  Walk(bounds.Step());
   EndCheckOnIndexUseInOwnBounds(restore);
   PushScope(Scope::Kind::ImpliedDos, nullptr);
-  DeclareStatementEntity(bounds.name, type);
+  DeclareStatementEntity(bounds.Name(), type);
   Walk(objects);
   PopScope();
   return false;
@@ -8016,7 +8016,7 @@ bool ConstructVisitor::Pre(const parser::DataStmtValue &x) {
   const auto &data{std::get<parser::DataStmtConstant>(x.t)};
   auto &mutableData{const_cast<parser::DataStmtConstant &>(data)};
   if (auto *elem{parser::Unwrap<parser::ArrayElement>(mutableData)}) {
-    if (const auto *name{std::get_if<parser::Name>(&elem->base.u)}) {
+    if (const auto *name{std::get_if<parser::Name>(&elem->Base().u)}) {
       if (const Symbol * symbol{FindSymbol(*name)};
           symbol && symbol->GetUltimate().has<DerivedTypeDetails>()) {
         mutableData.u = elem->ConvertToStructureConstructor(
@@ -8793,7 +8793,7 @@ bool ResolveNamesVisitor::Pre(const parser::ImportStmt &x) {
 
 const parser::Name *DeclarationVisitor::ResolveStructureComponent(
     const parser::StructureComponent &x) {
-  return FindComponent(ResolveDataRef(x.base), x.component);
+  return FindComponent(ResolveDataRef(x.Base()), x.Component());
 }
 
 const parser::Name *DeclarationVisitor::ResolveDesignator(
@@ -8818,8 +8818,8 @@ const parser::Name *DeclarationVisitor::ResolveDataRef(
             return ResolveStructureComponent(y.value());
           },
           [&](const Indirection<parser::ArrayElement> &y) {
-            Walk(y.value().subscripts);
-            const parser::Name *name{ResolveDataRef(y.value().base)};
+            Walk(y.value().Subscripts());
+            const parser::Name *name{ResolveDataRef(y.value().Base())};
             if (name && name->symbol) {
               if (!IsProcedure(*name->symbol)) {
                 ConvertToObjectEntity(*name->symbol);
@@ -8832,8 +8832,9 @@ const parser::Name *DeclarationVisitor::ResolveDataRef(
             return name;
           },
           [&](const Indirection<parser::CoindexedNamedObject> &y) {
-            Walk(y.value().imageSelector);
-            return ResolveDataRef(y.value().base);
+            const auto &[base, selector]{y.value().t};
+            Walk(selector);
+            return ResolveDataRef(base);
           },
       },
       x.u);
@@ -9340,7 +9341,7 @@ void ResolveNamesVisitor::HandleCall(
           [&](const parser::Name &x) { HandleProcedureName(procFlag, x); },
           [&](const parser::ProcComponentRef &x) {
             Walk(x);
-            const parser::Name &name{x.v.thing.component};
+            const parser::Name &name{x.v.thing.Component()};
             if (Symbol * symbol{name.symbol}) {
               if (IsProcedure(*symbol)) {
                 SetProcFlag(name, *symbol, procFlag);


        


More information about the flang-commits mailing list