[flang] Extension: accept NULL([MOLD=]) for ALLOCATABLE INTENT(IN) du… (#66256)

…mmy argument

Several compilers accept a null pointer (with or without a MOLD=) as an
actual argument for association with an INTENT(IN) allocatable dummy
argument. At runtime, the allocatable dummy argument appears to be in
the unallocated state. This seems useful, unambiguous, unlikely to
invalidate conforming code, and works with Intel, NAG, & XLF, so it
should be supported with an optional portability warning in this
compiler as well.
This commit is contained in:
Peter Klausler 2023-09-18 12:37:46 -07:00 committed by GitHub
parent f286141149
commit 61d361d69b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 19 deletions

View File

@ -298,6 +298,8 @@ end
* Unrestricted `INTRINSIC` functions are accepted for use in
`PROCEDURE` statements in generic interfaces, as in some other
compilers.
* A `NULL()` pointer is treated as an unallocated allocatable
when associated with an `INTENT(IN)` allocatable dummy argument.
### Extensions supported when enabled by options

View File

@ -37,7 +37,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
DistinguishableSpecifics, DefaultSave, PointerInSeqType, NonCharacterFormat,
SaveMainProgram, SaveBigMainProgramVariables,
DistinctArrayConstructorLengths, PPCVector, RelaxedIntentInChecking,
ForwardRefImplicitNoneData)
ForwardRefImplicitNoneData, NullActualForAllocatable)
// Portability and suspicious usage warnings for conforming code
ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,

View File

@ -661,17 +661,34 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
dummy.attrs.test(characteristics::DummyDataObject::Attr::Optional)};
bool actualIsNull{evaluate::IsNullPointer(actual)};
if (dummyIsAllocatable) {
if (!actualIsAllocatable && !(actualIsNull && dummyIsOptional)) {
if (actualIsAllocatable) {
if (actualIsCoindexed && dummy.intent != common::Intent::In) {
messages.Say(
"ALLOCATABLE %s must have INTENT(IN) to be associated with a coindexed actual argument"_err_en_US,
dummyName);
}
} else if (actualIsNull) {
if (dummyIsOptional) {
} else if (dummy.intent == common::Intent::In) {
// Extension (Intel, NAG, XLF): a NULL() pointer is an acceptable
// actual argument for an INTENT(IN) allocatable dummy, and it
// is treated as an unassociated allocatable.
if (context.languageFeatures().ShouldWarn(
common::LanguageFeature::NullActualForAllocatable)) {
messages.Say(
"Allocatable %s is associated with a null pointer"_port_en_US,
dummyName);
}
} else {
messages.Say(
"A null pointer may not be associated with allocatable %s without INTENT(IN)"_err_en_US,
dummyName);
}
} else {
messages.Say(
"ALLOCATABLE %s must be associated with an ALLOCATABLE actual argument"_err_en_US,
dummyName);
}
if (actualIsAllocatable && actualIsCoindexed &&
dummy.intent != common::Intent::In) {
messages.Say(
"ALLOCATABLE %s must have INTENT(IN) to be associated with a coindexed actual argument"_err_en_US,
dummyName);
}
if (!actualIsCoindexed && actualLastSymbol &&
actualLastSymbol->Corank() != dummy.type.corank()) {
messages.Say(
@ -791,7 +808,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
}
// NULL(MOLD=) checking for non-intrinsic procedures
if (!intrinsic && !dummyIsPointer && !dummyIsOptional && actualIsNull) {
if (!intrinsic && !dummyIsAllocatableOrPointer && !dummyIsOptional &&
actualIsNull) {
messages.Say(
"Actual argument associated with %s may not be null pointer %s"_err_en_US,
dummyName, actual.AsFortran());
@ -1083,12 +1101,19 @@ static void CheckExplicitInterfaceArg(evaluate::ActualArgument &arg,
} else if (object.attrs.test(characteristics::DummyDataObject::
Attr::Allocatable) &&
evaluate::IsNullPointer(*expr)) {
// Unsupported extension that more or less naturally falls
// out of other Fortran implementations that pass separate
// base address and descriptor address physical arguments
messages.Say(
"Null actual argument '%s' may not be associated with allocatable %s"_err_en_US,
expr->AsFortran(), dummyName);
if (object.intent == common::Intent::In) {
// Extension (Intel, NAG, XLF); see CheckExplicitDataArg.
if (context.languageFeatures().ShouldWarn(common::
LanguageFeature::NullActualForAllocatable)) {
messages.Say(
"Allocatable %s is associated with NULL()"_port_en_US,
dummyName);
}
} else {
messages.Say(
"NULL() actual argument '%s' may not be associated with allocatable %s without INTENT(IN)"_err_en_US,
expr->AsFortran(), dummyName);
}
} else {
messages.Say(
"Actual argument '%s' associated with %s is not a variable or typed expression"_err_en_US,

View File

@ -1,10 +1,10 @@
! RUN: %python %S/test_errors.py %s %flang_fc1
! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic
! Catch NULL() actual argument association with allocatable dummy argument
program test
!ERROR: Null actual argument 'NULL()' may not be associated with allocatable dummy argument 'a='
!ERROR: NULL() actual argument 'NULL()' may not be associated with allocatable dummy argument 'a=' without INTENT(IN)
call foo1(null())
!ERROR: Null actual argument 'NULL()' may not be associated with allocatable dummy argument 'a='
call foo2(null()) ! perhaps permissible later on user request
!PORTABILITY: Allocatable dummy argument 'a=' is associated with NULL()
call foo2(null())
call foo3(null()) ! ok
contains
subroutine foo1(a)