[flang] Don't fold SIZE()/SHAPE() into expression referencing optional dummy arguments
authorPeter Klausler <pklausler@nvidia.com>
Thu, 25 May 2023 23:01:52 +0000 (16:01 -0700)
committerPeter Klausler <pklausler@nvidia.com>
Wed, 31 May 2023 15:57:18 +0000 (08:57 -0700)
When computing the shape of an expression at compilation time as part of
folding an intrinsic function like SIZE(), don't create an expression that
increases a dependence on the presence of an optional dummy argument.

Differential Revision: https://reviews.llvm.org/D151737

flang/lib/Evaluate/shape.cpp
flang/test/Evaluate/elem-shape.f90 [new file with mode: 0644]

index 6f6baae..c7dcb1c 100644 (file)
@@ -805,9 +805,19 @@ auto GetShapeHelper::operator()(const ProcedureRef &call) const -> Result {
   if (call.Rank() == 0) {
     return ScalarShape();
   } else if (call.IsElemental()) {
-    for (const auto &arg : call.arguments()) {
-      if (arg && arg->Rank() > 0) {
-        return (*this)(*arg);
+    // Use the shape of an actual array argument associated with a
+    // non-OPTIONAL dummy object argument.
+    if (context_) {
+      if (auto chars{characteristics::Procedure::FromActuals(
+              call.proc(), call.arguments(), *context_)}) {
+        std::size_t j{0};
+        for (const auto &arg : call.arguments()) {
+          if (arg && arg->Rank() > 0 && j < chars->dummyArguments.size() &&
+              !chars->dummyArguments[j].IsOptional()) {
+            return (*this)(*arg);
+          }
+          ++j;
+        }
       }
     }
     return ScalarShape();
diff --git a/flang/test/Evaluate/elem-shape.f90 b/flang/test/Evaluate/elem-shape.f90
new file mode 100644 (file)
index 0000000..623c833
--- /dev/null
@@ -0,0 +1,16 @@
+! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
+! Ensure that optional arguments aren't used to fold SIZE() or SHAPE()
+module m
+ contains
+  subroutine sub(x,y)
+    real :: x(:), y(:)
+    optional x
+    !CHECK: PRINT *, int(size(y,dim=1,kind=8),kind=4)
+    print *, size(f(x,y))
+  end
+  elemental function f(x,y)
+    real, intent(in) :: x, y
+    optional x
+    f = y
+  end
+end