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, uniq_name = "_QQclX68656C6C6F"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) ! 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.box>> +! CHECK: hlfir.assign %[[VAL_7]]#0 to %[[VAL_9]] : !fir.ref>, !fir.ref>> ! 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.shape<1>, index, !fir.dscope) -> (!fir.ref>>, !fir.ref>>) ! 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.ref>> +! CHECK: hlfir.assign %[[VAL_13]] to %[[VAL_11]]#0 : !fir.ref>>, !fir.ref>> ! 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, uniq_name = "_QQclX68656C6C6F"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) ! 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>>, index, index) -> !fir.ref> +! CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_10]] (%[[VAL_15]]) typeparams %[[VAL_9]] : (!fir.ref>>, index, index) -> !fir.ref> ! CHECK: %[[VAL_17:.*]] = arith.constant false ! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_16]] : (!fir.ref>) -> !fir.ref ! 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