@@ -34,7 +34,8 @@ class IsConstantExprHelper
3434 : public AllTraverse<IsConstantExprHelper<INVARIANT>, true > {
3535public:
3636 using Base = AllTraverse<IsConstantExprHelper, true >;
37- IsConstantExprHelper () : Base{*this } {}
37+ explicit IsConstantExprHelper (const FoldingContext *c)
38+ : Base{*this }, context_{c} {}
3839 using Base::operator ();
3940
4041 // A missing expression is not considered to be constant.
@@ -91,10 +92,33 @@ class IsConstantExprHelper
9192 !sym.attrs ().test (semantics::Attr::VALUE)));
9293 }
9394
95+ bool operator ()(const ImpliedDoIndex &ido) const {
96+ return acImpliedDos_.find (ido.name ) != acImpliedDos_.end () || !context_ ||
97+ context_->GetImpliedDo (ido.name ).has_value ();
98+ }
99+ template <typename T> bool operator ()(const ImpliedDo<T> &ido) {
100+ if (!(*this )(ido.lower ()) || !(*this )(ido.upper ()) ||
101+ !(*this )(ido.stride ())) {
102+ return false ;
103+ }
104+ bool deleteAfter{acImpliedDos_.insert (ido.name ()).second };
105+ bool result{true };
106+ for (const auto &vals : ido.values ()) {
107+ result &= (*this )(vals);
108+ }
109+ if (deleteAfter) {
110+ acImpliedDos_.erase (ido.name ());
111+ }
112+ return result;
113+ }
114+
94115private:
95116 bool IsConstantStructureConstructorComponent (
96117 const Symbol &, const Expr<SomeType> &) const ;
97118 bool IsConstantExprShape (const Shape &) const ;
119+
120+ std::set<parser::CharBlock> acImpliedDos_;
121+ const FoldingContext *context_{nullptr };
98122};
99123
100124template <bool INVARIANT>
@@ -103,7 +127,8 @@ bool IsConstantExprHelper<INVARIANT>::IsConstantStructureConstructorComponent(
103127 if (IsAllocatable (component)) {
104128 return IsNullObjectPointer (&expr);
105129 } else if (IsPointer (component)) {
106- return IsNullPointerOrAllocatable (&expr) || IsInitialDataTarget (expr) ||
130+ return IsNullPointerOrAllocatable (&expr) ||
131+ IsInitialDataTarget (expr, /* messages=*/ nullptr , context_) ||
107132 IsInitialProcedureTarget (expr);
108133 } else {
109134 return (*this )(expr);
@@ -175,21 +200,27 @@ bool IsConstantExprHelper<INVARIANT>::IsConstantExprShape(
175200 return true ;
176201}
177202
178- template <typename A> bool IsConstantExpr (const A &x) {
179- return IsConstantExprHelper<false >{}(x);
203+ template <typename A> bool IsConstantExpr (const A &x, const FoldingContext *c ) {
204+ return IsConstantExprHelper<false >{c }(x);
180205}
181- template bool IsConstantExpr (const Expr<SomeType> &);
182- template bool IsConstantExpr (const Expr<SomeInteger> &);
183- template bool IsConstantExpr (const Expr<SubscriptInteger> &);
184- template bool IsConstantExpr (const StructureConstructor &);
206+ template bool IsConstantExpr (const Expr<SomeType> &, const FoldingContext *);
207+ template bool IsConstantExpr (const Expr<SomeInteger> &, const FoldingContext *);
208+ template bool IsConstantExpr (
209+ const Expr<SubscriptInteger> &, const FoldingContext *);
210+ template bool IsConstantExpr (
211+ const StructureConstructor &, const FoldingContext *);
185212
186213// IsScopeInvariantExpr()
187- template <typename A> bool IsScopeInvariantExpr (const A &x) {
188- return IsConstantExprHelper<true >{}(x);
214+ template <typename A>
215+ bool IsScopeInvariantExpr (const A &x, const FoldingContext *c) {
216+ return IsConstantExprHelper<true >{c}(x);
189217}
190- template bool IsScopeInvariantExpr (const Expr<SomeType> &);
191- template bool IsScopeInvariantExpr (const Expr<SomeInteger> &);
192- template bool IsScopeInvariantExpr (const Expr<SubscriptInteger> &);
218+ template bool IsScopeInvariantExpr (
219+ const Expr<SomeType> &, const FoldingContext *);
220+ template bool IsScopeInvariantExpr (
221+ const Expr<SomeInteger> &, const FoldingContext *);
222+ template bool IsScopeInvariantExpr (
223+ const Expr<SubscriptInteger> &, const FoldingContext *);
193224
194225// IsActuallyConstant()
195226struct IsActuallyConstantHelper {
@@ -207,13 +238,16 @@ struct IsActuallyConstantHelper {
207238 bool operator ()(const StructureConstructor &x) {
208239 for (const auto &pair : x) {
209240 const Expr<SomeType> &y{pair.second .value ()};
210- const auto sym{pair.first };
211- const bool compIsConstant{(*this )(y)};
212241 // If an allocatable component is initialized by a constant,
213242 // the structure constructor is not a constant.
214- if ((!compIsConstant && !IsNullPointerOrAllocatable (&y)) ||
215- (compIsConstant && IsAllocatable (sym))) {
216- return false ;
243+ if ((*this )(y)) {
244+ if (IsAllocatable (pair.first )) {
245+ return false ;
246+ }
247+ } else {
248+ if (!IsNullPointerOrAllocatable (&y)) {
249+ return false ;
250+ }
217251 }
218252 }
219253 return true ;
@@ -241,8 +275,9 @@ class IsInitialDataTargetHelper
241275public:
242276 using Base = AllTraverse<IsInitialDataTargetHelper, true >;
243277 using Base::operator ();
244- explicit IsInitialDataTargetHelper (parser::ContextualMessages *m)
245- : Base{*this }, messages_{m} {}
278+ explicit IsInitialDataTargetHelper (
279+ parser::ContextualMessages *m, const FoldingContext *c)
280+ : Base{*this }, messages_{m}, context_{c} {}
246281
247282 bool emittedMessage () const { return emittedMessage_; }
248283
@@ -292,15 +327,16 @@ class IsInitialDataTargetHelper
292327 bool operator ()(const StaticDataObject &) const { return false ; }
293328 bool operator ()(const TypeParamInquiry &) const { return false ; }
294329 bool operator ()(const Triplet &x) const {
295- return IsConstantExpr (x.lower ()) && IsConstantExpr (x.upper ()) &&
296- IsConstantExpr (x.stride ());
330+ return IsConstantExpr (x.lower (), context_) &&
331+ IsConstantExpr (x.upper (), context_) &&
332+ IsConstantExpr (x.stride (), context_);
297333 }
298334 bool operator ()(const Subscript &x) const {
299335 return common::visit (common::visitors{
300336 [&](const Triplet &t) { return (*this )(t); },
301337 [&](const auto &y) {
302338 return y.value ().Rank () == 0 &&
303- IsConstantExpr (y.value ());
339+ IsConstantExpr (y.value (), context_ );
304340 },
305341 },
306342 x.u );
@@ -310,8 +346,8 @@ class IsInitialDataTargetHelper
310346 return CheckVarOrComponent (x.GetLastSymbol ()) && (*this )(x.base ());
311347 }
312348 bool operator ()(const Substring &x) const {
313- return IsConstantExpr (x.lower ()) && IsConstantExpr (x. upper () ) &&
314- (*this )(x.parent ());
349+ return IsConstantExpr (x.lower (), context_ ) &&
350+ IsConstantExpr (x. upper (), context_) && (*this )(x.parent ());
315351 }
316352 bool operator ()(const DescriptorInquiry &) const { return false ; }
317353 template <typename T> bool operator ()(const ArrayConstructor<T> &) const {
@@ -358,13 +394,14 @@ class IsInitialDataTargetHelper
358394 return false ;
359395 }
360396
361- parser::ContextualMessages *messages_;
397+ parser::ContextualMessages *messages_{nullptr };
398+ const FoldingContext *context_{nullptr };
362399 bool emittedMessage_{false };
363400};
364401
365- bool IsInitialDataTarget (
366- const Expr<SomeType> &x, parser::ContextualMessages *messages) {
367- IsInitialDataTargetHelper helper{messages};
402+ bool IsInitialDataTarget (const Expr<SomeType> &x,
403+ parser::ContextualMessages *messages, const FoldingContext *context ) {
404+ IsInitialDataTargetHelper helper{messages, context };
368405 bool result{helper (x)};
369406 if (!result && messages && !helper.emittedMessage ()) {
370407 messages->Say (
@@ -732,7 +769,7 @@ class CheckSpecificationExprHelper
732769 x.base ().GetFirstSymbol (), x.base ().GetLastSymbol (), x.field ())) {
733770 auto restorer{common::ScopedSet (inInquiry_, true )};
734771 return (*this )(x.base ());
735- } else if (IsConstantExpr (x)) {
772+ } else if (IsConstantExpr (x, &context_ )) {
736773 return std::nullopt ;
737774 } else {
738775 return " non-constant descriptor inquiry not allowed for local object" ;
@@ -741,7 +778,7 @@ class CheckSpecificationExprHelper
741778
742779 Result operator ()(const TypeParamInquiry &inq) const {
743780 if (scope_.IsDerivedType ()) {
744- if (!IsConstantExpr (inq) &&
781+ if (!IsConstantExpr (inq, &context_ ) &&
745782 inq.base () /* X%T, not local T */ ) { // C750, C754
746783 return " non-constant reference to a type parameter inquiry not allowed "
747784 " for derived type components or type parameter values" ;
@@ -750,7 +787,7 @@ class CheckSpecificationExprHelper
750787 IsInquiryAlwaysPermissible (inq.base ()->GetFirstSymbol ())) {
751788 auto restorer{common::ScopedSet (inInquiry_, true )};
752789 return (*this )(inq.base ());
753- } else if (!IsConstantExpr (inq)) {
790+ } else if (!IsConstantExpr (inq, &context_ )) {
754791 return " non-constant type parameter inquiry not allowed for local object" ;
755792 }
756793 return std::nullopt ;
@@ -802,7 +839,7 @@ class CheckSpecificationExprHelper
802839 " ' not allowed for derived type components or type parameter"
803840 " values" ;
804841 }
805- if (inInquiry && !IsConstantExpr (x)) {
842+ if (inInquiry && !IsConstantExpr (x, &context_ )) {
806843 return " non-constant reference to inquiry intrinsic '" s +
807844 intrin.name +
808845 " ' not allowed for derived type components or type"
@@ -814,7 +851,7 @@ class CheckSpecificationExprHelper
814851 // DescriptorInquiry operations (LBOUND) are checked elsewhere. If a
815852 // call that makes it to here satisfies the requirements of a constant
816853 // expression (as Fortran defines it), it's fine.
817- if (IsConstantExpr (x)) {
854+ if (IsConstantExpr (x, &context_ )) {
818855 return std::nullopt ;
819856 }
820857 if (intrin.name == " present" ) {
0 commit comments