Index: flang/include/flang/Semantics/tools.h =================================================================== --- flang/include/flang/Semantics/tools.h +++ flang/include/flang/Semantics/tools.h @@ -123,7 +123,6 @@ bool HasIntrinsicTypeName(const Symbol &); bool IsSeparateModuleProcedureInterface(const Symbol *); bool HasAlternateReturns(const Symbol &); -bool InCommonBlock(const Symbol &); // Return an ultimate component of type that matches predicate, or nullptr. const Symbol *FindUltimateComponent(const DerivedTypeSpec &type, Index: flang/lib/Evaluate/check-expression.cpp =================================================================== --- flang/lib/Evaluate/check-expression.cpp +++ flang/lib/Evaluate/check-expression.cpp @@ -477,6 +477,42 @@ return std::nullopt; } +static bool IsNonLocal(const semantics::Symbol &symbol) { + return semantics::IsDummy(symbol) || symbol.has() || + symbol.owner().kind() == semantics::Scope::Kind::Module || + semantics::FindCommonBlockContaining(symbol) || + symbol.has(); +} + +static bool IsPermissibleInquiry(const semantics::Symbol &firstSymbol, + const semantics::Symbol &lastSymbol, DescriptorInquiry::Field field, + const semantics::Scope &localScope) { + if (IsNonLocal(firstSymbol)) { + return true; + } + if (&localScope != &firstSymbol.owner()) { + return true; + } + // Inquiries on local objects may not access a deferred bound or length. + const auto *object{lastSymbol.detailsIf()}; + switch (field) { + case DescriptorInquiry::Field::LowerBound: + case DescriptorInquiry::Field::Extent: + case DescriptorInquiry::Field::Stride: + return object && !object->shape().CanBeDeferredShape(); + case DescriptorInquiry::Field::Rank: + return true; // always known + case DescriptorInquiry::Field::Len: + return object && object->type() && + object->type()->category() == semantics::DeclTypeSpec::Character && + !object->type()->characterTypeSpec().length().isDeferred(); + default: + break; + } + // TODO: Handle non-deferred LEN type parameters of PDTs + return false; +} + // Specification expression validation (10.1.11(2), C1010) class CheckSpecificationExprHelper : public AnyTraverse= 1) { + if (const auto &arg{x.arguments().at(0)}) { + if (auto dataRef{ExtractDataRef(*arg, true, true)}) { + if (intrin.name == "allocated" || intrin.name == "associated" || + intrin.name == "is_contiguous") { // ok + } else if (intrin.name == "len" && + IsPermissibleInquiry(dataRef->GetFirstSymbol(), + dataRef->GetLastSymbol(), DescriptorInquiry::Field::Len, + scope_)) { // ok + } else if (intrin.name == "lbound" && + IsPermissibleInquiry(dataRef->GetFirstSymbol(), + dataRef->GetLastSymbol(), + DescriptorInquiry::Field::LowerBound, scope_)) { // ok + } else if ((intrin.name == "shape" || intrin.name == "size" || + intrin.name == "sizeof" || + intrin.name == "storage_size" || + intrin.name == "ubound") && + IsPermissibleInquiry(dataRef->GetFirstSymbol(), + dataRef->GetLastSymbol(), DescriptorInquiry::Field::Extent, + scope_)) { // ok + } else { + return "non-constant inquiry function '"s + intrin.name + + "' not allowed for local object"; + } + } + } + } } auto restorer{common::ScopedSet(inInquiry_, inInquiry)}; return (*this)(x.arguments()); Index: flang/lib/Semantics/check-declarations.cpp =================================================================== --- flang/lib/Semantics/check-declarations.cpp +++ flang/lib/Semantics/check-declarations.cpp @@ -261,7 +261,7 @@ messages_.Say( "A PROTECTED entity must be a variable or pointer"_err_en_US); } - if (InCommonBlock(symbol)) { // C856 + if (FindCommonBlockContaining(symbol)) { // C856 messages_.Say( "A PROTECTED entity may not be in a common block"_err_en_US); } Index: flang/lib/Semantics/compute-offsets.cpp =================================================================== --- flang/lib/Semantics/compute-offsets.cpp +++ flang/lib/Semantics/compute-offsets.cpp @@ -101,7 +101,7 @@ } // Assign offsets for non-COMMON EQUIVALENCE blocks for (auto &[symbol, blockInfo] : equivalenceBlock_) { - if (!InCommonBlock(*symbol)) { + if (!FindCommonBlockContaining(*symbol)) { DoSymbol(*symbol); DoEquivalenceBlockBase(*symbol, blockInfo); offset_ = std::max(offset_, symbol->offset() + blockInfo.size); @@ -110,7 +110,7 @@ // Process remaining non-COMMON symbols; this is all of them if there // was no use of EQUIVALENCE in the scope. for (auto &symbol : scope.GetSymbols()) { - if (!InCommonBlock(*symbol) && + if (!FindCommonBlockContaining(*symbol) && dependents_.find(symbol) == dependents_.end() && equivalenceBlock_.find(symbol) == equivalenceBlock_.end()) { DoSymbol(*symbol); Index: flang/lib/Semantics/resolve-names.cpp =================================================================== --- flang/lib/Semantics/resolve-names.cpp +++ flang/lib/Semantics/resolve-names.cpp @@ -1144,7 +1144,7 @@ name, symbol, "'%s' is already declared as a procedure"_err_en_US); } else if (std::is_same_v && symbol.has()) { - if (InCommonBlock(symbol)) { + if (FindCommonBlockContaining(symbol)) { SayWithDecl(name, symbol, "'%s' may not be a procedure as it is in a COMMON block"_err_en_US); } else { Index: flang/lib/Semantics/tools.cpp =================================================================== --- flang/lib/Semantics/tools.cpp +++ flang/lib/Semantics/tools.cpp @@ -1411,11 +1411,6 @@ return false; } -bool InCommonBlock(const Symbol &symbol) { - const auto *details{symbol.detailsIf()}; - return details && details->commonBlock(); -} - const std::optional &MaybeGetNodeName( const ConstructNode &construct) { return common::visit( Index: flang/test/Evaluate/errors01.f90 =================================================================== --- flang/test/Evaluate/errors01.f90 +++ flang/test/Evaluate/errors01.f90 @@ -100,6 +100,14 @@ !CHECK: error: DIM=4 argument to SPREAD must be between 1 and 3 integer, parameter :: bad3 = spread(matrix, 4, 1) end subroutine + subroutine s11 + character(:), allocatable :: x1 + !CHECK: error: Invalid specification expression: non-constant inquiry function 'len' not allowed for local object + character(len(x1)) :: x2 + real, allocatable :: x3(:) + !CHECK: error: Invalid specification expression: non-constant descriptor inquiry not allowed for local object + real :: x4(size(x3)) + end subroutine warnings real, parameter :: ok1 = scale(0.0, 99999) ! 0.0 real, parameter :: ok2 = scale(1.0, -99999) ! 0.0 Index: flang/test/Semantics/resolve89.f90 =================================================================== --- flang/test/Semantics/resolve89.f90 +++ flang/test/Semantics/resolve89.f90 @@ -54,7 +54,6 @@ ! This is OK real, dimension(merge(1, 2, allocated(mVar))) :: rVar - integer :: var = 3 !ERROR: Invalid specification expression: reference to impure function 'ivolatilestmtfunc' real, dimension(iVolatileStmtFunc()) :: arrayVarWithVolatile