Skip to content

Conversation

@klausler
Copy link
Contributor

Component references to array values had a couple of TODOs in the contiguity checker; implement them so that contiguity errors/warnings and code generation are more accurate. Specifically, "a(1:1)%b" is contiguous because there's a single element; "a(1:2)%b" is contiguous when the type of "a" has but a single component. The case of multiple components in the type is discontiguous when the array is known to have multiple elements.

Component references to array values had a couple of TODOs in
the contiguity checker; implement them so that contiguity errors/warnings
and code generation are more accurate.  Specifically, "a(1:1)%b" is
contiguous because there's a single element; "a(1:2)%b" is contiguous
when the type of "a" has but a single component.  The case of multiple
components in the type is discontiguous when the array is known to
have multiple elements.
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir flang:semantics labels Aug 12, 2025
@llvmbot
Copy link
Member

llvmbot commented Aug 12, 2025

@llvm/pr-subscribers-flang-fir-hlfir

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

Changes

Component references to array values had a couple of TODOs in the contiguity checker; implement them so that contiguity errors/warnings and code generation are more accurate. Specifically, "a(1:1)%b" is contiguous because there's a single element; "a(1:2)%b" is contiguous when the type of "a" has but a single component. The case of multiple components in the type is discontiguous when the array is known to have multiple elements.


Full diff: https://github.com/llvm/llvm-project/pull/153222.diff

3 Files Affected:

  • (modified) flang/lib/Evaluate/check-expression.cpp (+26-4)
  • (modified) flang/test/Lower/components.f90 (+3-3)
  • (added) flang/test/Semantics/contiguous02.f90 (+27)
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index 3d7f01d56c465..e8455bc372846 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -951,18 +951,40 @@ class IsContiguousHelper
     if (x.base().Rank() == 0) {
       return (*this)(x.GetLastSymbol());
     } else {
-      if (Result baseIsContiguous{(*this)(x.base())}) {
+      const DataRef &base{x.base()};
+      if (Result baseIsContiguous{(*this)(base)}) {
         if (!*baseIsContiguous) {
           return false;
+        } else {
+          bool sizeKnown{false};
+          if (auto constShape{GetConstantExtents(context_, x)}) {
+            sizeKnown = true;
+            if (GetSize(*constShape) <= 1) {
+              return true; // empty or singleton
+            }
+          }
+          const Symbol &last{base.GetLastSymbol()};
+          if (auto type{DynamicType::From(last)}) {
+            CHECK(type->category() == TypeCategory::Derived);
+            if (!type->IsPolymorphic()) {
+              const auto &derived{type->GetDerivedTypeSpec()};
+              if (const auto *scope{derived.scope()}) {
+                auto iter{scope->begin()};
+                if (++iter == scope->end()) {
+                  return true; // type has but one component
+                } else if (sizeKnown) {
+                  return false; // multiple components & array size is known > 1
+                }
+              }
+            }
+          }
         }
-        // TODO: should be true if base is contiguous and this is only
-        // component, or when the base has at most one element
       }
       return std::nullopt;
     }
   }
   Result operator()(const ComplexPart &x) const {
-    // TODO: should be true when base is empty array, too
+    // TODO: should be true when base is empty array or singleton, too
     return x.complex().Rank() == 0;
   }
   Result operator()(const Substring &x) const {
diff --git a/flang/test/Lower/components.f90 b/flang/test/Lower/components.f90
index 5afde4bd0a959..f0caddbaaa914 100644
--- a/flang/test/Lower/components.f90
+++ b/flang/test/Lower/components.f90
@@ -136,7 +136,7 @@ subroutine lhs_char_section(a)
 ! CHECK:           %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_5]] typeparams %[[VAL_6]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQclX68656C6C6F"} : (!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
 ! CHECK:           %[[VAL_8:.*]] = arith.constant 5 : index
 ! CHECK:           %[[VAL_9:.*]] = hlfir.designate %[[VAL_4]]#0{"c"}   shape %[[VAL_3]] typeparams %[[VAL_8]] : (!fir.ref<!fir.array<10x!fir.type<_QFlhs_char_sectionTt
-! CHECK:           hlfir.assign %[[VAL_7]]#0 to %[[VAL_9]] : !fir.ref<!fir.char<1,5>>, !fir.box<!fir.array<10x!fir.char<1,5>>>
+! CHECK:           hlfir.assign %[[VAL_7]]#0 to %[[VAL_9]] : !fir.ref<!fir.char<1,5>>, !fir.ref<!fir.array<10x!fir.char<1,5>>>
 ! CHECK:           return
 ! CHECK:         }
 
@@ -163,7 +163,7 @@ subroutine rhs_char_section(a, c)
 ! CHECK:           %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_7]](%[[VAL_10]]) typeparams %[[VAL_8]] dummy_scope %[[VAL_2]] {uniq_name = "_QFrhs_char_sectionEc"} : (!fir.ref<!fir.array<10x!fir.char<1,10>>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.ref<!fir.array<10x!fir.char<1,10>>>, !fir.ref<!fir.array<10x!fir.char<1,10>>>)
 ! CHECK:           %[[VAL_12:.*]] = arith.constant 10 : index
 ! CHECK:           %[[VAL_13:.*]] = hlfir.designate %[[VAL_5]]#0{"c"}   shape %[[VAL_4]] typeparams %[[VAL_12]] : (!fir.ref<!fir.array<10x!fir.type<_QFrhs_char_sectionTt
-! CHECK:           hlfir.assign %[[VAL_13]] to %[[VAL_11]]#0 : !fir.box<!fir.array<10x!fir.char<1,10>>>, !fir.ref<!fir.array<10x!fir.char<1,10>>>
+! CHECK:           hlfir.assign %[[VAL_13]] to %[[VAL_11]]#0 : !fir.ref<!fir.array<10x!fir.char<1,10>>>, !fir.ref<!fir.array<10x!fir.char<1,10>>>
 ! CHECK:           return
 ! CHECK:         }
 
@@ -192,7 +192,7 @@ subroutine elemental_char_section(a, i)
 ! CHECK:           %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_11]] typeparams %[[VAL_12]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQclX68656C6C6F"} : (!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
 ! CHECK:           %[[VAL_14:.*]] = hlfir.elemental %[[VAL_4]] unordered : (!fir.shape<1>) -> !hlfir.expr<10xi32> {
 ! CHECK:           ^bb0(%[[VAL_15:.*]]: index):
-! CHECK:             %[[VAL_16:.*]] = hlfir.designate %[[VAL_10]] (%[[VAL_15]])  typeparams %[[VAL_9]] : (!fir.box<!fir.array<10x!fir.char<1,10>>>, index, index) -> !fir.ref<!fir.char<1,10>>
+! CHECK:             %[[VAL_16:.*]] = hlfir.designate %[[VAL_10]] (%[[VAL_15]])  typeparams %[[VAL_9]] : (!fir.ref<!fir.array<10x!fir.char<1,10>>>, index, index) -> !fir.ref<!fir.char<1,10>>
 ! CHECK:             %[[VAL_17:.*]] = arith.constant false
 ! CHECK:             %[[VAL_18:.*]] = fir.convert %[[VAL_16]] : (!fir.ref<!fir.char<1,10>>) -> !fir.ref<i8>
 ! CHECK:             %[[VAL_19:.*]] = fir.convert %[[VAL_9]] : (index) -> i64
diff --git a/flang/test/Semantics/contiguous02.f90 b/flang/test/Semantics/contiguous02.f90
new file mode 100644
index 0000000000000..6543ea92b9403
--- /dev/null
+++ b/flang/test/Semantics/contiguous02.f90
@@ -0,0 +1,27 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic
+subroutine s1
+  type :: d1
+    real :: x
+  end type
+  type :: d2
+     type(d1) :: x
+  end type
+  type(d1), target :: a(5)
+  type(d2), target :: b(5)
+  real, pointer, contiguous :: c(:)
+  c => a%x ! okay, type has single component
+  c => b%x%x ! okay, types have single components
+end
+
+subroutine s2
+  type :: d1
+    real :: x, y
+  end type
+  type(d1), target :: b(5)
+  real, pointer, contiguous :: c(:)
+  !ERROR: CONTIGUOUS pointer may not be associated with a discontiguous target
+  c => b%x
+  c => b(1:1)%x ! okay, one element
+  !ERROR: CONTIGUOUS pointer may not be associated with a discontiguous target
+  c => b(1:2)%x
+end

@klausler klausler merged commit 24e9ee4 into llvm:main Sep 10, 2025
13 checks passed
@klausler klausler deleted the contiguous-ptr branch September 10, 2025 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flang:fir-hlfir flang:semantics flang Flang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants