Skip to content

[flang] Allow host-associated INTENT(OUT) in specification expr. #135426

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

Merged
merged 1 commit into from
Apr 14, 2025

Conversation

klausler
Copy link
Contributor

Nearly, but not all, other compilers have a blanket prohibition against the use of an INTENT(OUT) dummy argument in a specification expression. Some compilers, however, permit an INTENT(OUT) dummy argument to appear in a specification expression in a BLOCK construct or inner procedure via host association.

The argument some have put forth to accept this usage comes from a reading of 10.1.11 (specification expressions) in Fortran 2023 that, if followed consistently, would also require host-associated OPTIONAL dummy argument to be allowed. That would be dangerous for reasons that should be obvious.

However, I can agree that a non-OPTIONAL dummy argument can't be assumed to remain undefined on entry to a BLOCK construct or inner procedure, so we can accept host-associated INTENT(OUT) in specification expressions with a portability warning.

Nearly, but not all, other compilers have a blanket prohibition
against the use of an INTENT(OUT) dummy argument in a specification
expression.  Some compilers, however, permit an INTENT(OUT) dummy
argument to appear in a specification expression in a BLOCK construct
or inner procedure via host association.

The argument some have put forth to accept this usage comes from
a reading of 10.1.11 (specification expressions) in Fortran 2023
that, if followed consistently, would also require host-associated
OPTIONAL dummy argument to be allowed.  That would be dangerous
for reasons that should be obvious.

However, I can agree that a non-OPTIONAL dummy argument can't be
assumed to remain undefined on entry to a BLOCK construct or inner
procedure, so we can accept host-associated INTENT(OUT) in specification
expressions with a portability warning.
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:semantics labels Apr 11, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 11, 2025

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

Changes

Nearly, but not all, other compilers have a blanket prohibition against the use of an INTENT(OUT) dummy argument in a specification expression. Some compilers, however, permit an INTENT(OUT) dummy argument to appear in a specification expression in a BLOCK construct or inner procedure via host association.

The argument some have put forth to accept this usage comes from a reading of 10.1.11 (specification expressions) in Fortran 2023 that, if followed consistently, would also require host-associated OPTIONAL dummy argument to be allowed. That would be dangerous for reasons that should be obvious.

However, I can agree that a non-OPTIONAL dummy argument can't be assumed to remain undefined on entry to a BLOCK construct or inner procedure, so we can accept host-associated INTENT(OUT) in specification expressions with a portability warning.


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

5 Files Affected:

  • (modified) flang/docs/Extensions.md (+13)
  • (modified) flang/include/flang/Support/Fortran-features.h (+2-1)
  • (modified) flang/lib/Evaluate/check-expression.cpp (+24-8)
  • (modified) flang/lib/Support/Fortran-features.cpp (+1)
  • (modified) flang/test/Semantics/spec-expr.f90 (+13)
diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index d781dee75e07e..05e21ef2d33b5 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -825,6 +825,19 @@ print *, [(j,j=1,10)]
   of these values in violation of the restriction in f23 clause 17.11.42 set
   the mode to ieee_nearest.
 
+* Some compilers allow an `INTENT(OUT)` dummy argument's value to appear
+  via host association in a specification expression.  A non-host-associated
+  use is an error because an `INTENT(OUT)` dummy argument's value is not
+  defined.  The argument put forth to accept this usage in a `BLOCK` construct
+  or inner procedure is that the language in 10.1.11 (specification expressions)
+  allows any host-associated object to appear, but that's unconvincing
+  because it would also allow a host-associated `OPTIONAL` dummy argument to
+  be used in a nested scope, and that doesn't make sense.  This compiler
+  accepts an `INTENT(OUT)` non-`OPTIONAL` host-associated value to appear
+  in a specification expression via host association with a portability
+  warning since such values may have become defined by the time the nested
+  expression's value is required.
+
 ## De Facto Standard Features
 
 * `EXTENDS_TYPE_OF()` returns `.TRUE.` if both of its arguments have the
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index 335273100d70e..5b22313754a0f 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -75,7 +75,8 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
     VectorSubscriptFinalization, UndefinedFunctionResult, UselessIomsg,
     MismatchingDummyProcedure, SubscriptedEmptyArray, UnsignedLiteralTruncation,
     CompatibleDeclarationsFromDistinctModules,
-    NullActualForDefaultIntentAllocatable, UseAssociationIntoSameNameSubprogram)
+    NullActualForDefaultIntentAllocatable, UseAssociationIntoSameNameSubprogram,
+    HostAssociatedIntentOutInSpecExpr)
 
 using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
 using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index 4d272795ff9bd..78268cd13377a 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -545,6 +545,8 @@ class CheckSpecificationExprHelper
         !IsAllocatable(ultimate) && object &&
         (ultimate.test(Symbol::Flag::InDataStmt) ||
             object->init().has_value())};
+    bool hasHostAssociation{
+        &symbol.owner() != &scope_ || &ultimate.owner() != &scope_};
     if (const auto *assoc{
             ultimate.detailsIf<semantics::AssocEntityDetails>()}) {
       return (*this)(assoc->expr());
@@ -563,16 +565,30 @@ class CheckSpecificationExprHelper
       } else if (ultimate.attrs().test(semantics::Attr::OPTIONAL)) {
         return "reference to OPTIONAL dummy argument '"s +
             ultimate.name().ToString() + "'";
-      } else if (!inInquiry_ &&
+      } else if (!inInquiry_ && !hasHostAssociation &&
           ultimate.attrs().test(semantics::Attr::INTENT_OUT)) {
         return "reference to INTENT(OUT) dummy argument '"s +
             ultimate.name().ToString() + "'";
-      } else if (ultimate.has<semantics::ObjectEntityDetails>()) {
-        return std::nullopt;
-      } else {
+      } else if (!ultimate.has<semantics::ObjectEntityDetails>()) {
         return "dummy procedure argument";
+      } else {
+        // Sketchy case: some compilers allow an INTENT(OUT) dummy argument
+        // to be used in a specification expression if it is host-associated.
+        // The arguments raised in support this usage, however, depend on
+        // a reading of the standard that would also accept an OPTIONAL
+        // host-associated dummy argument, and that doesn't seem like a
+        // good idea.
+        if (!inInquiry_ && hasHostAssociation &&
+            ultimate.attrs().test(semantics::Attr::INTENT_OUT) &&
+            context_.languageFeatures().ShouldWarn(
+                common::UsageWarning::HostAssociatedIntentOutInSpecExpr)) {
+          context_.messages().Say(
+              "specification expression refers to host-associated INTENT(OUT) dummy argument '%s'"_port_en_US,
+              ultimate.name());
+        }
+        return std::nullopt;
       }
-    } else if (&symbol.owner() != &scope_ || &ultimate.owner() != &scope_) {
+    } else if (hasHostAssociation) {
       return std::nullopt; // host association is in play
     } else if (isInitialized &&
         context_.languageFeatures().IsEnabled(
@@ -582,7 +598,7 @@ class CheckSpecificationExprHelper
               common::LanguageFeature::SavedLocalInSpecExpr)) {
         context_.messages().Say(common::LanguageFeature::SavedLocalInSpecExpr,
             "specification expression refers to local object '%s' (initialized and saved)"_port_en_US,
-            ultimate.name().ToString());
+            ultimate.name());
       }
       return std::nullopt;
     } else if (const auto *object{
@@ -831,9 +847,9 @@ bool CheckSpecificationExprHelper::IsPermissibleInquiry(
 template <typename A>
 void CheckSpecificationExpr(const A &x, const semantics::Scope &scope,
     FoldingContext &context, bool forElementalFunctionResult) {
-  CheckSpecificationExprHelper helper{
+  CheckSpecificationExprHelper errors{
       scope, context, forElementalFunctionResult};
-  if (auto why{helper(x)}) {
+  if (auto why{errors(x)}) {
     context.messages().Say("Invalid specification expression%s: %s"_err_en_US,
         forElementalFunctionResult ? " for elemental function result" : "",
         *why);
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 4f1af27231301..b3cb62e62f5fb 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -86,6 +86,7 @@ LanguageFeatureControl::LanguageFeatureControl() {
   warnUsage_.set(UsageWarning::UnsignedLiteralTruncation);
   warnUsage_.set(UsageWarning::NullActualForDefaultIntentAllocatable);
   warnUsage_.set(UsageWarning::UseAssociationIntoSameNameSubprogram);
+  warnUsage_.set(UsageWarning::HostAssociatedIntentOutInSpecExpr);
   // New warnings, on by default
   warnLanguage_.set(LanguageFeature::SavedLocalInSpecExpr);
   warnLanguage_.set(LanguageFeature::NullActualForAllocatable);
diff --git a/flang/test/Semantics/spec-expr.f90 b/flang/test/Semantics/spec-expr.f90
index 9d209c3583b43..28ebea1109f1d 100644
--- a/flang/test/Semantics/spec-expr.f90
+++ b/flang/test/Semantics/spec-expr.f90
@@ -28,6 +28,19 @@ subroutine s2(inArg, inoutArg, outArg, optArg)
   real, dimension(optArg) :: realVar4
 
   outArg = 3
+  block
+    !PORTABILITY: specification expression refers to host-associated INTENT(OUT) dummy argument 'outarg'
+    real a(outArg)
+    !ERROR: Invalid specification expression: reference to OPTIONAL dummy argument 'optarg'
+    real b(optArg)
+  end block
+ contains
+  subroutine s2inner
+    !PORTABILITY: specification expression refers to host-associated INTENT(OUT) dummy argument 'outarg'
+    real a(outArg)
+    !ERROR: Invalid specification expression: reference to OPTIONAL dummy argument 'optarg'
+    real b(optArg)
+  end
 end subroutine s2
 
 ! an object designator with a base object that is in a common block,

Copy link
Contributor

@mleair mleair left a comment

Choose a reason for hiding this comment

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

LGTM

@klausler klausler merged commit 9f7aac1 into llvm:main Apr 14, 2025
15 checks passed
@klausler klausler deleted the intent-out branch April 14, 2025 16:00
var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
…m#135426)

Nearly, but not all, other compilers have a blanket prohibition against
the use of an INTENT(OUT) dummy argument in a specification expression.
Some compilers, however, permit an INTENT(OUT) dummy argument to appear
in a specification expression in a BLOCK construct or inner procedure
via host association.

The argument some have put forth to accept this usage comes from a
reading of 10.1.11 (specification expressions) in Fortran 2023 that, if
followed consistently, would also require host-associated OPTIONAL dummy
argument to be allowed. That would be dangerous for reasons that should
be obvious.

However, I can agree that a non-OPTIONAL dummy argument can't be assumed
to remain undefined on entry to a BLOCK construct or inner procedure, so
we can accept host-associated INTENT(OUT) in specification expressions
with a portability warning.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants