[flang-commits] [flang] [flang] Enumeration Type PR03 - Addition of name resolution and symbol table entries. (PR #192081)
via flang-commits
flang-commits at lists.llvm.org
Tue Apr 14 09:03:45 PDT 2026
https://github.com/kwyatt-ext created https://github.com/llvm/llvm-project/pull/192081
This PR implements the visitor methods for EnumerationTypeStmt, EnumerationEnumeratorStmt, and EndEnumerationTypeStmt.
The EnumerationTypeStmt handler creates a DerivedTypeDetails symbol (marked as an enumeration type) in the enclosing scope and pushes a DerivedType scope.
The EnumerationEnumeratorStmt handler creates PARAMETER symbols for each enumerator name in the enclosing scope, typed with a DerivedTypeSpec for the enumeration, and initialized with 1-based ordinal values.
Post(DerivedTypeSpec) is extended to recognize enumeration types and set the appropriate DerivedTypeSpec::Category.
AI Usage Disclosure: AI tools (Claude Opus 4.6) were used to assist with implementation of this feature and test code generation. I have reviewed, modified, and tested all AI-generated code.
>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/6] 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 ¶mDeclOrder() 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/6] 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()) {
>From c541b85221e6a4d1940be5b7b7be877a053e6e23 Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Thu, 26 Mar 2026 15:11:04 -0500
Subject: [PATCH 3/6] Enumeration Type PR02 - Addition of parse tree nodes
following F2023 spec definition.
---
flang/include/flang/Parser/dump-parse-tree.h | 4 +++
flang/include/flang/Parser/parse-tree.h | 31 +++++++++++++++++++-
flang/lib/Parser/Fortran-parsers.cpp | 28 ++++++++++++++++++
flang/lib/Parser/program-parsers.cpp | 6 ++--
flang/lib/Parser/unparse.cpp | 16 ++++++++++
5 files changed, 82 insertions(+), 3 deletions(-)
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 84c7b8d2a5349..9401d539ecb07 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -332,6 +332,10 @@ class ParseTreeDumper {
NODE(parser, EnumDefStmt)
NODE(parser, Enumerator)
NODE(parser, EnumeratorDefStmt)
+ NODE(parser, EnumerationTypeDef)
+ NODE(parser, EnumerationTypeStmt)
+ NODE(parser, EnumerationEnumeratorStmt)
+ NODE(parser, EndEnumerationTypeStmt)
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 4aec99c80bdae..b809d63cd3d1d 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
@@ -398,7 +399,8 @@ struct OtherSpecificationStmt {
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 +1232,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/lib/Parser/Fortran-parsers.cpp b/flang/lib/Parser/Fortran-parsers.cpp
index e86b5e7f79c74..66a642483bdc0 100644
--- a/flang/lib/Parser/Fortran-parsers.cpp
+++ b/flang/lib/Parser/Fortran-parsers.cpp
@@ -669,6 +669,34 @@ 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
+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 9d01bb74d70d3..7799cb7ce17c3 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);
}
>From 9a29ccb23edd5958eb881fac5050b4712c810a7f Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Fri, 10 Apr 2026 15:35:40 -0500
Subject: [PATCH 4/6] Clean-up and adding error message.
---
flang/include/flang/Parser/dump-parse-tree.h | 4 ++--
flang/include/flang/Parser/parse-tree.h | 7 ++++---
flang/lib/Parser/Fortran-parsers.cpp | 1 +
flang/lib/Semantics/resolve-names.cpp | 7 +++++++
4 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 9401d539ecb07..dca6aec559320 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -311,6 +311,7 @@ class ParseTreeDumper {
NODE(parser, EndChangeTeamStmt)
NODE(parser, EndCriticalStmt)
NODE(parser, EndDoStmt)
+ NODE(parser, EndEnumerationTypeStmt)
NODE(parser, EndEnumStmt)
NODE(parser, EndForallStmt)
NODE(parser, EndFunctionStmt)
@@ -332,10 +333,9 @@ class ParseTreeDumper {
NODE(parser, EnumDefStmt)
NODE(parser, Enumerator)
NODE(parser, EnumeratorDefStmt)
+ NODE(parser, EnumerationEnumeratorStmt)
NODE(parser, EnumerationTypeDef)
NODE(parser, EnumerationTypeStmt)
- NODE(parser, EnumerationEnumeratorStmt)
- NODE(parser, EndEnumerationTypeStmt)
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 b809d63cd3d1d..5ede3a9706c51 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -393,9 +393,10 @@ 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>,
diff --git a/flang/lib/Parser/Fortran-parsers.cpp b/flang/lib/Parser/Fortran-parsers.cpp
index 66a642483bdc0..a51c4cd48c2f6 100644
--- a/flang/lib/Parser/Fortran-parsers.cpp
+++ b/flang/lib/Parser/Fortran-parsers.cpp
@@ -688,6 +688,7 @@ TYPE_CONTEXT_PARSER("ENUMERATION TYPE statement"_en_US,
// 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)))
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index b6907cc792d76..f8d14990c099e 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 &);
@@ -5888,6 +5889,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{};
}
>From c4cfe9b734d59bcd6496b9cf77e9ad1da59d3307 Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Fri, 27 Mar 2026 14:18:11 -0500
Subject: [PATCH 5/6] Enumeration Type PR03 - Addition of name resolution and
symbol table entries.
---
flang/lib/Semantics/check-declarations.cpp | 4 +
flang/lib/Semantics/resolve-labels.cpp | 8 ++
flang/lib/Semantics/resolve-names.cpp | 99 ++++++++++++++++++++++
flang/lib/Semantics/rewrite-parse-tree.cpp | 1 +
4 files changed, 112 insertions(+)
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index b9c807a63638b..5a19608bb4343 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -1820,6 +1820,10 @@ void CheckHelper::CheckExternal(const Symbol &symbol) {
void CheckHelper::CheckDerivedType(
const Symbol &derivedType, const DerivedTypeDetails &details) {
+ if (details.isEnumerationType()) {
+ // Enumeration types have no components, parameters, or bindings to check.
+ return;
+ }
if (details.isForwardReferenced() && !context_.HasError(derivedType)) {
messages_.Say("The derived type '%s' has not been defined"_err_en_US,
derivedType.name());
diff --git a/flang/lib/Semantics/resolve-labels.cpp b/flang/lib/Semantics/resolve-labels.cpp
index 9454ef9fe928a..d35d9bee676e6 100644
--- a/flang/lib/Semantics/resolve-labels.cpp
+++ b/flang/lib/Semantics/resolve-labels.cpp
@@ -552,6 +552,14 @@ class ParseTreeAnalyzer {
PopDisposableMap();
}
+ // F2023 C7115
+ void Post(const parser::EnumerationTypeDef &enumTypeDef) {
+ CheckOptionalName<parser::EnumerationTypeStmt>(
+ "enumeration type definition", enumTypeDef,
+ std::get<parser::Statement<parser::EndEnumerationTypeStmt>>(
+ enumTypeDef.t));
+ }
+
void Post(const parser::LabelDoStmt &labelDoStmt) {
AddLabelReferenceFromDoStmt(std::get<parser::Label>(labelDoStmt.t));
}
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index f8d14990c099e..26fc48cd3ba5b 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -996,6 +996,9 @@ class DeclarationVisitor : public ArraySpecVisitor,
void Post(const parser::EnumDef &);
bool Pre(const parser::Enumerator &);
bool Pre(const parser::EnumerationTypeDef &);
+ void Post(const parser::EnumerationTypeStmt &);
+ bool Pre(const parser::EnumerationEnumeratorStmt &);
+ void Post(const parser::EndEnumerationTypeStmt &);
bool Pre(const parser::AccessSpec &);
bool Pre(const parser::AsynchronousStmt &);
bool Pre(const parser::ContiguousStmt &);
@@ -5899,6 +5902,66 @@ void DeclarationVisitor::Post(const parser::EnumDef &) {
enumerationState_ = EnumeratorState{};
}
+// F2023 R766 EnumerationTypeDef — scope is pushed in Post(EnumerationTypeStmt)
+// and popped in Post(EndEnumerationTypeStmt).
+bool DeclarationVisitor::Pre(const parser::EnumerationTypeDef &) {
+ return true;
+}
+
+// F2023 R767 EnumerationTypeStmt — create the enumeration type symbol
+// in the enclosing scope and push a DerivedType scope for it.
+void DeclarationVisitor::Post(const parser::EnumerationTypeStmt &x) {
+ const auto &name{std::get<parser::Name>(x.t)};
+ const auto &optAccessSpec{std::get<std::optional<parser::AccessSpec>>(x.t)};
+ Attrs attrs;
+ if (optAccessSpec) {
+ attrs.set(AccessSpecToAttr(*optAccessSpec));
+ if (!NonDerivedTypeScope().IsModule()) { // F2023 C7114
+ Say(currStmtSource().value(),
+ "Access specifier on ENUMERATION TYPE may only appear in the specification part of a module"_err_en_US);
+ }
+ }
+ DerivedTypeDetails details;
+ details.set_isEnumerationType(true);
+ auto &symbol{MakeSymbol(name, attrs, std::move(details))};
+ symbol.ReplaceName(name.source);
+ PushScope(Scope::Kind::DerivedType, &symbol);
+}
+
+// F2023 R768 EnumerationEnumeratorStmt — create PARAMETER symbols for
+// each enumerator name in the enclosing scope with 1-based ordinal init.
+bool DeclarationVisitor::Pre(const parser::EnumerationEnumeratorStmt &x) {
+ Scope &enclosingScope{NonDerivedTypeScope()};
+ // The current DerivedType scope's symbol is the enumeration type.
+ Symbol *typeSymbol{currScope().symbol()};
+ CHECK(typeSymbol);
+ auto &typeDetails{typeSymbol->get<DerivedTypeDetails>()};
+ // Build a DerivedTypeSpec for the enumeration type.
+ DerivedTypeSpec enumTypeSpec{typeSymbol->name(), *typeSymbol};
+ enumTypeSpec.set_category(DerivedTypeSpec::Category::EnumerationType);
+ DeclTypeSpec &declType{enclosingScope.MakeDerivedType(
+ DeclTypeSpec::TypeDerived, std::move(enumTypeSpec))};
+ for (const parser::Name &name : x.v) {
+ int ordinal{typeDetails.enumeratorCount() + 1};
+ // Create the enumerator symbol in the enclosing scope, not the
+ // enumeration type's own DerivedType scope.
+ Symbol &enumerator{
+ MakeSymbol(enclosingScope, name.source, Attrs{Attr::PARAMETER})};
+ Resolve(name, enumerator);
+ enumerator.set_details(ObjectEntityDetails{});
+ enumerator.SetType(declType);
+ enumerator.get<ObjectEntityDetails>().set_init(
+ SomeExpr{evaluate::Expr<evaluate::CInteger>{ordinal}});
+ typeDetails.set_enumeratorCount(ordinal);
+ }
+ return false;
+}
+
+// F2023 R769 EndEnumerationTypeStmt — pop the scope.
+void DeclarationVisitor::Post(const parser::EndEnumerationTypeStmt &) {
+ PopScope();
+}
+
bool DeclarationVisitor::Pre(const parser::AccessSpec &x) {
Attr attr{AccessSpecToAttr(x)};
if (!NonDerivedTypeScope().IsModule()) { // C817
@@ -6484,6 +6547,17 @@ void DeclarationVisitor::Post(const parser::DerivedTypeSpec &x) {
// in the current scope, this spec will be moved into that collection.
const auto &dtDetails{spec->typeSymbol().get<DerivedTypeDetails>()};
auto category{GetDeclTypeSpecCategory()};
+
+ // Enumeration types are a special case of derived types and are handled
+ // differently.
+ if (dtDetails.isEnumerationType()) {
+ spec->set_category(DerivedTypeSpec::Category::EnumerationType);
+ DeclTypeSpec &type{currScope().MakeDerivedType(category, std::move(*spec))};
+ SetDeclTypeSpec(type);
+ x.derivedTypeSpec = &GetDeclTypeSpec()->derivedTypeSpec();
+ return;
+ }
+
if (dtDetails.isForwardReferenced()) {
DeclTypeSpec &type{currScope().MakeDerivedType(category, std::move(*spec))};
SetDeclTypeSpec(type);
@@ -8642,6 +8716,12 @@ class ExecutionPartSkimmerBase {
return true;
}
void Post(const parser::DerivedTypeDef &) { PopScope(); }
+ bool Pre(const parser::EnumerationTypeStmt &x) {
+ Hide(std::get<parser::Name>(x.t));
+ PushScope();
+ return true;
+ }
+ void Post(const parser::EnumerationTypeDef &) { PopScope(); }
bool Pre(const parser::SelectTypeConstruct &) {
PushScope();
return true;
@@ -10778,6 +10858,25 @@ class DeferredCheckVisitor {
}
}
+ void Post(const parser::EnumerationTypeStmt &x) {
+ const auto &name{std::get<parser::Name>(x.t)};
+ if (Symbol * symbol{name.symbol}) {
+ if (Scope * scope{symbol->scope()}) {
+ if (scope->IsDerivedType()) {
+ CHECK(outerScope_ == nullptr);
+ outerScope_ = &resolver_.currScope();
+ resolver_.SetScope(*scope);
+ }
+ }
+ }
+ }
+ void Post(const parser::EndEnumerationTypeStmt &) {
+ if (outerScope_) {
+ resolver_.SetScope(*outerScope_);
+ outerScope_ = nullptr;
+ }
+ }
+
void Post(const parser::ProcInterface &pi) {
if (const auto *name{std::get_if<parser::Name>(&pi.u)}) {
resolver_.CheckExplicitInterface(*name);
diff --git a/flang/lib/Semantics/rewrite-parse-tree.cpp b/flang/lib/Semantics/rewrite-parse-tree.cpp
index 60e3e6ab3f5f1..a4c2aeabba68c 100644
--- a/flang/lib/Semantics/rewrite-parse-tree.cpp
+++ b/flang/lib/Semantics/rewrite-parse-tree.cpp
@@ -80,6 +80,7 @@ class RewriteMutator {
bool Pre(parser::EndSubmoduleStmt &) { return false; }
bool Pre(parser::EndSubroutineStmt &) { return false; }
bool Pre(parser::EndTypeStmt &) { return false; }
+ bool Pre(parser::EndEnumerationTypeStmt &) { return false; }
bool Pre(parser::OmpBlockConstruct &);
bool Pre(parser::OpenMPLoopConstruct &);
>From 95d5d67d03f070e8cc47fd7f394cc69f1e69ee13 Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Tue, 14 Apr 2026 10:43:44 -0500
Subject: [PATCH 6/6] Incorportating part of a downstream fix.
---
flang/lib/Semantics/resolve-names.cpp | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 26fc48cd3ba5b..e76c1dbcf6f89 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -5892,30 +5892,28 @@ 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{};
}
// F2023 R766 EnumerationTypeDef — scope is pushed in Post(EnumerationTypeStmt)
// and popped in Post(EndEnumerationTypeStmt).
-bool DeclarationVisitor::Pre(const parser::EnumerationTypeDef &) {
- return true;
+bool DeclarationVisitor::Pre(const parser::EnumerationTypeDef &x) {
+ BeginAttrs();
+ // TODO: Remove this and set true when ENUMERATION TYPEs are implemented.
+ Say(std::get<parser::Statement<parser::EnumerationTypeStmt>>(x.t).source,
+ "F2023 ENUMERATION TYPEs are not yet implemented"_err_en_US);
+ return false;
}
// F2023 R767 EnumerationTypeStmt — create the enumeration type symbol
// in the enclosing scope and push a DerivedType scope for it.
void DeclarationVisitor::Post(const parser::EnumerationTypeStmt &x) {
const auto &name{std::get<parser::Name>(x.t)};
- const auto &optAccessSpec{std::get<std::optional<parser::AccessSpec>>(x.t)};
- Attrs attrs;
- if (optAccessSpec) {
- attrs.set(AccessSpecToAttr(*optAccessSpec));
+ Attrs attrs{EndAttrs()};
+ if (const auto &optAccessSpec{
+ std::get<std::optional<parser::AccessSpec>>(x.t)};
+ optAccessSpec) {
if (!NonDerivedTypeScope().IsModule()) { // F2023 C7114
Say(currStmtSource().value(),
"Access specifier on ENUMERATION TYPE may only appear in the specification part of a module"_err_en_US);
More information about the flang-commits
mailing list