diff --git a/flang/include/flang/Common/Fortran-features.h b/flang/include/flang/Common/Fortran-features.h --- a/flang/include/flang/Common/Fortran-features.h +++ b/flang/include/flang/Common/Fortran-features.h @@ -36,7 +36,7 @@ ForwardRefImplicitNone, OpenAccessAppend, BOZAsDefaultInteger, DistinguishableSpecifics, DefaultSave, PointerInSeqType, NonCharacterFormat, SaveMainProgram, SaveBigMainProgramVariables, - DistinctArrayConstructorLengths, PPCVector) + DistinctArrayConstructorLengths, PPCVector, RelaxedIntentInChecking) // Portability and suspicious usage warnings for conforming code ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable, diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp --- a/flang/lib/Semantics/check-call.cpp +++ b/flang/lib/Semantics/check-call.cpp @@ -526,30 +526,49 @@ } // 15.5.2.5 -- actual & dummy are both POINTER or both ALLOCATABLE - if ((actualIsPointer && dummyIsPointer) || + // For INTENT(IN) we relax two checks that are in Fortran to + // prevent the callee from changing the type or to avoid having + // to use a descriptor. + if (!typesCompatible) { + // Don't pile on the errors emitted above + } else if ((actualIsPointer && dummyIsPointer) || (actualIsAllocatable && dummyIsAllocatable)) { bool actualIsUnlimited{actualType.type().IsUnlimitedPolymorphic()}; bool dummyIsUnlimited{dummy.type.type().IsUnlimitedPolymorphic()}; if (actualIsUnlimited != dummyIsUnlimited) { - if (typesCompatible) { + if (dummyIsUnlimited && dummy.intent == common::Intent::In && + context.IsEnabled(common::LanguageFeature::RelaxedIntentInChecking)) { + if (context.ShouldWarn( + common::LanguageFeature::RelaxedIntentInChecking)) { + messages.Say( + "If a POINTER or ALLOCATABLE dummy or actual argument is unlimited polymorphic, both should be so"_port_en_US); + } + } else { messages.Say( "If a POINTER or ALLOCATABLE dummy or actual argument is unlimited polymorphic, both must be so"_err_en_US); } } else if (dummyIsPolymorphic != actualIsPolymorphic) { - if (dummy.intent == common::Intent::In && typesCompatible) { - // extension: allow with warning, rule is only relevant for definables - messages.Say( - "If a POINTER or ALLOCATABLE dummy or actual argument is polymorphic, both should be so"_port_en_US); + if (dummyIsPolymorphic && dummy.intent == common::Intent::In && + context.IsEnabled(common::LanguageFeature::RelaxedIntentInChecking)) { + if (context.ShouldWarn( + common::LanguageFeature::RelaxedIntentInChecking)) { + messages.Say( + "If a POINTER or ALLOCATABLE dummy or actual argument is polymorphic, both should be so"_port_en_US); + } } else { messages.Say( "If a POINTER or ALLOCATABLE dummy or actual argument is polymorphic, both must be so"_err_en_US); } - } else if (!actualIsUnlimited && typesCompatible) { + } else if (!actualIsUnlimited) { if (!actualType.type().IsTkCompatibleWith(dummy.type.type())) { - if (dummy.intent == common::Intent::In) { - // extension: allow with warning, rule is only relevant for definables - messages.Say( - "POINTER or ALLOCATABLE dummy and actual arguments should have the same declared type and kind"_port_en_US); + if (dummy.intent == common::Intent::In && + context.IsEnabled( + common::LanguageFeature::RelaxedIntentInChecking)) { + if (context.ShouldWarn( + common::LanguageFeature::RelaxedIntentInChecking)) { + messages.Say( + "POINTER or ALLOCATABLE dummy and actual arguments should have the same declared type and kind"_port_en_US); + } } else { messages.Say( "POINTER or ALLOCATABLE dummy and actual arguments must have the same declared type and kind"_err_en_US); diff --git a/flang/test/Semantics/call36.f90 b/flang/test/Semantics/call36.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/call36.f90 @@ -0,0 +1,25 @@ +! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic +! Test the RelaxedIntentInChecking extension +module m + contains + subroutine intentInUnlimited(x) + class(*), dimension(..), pointer, intent(in) :: x + end + subroutine intentInOutUnlimited(x) + class(*), dimension(..), pointer, intent(in out) :: x + end + subroutine test + integer, target :: scalar + real, pointer :: arrayptr(:) + class(*), pointer :: unlimited(:) + call intentInUnlimited(scalar) + !ERROR: Actual argument associated with POINTER dummy argument 'x=' must also be POINTER unless INTENT(IN) + call intentInOutUnlimited(scalar) + !PORTABILITY: If a POINTER or ALLOCATABLE dummy or actual argument is unlimited polymorphic, both should be so + call intentInUnlimited(arrayptr) + !ERROR: If a POINTER or ALLOCATABLE dummy or actual argument is unlimited polymorphic, both must be so + call intentInOutUnlimited(arrayptr) + call intentInUnlimited(unlimited) ! ok + call intentInOutUnlimited(unlimited) ! ok + end +end