Skip to content

Commit 9f7aac1

Browse files
authored
[flang] Allow host-associated INTENT(OUT) in specification expr. (#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.
1 parent 8822006 commit 9f7aac1

File tree

5 files changed

+53
-9
lines changed

5 files changed

+53
-9
lines changed

flang/docs/Extensions.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,19 @@ print *, [(j,j=1,10)]
825825
of these values in violation of the restriction in f23 clause 17.11.42 set
826826
the mode to ieee_nearest.
827827

828+
* Some compilers allow an `INTENT(OUT)` dummy argument's value to appear
829+
via host association in a specification expression. A non-host-associated
830+
use is an error because an `INTENT(OUT)` dummy argument's value is not
831+
defined. The argument put forth to accept this usage in a `BLOCK` construct
832+
or inner procedure is that the language in 10.1.11 (specification expressions)
833+
allows any host-associated object to appear, but that's unconvincing
834+
because it would also allow a host-associated `OPTIONAL` dummy argument to
835+
be used in a nested scope, and that doesn't make sense. This compiler
836+
accepts an `INTENT(OUT)` non-`OPTIONAL` host-associated value to appear
837+
in a specification expression via host association with a portability
838+
warning since such values may have become defined by the time the nested
839+
expression's value is required.
840+
828841
## De Facto Standard Features
829842

830843
* `EXTENDS_TYPE_OF()` returns `.TRUE.` if both of its arguments have the

flang/include/flang/Support/Fortran-features.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
7575
VectorSubscriptFinalization, UndefinedFunctionResult, UselessIomsg,
7676
MismatchingDummyProcedure, SubscriptedEmptyArray, UnsignedLiteralTruncation,
7777
CompatibleDeclarationsFromDistinctModules,
78-
NullActualForDefaultIntentAllocatable, UseAssociationIntoSameNameSubprogram)
78+
NullActualForDefaultIntentAllocatable, UseAssociationIntoSameNameSubprogram,
79+
HostAssociatedIntentOutInSpecExpr)
7980

8081
using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
8182
using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;

flang/lib/Evaluate/check-expression.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,8 @@ class CheckSpecificationExprHelper
545545
!IsAllocatable(ultimate) && object &&
546546
(ultimate.test(Symbol::Flag::InDataStmt) ||
547547
object->init().has_value())};
548+
bool hasHostAssociation{
549+
&symbol.owner() != &scope_ || &ultimate.owner() != &scope_};
548550
if (const auto *assoc{
549551
ultimate.detailsIf<semantics::AssocEntityDetails>()}) {
550552
return (*this)(assoc->expr());
@@ -563,16 +565,30 @@ class CheckSpecificationExprHelper
563565
} else if (ultimate.attrs().test(semantics::Attr::OPTIONAL)) {
564566
return "reference to OPTIONAL dummy argument '"s +
565567
ultimate.name().ToString() + "'";
566-
} else if (!inInquiry_ &&
568+
} else if (!inInquiry_ && !hasHostAssociation &&
567569
ultimate.attrs().test(semantics::Attr::INTENT_OUT)) {
568570
return "reference to INTENT(OUT) dummy argument '"s +
569571
ultimate.name().ToString() + "'";
570-
} else if (ultimate.has<semantics::ObjectEntityDetails>()) {
571-
return std::nullopt;
572-
} else {
572+
} else if (!ultimate.has<semantics::ObjectEntityDetails>()) {
573573
return "dummy procedure argument";
574+
} else {
575+
// Sketchy case: some compilers allow an INTENT(OUT) dummy argument
576+
// to be used in a specification expression if it is host-associated.
577+
// The arguments raised in support this usage, however, depend on
578+
// a reading of the standard that would also accept an OPTIONAL
579+
// host-associated dummy argument, and that doesn't seem like a
580+
// good idea.
581+
if (!inInquiry_ && hasHostAssociation &&
582+
ultimate.attrs().test(semantics::Attr::INTENT_OUT) &&
583+
context_.languageFeatures().ShouldWarn(
584+
common::UsageWarning::HostAssociatedIntentOutInSpecExpr)) {
585+
context_.messages().Say(
586+
"specification expression refers to host-associated INTENT(OUT) dummy argument '%s'"_port_en_US,
587+
ultimate.name());
588+
}
589+
return std::nullopt;
574590
}
575-
} else if (&symbol.owner() != &scope_ || &ultimate.owner() != &scope_) {
591+
} else if (hasHostAssociation) {
576592
return std::nullopt; // host association is in play
577593
} else if (isInitialized &&
578594
context_.languageFeatures().IsEnabled(
@@ -582,7 +598,7 @@ class CheckSpecificationExprHelper
582598
common::LanguageFeature::SavedLocalInSpecExpr)) {
583599
context_.messages().Say(common::LanguageFeature::SavedLocalInSpecExpr,
584600
"specification expression refers to local object '%s' (initialized and saved)"_port_en_US,
585-
ultimate.name().ToString());
601+
ultimate.name());
586602
}
587603
return std::nullopt;
588604
} else if (const auto *object{
@@ -831,9 +847,9 @@ bool CheckSpecificationExprHelper::IsPermissibleInquiry(
831847
template <typename A>
832848
void CheckSpecificationExpr(const A &x, const semantics::Scope &scope,
833849
FoldingContext &context, bool forElementalFunctionResult) {
834-
CheckSpecificationExprHelper helper{
850+
CheckSpecificationExprHelper errors{
835851
scope, context, forElementalFunctionResult};
836-
if (auto why{helper(x)}) {
852+
if (auto why{errors(x)}) {
837853
context.messages().Say("Invalid specification expression%s: %s"_err_en_US,
838854
forElementalFunctionResult ? " for elemental function result" : "",
839855
*why);

flang/lib/Support/Fortran-features.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ LanguageFeatureControl::LanguageFeatureControl() {
8686
warnUsage_.set(UsageWarning::UnsignedLiteralTruncation);
8787
warnUsage_.set(UsageWarning::NullActualForDefaultIntentAllocatable);
8888
warnUsage_.set(UsageWarning::UseAssociationIntoSameNameSubprogram);
89+
warnUsage_.set(UsageWarning::HostAssociatedIntentOutInSpecExpr);
8990
// New warnings, on by default
9091
warnLanguage_.set(LanguageFeature::SavedLocalInSpecExpr);
9192
warnLanguage_.set(LanguageFeature::NullActualForAllocatable);

flang/test/Semantics/spec-expr.f90

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ subroutine s2(inArg, inoutArg, outArg, optArg)
2828
real, dimension(optArg) :: realVar4
2929

3030
outArg = 3
31+
block
32+
!PORTABILITY: specification expression refers to host-associated INTENT(OUT) dummy argument 'outarg'
33+
real a(outArg)
34+
!ERROR: Invalid specification expression: reference to OPTIONAL dummy argument 'optarg'
35+
real b(optArg)
36+
end block
37+
contains
38+
subroutine s2inner
39+
!PORTABILITY: specification expression refers to host-associated INTENT(OUT) dummy argument 'outarg'
40+
real a(outArg)
41+
!ERROR: Invalid specification expression: reference to OPTIONAL dummy argument 'optarg'
42+
real b(optArg)
43+
end
3144
end subroutine s2
3245

3346
! an object designator with a base object that is in a common block,

0 commit comments

Comments
 (0)