[flang] Warn about dangerous actual argument association with TARGET dummy arguments
authorPeter Klausler <pklausler@nvidia.com>
Tue, 14 Feb 2023 22:58:34 +0000 (14:58 -0800)
committerPeter Klausler <pklausler@nvidia.com>
Thu, 2 Mar 2023 17:16:14 +0000 (09:16 -0800)
The actual argument associated with a dummy argument with the TARGET attribute is
not required to be itself a target or pointer, or even to be a variable, but in
those cases, any pointer that is associated with the dummy argument during the
execution of the procedure is either going to be invalid afterwards because it
points to temporary storage that has since been deallocated or an optimization
time bomb because it aliases an object that isn't a target.  Add warnings for
these cases.

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

flang/lib/Semantics/check-call.cpp
flang/test/Semantics/call34.f90 [new file with mode: 0644]

index 23595dd..b5d912b 100644 (file)
@@ -441,7 +441,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
   // technically legal but worth emitting a warning
   // llvm-project issue #58973: constant actual argument passed in where dummy
   // argument is marked volatile
-  if (dummyIsVolatile && !IsVariable(actual)) {
+  bool actualIsVariable{evaluate::IsVariable(actual)};
+  if (dummyIsVolatile && !actualIsVariable) {
     messages.Say(
         "actual argument associated with VOLATILE %s is not a variable"_warn_en_US,
         dummyName);
@@ -599,6 +600,24 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
         "Actual argument associated with %s may not be null pointer %s"_err_en_US,
         dummyName, actual.AsFortran());
   }
+
+  // Warn about dubious actual argument association with a TARGET dummy argument
+  if (dummy.attrs.test(characteristics::DummyDataObject::Attr::Target)) {
+    bool actualIsTemp{!actualIsVariable || HasVectorSubscript(actual) ||
+        evaluate::ExtractCoarrayRef(actual)};
+    if (actualIsTemp) {
+      messages.Say(
+          "Any pointer associated with TARGET %s during this call will not be associated with the value of '%s' afterwards"_warn_en_US,
+          dummyName, actual.AsFortran());
+    } else {
+      auto actualSymbolVector{GetSymbolVector(actual)};
+      if (!evaluate::GetLastTarget(actualSymbolVector)) {
+        messages.Say(
+            "Any pointer associated with TARGET %s during this call must not be used afterwards, as '%s' is not a target"_warn_en_US,
+            dummyName, actual.AsFortran());
+      }
+    }
+  }
 }
 
 static void CheckProcedureArg(evaluate::ActualArgument &arg,
diff --git a/flang/test/Semantics/call34.f90 b/flang/test/Semantics/call34.f90
new file mode 100644 (file)
index 0000000..4f939f2
--- /dev/null
@@ -0,0 +1,22 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -Werror
+module m
+ contains
+  subroutine foo(a)
+    real, intent(in), target :: a(:)
+  end subroutine
+end module
+
+program test
+  use m
+  real, target :: a(1)
+  real :: b(1)
+  call foo(a) ! ok
+  !WARNING: Any pointer associated with TARGET dummy argument 'a=' during this call must not be used afterwards, as 'b' is not a target
+  call foo(b)
+  !WARNING: Any pointer associated with TARGET dummy argument 'a=' during this call will not be associated with the value of '(a)' afterwards
+  call foo((a))
+  !WARNING: Any pointer associated with TARGET dummy argument 'a=' during this call will not be associated with the value of 'a([INTEGER(8)::1_8])' afterwards
+  call foo(a([1]))
+  !ERROR: Scalar actual argument may not be associated with assumed-shape dummy argument 'a='
+  call foo(a(1))
+end