[flang] Accept initialized SAVE local in specification expression (#107656)

Specification expressions may contain references to dummy arguments,
host objects, module variables, and variables in COMMON blocks, since
they will have values on entry to the scope. A local variable with a
initializer and the SAVE attribute (which will always be implied by an
explicit initialization) will also always work, and is accepted by at
least one other compiler, so accept it with a warning.
This commit is contained in:
Peter Klausler
2024-09-10 14:13:09 -07:00
committed by GitHub
parent fe58527305
commit 26ac30bcec
6 changed files with 27 additions and 7 deletions

View File

@@ -386,6 +386,9 @@ end
probably by a C or C++ external definition.
* An automatic data object may be declared in the specification part
of the main program.
* A local data object may appear in a specification expression, even
when it is not a dummy argument or in COMMON, so long as it is
has the SAVE attribute and was initialized.
### Extensions supported when enabled by options

View File

@@ -51,7 +51,8 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
BadBranchTarget, ConvertedArgument, HollerithPolymorphic, ListDirectedSize,
NonBindCInteroperability, CudaManaged, CudaUnified,
PolymorphicActualAllocatableOrPointerToMonomorphicDummy, RelaxedPureDummy,
UndefinableAsynchronousOrVolatileActual, AutomaticInMainProgram, PrintCptr)
UndefinableAsynchronousOrVolatileActual, AutomaticInMainProgram, PrintCptr,
SavedLocalInSpecExpr)
// Portability and suspicious usage warnings
ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
@@ -146,6 +147,8 @@ public:
warnUsage_.set(UsageWarning::VectorSubscriptFinalization);
warnUsage_.set(UsageWarning::UndefinedFunctionResult);
warnUsage_.set(UsageWarning::UselessIomsg);
// New warnings, on by default
warnLanguage_.set(LanguageFeature::SavedLocalInSpecExpr);
}
LanguageFeatureControl(const LanguageFeatureControl &) = default;

View File

@@ -554,6 +554,18 @@ public:
}
} else if (&symbol.owner() != &scope_ || &ultimate.owner() != &scope_) {
return std::nullopt; // host association is in play
} else if (semantics::IsSaved(ultimate) &&
semantics::IsInitialized(ultimate) &&
context_.languageFeatures().IsEnabled(
common::LanguageFeature::SavedLocalInSpecExpr)) {
if (!scope_.IsModuleFile() &&
context_.languageFeatures().ShouldWarn(
common::LanguageFeature::SavedLocalInSpecExpr)) {
context_.messages().Say(
"specification expression refers to local object '%s' (initialized and saved)"_port_en_US,
ultimate.name().ToString());
}
return std::nullopt;
} else if (const auto *object{
ultimate.detailsIf<semantics::ObjectEntityDetails>()}) {
if (object->commonBlock()) {
@@ -781,8 +793,9 @@ bool CheckSpecificationExprHelper::IsPermissibleInquiry(
template <typename A>
void CheckSpecificationExpr(const A &x, const semantics::Scope &scope,
FoldingContext &context, bool forElementalFunctionResult) {
if (auto why{CheckSpecificationExprHelper{
scope, context, forElementalFunctionResult}(x)}) {
CheckSpecificationExprHelper helper{
scope, context, forElementalFunctionResult};
if (auto why{helper(x)}) {
context.messages().Say("Invalid specification expression%s: %s"_err_en_US,
forElementalFunctionResult ? " for elemental function result" : "",
*why);

View File

@@ -16,7 +16,7 @@ subroutine s1()
!
integer, parameter :: constVal = 1
integer :: nonConstVal = 1
!ERROR: Invalid specification expression: reference to local entity 'nonconstval'
!PORTABILITY: specification expression refers to local object 'nonconstval' (initialized and saved)
character(nonConstVal) :: colonString1
character(len=20, kind=constVal + 1) :: constKindString
character(len=:, kind=constVal + 1), pointer :: constKindString1
@@ -53,13 +53,13 @@ subroutine s1()
type (derived(constVal, 3)) :: constDerivedKind
!ERROR: Value of KIND type parameter 'typekind' must be constant
!ERROR: Invalid specification expression: reference to local entity 'nonconstval'
!PORTABILITY: specification expression refers to local object 'nonconstval' (initialized and saved)
type (derived(nonConstVal, 3)) :: nonConstDerivedKind
!OK because all type-params are constants
type (derived(3, constVal)) :: constDerivedLen
!ERROR: Invalid specification expression: reference to local entity 'nonconstval'
!PORTABILITY: specification expression refers to local object 'nonconstval' (initialized and saved)
type (derived(3, nonConstVal)) :: nonConstDerivedLen
!ERROR: 'colonderivedlen' has a type derived(typekind=3_4,typelen=:) with a deferred type parameter but is neither an allocatable nor an object pointer
type (derived(3, :)) :: colonDerivedLen

View File

@@ -60,6 +60,7 @@ end subroutine
block data
common /blk2/ n
data n/100/
!PORTABILITY: specification expression refers to local object 'n' (initialized and saved)
!ERROR: Automatic data object 'a' may not appear in a BLOCK DATA subprogram
real a(n)
end

View File

@@ -104,7 +104,7 @@ subroutine s7biii(x, y)
integer :: local = 5
! OK, since "localConst" is a constant
real, dimension(localConst) :: realArray1
!ERROR: Invalid specification expression: reference to local entity 'local'
!PORTABILITY: specification expression refers to local object 'local' (initialized and saved)
real, dimension(local) :: realArray2
real, dimension(size(realArray1)) :: realArray3 ! ok
real, dimension(size(x)) :: realArray4 ! ok