Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flang] Accept intrinsic functions in DATA statement variables #66229

Merged
merged 1 commit into from
Sep 13, 2023

Conversation

klausler
Copy link
Contributor

Pure intrinsic functions are acceptable in constant expressions so long as their arguments are constant expressions. Allow them to appear in subscripts in DATA statement variables.

Fixes #65046.

Pure intrinsic functions are acceptable in constant expressions
so long as their arguments are constant expressions.  Allow them
to appear in subscripts in DATA statement variables.

Fixes llvm#65046.
@klausler klausler requested a review from a team as a code owner September 13, 2023 16:27
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:semantics labels Sep 13, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Sep 13, 2023

@llvm/pr-subscribers-flang-semantics

Changes Pure intrinsic functions are acceptable in constant expressions so long as their arguments are constant expressions. Allow them to appear in subscripts in DATA statement variables.

Fixes #65046.

Full diff: https://github.com/llvm/llvm-project/pull/66229.diff

3 Files Affected:

  • (modified) flang/lib/Evaluate/check-expression.cpp (+11)
  • (modified) flang/lib/Semantics/check-data.cpp (+30-26)
  • (modified) flang/test/Semantics/data05.f90 (+4)
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index cfc67bf70dd0d63..29bd6eaa466bbc2 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -114,6 +114,7 @@ bool IsConstantExprHelper<INVARIANT>::operator()(
   // LBOUND, UBOUND, and SIZE with truly constant DIM= arguments will have
   // been rewritten into DescriptorInquiry operations.
   if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&call.proc().u)}) {
+    const characteristics::Procedure &proc{intrinsic->characteristics.value()};
     if (intrinsic->name == "kind" ||
         intrinsic->name == IntrinsicProcTable::InvalidName ||
         call.arguments().empty() || !call.arguments()[0]) {
@@ -129,6 +130,16 @@ bool IsConstantExprHelper<INVARIANT>::operator()(
     } else if (intrinsic->name == "shape" || intrinsic->name == "size") {
       auto shape{GetShape(call.arguments()[0]->UnwrapExpr())};
       return shape && IsConstantExprShape(*shape);
+    } else if (proc.IsPure()) {
+      for (const auto &arg : call.arguments()) {
+        if (!arg) {
+          return false;
+        } else if (const auto *expr{arg->UnwrapExpr()};
+                   !expr || !(*this)(*expr)) {
+          return false;
+        }
+      }
+      return true;
     }
     // TODO: STORAGE_SIZE
   }
diff --git a/flang/lib/Semantics/check-data.cpp b/flang/lib/Semantics/check-data.cpp
index 6916870907a63aa..72e021d03a96974 100644
--- a/flang/lib/Semantics/check-data.cpp
+++ b/flang/lib/Semantics/check-data.cpp
@@ -102,16 +102,16 @@ class DataVarChecker : public evaluate::AllTraverse<DataVarChecker, true> {
             lastSymbol.name().ToString());
         return false;
       }
-      RestrictPointer();
+      auto restorer{common::ScopedSet(isPointerAllowed_, false)};
+      return (*this)(component.base()) && (*this)(lastSymbol);
+    } else if (IsPointer(lastSymbol)) { // C877
+      context_.Say(source_,
+          "Data object must not contain pointer '%s' as a non-rightmost part"_err_en_US,
+          lastSymbol.name().ToString());
+      return false;
     } else {
-      if (IsPointer(lastSymbol)) { // C877
-        context_.Say(source_,
-            "Data object must not contain pointer '%s' as a non-rightmost part"_err_en_US,
-            lastSymbol.name().ToString());
-        return false;
-      }
+      return (*this)(component.base()) && (*this)(lastSymbol);
     }
-    return (*this)(component.base()) && (*this)(lastSymbol);
   }
   bool operator()(const evaluate::ArrayRef &arrayRef) {
     hasSubscript_ = true;
@@ -128,29 +128,32 @@ class DataVarChecker : public evaluate::AllTraverse<DataVarChecker, true> {
     return false;
   }
   bool operator()(const evaluate::Subscript &subs) {
-    DataVarChecker subscriptChecker{context_, source_};
-    subscriptChecker.RestrictPointer();
+    auto restorer1{common::ScopedSet(isPointerAllowed_, false)};
+    auto restorer2{common::ScopedSet(isFunctionAllowed_, true)};
     return common::visit(
-               common::visitors{
-                   [&](const evaluate::IndirectSubscriptIntegerExpr &expr) {
-                     return CheckSubscriptExpr(expr);
-                   },
-                   [&](const evaluate::Triplet &triplet) {
-                     return CheckSubscriptExpr(triplet.lower()) &&
-                         CheckSubscriptExpr(triplet.upper()) &&
-                         CheckSubscriptExpr(triplet.stride());
-                   },
-               },
-               subs.u) &&
-        subscriptChecker(subs.u);
+        common::visitors{
+            [&](const evaluate::IndirectSubscriptIntegerExpr &expr) {
+              return CheckSubscriptExpr(expr);
+            },
+            [&](const evaluate::Triplet &triplet) {
+              return CheckSubscriptExpr(triplet.lower()) &&
+                  CheckSubscriptExpr(triplet.upper()) &&
+                  CheckSubscriptExpr(triplet.stride());
+            },
+        },
+        subs.u);
   }
   template <typename T>
   bool operator()(const evaluate::FunctionRef<T> &) const { // C875
-    context_.Say(source_,
-        "Data object variable must not be a function reference"_err_en_US);
-    return false;
+    if (isFunctionAllowed_) {
+      // Must have been validated as a constant expression
+      return true;
+    } else {
+      context_.Say(source_,
+          "Data object variable must not be a function reference"_err_en_US);
+      return false;
+    }
   }
-  void RestrictPointer() { isPointerAllowed_ = false; }
 
 private:
   bool CheckSubscriptExpr(
@@ -178,6 +181,7 @@ class DataVarChecker : public evaluate::AllTraverse<DataVarChecker, true> {
   bool hasSubscript_{false};
   bool isPointerAllowed_{true};
   bool isFirstSymbol_{true};
+  bool isFunctionAllowed_{false};
 };
 
 static bool IsValidDataObject(const SomeExpr &expr) { // C878, C879
diff --git a/flang/test/Semantics/data05.f90 b/flang/test/Semantics/data05.f90
index 02bfd4663264597..f9fc858c8d54398 100644
--- a/flang/test/Semantics/data05.f90
+++ b/flang/test/Semantics/data05.f90
@@ -93,4 +93,8 @@ subroutine s13
     integer j(2)
     data j(2:1), j(1:2) /1,2/ ! CHECK: j (InDataStmt) size=8 offset=0: ObjectEntity type: INTEGER(4) shape: 1_8:2_8 init:[INTEGER(4)::1_4,2_4]
   end subroutine
+  subroutine s14
+    integer j(0:1)
+    data (j(modulo(k,2)),k=1,2) /3,4/ ! CHECK: j (InDataStmt) size=8 offset=0: ObjectEntity type: INTEGER(4) shape: 0_8:1_8 init:[INTEGER(4)::4_4,3_4]
+  end subroutine
 end module

Copy link
Contributor

@psteinfeld psteinfeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All builds and tests correctly and looks good.

@klausler klausler merged commit 7e013d6 into llvm:main Sep 13, 2023
4 checks passed
@klausler klausler deleted the bug65046 branch September 13, 2023 22:02
ZijunZhaoCCK pushed a commit to ZijunZhaoCCK/llvm-project that referenced this pull request Sep 19, 2023
…66229)

Pure intrinsic functions are acceptable in constant expressions so long
as their arguments are constant expressions. Allow them to appear in
subscripts in DATA statement variables.

Fixes llvm#65046.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[flang] intrinsic in initialization statement
3 participants