[flang-commits] [flang] [flang][semantics] add portability warning and tests for copy-in/copy-out case (PR #153263)

Andre Kuhlenschmidt via flang-commits flang-commits at lists.llvm.org
Wed Aug 20 15:53:04 PDT 2025


https://github.com/akuhlens updated https://github.com/llvm/llvm-project/pull/153263

>From 44ac39a08fb25e7874457025cada273fdb4a05ce Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Tue, 12 Aug 2025 12:44:30 -0700
Subject: [PATCH 1/3] initial commit

---
 flang/test/Semantics/call45.f90 | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 flang/test/Semantics/call45.f90

diff --git a/flang/test/Semantics/call45.f90 b/flang/test/Semantics/call45.f90
new file mode 100644
index 0000000000000..aca0767e0ead2
--- /dev/null
+++ b/flang/test/Semantics/call45.f90
@@ -0,0 +1,15 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic -Werror
+program call45
+    integer :: v(100) = [(i, i=1, 100)]
+    !ERROR: Actual argument associated with VOLATILE dummy argument 'v=' is not definable [-Wundefinable-asynchronous-or-volatile-actual]
+    !BECAUSE: Variable 'v([INTEGER(8)::1_8,2_8,2_8,3_8,3_8,3_8,4_8,4_8,4_8,4_8])' has a vector subscript
+    call sub(v([1,2,2,3,3,3,4,4,4,4]))
+    !OK: Some compilers don't allow this, but there doesn't seem to be a good reason to disallow it.
+    call sub(v(21:30))
+    print *, v
+contains
+    subroutine sub(v)
+        integer, volatile :: v(10)
+        v = 0
+    end subroutine sub
+end program call45

>From 49aa9ed93bd530652ffd6be7bc85cae7eb9a0e3b Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Thu, 14 Aug 2025 08:46:56 -0700
Subject: [PATCH 2/3] add portability warning

---
 flang/include/flang/Evaluate/tools.h          |  3 ++
 .../include/flang/Support/Fortran-features.h  |  3 +-
 flang/lib/Evaluate/tools.cpp                  |  4 ++
 flang/lib/Semantics/check-call.cpp            | 39 ++++++++++++-------
 flang/test/Semantics/call45.f90               |  1 +
 5 files changed, 36 insertions(+), 14 deletions(-)

diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index 212356136d6ee..401c1506c28c8 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -1124,6 +1124,9 @@ extern template semantics::UnorderedSymbolSet CollectCudaSymbols(
 // Predicate: does a variable contain a vector-valued subscript (not a triplet)?
 bool HasVectorSubscript(const Expr<SomeType> &);
 
+// Predicate: is an expression an expression a section of an array?
+bool IsArraySection(const Expr<SomeType> &expr);
+
 // Predicate: does an expression contain constant?
 bool HasConstant(const Expr<SomeType> &);
 
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index 743abf606ab5f..c05b7fe4fbd79 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -78,7 +78,8 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
     MismatchingDummyProcedure, SubscriptedEmptyArray, UnsignedLiteralTruncation,
     CompatibleDeclarationsFromDistinctModules,
     NullActualForDefaultIntentAllocatable, UseAssociationIntoSameNameSubprogram,
-    HostAssociatedIntentOutInSpecExpr, NonVolatilePointerToVolatile)
+    HostAssociatedIntentOutInSpecExpr, NonVolatilePointerToVolatile,
+    ArraySectionCopyInCopyOut)
 
 using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
 using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;
diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index 3b2c4f9f56016..c5f990b169663 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -1203,6 +1203,10 @@ bool HasVectorSubscript(const Expr<SomeType> &expr) {
   return HasVectorSubscriptHelper{}(expr);
 }
 
+bool IsArraySection(const Expr<SomeType> &expr) {
+  return expr.Rank() > 0 && IsVariable(expr) && !UnwrapWholeSymbolDataRef(expr);
+}
+
 // HasConstant()
 struct HasConstantHelper : public AnyTraverse<HasConstantHelper, bool,
                                /*TraverseAssocEntityDetails=*/false> {
diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp
index 83f59f0cac3df..b3258cd580915 100644
--- a/flang/lib/Semantics/check-call.cpp
+++ b/flang/lib/Semantics/check-call.cpp
@@ -779,24 +779,37 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
   // Cases when temporaries might be needed but must not be permitted.
   bool dummyIsAssumedShape{dummy.type.attrs().test(
       characteristics::TypeAndShape::Attr::AssumedShape)};
-  if ((actualIsAsynchronous || actualIsVolatile) &&
-      (dummyIsAsynchronous || dummyIsVolatile) && !dummyIsValue) {
-    if (actualCoarrayRef) { // C1538
-      messages.Say(
-          "Coindexed ASYNCHRONOUS or VOLATILE actual argument may not be associated with %s with ASYNCHRONOUS or VOLATILE attributes unless VALUE"_err_en_US,
-          dummyName);
-    }
-    if ((actualRank > 0 || actualIsAssumedRank) && !actualIsContiguous) {
-      if (dummyIsContiguous ||
-          !(dummyIsAssumedShape || dummyIsAssumedRank ||
-              (actualIsPointer && dummyIsPointer))) { // C1539 & C1540
+  if (!dummyIsValue && (dummyIsAsynchronous || dummyIsVolatile)) {
+    if (actualIsAsynchronous || actualIsVolatile) {
+      if (actualCoarrayRef) { // C1538
         messages.Say(
-            "ASYNCHRONOUS or VOLATILE actual argument that is not simply contiguous may not be associated with a contiguous ASYNCHRONOUS or VOLATILE %s"_err_en_US,
+            "Coindexed ASYNCHRONOUS or VOLATILE actual argument may not be associated with %s with ASYNCHRONOUS or VOLATILE attributes unless VALUE"_err_en_US,
             dummyName);
       }
+      if ((actualRank > 0 || actualIsAssumedRank) && !actualIsContiguous) {
+        if (dummyIsContiguous ||
+            !(dummyIsAssumedShape || dummyIsAssumedRank ||
+                (actualIsPointer && dummyIsPointer))) { // C1539 & C1540
+          messages.Say(
+              "ASYNCHRONOUS or VOLATILE actual argument that is not simply contiguous may not be associated with a contiguous ASYNCHRONOUS or VOLATILE %s"_err_en_US,
+              dummyName);
+        }
+      }
+      // The vector subscript case is handled by the definability check above.
+      // The copy-in/copy-out cases are handled by the previous checks.
+      // Nag, GFortran, and NVFortran all error on this case, even though it is
+      // ok, prossibly as an over-restriction of C1548.
+    } else if (!(dummyIsAssumedShape || dummyIsAssumedRank ||
+                   (actualIsPointer && dummyIsPointer)) &&
+        evaluate::IsArraySection(actual) &&
+        !evaluate::HasVectorSubscript(actual)) {
+      context.Warn(common::UsageWarning::ArraySectionCopyInCopyOut,
+          messages.at(),
+          "The array section '%s' may not be associated with %s with %s attribute, unless the dummy is assumed-shape or assumed-rank"_port_en_US,
+          actual.AsFortran(), dummyName,
+          dummyIsAsynchronous ? "ASYNCHRONOUS" : "VOLATILE");
     }
   }
-
   // 15.5.2.6 -- dummy is ALLOCATABLE
   bool dummyIsOptional{
       dummy.attrs.test(characteristics::DummyDataObject::Attr::Optional)};
diff --git a/flang/test/Semantics/call45.f90 b/flang/test/Semantics/call45.f90
index aca0767e0ead2..1a7523dfae627 100644
--- a/flang/test/Semantics/call45.f90
+++ b/flang/test/Semantics/call45.f90
@@ -5,6 +5,7 @@ program call45
     !BECAUSE: Variable 'v([INTEGER(8)::1_8,2_8,2_8,3_8,3_8,3_8,4_8,4_8,4_8,4_8])' has a vector subscript
     call sub(v([1,2,2,3,3,3,4,4,4,4]))
     !OK: Some compilers don't allow this, but there doesn't seem to be a good reason to disallow it.
+    !PORTABILITY: The array section 'v(21_8:30_8:1_8)' may not be associated with dummy argument 'v=' with VOLATILE attribute, unless the dummy is assumed-shape or assumed-rank [-Warray-section-copy-in-copy-out]
     call sub(v(21:30))
     print *, v
 contains

>From da93973e88195858eb3be9d94b0a75dcaa7df5c4 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Wed, 20 Aug 2025 15:14:39 -0700
Subject: [PATCH 3/3] address feedback

---
 flang/include/flang/Evaluate/tools.h          |  2 +-
 .../include/flang/Support/Fortran-features.h  |  4 +--
 flang/lib/Semantics/check-call.cpp            |  9 +++---
 flang/test/Semantics/call45.f90               | 29 +++++++++++++++++--
 4 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index 401c1506c28c8..c061decdb9e67 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -1124,7 +1124,7 @@ extern template semantics::UnorderedSymbolSet CollectCudaSymbols(
 // Predicate: does a variable contain a vector-valued subscript (not a triplet)?
 bool HasVectorSubscript(const Expr<SomeType> &);
 
-// Predicate: is an expression an expression a section of an array?
+// Predicate: is an expression a section of an array?
 bool IsArraySection(const Expr<SomeType> &expr);
 
 // Predicate: does an expression contain constant?
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index c05b7fe4fbd79..a70e6dd409e14 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -78,9 +78,7 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
     MismatchingDummyProcedure, SubscriptedEmptyArray, UnsignedLiteralTruncation,
     CompatibleDeclarationsFromDistinctModules,
     NullActualForDefaultIntentAllocatable, UseAssociationIntoSameNameSubprogram,
-    HostAssociatedIntentOutInSpecExpr, NonVolatilePointerToVolatile,
-    ArraySectionCopyInCopyOut)
-
+    HostAssociatedIntentOutInSpecExpr, NonVolatilePointerToVolatile)
 using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
 using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;
 using LanguageFeatureOrWarning = std::variant<LanguageFeature, UsageWarning>;
diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp
index b3258cd580915..e73e6d1fa87ec 100644
--- a/flang/lib/Semantics/check-call.cpp
+++ b/flang/lib/Semantics/check-call.cpp
@@ -781,7 +781,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
       characteristics::TypeAndShape::Attr::AssumedShape)};
   if (!dummyIsValue && (dummyIsAsynchronous || dummyIsVolatile)) {
     if (actualIsAsynchronous || actualIsVolatile) {
-      if (actualCoarrayRef) { // C1538
+      if (actualCoarrayRef) { // F'2023 C1547
         messages.Say(
             "Coindexed ASYNCHRONOUS or VOLATILE actual argument may not be associated with %s with ASYNCHRONOUS or VOLATILE attributes unless VALUE"_err_en_US,
             dummyName);
@@ -789,7 +789,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
       if ((actualRank > 0 || actualIsAssumedRank) && !actualIsContiguous) {
         if (dummyIsContiguous ||
             !(dummyIsAssumedShape || dummyIsAssumedRank ||
-                (actualIsPointer && dummyIsPointer))) { // C1539 & C1540
+                (actualIsPointer && dummyIsPointer))) { // F'2023 C1548 & C1549
           messages.Say(
               "ASYNCHRONOUS or VOLATILE actual argument that is not simply contiguous may not be associated with a contiguous ASYNCHRONOUS or VOLATILE %s"_err_en_US,
               dummyName);
@@ -803,9 +803,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
                    (actualIsPointer && dummyIsPointer)) &&
         evaluate::IsArraySection(actual) &&
         !evaluate::HasVectorSubscript(actual)) {
-      context.Warn(common::UsageWarning::ArraySectionCopyInCopyOut,
-          messages.at(),
-          "The array section '%s' may not be associated with %s with %s attribute, unless the dummy is assumed-shape or assumed-rank"_port_en_US,
+      context.Warn(common::UsageWarning::Portability, messages.at(),
+          "The array section '%s' should not be associated with %s with %s attribute, unless the dummy is assumed-shape or assumed-rank"_port_en_US,
           actual.AsFortran(), dummyName,
           dummyIsAsynchronous ? "ASYNCHRONOUS" : "VOLATILE");
     }
diff --git a/flang/test/Semantics/call45.f90 b/flang/test/Semantics/call45.f90
index 1a7523dfae627..751b0e91dea44 100644
--- a/flang/test/Semantics/call45.f90
+++ b/flang/test/Semantics/call45.f90
@@ -1,16 +1,39 @@
 ! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic -Werror
 program call45
-    integer :: v(100) = [(i, i=1, 100)]
+    integer, target :: v(100) = [(i, i=1, 100)]
+    integer, pointer :: p(:) => v
     !ERROR: Actual argument associated with VOLATILE dummy argument 'v=' is not definable [-Wundefinable-asynchronous-or-volatile-actual]
     !BECAUSE: Variable 'v([INTEGER(8)::1_8,2_8,2_8,3_8,3_8,3_8,4_8,4_8,4_8,4_8])' has a vector subscript
     call sub(v([1,2,2,3,3,3,4,4,4,4]))
-    !OK: Some compilers don't allow this, but there doesn't seem to be a good reason to disallow it.
-    !PORTABILITY: The array section 'v(21_8:30_8:1_8)' may not be associated with dummy argument 'v=' with VOLATILE attribute, unless the dummy is assumed-shape or assumed-rank [-Warray-section-copy-in-copy-out]
+    !PORTABILITY: The array section 'v(21_8:30_8:1_8)' should not be associated with dummy argument 'v=' with VOLATILE attribute, unless the dummy is assumed-shape or assumed-rank [-Wportability]
     call sub(v(21:30))
+    call sub2(v(21:40:2))
+    call sub4(p)
     print *, v
 contains
     subroutine sub(v)
         integer, volatile :: v(10)
         v = 0
     end subroutine sub
+    subroutine sub1(v)
+        integer, volatile :: v(:)
+        v = 0
+    end subroutine sub1
+    subroutine sub2(v)
+        integer :: v(:)
+        !TODO: This should either be an portability warning or copy-in-copy-out warning
+        call sub(v)
+        call sub1(v)
+    end subroutine sub2
+    subroutine sub3(v)
+        integer, pointer :: v(:)
+        v = 0
+    end subroutine sub3
+    subroutine sub4(v)
+        integer, pointer :: v(:)
+        !TODO: This should either be a portability warning or copy-in-copy-out warning
+        call sub(v)
+        call sub1(v)
+        call sub3(v)
+    end subroutine sub4
 end program call45



More information about the flang-commits mailing list