Skip to content

[flang] Add warnings about undefinable actuals for ASYNCHRONOUS/VOLAT… #93851

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
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions flang/docs/Extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,16 @@ end
This enables atomic memory operations to be naturally represented
as `PURE` functions, which allows their use in parallel constructs
and `DO CONCURRENT`.
* A non-definable actual argument, including the case of a vector
subscript, may be associated with an `ASYNCHRONOUS` or `VOLATILE`
dummy argument, F'2023 15.5.2.5 p31 notwithstanding.
The effects of these attributes are scoped over the lifetime of
the procedure reference, and they can by added by internal subprograms
and `BLOCK` constructs within the procedure.
Further, a dummy argument can acquire the `ASYNCHRONOUS` attribute
implicitly simply appearing in an asynchronous data transfer statement,
without the attribute being visible in the procedure's explicit
interface.

## Extensions, deletions, and legacy features supported by default

Expand Down
8 changes: 4 additions & 4 deletions flang/include/flang/Common/Fortran-features.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
EmptySequenceType, NonSequenceCrayPointee, BranchIntoConstruct,
BadBranchTarget, ConvertedArgument, HollerithPolymorphic, ListDirectedSize,
NonBindCInteroperability, CudaManaged, CudaUnified,
PolymorphicActualAllocatableOrPointerToMonomorphicDummy, RelaxedPureDummy)
PolymorphicActualAllocatableOrPointerToMonomorphicDummy, RelaxedPureDummy,
UndefinableAsynchronousOrVolatileActual)

// Portability and suspicious usage warnings
ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
NonTargetPassedToTarget, PointerToPossibleNoncontiguous,
ShortCharacterActual, ShortArrayActual, ExprPassedToVolatile,
ImplicitInterfaceActual, PolymorphicTransferArg,
PointerComponentTransferArg, TransferSizePresence,
ShortCharacterActual, ShortArrayActual, ImplicitInterfaceActual,
PolymorphicTransferArg, PointerComponentTransferArg, TransferSizePresence,
F202XAllocatableBreakingChange, OptionalMustBePresent, CommonBlockPadding,
LogicalVsCBool, BindCCharLength, ProcDummyArgShapes, ExternalNameConflict,
FoldingException, FoldingAvoidsRuntimeCrash, FoldingValueChecks,
Expand Down
65 changes: 35 additions & 30 deletions flang/lib/Semantics/check-call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -652,40 +652,44 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,

// Definability
bool actualIsVariable{evaluate::IsVariable(actual)};
const char *reason{nullptr};
if (dummy.intent == common::Intent::Out) {
reason = "INTENT(OUT)";
} else if (dummy.intent == common::Intent::InOut) {
reason = "INTENT(IN OUT)";
}
if (reason && scope) {
// Problems with polymorphism are caught in the callee's definition.
DefinabilityFlags flags{DefinabilityFlag::PolymorphicOkInPure};
if (isElemental) { // 15.5.2.4(21)
flags.set(DefinabilityFlag::VectorSubscriptIsOk);
}
if (actualIsPointer && dummyIsPointer) { // 19.6.8
flags.set(DefinabilityFlag::PointerDefinition);
if (scope) {
std::optional<parser::MessageFixedText> undefinableMessage;
if (dummy.intent == common::Intent::Out) {
undefinableMessage =
"Actual argument associated with INTENT(OUT) %s is not definable"_err_en_US;
} else if (dummy.intent == common::Intent::InOut) {
undefinableMessage =
"Actual argument associated with INTENT(IN OUT) %s is not definable"_err_en_US;
} else if (context.ShouldWarn(common::LanguageFeature::
UndefinableAsynchronousOrVolatileActual)) {
if (dummy.attrs.test(
characteristics::DummyDataObject::Attr::Asynchronous)) {
undefinableMessage =
"Actual argument associated with ASYNCHRONOUS %s is not definable"_warn_en_US;
} else if (dummy.attrs.test(
characteristics::DummyDataObject::Attr::Volatile)) {
undefinableMessage =
"Actual argument associated with VOLATILE %s is not definable"_warn_en_US;
}
}
if (auto whyNot{WhyNotDefinable(messages.at(), *scope, flags, actual)}) {
if (auto *msg{messages.Say(
"Actual argument associated with %s %s is not definable"_err_en_US,
reason, dummyName)}) {
msg->Attach(std::move(*whyNot));
if (undefinableMessage) {
// Problems with polymorphism are caught in the callee's definition.
DefinabilityFlags flags{DefinabilityFlag::PolymorphicOkInPure};
if (isElemental) { // 15.5.2.4(21)
flags.set(DefinabilityFlag::VectorSubscriptIsOk);
}
if (actualIsPointer && dummyIsPointer) { // 19.6.8
flags.set(DefinabilityFlag::PointerDefinition);
}
if (auto whyNot{WhyNotDefinable(messages.at(), *scope, flags, actual)}) {
if (auto *msg{
messages.Say(std::move(*undefinableMessage), dummyName)}) {
msg->Attach(std::move(*whyNot));
}
}
}
}

// technically legal but worth emitting a warning
// llvm-project issue #58973: constant actual argument passed in where dummy
// argument is marked volatile
if (dummyIsVolatile && !actualIsVariable &&
context.ShouldWarn(common::UsageWarning::ExprPassedToVolatile)) {
messages.Say(
"actual argument associated with VOLATILE %s is not a variable"_warn_en_US,
dummyName);
}

// Cases when temporaries might be needed but must not be permitted.
bool actualIsContiguous{IsSimplyContiguous(actual, foldingContext)};
bool dummyIsAssumedShape{dummy.type.attrs().test(
Expand Down Expand Up @@ -883,7 +887,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
dummyName, actual.AsFortran());
}

// Warn about dubious actual argument association with a TARGET dummy argument
// Warn about dubious actual argument association with a TARGET dummy
// argument
if (dummy.attrs.test(characteristics::DummyDataObject::Attr::Target) &&
context.ShouldWarn(common::UsageWarning::NonTargetPassedToTarget)) {
bool actualIsTemp{!actualIsVariable || HasVectorSubscript(actual) ||
Expand Down
8 changes: 6 additions & 2 deletions flang/test/Semantics/call03.f90
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,12 @@ subroutine test12 ! 15.5.2.4(21)
!ERROR: Actual argument associated with INTENT(IN OUT) dummy argument 'x=' is not definable
!BECAUSE: Variable 'a(int(j,kind=8))' has a vector subscript
call intentinout_arr(a(j))
call asynchronous_arr(a(j)) ! ok
call volatile_arr(a(j)) ! ok
!WARNING: Actual argument associated with ASYNCHRONOUS dummy argument 'x=' is not definable
!BECAUSE: Variable 'a(int(j,kind=8))' has a vector subscript
call asynchronous_arr(a(j))
!WARNING: Actual argument associated with VOLATILE dummy argument 'x=' is not definable
!BECAUSE: Variable 'a(int(j,kind=8))' has a vector subscript
call volatile_arr(a(j))
end subroutine

subroutine coarr(x)
Expand Down
45 changes: 30 additions & 15 deletions flang/test/Semantics/call30.f90
Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,50 @@ subroutine vol_dum_int_arr(my_int_arr)
end subroutine vol_dum_int_arr

subroutine test_all_subprograms()
!WARNING: actual argument associated with VOLATILE dummy argument 'my_int=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_int=' is not definable
!BECAUSE: '6_4' is not a variable or pointer
call vol_dum_int(6)
!WARNING: actual argument associated with VOLATILE dummy argument 'my_int=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_int=' is not definable
!BECAUSE: '18_4' is not a variable or pointer
call vol_dum_int(6+12)
!WARNING: actual argument associated with VOLATILE dummy argument 'my_int=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_int=' is not definable
!BECAUSE: '72_4' is not a variable or pointer
call vol_dum_int(6*12)
!WARNING: actual argument associated with VOLATILE dummy argument 'my_int=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_int=' is not definable
!BECAUSE: '-3_4' is not a variable or pointer
call vol_dum_int(-6/2)
!WARNING: actual argument associated with VOLATILE dummy argument 'my_real=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_real=' is not definable
!BECAUSE: '3.1415927410125732421875_4' is not a variable or pointer
call vol_dum_real(3.141592653)
!WARNING: actual argument associated with VOLATILE dummy argument 'my_real=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_real=' is not definable
!BECAUSE: '3.1415927410125732421875_4' is not a variable or pointer
call vol_dum_real(3.141592653 + (-10.6e-11))
!WARNING: actual argument associated with VOLATILE dummy argument 'my_real=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_real=' is not definable
!BECAUSE: '3.3300884272335906644002534449100494384765625e-10_4' is not a variable or pointer
call vol_dum_real(3.141592653 * 10.6e-11)
!WARNING: actual argument associated with VOLATILE dummy argument 'my_real=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_real=' is not definable
!BECAUSE: '-2.9637666816e10_4' is not a variable or pointer
call vol_dum_real(3.141592653 / (-10.6e-11))
!WARNING: actual argument associated with VOLATILE dummy argument 'my_complex=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_complex=' is not definable
!BECAUSE: '(1._4,3.2000000476837158203125_4)' is not a variable or pointer
call vol_dum_complex((1., 3.2))
!WARNING: actual argument associated with VOLATILE dummy argument 'my_complex=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_complex=' is not definable
!BECAUSE: '(-1._4,6.340000152587890625_4)' is not a variable or pointer
call vol_dum_complex((1., 3.2) + (-2., 3.14))
!WARNING: actual argument associated with VOLATILE dummy argument 'my_complex=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_complex=' is not definable
!BECAUSE: '(-1.2048000335693359375e1_4,-3.2599999904632568359375_4)' is not a variable or pointer
call vol_dum_complex((1., 3.2) * (-2., 3.14))
!WARNING: actual argument associated with VOLATILE dummy argument 'my_complex=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_complex=' is not definable
!BECAUSE: '(5.80680549144744873046875e-1_4,-6.8833148479461669921875e-1_4)' is not a variable or pointer
call vol_dum_complex((1., 3.2) / (-2., 3.14))
!WARNING: actual argument associated with VOLATILE dummy argument 'my_int_arr=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_int_arr=' is not definable
!BECAUSE: '[INTEGER(4)::1_4,2_4,3_4,4_4]' is not a variable or pointer
call vol_dum_int_arr((/ 1, 2, 3, 4 /))
!WARNING: actual argument associated with VOLATILE dummy argument 'my_int_arr=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_int_arr=' is not definable
!BECAUSE: 'reshape([INTEGER(4)::1_4,2_4,3_4,4_4],shape=[2,2])' is not a variable or pointer
call vol_dum_int_arr(reshape((/ 1, 2, 3, 4 /), (/ 2, 2/)))
!WARNING: actual argument associated with VOLATILE dummy argument 'my_int_arr=' is not a variable
!WARNING: Actual argument associated with VOLATILE dummy argument 'my_int_arr=' is not definable
!BECAUSE: '[INTEGER(4)::1_4,2_4,3_4,4_4]' is not a variable or pointer
call vol_dum_int_arr((/ 1, 2, 3, 4 /))
end subroutine test_all_subprograms
end module m
Loading