[flang-commits] [flang] [flang] Fix: Reject OPTIONAL dummy arguments for DIM in ALL/ANY/COUNT (PR #171971)

Sairudra More via flang-commits flang-commits at lists.llvm.org
Thu Dec 11 23:16:35 PST 2025


https://github.com/Saieiei created https://github.com/llvm/llvm-project/pull/171971

Flang was incorrectly accepting OPTIONAL dummy arguments for the DIM parameter in intrinsic functions ALL, ANY, and COUNT. This violates the Fortran 2018 standard (Section 16.9.5) which explicitly requires that the DIM argument must not be an OPTIONAL dummy argument.

The root cause was a conditional check that only validated DIM arguments when the intrinsic parameter was marked as 'required'. However, ALL/ANY/COUNT define their DIM parameter as 'optional' (meaning the parameter itself is optional in the call), which prevented the OPTIONAL validation from running.

This fix removes the incorrect gate and properly checks whether the actual argument is an OPTIONAL dummy, issuing an error and rejecting the call as required by the standard.

Also updated test expectations in dim01.f90 to expect errors instead of warnings for OPTIONAL DIM arguments.

>From 961a0ae11fbffbb5eafe7068b5def2481b338d8f Mon Sep 17 00:00:00 2001
From: Saieiei <sairudra60 at gmail.com>
Date: Fri, 12 Dec 2025 00:30:11 -0600
Subject: [PATCH] [flang] Fix: Reject OPTIONAL dummy arguments for DIM in
 ALL/ANY/COUNT

Flang was incorrectly accepting OPTIONAL dummy arguments for the DIM
parameter in intrinsic functions ALL, ANY, and COUNT. This violates the
Fortran 2018 standard (Section 16.9.5) which explicitly requires that
the DIM argument must not be an OPTIONAL dummy argument.

The root cause was a conditional check that only validated DIM arguments
when the intrinsic parameter was marked as 'required'. However, ALL/ANY/COUNT
define their DIM parameter as 'optional' (meaning the parameter itself is
optional in the call), which prevented the OPTIONAL validation from running.

This fix removes the incorrect gate and properly checks whether the actual
argument is an OPTIONAL dummy, issuing an error and rejecting the call as
required by the standard.

Also updated test expectations in dim01.f90 to expect errors instead of
warnings for OPTIONAL DIM arguments.

Fixes: CPE-9659
---
 flang/lib/Evaluate/intrinsics.cpp | 38 ++++++++++++++++++-------------
 flang/test/Semantics/dim01.f90    | 16 ++++++-------
 2 files changed, 30 insertions(+), 24 deletions(-)

diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index da39f199cab43..142bd56269381 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -1914,7 +1914,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
   // arguments in a procedure reference.
   std::size_t dummyArgPatterns{0};
   for (; dummyArgPatterns < maxArguments && dummy[dummyArgPatterns].keyword;
-       ++dummyArgPatterns) {
+      ++dummyArgPatterns) {
   }
   // MAX and MIN (and others that map to them) allow their last argument to
   // be repeated indefinitely.  The actualForDummy vector is sized
@@ -2663,17 +2663,23 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
     case Rank::dimRemovedOrScalar:
     case Rank::locReduced:
     case Rank::scalarIfDim:
-      if (dummy[*dimArg].optionality == Optionality::required) {
-        if (const Symbol *whole{
-                UnwrapWholeSymbolOrComponentDataRef(actualForDummy[*dimArg])}) {
-          if (IsOptional(*whole) || IsAllocatableOrObjectPointer(whole)) {
-            if (rank == Rank::scalarIfDim || arrayRank.value_or(-1) == 1) {
-              context.Warn(common::UsageWarning::OptionalMustBePresent,
-                  "The actual argument for DIM= is optional, pointer, or allocatable, and it is assumed to be present and equal to 1 at execution time"_warn_en_US);
-            } else {
-              context.Warn(common::UsageWarning::OptionalMustBePresent,
-                  "The actual argument for DIM= is optional, pointer, or allocatable, and may not be absent during execution; parenthesize to silence this warning"_warn_en_US);
-            }
+      // Check if the actual argument for DIM is an OPTIONAL dummy argument
+      if (const Symbol *whole{
+              UnwrapWholeSymbolOrComponentDataRef(actualForDummy[*dimArg])}) {
+        if (IsOptional(*whole)) {
+          // Fortran 2018 standard: The DIM argument to ALL, ANY, COUNT, etc.
+          // must not be an OPTIONAL dummy argument
+          messages.Say(
+              "The actual argument for DIM= must not be OPTIONAL"_err_en_US);
+          return std::nullopt;
+        } else if (dummy[*dimArg].optionality == Optionality::required &&
+            IsAllocatableOrObjectPointer(whole)) {
+          if (rank == Rank::scalarIfDim || arrayRank.value_or(-1) == 1) {
+            context.Warn(common::UsageWarning::OptionalMustBePresent,
+                "The actual argument for DIM= is pointer or allocatable, and it is assumed to be present and equal to 1 at execution time"_warn_en_US);
+          } else {
+            context.Warn(common::UsageWarning::OptionalMustBePresent,
+                "The actual argument for DIM= is pointer or allocatable, and may not be absent during execution; parenthesize to silence this warning"_warn_en_US);
           }
         }
       }
@@ -2739,7 +2745,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
   // Rearrange the actual arguments into dummy argument order.
   ActualArguments rearranged(dummies);
   for (std::size_t j{0}; j < dummies; ++j) {
-    if (ActualArgument *arg{actualForDummy[j]}) {
+    if (ActualArgument * arg{actualForDummy[j]}) {
       rearranged[j] = std::move(*arg);
     }
   }
@@ -3636,7 +3642,7 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
   parser::Messages specificBuffer;
   auto specificRange{specificFuncs_.equal_range(call.name)};
   for (auto specIter{specificRange.first}; specIter != specificRange.second;
-       ++specIter) {
+      ++specIter) {
     // We only need to check the cases with distinct generic names.
     if (const char *genericName{specIter->second->generic}) {
       if (auto specificCall{
@@ -3658,13 +3664,13 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
   if (context.languageFeatures().IsEnabled(common::LanguageFeature::
               UseGenericIntrinsicWhenSpecificDoesntMatch)) {
     for (auto specIter{specificRange.first}; specIter != specificRange.second;
-         ++specIter) {
+        ++specIter) {
       // We only need to check the cases with distinct generic names.
       if (const char *genericName{specIter->second->generic}) {
         if (specIter->second->useGenericAndForceResultType) {
           auto genericRange{genericFuncs_.equal_range(genericName)};
           for (auto genIter{genericRange.first}; genIter != genericRange.second;
-               ++genIter) {
+              ++genIter) {
             if (auto specificCall{
                     matchOrBufferMessages(*genIter->second, specificBuffer)}) {
               // Force the call result type to the specific intrinsic result
diff --git a/flang/test/Semantics/dim01.f90 b/flang/test/Semantics/dim01.f90
index c00cd39ecd097..6a29cdba81dbd 100644
--- a/flang/test/Semantics/dim01.f90
+++ b/flang/test/Semantics/dim01.f90
@@ -16,21 +16,21 @@ function f0b(a)
   function f1(a,d)
     real, intent(in) :: a(:)
     integer, optional, intent(in) :: d
-    !PORTABILITY: The actual argument for DIM= is optional, pointer, or allocatable, and it is assumed to be present and equal to 1 at execution time [-Woptional-must-be-present]
+    !ERROR: The actual argument for DIM= must not be OPTIONAL
     f1 = sum(a,dim=d)
-    !PORTABILITY: The actual argument for DIM= is optional, pointer, or allocatable, and it is assumed to be present and equal to 1 at execution time [-Woptional-must-be-present]
+    !ERROR: The actual argument for DIM= must not be OPTIONAL
     f1 = norm2(a,dim=d)
   end function
   function f2(a,d)
     real, intent(in) :: a(:)
     integer, pointer, intent(in) :: d
-    !PORTABILITY: The actual argument for DIM= is optional, pointer, or allocatable, and it is assumed to be present and equal to 1 at execution time [-Woptional-must-be-present]
+    !PORTABILITY: The actual argument for DIM= is pointer or allocatable, and it is assumed to be present and equal to 1 at execution time [-Woptional-must-be-present]
     f2 = sum(a,dim=d)
   end function
   function f3(a,d)
     real, intent(in) :: a(:)
     integer, allocatable, intent(in) :: d
-    !PORTABILITY: The actual argument for DIM= is optional, pointer, or allocatable, and it is assumed to be present and equal to 1 at execution time [-Woptional-must-be-present]
+    !PORTABILITY: The actual argument for DIM= is pointer or allocatable, and it is assumed to be present and equal to 1 at execution time [-Woptional-must-be-present]
     f3 = sum(a,dim=d)
   end function
   function f10a(a)
@@ -49,23 +49,23 @@ function f11(a,d)
     real, intent(in) :: a(:,:)
     integer, optional, intent(in) :: d
     real, allocatable :: f11(:)
-    !WARNING: The actual argument for DIM= is optional, pointer, or allocatable, and may not be absent during execution; parenthesize to silence this warning [-Woptional-must-be-present]
+    !ERROR: The actual argument for DIM= must not be OPTIONAL
     f11 = sum(a,dim=d)
-    !WARNING: The actual argument for DIM= is optional, pointer, or allocatable, and may not be absent during execution; parenthesize to silence this warning [-Woptional-must-be-present]
+    !ERROR: The actual argument for DIM= must not be OPTIONAL
     f11 = norm2(a,dim=d)
   end function
   function f12(a,d)
     real, intent(in) :: a(:,:)
     integer, pointer, intent(in) :: d
     real, allocatable :: f12(:)
-    !WARNING: The actual argument for DIM= is optional, pointer, or allocatable, and may not be absent during execution; parenthesize to silence this warning [-Woptional-must-be-present]
+    !WARNING: The actual argument for DIM= is pointer or allocatable, and may not be absent during execution; parenthesize to silence this warning [-Woptional-must-be-present]
     f12 = sum(a,dim=d)
   end function
   function f13(a,d)
     real, intent(in) :: a(:,:)
     integer, allocatable, intent(in) :: d
     real, allocatable :: f13(:)
-    !WARNING: The actual argument for DIM= is optional, pointer, or allocatable, and may not be absent during execution; parenthesize to silence this warning [-Woptional-must-be-present]
+    !WARNING: The actual argument for DIM= is pointer or allocatable, and may not be absent during execution; parenthesize to silence this warning [-Woptional-must-be-present]
     f13 = sum(a,dim=d)
   end function
 end module



More information about the flang-commits mailing list