[flang-commits] [flang] [flang] Fix semantic checks for MOVE_ALLOC (PR #77362)
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Mon Jan 8 11:16:02 PST 2024
https://github.com/klausler created https://github.com/llvm/llvm-project/pull/77362
The checking of calls to the intrinsic subroutine MOVE_ALLOC is not insisting that its first two arguments be whole allocatable variables or components. Fix, move the code into check-calls.cpp (a better home for such things), and clean up the tests.
Fixes https://github.com/llvm/llvm-project/issues/77230.
>From 737dff1ae02e9449b2acc44f6b7cb795d0859062 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Mon, 8 Jan 2024 11:12:48 -0800
Subject: [PATCH] [flang] Fix semantic checks for MOVE_ALLOC
The checking of calls to the intrinsic subroutine MOVE_ALLOC is not
insisting that its first two arguments be whole allocatable variables
or components. Fix, move the code into check-calls.cpp (a better home
for such things), and clean up the tests.
Fixes https://github.com/llvm/llvm-project/issues/77230.
---
flang/include/flang/Evaluate/tools.h | 4 ++
flang/lib/Evaluate/intrinsics.cpp | 62 +++++++---------------------
flang/lib/Evaluate/tools.cpp | 13 ++++++
flang/lib/Semantics/check-call.cpp | 39 +++++++++++++++++
flang/test/Semantics/move_alloc.f90 | 32 ++++++++------
5 files changed, 89 insertions(+), 61 deletions(-)
diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index c0cbb05c009d6b..056bad5e0d6988 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -1192,6 +1192,10 @@ class ArrayConstantBoundChanger {
std::optional<bool> AreEquivalentInInterface(
const Expr<SubscriptInteger> &, const Expr<SubscriptInteger> &);
+bool CheckForCoindexedObject(parser::ContextualMessages &,
+ const std::optional<ActualArgument> &, const std::string &procName,
+ const std::string &argName);
+
} // namespace Fortran::evaluate
namespace Fortran::semantics {
diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index 08cec73d88ced2..da6d5970089884 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -2727,28 +2727,13 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer(
}
}
-static bool CheckForCoindexedObject(FoldingContext &context,
- const std::optional<ActualArgument> &arg, const std::string &procName,
- const std::string &argName) {
- bool ok{true};
- if (arg) {
- if (ExtractCoarrayRef(arg->UnwrapExpr())) {
- ok = false;
- context.messages().Say(arg->sourceLocation(),
- "'%s' argument to '%s' may not be a coindexed object"_err_en_US,
- argName, procName);
- }
- }
- return ok;
-}
-
// Function C_LOC(X) from intrinsic module ISO_C_BINDING (18.2.3.6)
std::optional<SpecificCall> IntrinsicProcTable::Implementation::HandleC_Loc(
ActualArguments &arguments, FoldingContext &context) const {
static const char *const keywords[]{"x", nullptr};
if (CheckAndRearrangeArguments(arguments, context.messages(), keywords)) {
CHECK(arguments.size() == 1);
- CheckForCoindexedObject(context, arguments[0], "c_loc", "x");
+ CheckForCoindexedObject(context.messages(), arguments[0], "c_loc", "x");
const auto *expr{arguments[0].value().UnwrapExpr()};
if (expr &&
!(IsObjectPointer(*expr) ||
@@ -2876,7 +2861,7 @@ static bool CheckAtomicDefineAndRef(FoldingContext &context,
}
return sameType &&
- CheckForCoindexedObject(context, statArg, procName, "stat");
+ CheckForCoindexedObject(context.messages(), statArg, procName, "stat");
}
// Applies any semantic checks peculiar to an intrinsic.
@@ -2900,25 +2885,29 @@ static bool ApplySpecificChecks(SpecificCall &call, FoldingContext &context) {
// Now handled in Semantics/check-call.cpp
} else if (name == "atomic_and" || name == "atomic_or" ||
name == "atomic_xor") {
- return CheckForCoindexedObject(context, call.arguments[2], name, "stat");
+ return CheckForCoindexedObject(
+ context.messages(), call.arguments[2], name, "stat");
} else if (name == "atomic_cas") {
- return CheckForCoindexedObject(context, call.arguments[4], name, "stat");
+ return CheckForCoindexedObject(
+ context.messages(), call.arguments[4], name, "stat");
} else if (name == "atomic_define") {
return CheckAtomicDefineAndRef(
context, call.arguments[0], call.arguments[1], call.arguments[2], name);
} else if (name == "atomic_fetch_add" || name == "atomic_fetch_and" ||
name == "atomic_fetch_or" || name == "atomic_fetch_xor") {
- return CheckForCoindexedObject(context, call.arguments[3], name, "stat");
+ return CheckForCoindexedObject(
+ context.messages(), call.arguments[3], name, "stat");
} else if (name == "atomic_ref") {
return CheckAtomicDefineAndRef(
context, call.arguments[1], call.arguments[0], call.arguments[2], name);
} else if (name == "co_broadcast" || name == "co_max" || name == "co_min" ||
name == "co_sum") {
- bool aOk{CheckForCoindexedObject(context, call.arguments[0], name, "a")};
- bool statOk{
- CheckForCoindexedObject(context, call.arguments[2], name, "stat")};
- bool errmsgOk{
- CheckForCoindexedObject(context, call.arguments[3], name, "errmsg")};
+ bool aOk{CheckForCoindexedObject(
+ context.messages(), call.arguments[0], name, "a")};
+ bool statOk{CheckForCoindexedObject(
+ context.messages(), call.arguments[2], name, "stat")};
+ bool errmsgOk{CheckForCoindexedObject(
+ context.messages(), call.arguments[3], name, "errmsg")};
ok = aOk && statOk && errmsgOk;
} else if (name == "image_status") {
if (const auto &arg{call.arguments[0]}) {
@@ -2935,29 +2924,6 @@ static bool ApplySpecificChecks(SpecificCall &call, FoldingContext &context) {
arg ? arg->sourceLocation() : context.messages().at(),
"Argument of LOC() must be an object or procedure"_err_en_US);
}
- } else if (name == "move_alloc") {
- ok &= CheckForCoindexedObject(context, call.arguments[0], name, "from");
- ok &= CheckForCoindexedObject(context, call.arguments[1], name, "to");
- ok &= CheckForCoindexedObject(context, call.arguments[2], name, "stat");
- ok &= CheckForCoindexedObject(context, call.arguments[3], name, "errmsg");
- if (call.arguments[0] && call.arguments[1]) {
- for (int j{0}; j < 2; ++j) {
- if (const Symbol *last{GetLastSymbol(call.arguments[j])};
- last && !IsAllocatable(last->GetUltimate())) {
- context.messages().Say(call.arguments[j]->sourceLocation(),
- "Argument #%d to MOVE_ALLOC must be allocatable"_err_en_US,
- j + 1);
- ok = false;
- }
- }
- auto type0{call.arguments[0]->GetType()};
- auto type1{call.arguments[1]->GetType()};
- if (type0 && type1 && type0->IsPolymorphic() && !type1->IsPolymorphic()) {
- context.messages().Say(call.arguments[1]->sourceLocation(),
- "When MOVE_ALLOC(FROM=) is polymorphic, TO= must also be polymorphic"_err_en_US);
- ok = false;
- }
- }
} else if (name == "present") {
const auto &arg{call.arguments[0]};
if (arg) {
diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index 7834364bccc400..e57058c7ac1479 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -1353,6 +1353,19 @@ std::optional<bool> AreEquivalentInInterface(
}
}
+bool CheckForCoindexedObject(parser::ContextualMessages &messages,
+ const std::optional<ActualArgument> &arg, const std::string &procName,
+ const std::string &argName) {
+ if (arg && ExtractCoarrayRef(arg->UnwrapExpr())) {
+ messages.Say(arg->sourceLocation(),
+ "'%s' argument to '%s' may not be a coindexed object"_err_en_US,
+ argName, procName);
+ return false;
+ } else {
+ return true;
+ }
+}
+
} // namespace Fortran::evaluate
namespace Fortran::semantics {
diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp
index ec8f99ca6bf48e..a8927e94481d4b 100644
--- a/flang/lib/Semantics/check-call.cpp
+++ b/flang/lib/Semantics/check-call.cpp
@@ -1431,6 +1431,43 @@ static void CheckAssociated(evaluate::ActualArguments &arguments,
}
}
+// MOVE_ALLOC (F'2023 16.9.147)
+static void CheckMove_Alloc(evaluate::ActualArguments &arguments,
+ parser::ContextualMessages &messages) {
+ if (arguments.size() >= 1) {
+ evaluate::CheckForCoindexedObject(
+ messages, arguments[0], "move_alloc", "from");
+ }
+ if (arguments.size() >= 2) {
+ evaluate::CheckForCoindexedObject(
+ messages, arguments[1], "move_alloc", "to");
+ }
+ if (arguments.size() >= 3) {
+ evaluate::CheckForCoindexedObject(
+ messages, arguments[2], "move_alloc", "stat");
+ }
+ if (arguments.size() >= 4) {
+ evaluate::CheckForCoindexedObject(
+ messages, arguments[3], "move_alloc", "errmsg");
+ }
+ if (arguments.size() >= 2 && arguments[0] && arguments[1]) {
+ for (int j{0}; j < 2; ++j) {
+ if (const Symbol *
+ whole{UnwrapWholeSymbolOrComponentDataRef(arguments[j])};
+ !whole || !IsAllocatable(whole->GetUltimate())) {
+ messages.Say(*arguments[j]->sourceLocation(),
+ "Argument #%d to MOVE_ALLOC must be allocatable"_err_en_US, j + 1);
+ }
+ }
+ auto type0{arguments[0]->GetType()};
+ auto type1{arguments[1]->GetType()};
+ if (type0 && type1 && type0->IsPolymorphic() && !type1->IsPolymorphic()) {
+ messages.Say(arguments[1]->sourceLocation(),
+ "When MOVE_ALLOC(FROM=) is polymorphic, TO= must also be polymorphic"_err_en_US);
+ }
+ }
+}
+
// REDUCE (F'2023 16.9.173)
static void CheckReduce(
evaluate::ActualArguments &arguments, evaluate::FoldingContext &context) {
@@ -1639,6 +1676,8 @@ static void CheckSpecificIntrinsic(evaluate::ActualArguments &arguments,
const evaluate::SpecificIntrinsic &intrinsic) {
if (intrinsic.name == "associated") {
CheckAssociated(arguments, context, scope);
+ } else if (intrinsic.name == "move_alloc") {
+ CheckMove_Alloc(arguments, context.foldingContext().messages());
} else if (intrinsic.name == "reduce") {
CheckReduce(arguments, context.foldingContext());
} else if (intrinsic.name == "transfer") {
diff --git a/flang/test/Semantics/move_alloc.f90 b/flang/test/Semantics/move_alloc.f90
index a67fdca9701e5e..3303a002039bb8 100644
--- a/flang/test/Semantics/move_alloc.f90
+++ b/flang/test/Semantics/move_alloc.f90
@@ -1,7 +1,11 @@
! RUN: %python %S/test_errors.py %s %flang_fc1
! Check for semantic errors in move_alloc() subroutine calls
program main
- integer, allocatable :: a(:)[:], b(:)[:], c(:)[:], d(:)[:], f(:)
+ integer, allocatable :: a(:)[:], b(:)[:], f(:), g(:)
+ type alloc_component
+ integer, allocatable :: a(:)
+ end type
+ type(alloc_component) :: c[*], d[*]
!ERROR: 'e' is an ALLOCATABLE coarray and must have a deferred coshape
integer, allocatable :: e(:)[*]
integer status, coindexed_status[*]
@@ -18,42 +22,39 @@ program main
a = [ 1, 2, 3 ]
call move_alloc(a, b, status, message)
- allocate(c(3)[*])
- c = [ 1, 2, 3 ]
-
!ERROR: too many actual arguments for intrinsic 'move_alloc'
call move_alloc(a, b, status, message, 1)
! standards non-conforming
!ERROR: 'from' argument to 'move_alloc' may not be a coindexed object
- call move_alloc(c[1], d)
+ call move_alloc(c[1]%a, f)
!ERROR: 'to' argument to 'move_alloc' may not be a coindexed object
- call move_alloc(c, d[1])
+ call move_alloc(f, d[1]%a)
!ERROR: 'stat' argument to 'move_alloc' may not be a coindexed object
- call move_alloc(c, d, coindexed_status[1])
+ call move_alloc(f, g, coindexed_status[1])
!ERROR: 'errmsg' argument to 'move_alloc' may not be a coindexed object
- call move_alloc(c, d, status, coindexed_message[1])
+ call move_alloc(f, g, status, coindexed_message[1])
!ERROR: 'errmsg' argument to 'move_alloc' may not be a coindexed object
- call move_alloc(c, d, errmsg=coindexed_message[1])
+ call move_alloc(f, g, errmsg=coindexed_message[1])
!ERROR: 'errmsg' argument to 'move_alloc' may not be a coindexed object
- call move_alloc(c, d, errmsg=coindexed_message[1], stat=status)
+ call move_alloc(f, g, errmsg=coindexed_message[1], stat=status)
!ERROR: 'stat' argument to 'move_alloc' may not be a coindexed object
- call move_alloc(c, d, stat=coindexed_status[1])
+ call move_alloc(f, g, stat=coindexed_status[1])
!ERROR: 'stat' argument to 'move_alloc' may not be a coindexed object
- call move_alloc(c, d, errmsg=message, stat=coindexed_status[1])
+ call move_alloc(f, g, errmsg=message, stat=coindexed_status[1])
!ERROR: 'from' argument to 'move_alloc' may not be a coindexed object
!ERROR: 'to' argument to 'move_alloc' may not be a coindexed object
!ERROR: 'stat' argument to 'move_alloc' may not be a coindexed object
!ERROR: 'errmsg' argument to 'move_alloc' may not be a coindexed object
- call move_alloc(c[1], d[1], stat=coindexed_status[1], errmsg=coindexed_message[1])
+ call move_alloc(c[1]%a, d[1]%a, stat=coindexed_status[1], errmsg=coindexed_message[1])
!ERROR: Argument #1 to MOVE_ALLOC must be allocatable
call move_alloc(nonAllocatable, f)
@@ -67,4 +68,9 @@ program main
!ERROR: Actual argument for 'to=' has bad type or kind 'CHARACTER(KIND=1,LEN=3_8)'
call move_alloc(ca, cb)
+ !ERROR: Argument #1 to MOVE_ALLOC must be allocatable
+ call move_alloc(f(::2), g)
+ !ERROR: Argument #2 to MOVE_ALLOC must be allocatable
+ call move_alloc(f, g(::2))
+
end program main
More information about the flang-commits
mailing list