[flang-commits] [flang] [flang] Reject SIZE of TRANSFER with non-constant source in constant expressions (PR #178939)

via flang-commits flang-commits at lists.llvm.org
Fri Jan 30 10:54:04 PST 2026


https://github.com/Ritanya-B-Bharadwaj updated https://github.com/llvm/llvm-project/pull/178939

>From 25437423696758ea38d96243cc684a761a07beff Mon Sep 17 00:00:00 2001
From: Ritanya B Bharadwaj <ritanya.b.bharadwaj at gmail.com>
Date: Fri, 30 Jan 2026 12:47:16 -0600
Subject: [PATCH 1/2] Fixing flang issue #178426

---
 flang/lib/Evaluate/check-expression.cpp | 12 ++++++++++--
 flang/lib/Evaluate/fold-integer.cpp     | 23 +++++++++++++++++++++++
 flang/test/Semantics/size-const.f90     | 22 ++++++++++++++++++++++
 3 files changed, 55 insertions(+), 2 deletions(-)
 create mode 100644 flang/test/Semantics/size-const.f90

diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index f7636ecacfb78..cd7d75bb8e7b3 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -130,8 +130,16 @@ bool IsConstantExprHelper<INVARIANT>::operator()(
       auto base{ExtractNamedEntity(call.arguments()[0]->UnwrapExpr())};
       return base && IsConstantExprShape(GetUBOUNDs(*base));
     } else if (intrinsic->name == "shape" || intrinsic->name == "size") {
-      auto shape{GetShape(call.arguments()[0]->UnwrapExpr())};
-      return shape && IsConstantExprShape(*shape);
+      auto base{ExtractNamedEntity(call.arguments()[0]->UnwrapExpr())};
+      if (base) {
+        auto shape{GetShape(*base)};
+	return shape && IsConstantExprShape(*shape);
+      } else {
+        // Argument is not a named entity (e.g., it's a function call);
+	// it must be a constant expression for SIZE/SHAPE to be constant.
+	const auto *argExpr{call.arguments()[0]->UnwrapExpr()};
+	return argExpr && (*this)(*argExpr);
+      }
     } else if (proc.IsPure()) {
       std::size_t j{0};
       for (const auto &arg : call.arguments()) {
diff --git a/flang/lib/Evaluate/fold-integer.cpp b/flang/lib/Evaluate/fold-integer.cpp
index 3628497531ef1..624e9a9719b1f 100644
--- a/flang/lib/Evaluate/fold-integer.cpp
+++ b/flang/lib/Evaluate/fold-integer.cpp
@@ -13,6 +13,25 @@
 
 namespace Fortran::evaluate {
 
+// Check if the argument is a TRANSFER intrinsic call with a non-constant
+// source. SIZE of such a call cannot be folded.
+static bool IsNonConstantTransferArg(const ActualArgument &arg) {
+  if (const auto *expr{arg.UnwrapExpr()}) {
+    if (const auto *procRef{UnwrapProcedureRef(*expr)}) {
+      if (const auto *intrinsic{procRef->proc().GetSpecificIntrinsic()};
+          intrinsic && intrinsic->name == "transfer" &&
+          !procRef->arguments().empty()) {
+        if (const auto &sourceArg{procRef->arguments()[0]}) {
+          if (const auto *sourceExpr{sourceArg->UnwrapExpr()}) {
+            return !IsConstantExpr(*sourceExpr);
+          }
+        }
+      }
+    }
+  }
+  return false;
+}
+
 // Given a collection of ConstantSubscripts values, package them as a Constant.
 // Return scalar value if asScalar == true and shape-dim array otherwise.
 template <typename T>
@@ -1389,6 +1408,10 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
           return result.value;
         }));
   } else if (name == "size") {
+    // Don't fold SIZE of TRANSFER with non-constant source.
+    if (IsNonConstantTransferArg(args[0].value())) {
+      return Expr<T>{std::move(funcRef)};
+    }
     if (auto shape{GetContextFreeShape(context, args[0])}) {
       if (args[1]) { // DIM= is present, get one extent
         std::optional<int> dim;
diff --git a/flang/test/Semantics/size-const.f90 b/flang/test/Semantics/size-const.f90
new file mode 100644
index 0000000000000..41132df9f5396
--- /dev/null
+++ b/flang/test/Semantics/size-const.f90
@@ -0,0 +1,22 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! Test that SIZE of TRANSFER with non-constant SOURCE argument
+! is not accepted as a constant expression (per F2018 10.1.12)
+
+program test
+  implicit none
+  type t
+    integer :: n
+  end type t
+
+  type(t) :: s
+  type(t), parameter :: s_const = t(42)
+
+  !ERROR: Must be a constant value
+  integer :: k = size(transfer(s, [1]))
+  !ERROR: Must be a constant value
+  integer, parameter :: m = size(transfer(s, [1]))
+
+  integer :: ok1 = size(transfer(s_const, [1]))
+  integer, parameter :: ok2 = size(transfer(s_const, [1]))
+
+end program test

>From 1703d6284e1fd688383a5d91da2e054a4a550359 Mon Sep 17 00:00:00 2001
From: Ritanya-B-Bharadwaj <ritanya.b.bharadwaj at gmail.com>
Date: Sat, 31 Jan 2026 00:23:55 +0530
Subject: [PATCH 2/2] Update check-expression.cpp

---
 flang/lib/Evaluate/check-expression.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index cd7d75bb8e7b3..b3f66dd56c4d4 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -133,12 +133,12 @@ bool IsConstantExprHelper<INVARIANT>::operator()(
       auto base{ExtractNamedEntity(call.arguments()[0]->UnwrapExpr())};
       if (base) {
         auto shape{GetShape(*base)};
-	return shape && IsConstantExprShape(*shape);
+	    return shape && IsConstantExprShape(*shape);
       } else {
         // Argument is not a named entity (e.g., it's a function call);
-	// it must be a constant expression for SIZE/SHAPE to be constant.
-	const auto *argExpr{call.arguments()[0]->UnwrapExpr()};
-	return argExpr && (*this)(*argExpr);
+	    // it must be a constant expression for SIZE/SHAPE to be constant.
+	    const auto *argExpr{call.arguments()[0]->UnwrapExpr()};
+	    return argExpr && (*this)(*argExpr);
       }
     } else if (proc.IsPure()) {
       std::size_t j{0};



More information about the flang-commits mailing list