@@ -507,53 +507,17 @@ std::optional<Expr<SomeType>> NonPointerInitializationExpr(const Symbol &symbol,
507
507
return std::nullopt;
508
508
}
509
509
510
- static bool IsNonLocal (const semantics::Symbol &symbol) {
511
- return semantics::IsDummy (symbol) || symbol.has <semantics::UseDetails>() ||
512
- symbol.owner ().kind () == semantics::Scope::Kind::Module ||
513
- semantics::FindCommonBlockContaining (symbol) ||
514
- symbol.has <semantics::HostAssocDetails>();
515
- }
516
-
517
- static bool IsPermissibleInquiry (const semantics::Symbol &firstSymbol,
518
- const semantics::Symbol &lastSymbol, DescriptorInquiry::Field field,
519
- const semantics::Scope &localScope) {
520
- if (IsNonLocal (firstSymbol)) {
521
- return true ;
522
- }
523
- if (&localScope != &firstSymbol.owner ()) {
524
- return true ;
525
- }
526
- // Inquiries on local objects may not access a deferred bound or length.
527
- // (This code used to be a switch, but it proved impossible to write it
528
- // thus without running afoul of bogus warnings from different C++
529
- // compilers.)
530
- if (field == DescriptorInquiry::Field::Rank) {
531
- return true ; // always known
532
- }
533
- const auto *object{lastSymbol.detailsIf <semantics::ObjectEntityDetails>()};
534
- if (field == DescriptorInquiry::Field::LowerBound ||
535
- field == DescriptorInquiry::Field::Extent ||
536
- field == DescriptorInquiry::Field::Stride) {
537
- return object && !object->shape ().CanBeDeferredShape ();
538
- }
539
- if (field == DescriptorInquiry::Field::Len) {
540
- return object && object->type () &&
541
- object->type ()->category () == semantics::DeclTypeSpec::Character &&
542
- !object->type ()->characterTypeSpec ().length ().isDeferred ();
543
- }
544
- return false ;
545
- }
546
-
547
510
// Specification expression validation (10.1.11(2), C1010)
548
511
class CheckSpecificationExprHelper
549
512
: public AnyTraverse<CheckSpecificationExprHelper,
550
513
std::optional<std::string>> {
551
514
public:
552
515
using Result = std::optional<std::string>;
553
516
using Base = AnyTraverse<CheckSpecificationExprHelper, Result>;
554
- explicit CheckSpecificationExprHelper (
555
- const semantics::Scope &s, FoldingContext &context)
556
- : Base{*this }, scope_{s}, context_{context} {}
517
+ explicit CheckSpecificationExprHelper (const semantics::Scope &s,
518
+ FoldingContext &context, bool forElementalFunctionResult)
519
+ : Base{*this }, scope_{s}, context_{context},
520
+ forElementalFunctionResult_{forElementalFunctionResult} {}
557
521
using Base::operator ();
558
522
559
523
Result operator ()(const CoarrayRef &) const { return " coindexed reference" ; }
@@ -572,7 +536,10 @@ class CheckSpecificationExprHelper
572
536
" reference variable '" s +
573
537
ultimate.name ().ToString () + " '" ;
574
538
} else if (IsDummy (ultimate)) {
575
- if (ultimate.attrs ().test (semantics::Attr::OPTIONAL)) {
539
+ if (!inInquiry_ && forElementalFunctionResult_) {
540
+ return " dependence on value of dummy argument '" s +
541
+ ultimate.name ().ToString () + " '" ;
542
+ } else if (ultimate.attrs ().test (semantics::Attr::OPTIONAL)) {
576
543
return " reference to OPTIONAL dummy argument '" s +
577
544
ultimate.name ().ToString () + " '" ;
578
545
} else if (!inInquiry_ &&
@@ -629,8 +596,8 @@ class CheckSpecificationExprHelper
629
596
// expressions will have been converted to expressions over descriptor
630
597
// inquiries by Fold().
631
598
// Catch REAL, ALLOCATABLE :: X(:); REAL :: Y(SIZE(X))
632
- if (IsPermissibleInquiry (x. base (). GetFirstSymbol (),
633
- x.base ().GetLastSymbol (), x.field (), scope_ )) {
599
+ if (IsPermissibleInquiry (
600
+ x.base ().GetFirstSymbol (), x.base (). GetLastSymbol (), x. field () )) {
634
601
auto restorer{common::ScopedSet (inInquiry_, true )};
635
602
return (*this )(x.base ());
636
603
} else if (IsConstantExpr (x)) {
@@ -641,10 +608,18 @@ class CheckSpecificationExprHelper
641
608
}
642
609
643
610
Result operator ()(const TypeParamInquiry &inq) const {
644
- if (scope_.IsDerivedType () && !IsConstantExpr (inq) &&
645
- inq.base () /* X%T, not local T */ ) { // C750, C754
646
- return " non-constant reference to a type parameter inquiry not "
647
- " allowed for derived type components or type parameter values" ;
611
+ if (scope_.IsDerivedType ()) {
612
+ if (!IsConstantExpr (inq) &&
613
+ inq.base () /* X%T, not local T */ ) { // C750, C754
614
+ return " non-constant reference to a type parameter inquiry not allowed "
615
+ " for derived type components or type parameter values" ;
616
+ }
617
+ } else if (inq.base () &&
618
+ IsInquiryAlwaysPermissible (inq.base ()->GetFirstSymbol ())) {
619
+ auto restorer{common::ScopedSet (inInquiry_, true )};
620
+ return (*this )(inq.base ());
621
+ } else if (!IsConstantExpr (inq)) {
622
+ return " non-constant type parameter inquiry not allowed for local object" ;
648
623
}
649
624
return std::nullopt;
650
625
}
@@ -719,19 +694,19 @@ class CheckSpecificationExprHelper
719
694
intrin.name == " is_contiguous" ) { // ok
720
695
} else if (intrin.name == " len" &&
721
696
IsPermissibleInquiry (dataRef->GetFirstSymbol (),
722
- dataRef->GetLastSymbol (), DescriptorInquiry::Field::Len,
723
- scope_ )) { // ok
697
+ dataRef->GetLastSymbol (),
698
+ DescriptorInquiry::Field::Len )) { // ok
724
699
} else if (intrin.name == " lbound" &&
725
700
IsPermissibleInquiry (dataRef->GetFirstSymbol (),
726
701
dataRef->GetLastSymbol (),
727
- DescriptorInquiry::Field::LowerBound, scope_ )) { // ok
702
+ DescriptorInquiry::Field::LowerBound)) { // ok
728
703
} else if ((intrin.name == " shape" || intrin.name == " size" ||
729
704
intrin.name == " sizeof" ||
730
705
intrin.name == " storage_size" ||
731
706
intrin.name == " ubound" ) &&
732
707
IsPermissibleInquiry (dataRef->GetFirstSymbol (),
733
- dataRef->GetLastSymbol (), DescriptorInquiry::Field::Extent,
734
- scope_ )) { // ok
708
+ dataRef->GetLastSymbol (),
709
+ DescriptorInquiry::Field::Extent )) { // ok
735
710
} else {
736
711
return " non-constant inquiry function '" s + intrin.name +
737
712
" ' not allowed for local object" ;
@@ -750,32 +725,86 @@ class CheckSpecificationExprHelper
750
725
// Contextual information: this flag is true when in an argument to
751
726
// an inquiry intrinsic like SIZE().
752
727
mutable bool inInquiry_{false };
728
+ bool forElementalFunctionResult_{false }; // F'2023 C15121
753
729
const std::set<std::string> badIntrinsicsForComponents_{
754
730
" allocated" , " associated" , " extends_type_of" , " present" , " same_type_as" };
731
+
732
+ bool IsInquiryAlwaysPermissible (const semantics::Symbol &) const ;
733
+ bool IsPermissibleInquiry (const semantics::Symbol &firstSymbol,
734
+ const semantics::Symbol &lastSymbol,
735
+ DescriptorInquiry::Field field) const ;
755
736
};
756
737
738
+ bool CheckSpecificationExprHelper::IsInquiryAlwaysPermissible (
739
+ const semantics::Symbol &symbol) const {
740
+ if (&symbol.owner () != &scope_ || symbol.has <semantics::UseDetails>() ||
741
+ symbol.owner ().kind () == semantics::Scope::Kind::Module ||
742
+ semantics::FindCommonBlockContaining (symbol) ||
743
+ symbol.has <semantics::HostAssocDetails>()) {
744
+ return true ; // it's nonlocal
745
+ } else if (semantics::IsDummy (symbol) && !forElementalFunctionResult_) {
746
+ return true ;
747
+ } else {
748
+ return false ;
749
+ }
750
+ }
751
+
752
+ bool CheckSpecificationExprHelper::IsPermissibleInquiry (
753
+ const semantics::Symbol &firstSymbol, const semantics::Symbol &lastSymbol,
754
+ DescriptorInquiry::Field field) const {
755
+ if (IsInquiryAlwaysPermissible (firstSymbol)) {
756
+ return true ;
757
+ }
758
+ // Inquiries on local objects may not access a deferred bound or length.
759
+ // (This code used to be a switch, but it proved impossible to write it
760
+ // thus without running afoul of bogus warnings from different C++
761
+ // compilers.)
762
+ if (field == DescriptorInquiry::Field::Rank) {
763
+ return true ; // always known
764
+ }
765
+ const auto *object{lastSymbol.detailsIf <semantics::ObjectEntityDetails>()};
766
+ if (field == DescriptorInquiry::Field::LowerBound ||
767
+ field == DescriptorInquiry::Field::Extent ||
768
+ field == DescriptorInquiry::Field::Stride) {
769
+ return object && !object->shape ().CanBeDeferredShape ();
770
+ }
771
+ if (field == DescriptorInquiry::Field::Len) {
772
+ return object && object->type () &&
773
+ object->type ()->category () == semantics::DeclTypeSpec::Character &&
774
+ !object->type ()->characterTypeSpec ().length ().isDeferred ();
775
+ }
776
+ return false ;
777
+ }
778
+
757
779
template <typename A>
758
- void CheckSpecificationExpr (
759
- const A &x, const semantics::Scope &scope, FoldingContext &context) {
760
- if (auto why{CheckSpecificationExprHelper{scope, context}(x)}) {
761
- context.messages ().Say (
762
- " Invalid specification expression: %s" _err_en_US, *why);
780
+ void CheckSpecificationExpr (const A &x, const semantics::Scope &scope,
781
+ FoldingContext &context, bool forElementalFunctionResult) {
782
+ if (auto why{CheckSpecificationExprHelper{
783
+ scope, context, forElementalFunctionResult}(x)}) {
784
+ context.messages ().Say (" Invalid specification expression%s: %s" _err_en_US,
785
+ forElementalFunctionResult ? " for elemental function result" : " " ,
786
+ *why);
763
787
}
764
788
}
765
789
766
- template void CheckSpecificationExpr (
767
- const Expr<SomeType> &, const semantics::Scope &, FoldingContext &);
768
- template void CheckSpecificationExpr (
769
- const Expr<SomeInteger> &, const semantics::Scope &, FoldingContext &);
770
- template void CheckSpecificationExpr (
771
- const Expr<SubscriptInteger> &, const semantics::Scope &, FoldingContext &);
790
+ template void CheckSpecificationExpr (const Expr<SomeType> &,
791
+ const semantics::Scope &, FoldingContext &,
792
+ bool forElementalFunctionResult);
793
+ template void CheckSpecificationExpr (const Expr<SomeInteger> &,
794
+ const semantics::Scope &, FoldingContext &,
795
+ bool forElementalFunctionResult);
796
+ template void CheckSpecificationExpr (const Expr<SubscriptInteger> &,
797
+ const semantics::Scope &, FoldingContext &,
798
+ bool forElementalFunctionResult);
772
799
template void CheckSpecificationExpr (const std::optional<Expr<SomeType>> &,
773
- const semantics::Scope &, FoldingContext &);
800
+ const semantics::Scope &, FoldingContext &,
801
+ bool forElementalFunctionResult);
774
802
template void CheckSpecificationExpr (const std::optional<Expr<SomeInteger>> &,
775
- const semantics::Scope &, FoldingContext &);
803
+ const semantics::Scope &, FoldingContext &,
804
+ bool forElementalFunctionResult);
776
805
template void CheckSpecificationExpr (
777
806
const std::optional<Expr<SubscriptInteger>> &, const semantics::Scope &,
778
- FoldingContext &);
807
+ FoldingContext &, bool forElementalFunctionResult );
779
808
780
809
// IsContiguous() -- 9.5.4
781
810
class IsContiguousHelper
0 commit comments