Skip to content

Commit a92306b

Browse files
committed
[flang] Add documentation, control, and portability warning for extension
f18 allows, as an extension, an assumed-rank array to be storage sequence associated with a dummy argument. Document the extension, make it disableable, and add an optional portability warning. Fixes #114080.
1 parent 850d42f commit a92306b

File tree

5 files changed

+65
-10
lines changed

5 files changed

+65
-10
lines changed

flang/docs/Extensions.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,9 @@ end
391391
has the SAVE attribute and was initialized.
392392
* `PRINT namelistname` is accepted and interpreted as
393393
`WRITE(*,NML=namelistname)`, a near-universal extension.
394+
* A contiguous assumed-rank array can be storage associated with a
395+
non-assumed-rank dummy array if it otherwise meets the requirements
396+
for storage association in F'2023 15.5.2.12.
394397

395398
### Extensions supported when enabled by options
396399

flang/include/flang/Common/Fortran-features.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
5353
NonBindCInteroperability, CudaManaged, CudaUnified,
5454
PolymorphicActualAllocatableOrPointerToMonomorphicDummy, RelaxedPureDummy,
5555
UndefinableAsynchronousOrVolatileActual, AutomaticInMainProgram, PrintCptr,
56-
SavedLocalInSpecExpr, PrintNamelist)
56+
SavedLocalInSpecExpr, PrintNamelist, AssumedRankSequenceAssociation)
5757

5858
// Portability and suspicious usage warnings
5959
ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,

flang/lib/Semantics/check-call.cpp

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,21 @@ static void CheckCharacterActual(evaluate::Expr<evaluate::SomeType> &actual,
135135
dummy.type.type().kind() == actualType.type().kind() &&
136136
!dummy.attrs.test(
137137
characteristics::DummyDataObject::Attr::DeducedFromActual)) {
138+
bool actualIsAssumedRank{evaluate::IsAssumedRank(actual)};
139+
if (actualIsAssumedRank) {
140+
if (!context.languageFeatures().IsEnabled(
141+
common::LanguageFeature::AssumedRankSequenceAssociation)) {
142+
messages.Say(
143+
"Assumed-rank character array may not be storage sequence associated with a dummy argument"_err_en_US);
144+
} else if (!evaluate::IsContiguous(actual, context.foldingContext())) {
145+
messages.Say(
146+
"Assumed-rank character array may not be storage sequence associated with a dummy argument if possibly discontiguous"_err_en_US);
147+
} else {
148+
context.Warn(common::LanguageFeature::AssumedRankSequenceAssociation,
149+
messages.at(),
150+
"Assumed-rank character array should not be storage sequence associated with a dummy argument"_port_en_US);
151+
}
152+
}
138153
if (dummy.type.LEN() && actualType.LEN()) {
139154
evaluate::FoldingContext &foldingContext{context.foldingContext()};
140155
auto dummyLength{
@@ -148,7 +163,7 @@ static void CheckCharacterActual(evaluate::Expr<evaluate::SomeType> &actual,
148163
if (auto dummySize{evaluate::ToInt64(evaluate::Fold(
149164
foldingContext, evaluate::GetSize(dummy.type.shape())))}) {
150165
auto dummyChars{*dummySize * *dummyLength};
151-
if (actualType.Rank() == 0) {
166+
if (actualType.Rank() == 0 && !actualIsAssumedRank) {
152167
evaluate::DesignatorFolder folder{
153168
context.foldingContext(), /*getLastComponent=*/true};
154169
if (auto actualOffset{folder.FoldDesignator(actual)}) {
@@ -602,7 +617,22 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
602617
characteristics::DummyDataObject::Attr::DeducedFromActual)) {
603618
if (auto dummySize{evaluate::ToInt64(evaluate::Fold(
604619
foldingContext, evaluate::GetSize(dummy.type.shape())))}) {
605-
if (actualRank == 0 && !actualIsAssumedRank) {
620+
if (actualIsAssumedRank) {
621+
if (!context.languageFeatures().IsEnabled(
622+
common::LanguageFeature::AssumedRankSequenceAssociation)) {
623+
messages.Say(
624+
"Assumed-rank array may not be storage sequence associated with a dummy argument"_err_en_US);
625+
} else if (!evaluate::IsContiguous(
626+
actual, context.foldingContext())) {
627+
messages.Say(
628+
"Assumed-rank array may not be storage sequence associated with a dummy argument if possibly discontiguous"_err_en_US);
629+
} else {
630+
context.Warn(
631+
common::LanguageFeature::AssumedRankSequenceAssociation,
632+
messages.at(),
633+
"Assumed-rank array should not be storage sequence associated with a dummy argument"_port_en_US);
634+
}
635+
} else if (actualRank == 0) {
606636
if (evaluate::IsArrayElement(actual)) {
607637
// Actual argument is a scalar array element
608638
evaluate::DesignatorFolder folder{
@@ -643,7 +673,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
643673
}
644674
}
645675
}
646-
} else { // actualRank > 0 || actualIsAssumedRank
676+
} else {
647677
if (auto actualSize{evaluate::ToInt64(evaluate::Fold(
648678
foldingContext, evaluate::GetSize(actualType.shape())))};
649679
actualSize && *actualSize < *dummySize) {

flang/test/Lower/HLFIR/convert-variable-assumed-rank.f90

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ subroutine test_intrinsic(x)
1919

2020
subroutine test_character_explicit_len(x, n)
2121
integer(8) :: n
22-
character(n) :: x(..)
22+
character(n), contiguous :: x(..)
2323
call takes_char(x)
2424
end subroutine
2525

2626
subroutine test_character_assumed_len(x)
27-
character(*) :: x(..)
27+
character(*), contiguous :: x(..)
2828
call takes_char(x)
2929
end subroutine
3030

@@ -58,23 +58,23 @@ subroutine test_assumed_length_alloc(x)
5858
! CHECK: }
5959

6060
! CHECK-LABEL: func.func @_QMassumed_rank_testsPtest_character_explicit_len(
61-
! CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<*:!fir.char<1,?>>> {fir.bindc_name = "x"},
61+
! CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<*:!fir.char<1,?>>> {fir.bindc_name = "x", fir.contiguous},
6262
! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<i64> {fir.bindc_name = "n"}) {
6363
! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope
6464
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] dummy_scope %[[VAL_2]] {uniq_name = "_QMassumed_rank_testsFtest_character_explicit_lenEn"} : (!fir.ref<i64>, !fir.dscope) -> (!fir.ref<i64>, !fir.ref<i64>)
6565
! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<i64>
6666
! CHECK: %[[VAL_5:.*]] = arith.constant 0 : i64
6767
! CHECK: %[[VAL_6:.*]] = arith.cmpi sgt, %[[VAL_4]], %[[VAL_5]] : i64
6868
! CHECK: %[[VAL_7:.*]] = arith.select %[[VAL_6]], %[[VAL_4]], %[[VAL_5]] : i64
69-
! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_0]] typeparams %[[VAL_7]] dummy_scope %[[VAL_2]] {uniq_name = "_QMassumed_rank_testsFtest_character_explicit_lenEx"} : (!fir.box<!fir.array<*:!fir.char<1,?>>>, i64, !fir.dscope) -> (!fir.box<!fir.array<*:!fir.char<1,?>>>, !fir.box<!fir.array<*:!fir.char<1,?>>>)
69+
! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_0]] typeparams %[[VAL_7]] dummy_scope %[[VAL_2]] {fortran_attrs = #fir.var_attrs<contiguous>, uniq_name = "_QMassumed_rank_testsFtest_character_explicit_lenEx"} : (!fir.box<!fir.array<*:!fir.char<1,?>>>, i64, !fir.dscope) -> (!fir.box<!fir.array<*:!fir.char<1,?>>>, !fir.box<!fir.array<*:!fir.char<1,?>>>)
7070
! CHECK: fir.call @_QPtakes_char(%[[VAL_8]]#0) fastmath<contract> : (!fir.box<!fir.array<*:!fir.char<1,?>>>) -> ()
7171
! CHECK: return
7272
! CHECK: }
7373

7474
! CHECK-LABEL: func.func @_QMassumed_rank_testsPtest_character_assumed_len(
75-
! CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<*:!fir.char<1,?>>> {fir.bindc_name = "x"}) {
75+
! CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<*:!fir.char<1,?>>> {fir.bindc_name = "x", fir.contiguous}) {
7676
! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
77-
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "_QMassumed_rank_testsFtest_character_assumed_lenEx"} : (!fir.box<!fir.array<*:!fir.char<1,?>>>, !fir.dscope) -> (!fir.box<!fir.array<*:!fir.char<1,?>>>, !fir.box<!fir.array<*:!fir.char<1,?>>>)
77+
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs<contiguous>, uniq_name = "_QMassumed_rank_testsFtest_character_assumed_lenEx"} : (!fir.box<!fir.array<*:!fir.char<1,?>>>, !fir.dscope) -> (!fir.box<!fir.array<*:!fir.char<1,?>>>, !fir.box<!fir.array<*:!fir.char<1,?>>>)
7878
! CHECK: fir.call @_QPtakes_char(%[[VAL_2]]#0) fastmath<contract> : (!fir.box<!fir.array<*:!fir.char<1,?>>>) -> ()
7979
! CHECK: return
8080
! CHECK: }

flang/test/Semantics/call38.f90

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,3 +522,25 @@ subroutine test
522522
call scalar('a')
523523
end
524524
end
525+
526+
subroutine bug114080(arg, contigArg)
527+
character(*) :: arg(..)
528+
character(*), contiguous :: contigArg(..)
529+
interface
530+
subroutine sub1(arg1) bind(c)
531+
character(1) :: arg1(2,4)
532+
end subroutine
533+
end interface
534+
!ERROR: Assumed-rank character array may not be storage sequence associated with a dummy argument if possibly discontiguous
535+
call sub1(arg)
536+
!WARNING: Assumed-rank character array should not be storage sequence associated with a dummy argument
537+
call sub1(contigArg)
538+
!ERROR: Assumed-rank character array may not be storage sequence associated with a dummy argument if possibly discontiguous
539+
call sub2(arg)
540+
!WARNING: Assumed-rank character array should not be storage sequence associated with a dummy argument
541+
call sub2(contigArg)
542+
contains
543+
subroutine sub2(arg2)
544+
character(*) :: arg2(10)
545+
end subroutine sub2
546+
end subroutine

0 commit comments

Comments
 (0)