[flang] Prevent character length setting with dangling ac-do-variable.
authorSlava Zakharin <szakharin@nvidia.com>
Mon, 8 May 2023 23:21:14 +0000 (16:21 -0700)
committerSlava Zakharin <szakharin@nvidia.com>
Mon, 8 May 2023 23:57:07 +0000 (16:57 -0700)
This fixes LEN inquiry on array constructors where the length
expression includes references to the ac-do-variable.

Reviewed By: klausler

Differential Revision: https://reviews.llvm.org/D150149

flang/lib/Semantics/expression.cpp
flang/test/Evaluate/rewrite01.f90

index 1440147..6047f8d 100644 (file)
@@ -1475,7 +1475,20 @@ public:
         ArrayConstructor<T> result{MakeSpecific<T>(std::move(values_))};
         if constexpr (T::category == TypeCategory::Character) {
           if (auto len{type_->LEN()}) {
-            if (IsConstantExpr(*len)) {
+            // The ac-do-variables may be treated as constant expressions,
+            // if some conditions on ac-implied-do-control hold (10.1.12 (12)).
+            // At the same time, they may be treated as constant expressions
+            // only in the context of the ac-implied-do, but setting
+            // the character length here may result in complete elimination
+            // of the ac-implied-do. For example:
+            //   character(10) :: c
+            //   ... len([(c(i:i), integer(8)::i = 1,4)])
+            // would be evaulated into:
+            //   ... int(max(0_8,i-i+1_8),kind=4)
+            // with a dangling reference to the ac-do-variable.
+            // Prevent this by checking for the ac-do-variable references
+            // in the 'len' expression.
+            if (!ContainsAnyImpliedDoIndex(*len) && IsConstantExpr(*len)) {
               result.set_LEN(std::move(*len));
             }
           }
index cbcbfb9..0fa3581 100644 (file)
@@ -234,10 +234,13 @@ end subroutine
 subroutine array_ctor_implied_do_index(x, j)
   integer :: x(:)
   integer(8) :: j
+  character(10) :: c
   !CHECK: PRINT *, size([INTEGER(4)::(x(1_8:i:1_8),INTEGER(8)::i=1_8,2_8,1_8)])
   print *, size([(x(1:i), integer(8)::i=1,2)])
   !CHECK: PRINT *, int(0_8+2_8*(0_8+max((j-1_8+1_8)/1_8,0_8)),kind=4)
   print *, size([(x(1:j), integer(8)::i=1,2)])
+  !CHECK: PRINT *, len([(c(i:i),INTEGER(8)::i=1_8,4_8,1_8)])
+  print *, len([(c(i:i), integer(8)::i = 1,4)])
 end subroutine
 
 end module