mirror of
https://github.com/intel/llvm.git
synced 2026-01-21 04:14:03 +08:00
[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:
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user