[flang-commits] [flang] [llvm] [flang] Enumeration Type: (PR 3/5) Intrinsics + I/O + Modules (PR #193235)
via flang-commits
flang-commits at lists.llvm.org
Tue Aug 4 12:47:12 PDT 2026
================
@@ -1290,7 +1290,123 @@ Expr<T> FoldOperation(FoldingContext &context, FunctionRef<T> &&funcRef) {
return Folder<T>{context}.UNPACK(std::move(funcRef));
}
// TODO: extends_type_of, same_type_as
- if constexpr (!std::is_same_v<T, SomeDerived>) {
+ if constexpr (std::is_same_v<T, SomeDerived>) {
+ // Fold enumeration type intrinsics: HUGE(enum), NEXT(enum),
+ // PREVIOUS(enum)
+ if (name == "huge") {
+ // HUGE was eagerly folded — the first arg is the constant result
+ if (args.size() >= 1 && args[0]) {
+ if (auto *expr{UnwrapExpr<Expr<SomeDerived>>(args[0])}) {
+ return std::move(*expr);
+ }
+ }
+ } else if (name == "next" || name == "previous") {
+ // Don't fold if STAT is present — STAT assignment is a side effect
+ if (args.size() >= 2 && args[1]) {
+ return Expr<T>{std::move(funcRef)};
+ }
+ if (args.size() >= 1 && args[0]) {
+ if (auto *expr{UnwrapExpr<Expr<SomeDerived>>(args[0])}) {
+ if (auto type{expr->GetType()}) {
+ if (const auto *derived{GetDerivedTypeSpec(*type)}) {
+ if (derived->IsEnumerationType()) {
+ if (const auto *scope{derived->GetScope()}) {
+ auto ordIter{scope->find(semantics::SourceName{
+ semantics::DerivedTypeDetails::ordinalComponentName,
+ sizeof(semantics::DerivedTypeDetails::
+ ordinalComponentName) -
+ 1})};
+ if (ordIter != scope->end()) {
+ const semantics::Symbol &ordSym{*ordIter->second};
+ int count{derived->typeSymbol()
+ .GetUltimate()
+ .get<semantics::DerivedTypeDetails>()
+ .enumeratorCount()};
+ // Extract ordinal from constant value
+ if (auto *constant{
+ UnwrapConstantValue<SomeDerived>(*expr)}) {
+ const bool isNext{name == "next"};
+ // Boundary without STAT= is runtime error
+ // termination; diagnose and leave the reference
+ // unfolded (matches the scalar behavior).
+ auto boundaryBail{[&]() -> Expr<T> {
+ context.messages().Say(isNext
+ ? "NEXT() of last enumerator without STAT= causes error termination"_err_en_US
+ : "PREVIOUS() of first enumerator without STAT= causes error termination"_err_en_US);
+ return Expr<T>{std::move(funcRef)};
+ }};
+ if (auto sc{constant->GetScalarValue()}) {
+ if (auto ordExpr{sc->Find(ordSym)}) {
+ if (auto ordVal{ToInt64(*ordExpr)}) {
+ if (isNext ? *ordVal >= count : *ordVal <= 1) {
+ return boundaryBail();
----------------
kwyatt-ext wrote:
This revealed that constant folding was being too aggressive. It now looks to see if the actual expression being folded is required to be constant in context. If so, it reports the error, otherwise it sends it through to runtime processing. My original fix simply sent it through allowing constant expression analysis to catch it later. That error message works but isn't as clear. If the approach here is too intrusive, I can go back to the general error message.
https://github.com/llvm/llvm-project/pull/193235
More information about the flang-commits
mailing list