[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