[flang-commits] [flang] [flang] Enumeration Type: (PR 1/5) Foundation types + Parser (PR #192651)

via flang-commits flang-commits at lists.llvm.org
Mon Jun 8 08:35:20 PDT 2026


https://github.com/kwyatt-ext updated https://github.com/llvm/llvm-project/pull/192651

>From fd08cd19104776a016d95e10e2e10827ffef38ef Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Thu, 16 Apr 2026 12:47:22 -0500
Subject: [PATCH 1/6] Enumeration Type Sem-1: Foundation types + Parser (PRs
 1-2)

Adds DerivedTypeSpec::Category::EnumerationType to the type system,
parse tree nodes for ENUMERATION TYPE per F2023, and parser/unparser
support. Includes a stub in resolve-names that rejects ENUMERATION TYPE
as 'not yet implemented' (enabled in Sem-2).

Files from original PRs 1-2.
---
 flang/include/flang/Parser/dump-parse-tree.h |  4 +++
 flang/include/flang/Parser/parse-tree.h      | 38 +++++++++++++++++---
 flang/include/flang/Semantics/symbol.h       |  8 +++++
 flang/include/flang/Semantics/tools.h        |  2 ++
 flang/include/flang/Semantics/type.h         | 11 +++++-
 flang/lib/Evaluate/type.cpp                  | 11 +++---
 flang/lib/Lower/ConvertType.cpp              |  3 ++
 flang/lib/Parser/Fortran-parsers.cpp         | 29 +++++++++++++++
 flang/lib/Parser/program-parsers.cpp         |  6 ++--
 flang/lib/Parser/unparse.cpp                 | 16 +++++++++
 flang/lib/Semantics/resolve-names.cpp        |  7 ++++
 flang/lib/Semantics/symbol.cpp               |  1 +
 flang/lib/Semantics/tools.cpp                | 11 ++++++
 flang/lib/Semantics/type.cpp                 | 20 +++++++++++
 14 files changed, 155 insertions(+), 12 deletions(-)

diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index eefab487413da..1d37d03b60a6c 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -312,6 +312,7 @@ class ParseTreeDumper {
   NODE(parser, EndChangeTeamStmt)
   NODE(parser, EndCriticalStmt)
   NODE(parser, EndDoStmt)
+  NODE(parser, EndEnumerationTypeStmt)
   NODE(parser, EndEnumStmt)
   NODE(parser, EndForallStmt)
   NODE(parser, EndFunctionStmt)
@@ -333,6 +334,9 @@ class ParseTreeDumper {
   NODE(parser, EnumDefStmt)
   NODE(parser, Enumerator)
   NODE(parser, EnumeratorDefStmt)
+  NODE(parser, EnumerationEnumeratorStmt)
+  NODE(parser, EnumerationTypeDef)
+  NODE(parser, EnumerationTypeStmt)
   NODE(parser, EorLabel)
   NODE(parser, EquivalenceObject)
   NODE(parser, EquivalenceStmt)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 960ebbcc99efb..2dc5201278d20 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -156,6 +156,7 @@ struct SubroutineSubprogram; // R1534
 // with order of the the requirement productions in the grammar.
 struct DerivedTypeDef; // R726
 struct EnumDef; // R759
+struct EnumerationTypeDef; // F2023 R766
 struct TypeDeclarationStmt; // R801
 struct AccessStmt; // R827
 struct AllocatableStmt; // R829
@@ -392,13 +393,15 @@ struct OtherSpecificationStmt {
 };
 
 // R508 specification-construct ->
-//        derived-type-def | enum-def | generic-stmt | interface-block |
-//        parameter-stmt | procedure-declaration-stmt |
-//        other-specification-stmt | type-declaration-stmt
+//        derived-type-def | enum-def | enumeration-type-def |
+//        generic-stmt | interface-block | parameter-stmt |
+//        procedure-declaration-stmt | other-specification-stmt |
+//        type-declaration-stmt
 struct SpecificationConstruct {
   UNION_CLASS_BOILERPLATE(SpecificationConstruct);
   std::variant<common::Indirection<DerivedTypeDef>,
-      common::Indirection<EnumDef>, Statement<common::Indirection<GenericStmt>>,
+      common::Indirection<EnumDef>, common::Indirection<EnumerationTypeDef>,
+      Statement<common::Indirection<GenericStmt>>,
       common::Indirection<InterfaceBlock>,
       Statement<common::Indirection<ParameterStmt>>,
       Statement<common::Indirection<OldParameterStmt>>,
@@ -1230,6 +1233,33 @@ struct EnumDef {
       t;
 };
 
+// F2023 R767 enumeration-type-stmt ->
+//        ENUMERATION TYPE [ [ , access-spec ] :: ] enumeration-type-name
+struct EnumerationTypeStmt {
+  TUPLE_CLASS_BOILERPLATE(EnumerationTypeStmt);
+  std::tuple<std::optional<AccessSpec>, Name> t;
+};
+
+// F2023 R768 enumeration-enumerator-stmt -> ENUMERATOR [ :: ]
+// enumerator-name-list
+WRAPPER_CLASS(EnumerationEnumeratorStmt, std::list<Name>);
+
+// F2023 R769 end-enumeration-type-stmt ->
+//        END ENUMERATION TYPE [ enumeration-type-name ]
+WRAPPER_CLASS(EndEnumerationTypeStmt, std::optional<Name>);
+
+// F2023 R766 enumeration-type-def ->
+//        enumeration-type-stmt
+//        enumeration-enumerator-stmt [ enumeration-enumerator-stmt ]...
+//        end-enumeration-type-stmt
+struct EnumerationTypeDef {
+  TUPLE_CLASS_BOILERPLATE(EnumerationTypeDef);
+  std::tuple<Statement<EnumerationTypeStmt>,
+      std::list<Statement<EnumerationEnumeratorStmt>>,
+      Statement<EndEnumerationTypeStmt>>
+      t;
+};
+
 // R773 ac-value -> expr | ac-implied-do
 struct AcValue {
   struct Triplet { // PGI/Intel extension
diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index 4c422ac5f471a..72b09e2b89dd6 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -497,6 +497,10 @@ class DerivedTypeDetails {
   const SymbolVector &paramDeclOrder() const { return paramDeclOrder_; }
   bool sequence() const { return sequence_; }
   bool isDECStructure() const { return isDECStructure_; }
+  bool isEnumerationType() const { return isEnumerationType_; }
+  void set_isEnumerationType(bool x = true) { isEnumerationType_ = x; }
+  int enumeratorCount() const { return enumeratorCount_; }
+  void set_enumeratorCount(int n) { enumeratorCount_ = n; }
   std::map<SourceName, SymbolRef> &finals() { return finals_; }
   const std::map<SourceName, SymbolRef> &finals() const { return finals_; }
   bool isForwardReferenced() const { return isForwardReferenced_; }
@@ -548,6 +552,10 @@ class DerivedTypeDetails {
   bool isForwardReferenced_{false};
   std::map<SourceName, const parser::Expr *> originalKindParameterMap_;
 
+  // These fields are only used if the derived type is an enumeration type.
+  bool isEnumerationType_{false};
+  int enumeratorCount_{0};
+
   friend llvm::raw_ostream &operator<<(
       llvm::raw_ostream &, const DerivedTypeDetails &);
 };
diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h
index d2e2be2548d2e..808e885b2b3c5 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -197,6 +197,8 @@ bool IsExternal(const Symbol &);
 bool IsModuleProcedure(const Symbol &);
 bool HasCoarray(const parser::Expr &);
 bool IsAssumedType(const Symbol &);
+bool IsEnumerationType(const Symbol &);
+bool IsEnumerationType(const DerivedTypeSpec &);
 bool IsPolymorphic(const Symbol &);
 bool IsUnlimitedPolymorphic(const Symbol &);
 bool IsPolymorphicAllocatable(const Symbol &);
diff --git a/flang/include/flang/Semantics/type.h b/flang/include/flang/Semantics/type.h
index 3a07b6ee2ec1c..9d0a2427c1b6f 100644
--- a/flang/include/flang/Semantics/type.h
+++ b/flang/include/flang/Semantics/type.h
@@ -263,7 +263,13 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &, const ArraySpec &);
 // The name may not match the symbol's name in case of a USE rename.
 class DerivedTypeSpec {
 public:
-  enum class Category { DerivedType, IntrinsicVector, PairVector, QuadVector };
+  enum class Category {
+    DerivedType,
+    IntrinsicVector,
+    PairVector,
+    QuadVector,
+    EnumerationType
+  };
 
   using RawParameter = std::pair<const parser::Keyword *, ParamValue>;
   using RawParameters = std::vector<RawParameter>;
@@ -335,6 +341,9 @@ class DerivedTypeSpec {
     return category_ == Category::IntrinsicVector ||
         category_ == Category::PairVector || category_ == Category::QuadVector;
   }
+  bool IsEnumerationType() const {
+    return category_ == Category::EnumerationType;
+  }
 
 private:
   SourceName name_;
diff --git a/flang/lib/Evaluate/type.cpp b/flang/lib/Evaluate/type.cpp
index 99dc8b1e5c676..7c1fc804d69ef 100644
--- a/flang/lib/Evaluate/type.cpp
+++ b/flang/lib/Evaluate/type.cpp
@@ -158,8 +158,9 @@ std::size_t DynamicType::GetAlignment(
     switch (GetDerivedTypeSpec().category()) {
       SWITCH_COVERS_ALL_CASES
     case semantics::DerivedTypeSpec::Category::DerivedType:
-      if (derived_ && derived_->scope()) {
-        return derived_->scope()->alignment().value_or(1);
+    case semantics::DerivedTypeSpec::Category::EnumerationType:
+      if (derived_ && derived_->GetScope()) {
+        return derived_->GetScope()->alignment().value_or(1);
       }
       break;
     case semantics::DerivedTypeSpec::Category::IntrinsicVector:
@@ -199,9 +200,9 @@ std::optional<Expr<SubscriptInteger>> DynamicType::MeasureSizeInBytes(
     }
     break;
   case TypeCategory::Derived:
-    if (!IsPolymorphic() && derived_ && derived_->scope()) {
-      auto size{derived_->scope()->size()};
-      auto align{aligned ? derived_->scope()->alignment().value_or(0) : 0};
+    if (!IsPolymorphic() && derived_ && derived_->GetScope()) {
+      auto size{derived_->GetScope()->size()};
+      auto align{aligned ? derived_->GetScope()->alignment().value_or(0) : 0};
       auto alignedSize{align > 0 ? ((size + align - 1) / align) * align : size};
       return Expr<SubscriptInteger>{
           static_cast<ConstantSubscript>(alignedSize)};
diff --git a/flang/lib/Lower/ConvertType.cpp b/flang/lib/Lower/ConvertType.cpp
index 0d343968374f0..28d2c1be5e6fc 100644
--- a/flang/lib/Lower/ConvertType.cpp
+++ b/flang/lib/Lower/ConvertType.cpp
@@ -371,6 +371,9 @@ struct TypeBuilderImpl {
                                   mlir::IntegerType::get(context, 1));
     case (Fortran::semantics::DerivedTypeSpec::Category::DerivedType):
       Fortran::common::die("Vector element type not implemented");
+    case (Fortran::semantics::DerivedTypeSpec::Category::EnumerationType):
+      Fortran::common::die(
+          "Vector element type not implemented for enumeration");
     }
   }
 
diff --git a/flang/lib/Parser/Fortran-parsers.cpp b/flang/lib/Parser/Fortran-parsers.cpp
index b67475074217c..df7c25de52faf 100644
--- a/flang/lib/Parser/Fortran-parsers.cpp
+++ b/flang/lib/Parser/Fortran-parsers.cpp
@@ -669,6 +669,35 @@ TYPE_PARSER(
 TYPE_PARSER(recovery("END ENUM"_tok, constructEndStmtErrorRecovery) >>
     construct<EndEnumStmt>())
 
+// F2023 R766 enumeration-type-def ->
+//        enumeration-type-stmt
+//        enumeration-enumerator-stmt [ enumeration-enumerator-stmt ]...
+//        end-enumeration-type-stmt
+TYPE_CONTEXT_PARSER("enumeration type definition"_en_US,
+    construct<EnumerationTypeDef>(statement(Parser<EnumerationTypeStmt>{}),
+        some(unambiguousStatement(Parser<EnumerationEnumeratorStmt>{})),
+        statement(Parser<EndEnumerationTypeStmt>{})))
+
+// F2023 R767 enumeration-type-stmt ->
+//        ENUMERATION TYPE [ [ , access-spec ] :: ] enumeration-type-name
+TYPE_CONTEXT_PARSER("ENUMERATION TYPE statement"_en_US,
+    construct<EnumerationTypeStmt>(
+        "ENUMERATION TYPE" >> maybe("," >> accessSpec) / "::", name) ||
+        construct<EnumerationTypeStmt>(
+            "ENUMERATION TYPE" >> construct<std::optional<AccessSpec>>(), name))
+
+// F2023 R768 enumeration-enumerator-stmt -> ENUMERATOR [ :: ]
+// enumerator-name-list
+//   (Note: distinct from R761 enumerator-def-stmt — no "= expr" allowed here)
+TYPE_CONTEXT_PARSER("ENUMERATOR statement in ENUMERATION TYPE"_en_US,
+    construct<EnumerationEnumeratorStmt>(
+        "ENUMERATOR" >> maybe("::"_tok) >> nonemptyList(name)))
+
+// F2023 R769 end-enumeration-type-stmt ->
+//        END ENUMERATION TYPE [ enumeration-type-name ]
+TYPE_PARSER(construct<EndEnumerationTypeStmt>(recovery(
+    "END ENUMERATION TYPE" >> maybe(name), namedConstructEndStmtErrorRecovery)))
+
 // R801 type-declaration-stmt ->
 //        declaration-type-spec [[, attr-spec]... ::] entity-decl-list
 constexpr auto entityDeclWithoutEqInit{
diff --git a/flang/lib/Parser/program-parsers.cpp b/flang/lib/Parser/program-parsers.cpp
index b26603b5aea45..8a81ce6243711 100644
--- a/flang/lib/Parser/program-parsers.cpp
+++ b/flang/lib/Parser/program-parsers.cpp
@@ -183,12 +183,14 @@ constexpr auto limitedSpecificationPart{inContext("specification part"_en_US,
         implicitPart, many(limitedDeclarationConstruct)))};
 
 // R508 specification-construct ->
-//        derived-type-def | enum-def | generic-stmt | interface-block |
-//        parameter-stmt | procedure-declaration-stmt |
+//        derived-type-def | enum-def |  enumeration-type-def | generic-stmt |
+//        interface-block | parameter-stmt | procedure-declaration-stmt |
 //        other-specification-stmt | type-declaration-stmt
 TYPE_CONTEXT_PARSER("specification construct"_en_US,
     first(construct<SpecificationConstruct>(indirect(Parser<DerivedTypeDef>{})),
         construct<SpecificationConstruct>(indirect(Parser<EnumDef>{})),
+        construct<SpecificationConstruct>(
+            indirect(Parser<EnumerationTypeDef>{})),
         construct<SpecificationConstruct>(
             statement(indirect(Parser<GenericStmt>{}))),
         construct<SpecificationConstruct>(indirect(interfaceBlock)),
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 5ddd0cfc3a1ef..fdb3076f9559c 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -425,6 +425,22 @@ class UnparseVisitor {
   void Post(const EndEnumStmt &) { // R763
     Outdent(), Word("END ENUM");
   }
+  void Unparse(const EnumerationTypeStmt &x) { // F2023 R767
+    Word("ENUMERATION TYPE");
+    Walk(", ", std::get<std::optional<AccessSpec>>(x.t), " :: ");
+    if (!std::get<std::optional<AccessSpec>>(x.t)) {
+      Word(" :: ");
+    }
+    Walk(std::get<Name>(x.t));
+    Indent();
+  }
+  void Unparse(const EnumerationEnumeratorStmt &x) { // F2023 R768
+    Word("ENUMERATOR :: "), Walk(x.v, ", ");
+  }
+  void Unparse(const EndEnumerationTypeStmt &x) { // F2023 R769
+    Outdent(), Word("END ENUMERATION TYPE");
+    Walk(" ", x.v);
+  }
   void Unparse(const BOZLiteralConstant &x) { // R764 - R767
     Put(x.v);
   }
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index e1c1167af1604..13aff743ce0ab 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -995,6 +995,7 @@ class DeclarationVisitor : public ArraySpecVisitor,
   bool Pre(const parser::NamedConstant &);
   void Post(const parser::EnumDef &);
   bool Pre(const parser::Enumerator &);
+  bool Pre(const parser::EnumerationTypeDef &);
   bool Pre(const parser::AccessSpec &);
   bool Pre(const parser::AsynchronousStmt &);
   bool Pre(const parser::ContiguousStmt &);
@@ -5892,6 +5893,12 @@ bool DeclarationVisitor::Pre(const parser::Enumerator &enumerator) {
   return false;
 }
 
+bool DeclarationVisitor::Pre(const parser::EnumerationTypeDef &x) {
+  Say(std::get<parser::Statement<parser::EnumerationTypeStmt>>(x.t).source,
+      "F2023 ENUMERATION TYPEs are not yet implemented"_err_en_US);
+  return false;
+}
+
 void DeclarationVisitor::Post(const parser::EnumDef &) {
   enumerationState_ = EnumeratorState{};
 }
diff --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp
index ed0715a422e78..65c8eb2e3d040 100644
--- a/flang/lib/Semantics/symbol.cpp
+++ b/flang/lib/Semantics/symbol.cpp
@@ -580,6 +580,7 @@ llvm::raw_ostream &operator<<(
 llvm::raw_ostream &operator<<(
     llvm::raw_ostream &os, const DerivedTypeDetails &x) {
   DumpBool(os, "sequence", x.sequence_);
+  DumpBool(os, "isEnumerationType", x.isEnumerationType_);
   DumpList(os, "components", x.componentNames_);
   return os;
 }
diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index e0e8727251ed8..325d84d4a3349 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -1070,6 +1070,17 @@ bool IsAssumedType(const Symbol &symbol) {
   return false;
 }
 
+bool IsEnumerationType(const Symbol &symbol) {
+  if (const auto *details{symbol.detailsIf<DerivedTypeDetails>()}) {
+    return details->isEnumerationType();
+  }
+  return false;
+}
+
+bool IsEnumerationType(const DerivedTypeSpec &derived) {
+  return derived.IsEnumerationType();
+}
+
 bool IsPolymorphic(const Symbol &symbol) {
   if (const DeclTypeSpec * type{symbol.GetType()}) {
     return type->IsPolymorphic();
diff --git a/flang/lib/Semantics/type.cpp b/flang/lib/Semantics/type.cpp
index bb8fddbffd945..9b91c32adbc76 100644
--- a/flang/lib/Semantics/type.cpp
+++ b/flang/lib/Semantics/type.cpp
@@ -355,6 +355,20 @@ void DerivedTypeSpec::Instantiate(Scope &containingScope) {
     return;
   }
   instantiated_ = true;
+
+  if (IsEnumerationType()) {
+    // Enumeration types have no components, no parameters, and need
+    // no instantiation, but scope_ must be set so that callers of
+    // scope() (e.g., GetAlignment, MeasureSizeInBytes) can access
+    // the type's size and alignment.
+    scope_ = typeSymbol_.scope();
+    Scope &mutableTypeScope{const_cast<Scope &>(*scope_)};
+    if (!mutableTypeScope.derivedTypeSpec()) {
+      mutableTypeScope.set_derivedTypeSpec(*this);
+    }
+    return;
+  }
+
   auto &context{containingScope.context()};
   auto &foldingContext{context.foldingContext()};
   if (IsForwardReferenced()) {
@@ -738,6 +752,8 @@ std::string DerivedTypeSpec::VectorTypeAsFortran() const {
     break;
   case (Fortran::semantics::DerivedTypeSpec::Category::DerivedType):
     Fortran::common::die("Vector element type not implemented");
+  case (Fortran::semantics::DerivedTypeSpec::Category::EnumerationType):
+    Fortran::common::die("Vector element type not implemented for enumeration");
   }
   return buf;
 }
@@ -745,6 +761,10 @@ std::string DerivedTypeSpec::VectorTypeAsFortran() const {
 std::string DerivedTypeSpec::AsFortran() const {
   std::string buf;
   llvm::raw_string_ostream ss{buf};
+  if (IsEnumerationType()) {
+    ss << "ENUMERATION TYPE :: " << originalTypeSymbol_.name();
+    return buf;
+  }
   ss << originalTypeSymbol_.name();
   if (!rawParameters_.empty()) {
     CHECK(parameters_.empty());

>From 0cc39bbadb352e42a6157174275fb659d665dea7 Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Thu, 16 Apr 2026 15:06:39 -0500
Subject: [PATCH 2/6] Adding a parser test.

---
 flang/test/Parser/enumeration-type.f90 | 113 +++++++++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 flang/test/Parser/enumeration-type.f90

diff --git a/flang/test/Parser/enumeration-type.f90 b/flang/test/Parser/enumeration-type.f90
new file mode 100644
index 0000000000000..e984c127bb4e0
--- /dev/null
+++ b/flang/test/Parser/enumeration-type.f90
@@ -0,0 +1,113 @@
+! RUN: %flang_fc1 -fdebug-unparse-no-sema %s 2>&1 | FileCheck %s
+! RUN: %flang_fc1 -fdebug-dump-parse-tree-no-sema %s 2>&1 | FileCheck %s -check-prefix=TREE
+
+! Test parsing of F2023 enumeration type definitions (R766-R769)
+
+module m
+  ! Basic enumeration type with double-colon
+  ! CHECK: ENUMERATION TYPE :: color
+  ! CHECK: ENUMERATOR :: red, green, blue
+  ! CHECK: END ENUMERATION TYPE color
+  ! TREE: EnumerationTypeDef
+  ! TREE: EnumerationTypeStmt
+  ! TREE: Name = 'color'
+  ! TREE: EnumerationEnumeratorStmt
+  ! TREE: Name = 'red'
+  ! TREE: Name = 'green'
+  ! TREE: Name = 'blue'
+  ! TREE: EndEnumerationTypeStmt
+  ! TREE: Name = 'color'
+  enumeration type :: color
+    enumerator :: red, green, blue
+  end enumeration type color
+
+  ! Without double-colon on ENUMERATION TYPE statement
+  ! CHECK: ENUMERATION TYPE :: direction
+  ! CHECK: ENUMERATOR :: north, south, east, west
+  ! CHECK: END ENUMERATION TYPE direction
+  ! TREE: EnumerationTypeDef
+  ! TREE: EnumerationTypeStmt
+  ! TREE: Name = 'direction'
+  ! TREE: EnumerationEnumeratorStmt
+  ! TREE: Name = 'north'
+  ! TREE: Name = 'south'
+  ! TREE: Name = 'east'
+  ! TREE: Name = 'west'
+  ! TREE: EndEnumerationTypeStmt
+  ! TREE: Name = 'direction'
+  enumeration type direction
+    enumerator north, south, east, west
+  end enumeration type direction
+
+  ! With access-spec (PUBLIC)
+  ! CHECK: ENUMERATION TYPE, PUBLIC :: priority
+  ! CHECK: ENUMERATOR :: low, medium, high
+  ! CHECK: END ENUMERATION TYPE priority
+  ! TREE: EnumerationTypeDef
+  ! TREE: EnumerationTypeStmt
+  ! TREE: AccessSpec -> Kind = Public
+  ! TREE: Name = 'priority'
+  ! TREE: EnumerationEnumeratorStmt
+  ! TREE: Name = 'low'
+  ! TREE: Name = 'medium'
+  ! TREE: Name = 'high'
+  ! TREE: EndEnumerationTypeStmt
+  enumeration type, public :: priority
+    enumerator :: low, medium, high
+  end enumeration type priority
+
+  ! With access-spec (PRIVATE)
+  ! CHECK: ENUMERATION TYPE, PRIVATE :: internal_state
+  ! CHECK: ENUMERATOR :: idle, running
+  ! CHECK: END ENUMERATION TYPE internal_state
+  ! TREE: EnumerationTypeDef
+  ! TREE: EnumerationTypeStmt
+  ! TREE: AccessSpec -> Kind = Private
+  ! TREE: Name = 'internal_state'
+  ! TREE: EnumerationEnumeratorStmt
+  ! TREE: Name = 'idle'
+  ! TREE: Name = 'running'
+  ! TREE: EndEnumerationTypeStmt
+  enumeration type, private :: internal_state
+    enumerator :: idle, running
+  end enumeration type internal_state
+
+  ! Multiple ENUMERATOR statements
+  ! CHECK: ENUMERATION TYPE :: season
+  ! CHECK: ENUMERATOR :: spring
+  ! CHECK: ENUMERATOR :: summer
+  ! CHECK: ENUMERATOR :: autumn, winter
+  ! CHECK: END ENUMERATION TYPE season
+  ! TREE: EnumerationTypeDef
+  ! TREE: EnumerationTypeStmt
+  ! TREE: Name = 'season'
+  ! TREE: EnumerationEnumeratorStmt
+  ! TREE: Name = 'spring'
+  ! TREE: EnumerationEnumeratorStmt
+  ! TREE: Name = 'summer'
+  ! TREE: EnumerationEnumeratorStmt
+  ! TREE: Name = 'autumn'
+  ! TREE: Name = 'winter'
+  ! TREE: EndEnumerationTypeStmt
+  ! TREE: Name = 'season'
+  enumeration type :: season
+    enumerator :: spring
+    enumerator :: summer
+    enumerator :: autumn, winter
+  end enumeration type season
+
+  ! End statement without name
+  ! CHECK: ENUMERATION TYPE :: simple
+  ! CHECK: ENUMERATOR :: a, b
+  ! CHECK: END ENUMERATION TYPE
+  ! TREE: EnumerationTypeDef
+  ! TREE: EnumerationTypeStmt
+  ! TREE: Name = 'simple'
+  ! TREE: EnumerationEnumeratorStmt
+  ! TREE: Name = 'a'
+  ! TREE: Name = 'b'
+  ! TREE: EndEnumerationTypeStmt
+  enumeration type :: simple
+    enumerator :: a, b
+  end enumeration type
+end module

>From e26fb3db4d0a68d9c11735d1b9eb68fb8c03d319 Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Thu, 21 May 2026 15:14:22 -0500
Subject: [PATCH 3/6] Restoring scope/GetScope separation for
 non-EnumerationType types.

---
 flang/lib/Evaluate/type.cpp | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/flang/lib/Evaluate/type.cpp b/flang/lib/Evaluate/type.cpp
index 7c1fc804d69ef..c0f3c6d9eaf84 100644
--- a/flang/lib/Evaluate/type.cpp
+++ b/flang/lib/Evaluate/type.cpp
@@ -158,12 +158,19 @@ std::size_t DynamicType::GetAlignment(
     switch (GetDerivedTypeSpec().category()) {
       SWITCH_COVERS_ALL_CASES
     case semantics::DerivedTypeSpec::Category::DerivedType:
+      if (derived_ && derived_->scope()) {
+        return derived_->scope()->alignment().value_or(1);
+      }
+      break;
+
+      // EnumerationTypes skip normal instantiation and may not have scope set.
     case semantics::DerivedTypeSpec::Category::EnumerationType:
       if (derived_ && derived_->GetScope()) {
         return derived_->GetScope()->alignment().value_or(1);
       }
       break;
-    case semantics::DerivedTypeSpec::Category::IntrinsicVector:
+
+      case semantics::DerivedTypeSpec::Category::IntrinsicVector:
     case semantics::DerivedTypeSpec::Category::PairVector:
     case semantics::DerivedTypeSpec::Category::QuadVector:
       if (derived_ && derived_->scope()) {
@@ -200,13 +207,23 @@ std::optional<Expr<SubscriptInteger>> DynamicType::MeasureSizeInBytes(
     }
     break;
   case TypeCategory::Derived:
-    if (!IsPolymorphic() && derived_ && derived_->GetScope()) {
+    // EnumerationTypes might not have scope set yet.
+    if (derived_ && (GetDerivedTypeSpec().category() ==
+          semantics::DerivedTypeSpec::Category::EnumerationType) &&
+          derived_->GetScope()) {
       auto size{derived_->GetScope()->size()};
       auto align{aligned ? derived_->GetScope()->alignment().value_or(0) : 0};
       auto alignedSize{align > 0 ? ((size + align - 1) / align) * align : size};
       return Expr<SubscriptInteger>{
           static_cast<ConstantSubscript>(alignedSize)};
     }
+    if (!IsPolymorphic() && derived_ && derived_->scope()) {
+      auto size{derived_->scope()->size()};
+      auto align{aligned ? derived_->scope()->alignment().value_or(0) : 0};
+      auto alignedSize{align > 0 ? ((size + align - 1) / align) * align : size};
+      return Expr<SubscriptInteger>{
+          static_cast<ConstantSubscript>(alignedSize)};
+    }
     break;
   }
   return std::nullopt;

>From 24a77c303ff41640afb055e10070dc5353241756 Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Thu, 21 May 2026 16:47:44 -0500
Subject: [PATCH 4/6] Fixing code formatting issue and added additional
 comments to code.

---
 flang/lib/Evaluate/type.cpp | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/flang/lib/Evaluate/type.cpp b/flang/lib/Evaluate/type.cpp
index c0f3c6d9eaf84..6540728aaf44f 100644
--- a/flang/lib/Evaluate/type.cpp
+++ b/flang/lib/Evaluate/type.cpp
@@ -163,14 +163,14 @@ std::size_t DynamicType::GetAlignment(
       }
       break;
 
-      // EnumerationTypes skip normal instantiation and may not have scope set.
+    // EnumerationTypes skip normal instantiation and may not have scope set.
     case semantics::DerivedTypeSpec::Category::EnumerationType:
       if (derived_ && derived_->GetScope()) {
         return derived_->GetScope()->alignment().value_or(1);
       }
       break;
 
-      case semantics::DerivedTypeSpec::Category::IntrinsicVector:
+    case semantics::DerivedTypeSpec::Category::IntrinsicVector:
     case semantics::DerivedTypeSpec::Category::PairVector:
     case semantics::DerivedTypeSpec::Category::QuadVector:
       if (derived_ && derived_->scope()) {
@@ -207,7 +207,10 @@ std::optional<Expr<SubscriptInteger>> DynamicType::MeasureSizeInBytes(
     }
     break;
   case TypeCategory::Derived:
-    // EnumerationTypes might not have scope set yet.
+    // EnumerationTypes might not have scope set yet, so they need to use
+    // GetScope() instead of scope().  Since EnumerationTypes are an internal
+    // only type, they can never be polymorphic, so the check in the
+    // corresponding conditional below is unnecessary here.
     if (derived_ && (GetDerivedTypeSpec().category() ==
           semantics::DerivedTypeSpec::Category::EnumerationType) &&
           derived_->GetScope()) {
@@ -217,6 +220,7 @@ std::optional<Expr<SubscriptInteger>> DynamicType::MeasureSizeInBytes(
       return Expr<SubscriptInteger>{
           static_cast<ConstantSubscript>(alignedSize)};
     }
+    // Regular derived type path.
     if (!IsPolymorphic() && derived_ && derived_->scope()) {
       auto size{derived_->scope()->size()};
       auto align{aligned ? derived_->scope()->alignment().value_or(0) : 0};

>From 9578642599ca6323bab3bb7a9df2bff960d4a7ad Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Thu, 21 May 2026 17:01:22 -0500
Subject: [PATCH 5/6] Still fighting a clang-format issue.

---
 flang/lib/Evaluate/type.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/flang/lib/Evaluate/type.cpp b/flang/lib/Evaluate/type.cpp
index 6540728aaf44f..226abca315565 100644
--- a/flang/lib/Evaluate/type.cpp
+++ b/flang/lib/Evaluate/type.cpp
@@ -211,9 +211,10 @@ std::optional<Expr<SubscriptInteger>> DynamicType::MeasureSizeInBytes(
     // GetScope() instead of scope().  Since EnumerationTypes are an internal
     // only type, they can never be polymorphic, so the check in the
     // corresponding conditional below is unnecessary here.
-    if (derived_ && (GetDerivedTypeSpec().category() ==
-          semantics::DerivedTypeSpec::Category::EnumerationType) &&
-          derived_->GetScope()) {
+    if (derived_ &&
+        (GetDerivedTypeSpec().category() ==
+            semantics::DerivedTypeSpec::Category::EnumerationType) &&
+        derived_->GetScope()) {
       auto size{derived_->GetScope()->size()};
       auto align{aligned ? derived_->GetScope()->alignment().value_or(0) : 0};
       auto alignedSize{align > 0 ? ((size + align - 1) / align) * align : size};

>From 2be284b965b605e1abaa5ef12fecd961b3891d4b Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Fri, 29 May 2026 15:47:52 -0500
Subject: [PATCH 6/6] Cleaned up unparse code.

---
 flang/lib/Parser/unparse.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index fdb3076f9559c..11eb9113fa1f6 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -427,10 +427,8 @@ class UnparseVisitor {
   }
   void Unparse(const EnumerationTypeStmt &x) { // F2023 R767
     Word("ENUMERATION TYPE");
-    Walk(", ", std::get<std::optional<AccessSpec>>(x.t), " :: ");
-    if (!std::get<std::optional<AccessSpec>>(x.t)) {
-      Word(" :: ");
-    }
+    Walk(", ", std::get<std::optional<AccessSpec>>(x.t));
+    Word(" :: ");
     Walk(std::get<Name>(x.t));
     Indent();
   }



More information about the flang-commits mailing list