Skip to content

Commit 4a47634

Browse files
authored
[flang][OpenMP] Support substrings and complex part refs for DEPEND (#143907)
Fixes #142404 The parser can't tell the difference between array indexing and a substring: that has to be done in semantics once we have types. Substrings can only be in the form string([lower]:[higher]) not string(index) or string(lower:higher:step). I added semantic checks to catch this for the DEPEND clause. This patch also adds lowering for correct substrings and for complex part references.
1 parent 85a9f2e commit 4a47634

File tree

7 files changed

+250
-21
lines changed

7 files changed

+250
-21
lines changed

flang/include/flang/Evaluate/tools.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -490,26 +490,30 @@ template <typename A> std::optional<CoarrayRef> ExtractCoarrayRef(const A &x) {
490490
}
491491
}
492492

493-
struct ExtractSubstringHelper {
494-
template <typename T> static std::optional<Substring> visit(T &&) {
493+
template <typename TARGET> struct ExtractFromExprDesignatorHelper {
494+
template <typename T> static std::optional<TARGET> visit(T &&) {
495495
return std::nullopt;
496496
}
497497

498-
static std::optional<Substring> visit(const Substring &e) { return e; }
498+
static std::optional<TARGET> visit(const TARGET &t) { return t; }
499499

500500
template <typename T>
501-
static std::optional<Substring> visit(const Designator<T> &e) {
501+
static std::optional<TARGET> visit(const Designator<T> &e) {
502502
return common::visit([](auto &&s) { return visit(s); }, e.u);
503503
}
504504

505-
template <typename T>
506-
static std::optional<Substring> visit(const Expr<T> &e) {
505+
template <typename T> static std::optional<TARGET> visit(const Expr<T> &e) {
507506
return common::visit([](auto &&s) { return visit(s); }, e.u);
508507
}
509508
};
510509

511510
template <typename A> std::optional<Substring> ExtractSubstring(const A &x) {
512-
return ExtractSubstringHelper::visit(x);
511+
return ExtractFromExprDesignatorHelper<Substring>::visit(x);
512+
}
513+
514+
template <typename A>
515+
std::optional<ComplexPart> ExtractComplexPart(const A &x) {
516+
return ExtractFromExprDesignatorHelper<ComplexPart>::visit(x);
513517
}
514518

515519
// If an expression is simply a whole symbol data designator,

flang/lib/Lower/OpenMP/ClauseProcessor.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -926,14 +926,10 @@ bool ClauseProcessor::processDepend(lower::SymMap &symMap,
926926
for (const omp::Object &object : objects) {
927927
assert(object.ref() && "Expecting designator");
928928
mlir::Value dependVar;
929+
SomeExpr expr = *object.ref();
929930

930-
if (evaluate::ExtractSubstring(*object.ref())) {
931-
TODO(converter.getCurrentLocation(),
932-
"substring not supported for task depend");
933-
} else if (evaluate::IsArrayElement(*object.ref())) {
934-
// Array Section
935-
SomeExpr expr = *object.ref();
936-
931+
if (evaluate::IsArrayElement(expr) || evaluate::ExtractSubstring(expr)) {
932+
// Array Section or character (sub)string
937933
if (isVectorSubscript(expr)) {
938934
// OpenMP needs the address of the first indexed element (required by
939935
// the standard to be the lowest index) to identify the dependency. We
@@ -947,7 +943,8 @@ bool ClauseProcessor::processDepend(lower::SymMap &symMap,
947943
converter.getCurrentLocation(), converter, expr, symMap, stmtCtx);
948944
dependVar = entity.getBase();
949945
}
950-
} else if (evaluate::isStructureComponent(*object.ref())) {
946+
} else if (evaluate::isStructureComponent(expr) ||
947+
evaluate::ExtractComplexPart(expr)) {
951948
SomeExpr expr = *object.ref();
952949
hlfir::EntityWithAttributes entity = convertExprToHLFIR(
953950
converter.getCurrentLocation(), converter, expr, symMap, stmtCtx);

flang/lib/Lower/OpenMP/Clauses.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,19 +70,18 @@ struct SymbolAndDesignatorExtractor {
7070

7171
static void verify(const SymbolWithDesignator &sd) {
7272
const semantics::Symbol *symbol = std::get<0>(sd);
73-
assert(symbol && "Expecting symbol");
74-
auto &maybeDsg = std::get<1>(sd);
73+
const std::optional<evaluate::Expr<evaluate::SomeType>> &maybeDsg =
74+
std::get<1>(sd);
7575
if (!maybeDsg)
7676
return; // Symbol with no designator -> OK
77-
std::optional<evaluate::DataRef> maybeRef =
78-
evaluate::ExtractDataRef(*maybeDsg);
77+
assert(symbol && "Expecting symbol");
78+
std::optional<evaluate::DataRef> maybeRef = evaluate::ExtractDataRef(
79+
*maybeDsg, /*intoSubstring=*/true, /*intoComplexPart=*/true);
7980
if (maybeRef) {
8081
if (&maybeRef->GetLastSymbol() == symbol)
8182
return; // Symbol with a designator for it -> OK
8283
llvm_unreachable("Expecting designator for given symbol");
8384
} else {
84-
// This could still be a Substring or ComplexPart, but at least Substring
85-
// is not allowed in OpenMP.
8685
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
8786
maybeDsg->dump();
8887
#endif

flang/lib/Semantics/check-omp-structure.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "resolve-names-utils.h"
1212
#include "flang/Evaluate/check-expression.h"
1313
#include "flang/Evaluate/expression.h"
14+
#include "flang/Evaluate/shape.h"
1415
#include "flang/Evaluate/type.h"
1516
#include "flang/Parser/parse-tree.h"
1617
#include "flang/Semantics/expression.h"
@@ -6524,6 +6525,29 @@ void OmpStructureChecker::CheckDependList(const parser::DataRef &d) {
65246525
void OmpStructureChecker::CheckArraySection(
65256526
const parser::ArrayElement &arrayElement, const parser::Name &name,
65266527
const llvm::omp::Clause clause) {
6528+
// Sometimes substring operations are incorrectly parsed as array accesses.
6529+
// Detect this by looking for array accesses on character variables which are
6530+
// not arrays.
6531+
bool isSubstring{false};
6532+
evaluate::ExpressionAnalyzer ea{context_};
6533+
if (MaybeExpr expr = ea.Analyze(arrayElement.base)) {
6534+
std::optional<evaluate::Shape> shape = evaluate::GetShape(expr);
6535+
// Not an array: rank 0
6536+
if (shape && shape->size() == 0) {
6537+
if (std::optional<evaluate::DynamicType> type = expr->GetType()) {
6538+
if (type->category() == evaluate::TypeCategory::Character) {
6539+
// Substrings are explicitly denied by the standard [6.0:163:9-11].
6540+
// This is supported as an extension. This restriction was added in
6541+
// OpenMP 5.2.
6542+
isSubstring = true;
6543+
context_.Say(GetContext().clauseSource,
6544+
"The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2."_port_en_US);
6545+
} else {
6546+
llvm_unreachable("Array indexing on a variable that isn't an array");
6547+
}
6548+
}
6549+
}
6550+
}
65276551
if (!arrayElement.subscripts.empty()) {
65286552
for (const auto &subscript : arrayElement.subscripts) {
65296553
if (const auto *triplet{
@@ -6541,6 +6565,10 @@ void OmpStructureChecker::CheckArraySection(
65416565
name.ToString(),
65426566
parser::ToUpperCaseLetters(getClauseName(clause).str()));
65436567
}
6568+
if (isSubstring) {
6569+
context_.Say(GetContext().clauseSource,
6570+
"Cannot specify a step for a substring"_err_en_US);
6571+
}
65446572
}
65456573
const auto &lower{std::get<0>(triplet->t)};
65466574
const auto &upper{std::get<1>(triplet->t)};
@@ -6564,6 +6592,12 @@ void OmpStructureChecker::CheckArraySection(
65646592
}
65656593
}
65666594
}
6595+
} else if (std::get_if<parser::IntExpr>(&subscript.u)) {
6596+
// base(n) is valid as an array index but not as a substring operation
6597+
if (isSubstring) {
6598+
context_.Say(GetContext().clauseSource,
6599+
"Substrings must be in the form parent-string(lb:ub)"_err_en_US);
6600+
}
65676601
}
65686602
}
65696603
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
! RUN: %flang_fc1 -fopenmp -emit-hlfir -o - %s | FileCheck %s
2+
3+
subroutine depend_complex(z)
4+
! CHECK-LABEL: func.func @_QPdepend_complex(
5+
! CHECK-SAME: %[[ARG0:.*]]: !fir.ref<complex<f32>> {fir.bindc_name = "z"}) {
6+
complex :: z
7+
! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
8+
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {uniq_name = "_QFdepend_complexEz"} : (!fir.ref<complex<f32>>, !fir.dscope) -> (!fir.ref<complex<f32>>, !fir.ref<complex<f32>>)
9+
!$omp task depend(in:z%re)
10+
! CHECK: %[[VAL_2:.*]] = hlfir.designate %[[VAL_1]]#0 real : (!fir.ref<complex<f32>>) -> !fir.ref<f32>
11+
! CHECK: omp.task depend(taskdependin -> %[[VAL_2]] : !fir.ref<f32>) {
12+
! CHECK: omp.terminator
13+
! CHECK: }
14+
!$omp end task
15+
!$omp task depend(in:z%im)
16+
! CHECK: %[[VAL_3:.*]] = hlfir.designate %[[VAL_1]]#0 imag : (!fir.ref<complex<f32>>) -> !fir.ref<f32>
17+
! CHECK: omp.task depend(taskdependin -> %[[VAL_3]] : !fir.ref<f32>) {
18+
! CHECK: omp.terminator
19+
! CHECK: }
20+
!$omp end task
21+
end subroutine
22+
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - | FileCheck %s
2+
3+
subroutine substring_0(c)
4+
character(:), pointer :: c
5+
!$omp task depend(out:c(:))
6+
!$omp end task
7+
end
8+
! CHECK-LABEL: func.func @_QPsubstring_0(
9+
! CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>> {fir.bindc_name = "c"}) {
10+
! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
11+
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFsubstring_0Ec"} : (!fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>)
12+
! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>
13+
! CHECK: %[[VAL_3:.*]] = fir.box_addr %[[VAL_2]] : (!fir.box<!fir.ptr<!fir.char<1,?>>>) -> !fir.ptr<!fir.char<1,?>>
14+
! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>
15+
! CHECK: %[[VAL_5:.*]] = fir.box_elesize %[[VAL_4]] : (!fir.box<!fir.ptr<!fir.char<1,?>>>) -> index
16+
! CHECK: %[[VAL_6:.*]] = fir.emboxchar %[[VAL_3]], %[[VAL_5]] : (!fir.ptr<!fir.char<1,?>>, index) -> !fir.boxchar<1>
17+
! CHECK: %[[VAL_7:.*]] = arith.constant 1 : index
18+
! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>
19+
! CHECK: %[[VAL_9:.*]] = fir.box_elesize %[[VAL_8]] : (!fir.box<!fir.ptr<!fir.char<1,?>>>) -> index
20+
! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (index) -> i64
21+
! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> index
22+
! CHECK: %[[VAL_12:.*]] = arith.constant 1 : index
23+
! CHECK: %[[VAL_13:.*]] = arith.subi %[[VAL_11]], %[[VAL_7]] : index
24+
! CHECK: %[[VAL_14:.*]] = arith.addi %[[VAL_13]], %[[VAL_12]] : index
25+
! CHECK: %[[VAL_15:.*]] = arith.constant 0 : index
26+
! CHECK: %[[VAL_16:.*]] = arith.cmpi sgt, %[[VAL_14]], %[[VAL_15]] : index
27+
! CHECK: %[[VAL_17:.*]] = arith.select %[[VAL_16]], %[[VAL_14]], %[[VAL_15]] : index
28+
! CHECK: %[[VAL_18:.*]] = hlfir.designate %[[VAL_6]] substr %[[VAL_7]], %[[VAL_11]] typeparams %[[VAL_17]] : (!fir.boxchar<1>, index, index, index) -> !fir.boxchar<1>
29+
! CHECK: %[[VAL_19:.*]] = fir.box_addr %[[VAL_18]] : (!fir.boxchar<1>) -> !fir.ref<!fir.char<1,?>>
30+
! CHECK: omp.task depend(taskdependout -> %[[VAL_19]] : !fir.ref<!fir.char<1,?>>) {
31+
! CHECK: omp.terminator
32+
! CHECK: }
33+
! CHECK: return
34+
! CHECK: }
35+
36+
subroutine substring_1(c)
37+
character(:), pointer :: c
38+
!$omp task depend(out:c(2:))
39+
!$omp end task
40+
end
41+
! CHECK-LABEL: func.func @_QPsubstring_1(
42+
! CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>> {fir.bindc_name = "c"}) {
43+
! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
44+
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFsubstring_1Ec"} : (!fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>)
45+
! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>
46+
! CHECK: %[[VAL_3:.*]] = fir.box_addr %[[VAL_2]] : (!fir.box<!fir.ptr<!fir.char<1,?>>>) -> !fir.ptr<!fir.char<1,?>>
47+
! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>
48+
! CHECK: %[[VAL_5:.*]] = fir.box_elesize %[[VAL_4]] : (!fir.box<!fir.ptr<!fir.char<1,?>>>) -> index
49+
! CHECK: %[[VAL_6:.*]] = fir.emboxchar %[[VAL_3]], %[[VAL_5]] : (!fir.ptr<!fir.char<1,?>>, index) -> !fir.boxchar<1>
50+
! CHECK: %[[VAL_7:.*]] = arith.constant 2 : index
51+
! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>
52+
! CHECK: %[[VAL_9:.*]] = fir.box_elesize %[[VAL_8]] : (!fir.box<!fir.ptr<!fir.char<1,?>>>) -> index
53+
! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (index) -> i64
54+
! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> index
55+
! CHECK: %[[VAL_12:.*]] = arith.constant 1 : index
56+
! CHECK: %[[VAL_13:.*]] = arith.subi %[[VAL_11]], %[[VAL_7]] : index
57+
! CHECK: %[[VAL_14:.*]] = arith.addi %[[VAL_13]], %[[VAL_12]] : index
58+
! CHECK: %[[VAL_15:.*]] = arith.constant 0 : index
59+
! CHECK: %[[VAL_16:.*]] = arith.cmpi sgt, %[[VAL_14]], %[[VAL_15]] : index
60+
! CHECK: %[[VAL_17:.*]] = arith.select %[[VAL_16]], %[[VAL_14]], %[[VAL_15]] : index
61+
! CHECK: %[[VAL_18:.*]] = hlfir.designate %[[VAL_6]] substr %[[VAL_7]], %[[VAL_11]] typeparams %[[VAL_17]] : (!fir.boxchar<1>, index, index, index) -> !fir.boxchar<1>
62+
! CHECK: %[[VAL_19:.*]] = fir.box_addr %[[VAL_18]] : (!fir.boxchar<1>) -> !fir.ref<!fir.char<1,?>>
63+
! CHECK: omp.task depend(taskdependout -> %[[VAL_19]] : !fir.ref<!fir.char<1,?>>) {
64+
! CHECK: omp.terminator
65+
! CHECK: }
66+
! CHECK: return
67+
! CHECK: }
68+
69+
subroutine substring_2(c)
70+
character(:), pointer :: c
71+
!$omp task depend(out:c(:2))
72+
!$omp end task
73+
end
74+
! CHECK-LABEL: func.func @_QPsubstring_2(
75+
! CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>> {fir.bindc_name = "c"}) {
76+
! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
77+
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFsubstring_2Ec"} : (!fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>)
78+
! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>
79+
! CHECK: %[[VAL_3:.*]] = fir.box_addr %[[VAL_2]] : (!fir.box<!fir.ptr<!fir.char<1,?>>>) -> !fir.ptr<!fir.char<1,?>>
80+
! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>
81+
! CHECK: %[[VAL_5:.*]] = fir.box_elesize %[[VAL_4]] : (!fir.box<!fir.ptr<!fir.char<1,?>>>) -> index
82+
! CHECK: %[[VAL_6:.*]] = fir.emboxchar %[[VAL_3]], %[[VAL_5]] : (!fir.ptr<!fir.char<1,?>>, index) -> !fir.boxchar<1>
83+
! CHECK: %[[VAL_7:.*]] = arith.constant 1 : index
84+
! CHECK: %[[VAL_8:.*]] = arith.constant 2 : index
85+
! CHECK: %[[VAL_9:.*]] = arith.constant 2 : index
86+
! CHECK: %[[VAL_10:.*]] = hlfir.designate %[[VAL_6]] substr %[[VAL_7]], %[[VAL_8]] typeparams %[[VAL_9]] : (!fir.boxchar<1>, index, index, index) -> !fir.ref<!fir.char<1,2>>
87+
! CHECK: omp.task depend(taskdependout -> %[[VAL_10]] : !fir.ref<!fir.char<1,2>>) {
88+
! CHECK: omp.terminator
89+
! CHECK: }
90+
! CHECK: return
91+
! CHECK: }
92+
93+
subroutine substring_4(c)
94+
character(:), pointer :: c
95+
!$omp task depend(out:c)
96+
!$omp end task
97+
end
98+
! CHECK-LABEL: func.func @_QPsubstring_4(
99+
! CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>> {fir.bindc_name = "c"}) {
100+
! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
101+
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFsubstring_4Ec"} : (!fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>)
102+
! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.char<1,?>>>>
103+
! CHECK: %[[VAL_3:.*]] = fir.box_addr %[[VAL_2]] : (!fir.box<!fir.ptr<!fir.char<1,?>>>) -> !fir.ptr<!fir.char<1,?>>
104+
! CHECK: omp.task depend(taskdependout -> %[[VAL_3]] : !fir.ptr<!fir.char<1,?>>) {
105+
! CHECK: omp.terminator
106+
! CHECK: }
107+
! CHECK: return
108+
! CHECK: }
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
! RUN: %python %S/../test_errors.py %s %flang -fopenmp
2+
! Test for parsing confusion between array indexing and string subscripts
3+
4+
! This is okay: selects the whole substring
5+
subroutine substring_0(c)
6+
character(:), pointer :: c
7+
!PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
8+
!$omp task depend(out:c(:))
9+
!$omp end task
10+
end
11+
12+
! This is okay: selects from the second character onwards
13+
subroutine substring_1(c)
14+
character(:), pointer :: c
15+
!PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
16+
!$omp task depend(out:c(2:))
17+
!$omp end task
18+
end
19+
20+
! This is okay: selects the first 2 characters
21+
subroutine substring_2(c)
22+
character(:), pointer :: c
23+
!PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
24+
!$omp task depend(out:c(:2))
25+
!$omp end task
26+
end
27+
28+
! Error
29+
subroutine substring_3(c)
30+
character(:), pointer :: c
31+
!PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
32+
!ERROR: Substrings must be in the form parent-string(lb:ub)
33+
!$omp task depend(out:c(2))
34+
!$omp end task
35+
end
36+
37+
! This is okay: interpreted as indexing into the array not as a substring
38+
subroutine substring_3b(c)
39+
character(:), pointer :: c(:)
40+
!$omp task depend(out:c(2))
41+
!$omp end task
42+
end
43+
44+
! This is okay: no indexing or substring at all
45+
subroutine substring_4(c)
46+
character(:), pointer :: c
47+
!$omp task depend(out:c)
48+
!$omp end task
49+
end
50+
51+
! This is not okay: substrings can't have a stride
52+
subroutine substring_5(c)
53+
character(:), pointer :: c
54+
!PORTABILITY: The use of substrings in OpenMP argument lists has been disallowed since OpenMP 5.2.
55+
!ERROR: Cannot specify a step for a substring
56+
!$omp task depend(out:c(1:20:5))
57+
!$omp end task
58+
end
59+
60+
! This is okay: interpreted as indexing the array
61+
subroutine substring_5b(c)
62+
character(:), pointer :: c(:)
63+
!$omp task depend(out:c(1:20:5))
64+
!$omp end task
65+
end

0 commit comments

Comments
 (0)