[flang] Improve contiguity checker for component references (#153222)

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.
This commit is contained in:
Peter Klausler 2025-09-10 13:13:36 -07:00 committed by GitHub
parent 3af202abf8
commit 24e9ee44a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 56 additions and 7 deletions

View File

@ -1026,18 +1026,40 @@ public:
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 {

View File

@ -136,7 +136,7 @@ end subroutine
! 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 @@ end subroutine
! 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 @@ end subroutine
! 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

View File

@ -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