[flang-commits] [flang] Enumeration Type PR01 - Initial Addition of Enumeration Type as an extension of Derived Type (PR #191491)

via flang-commits flang-commits at lists.llvm.org
Fri Apr 10 11:56:04 PDT 2026


https://github.com/kwyatt-ext created https://github.com/llvm/llvm-project/pull/191491

This PR creates the concept of an ENUMERATIONTYPE.  It is implemented as a special case of a Derived Type internally to the compiler.

>From a5f935eaa45da067d1a964a1ab3ba69a572b2542 Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Wed, 25 Mar 2026 15:36:25 -0500
Subject: [PATCH 1/2] Enumeration Type PR01 - Initial Addition of Type as an
 extension of Derived Type

---
 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            |  2 ++
 flang/lib/Lower/ConvertType.cpp        |  3 +++
 flang/lib/Semantics/symbol.cpp         |  1 +
 flang/lib/Semantics/tools.cpp          | 11 +++++++++++
 flang/lib/Semantics/type.cpp           |  6 ++++++
 8 files changed, 43 insertions(+), 1 deletion(-)

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..40e34b42ba3f6 100644
--- a/flang/lib/Evaluate/type.cpp
+++ b/flang/lib/Evaluate/type.cpp
@@ -170,6 +170,8 @@ std::size_t DynamicType::GetAlignment(
       } else {
         common::die("Missing scope for Vector type.");
       }
+    case semantics::DerivedTypeSpec::Category::EnumerationType:
+      break; // treat like DerivedType for alignment purposes
     }
   } else {
     return targetCharacteristics.GetAlignment(category_, kind());
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/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 68307f7504e28..a792e65aab9fa 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..13b3b041087cd 100644
--- a/flang/lib/Semantics/type.cpp
+++ b/flang/lib/Semantics/type.cpp
@@ -738,6 +738,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 +747,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 88f594d667ce1df5742095218fc61b6a980615a0 Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Fri, 10 Apr 2026 13:50:34 -0500
Subject: [PATCH 2/2] Correcting GetAlignment() issue.

---
 flang/lib/Evaluate/type.cpp  | 13 ++++++-------
 flang/lib/Semantics/type.cpp | 14 ++++++++++++++
 2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/flang/lib/Evaluate/type.cpp b/flang/lib/Evaluate/type.cpp
index 40e34b42ba3f6..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:
@@ -170,8 +171,6 @@ std::size_t DynamicType::GetAlignment(
       } else {
         common::die("Missing scope for Vector type.");
       }
-    case semantics::DerivedTypeSpec::Category::EnumerationType:
-      break; // treat like DerivedType for alignment purposes
     }
   } else {
     return targetCharacteristics.GetAlignment(category_, kind());
@@ -201,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/Semantics/type.cpp b/flang/lib/Semantics/type.cpp
index 13b3b041087cd..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()) {



More information about the flang-commits mailing list