Skip to content

Commit 15d22c2

Browse files
kparzyszHoney Goyal
authored andcommitted
[flang][OpenMP] Reject END DO on construct that crosses label-DO (llvm#169714)
In a label-DO construct where two or more loops share the same teminator, an OpenMP construct must enclose all the loops if an end-directive is present. E.g. ``` do 100 i = 1,10 !$omp do do 100 j = 1,10 100 continue !$omp end do ! Error, but ok if this line is removed ``` Fixes llvm#169536.
1 parent 89301e9 commit 15d22c2

File tree

6 files changed

+51
-8
lines changed

6 files changed

+51
-8
lines changed

flang/include/flang/Parser/parse-tree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4982,7 +4982,7 @@ struct OmpClauseList {
49824982
// --- Directives and constructs
49834983

49844984
struct OmpDirectiveSpecification {
4985-
ENUM_CLASS(Flag, DeprecatedSyntax)
4985+
ENUM_CLASS(Flag, DeprecatedSyntax, CrossesLabelDo)
49864986
using Flags = common::EnumSet<Flag, Flag_enumSize>;
49874987

49884988
TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification);

flang/lib/Semantics/canonicalize-do.cpp

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,12 @@ class CanonicalizationOfDoLoops {
9292
[&](common::Indirection<OpenMPConstruct> &construct) {
9393
// If the body of the OpenMP construct ends with a label,
9494
// treat the label as ending the construct itself.
95-
CanonicalizeIfMatch(
96-
block, stack, i, omp::GetFinalLabel(construct.value()));
95+
OpenMPConstruct &omp{construct.value()};
96+
if (CanonicalizeIfMatch(
97+
block, stack, i, omp::GetFinalLabel(omp))) {
98+
MarkOpenMPConstruct(
99+
omp, OmpDirectiveSpecification::Flag::CrossesLabelDo);
100+
}
97101
},
98102
},
99103
executableConstruct->u);
@@ -103,12 +107,12 @@ class CanonicalizationOfDoLoops {
103107

104108
private:
105109
template <typename T>
106-
void CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
110+
bool CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
107111
Block::iterator &i, Statement<T> &statement) {
108-
CanonicalizeIfMatch(originalBlock, stack, i, statement.label);
112+
return CanonicalizeIfMatch(originalBlock, stack, i, statement.label);
109113
}
110114

111-
void CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
115+
bool CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
112116
Block::iterator &i, std::optional<Label> label) {
113117
if (!stack.empty() && label && stack.back().label == *label) {
114118
auto currentLabel{stack.back().label};
@@ -141,8 +145,27 @@ class CanonicalizationOfDoLoops {
141145
stack.pop_back();
142146
} while (!stack.empty() && stack.back().label == currentLabel);
143147
i = --next;
148+
return true;
149+
} else {
150+
return false;
144151
}
145152
}
153+
154+
void MarkOpenMPConstruct(
155+
OpenMPConstruct &omp, OmpDirectiveSpecification::Flag flag) {
156+
common::visit(
157+
[&](const auto &s) {
158+
using S = std::decay_t<decltype(s)>;
159+
if constexpr (std::is_base_of_v<OmpBlockConstruct, S> ||
160+
std::is_same_v<OpenMPLoopConstruct, S>) {
161+
const OmpDirectiveSpecification &beginSpec{s.BeginDir()};
162+
auto &flags{
163+
std::get<OmpDirectiveSpecification::Flags>(beginSpec.t)};
164+
const_cast<OmpDirectiveSpecification::Flags &>(flags).set(flag);
165+
}
166+
},
167+
omp.u);
168+
}
146169
};
147170

148171
bool CanonicalizeDo(Program &program) {

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,25 @@ void OmpStructureChecker::CheckNestedConstruct(
290290
const parser::OpenMPLoopConstruct &x) {
291291
size_t nestedCount{0};
292292

293+
// End-directive is not allowed in such cases:
294+
// do 100 i = ...
295+
// !$omp do
296+
// do 100 j = ...
297+
// 100 continue
298+
// !$omp end do ! error
299+
const parser::OmpDirectiveSpecification &beginSpec{x.BeginDir()};
300+
auto &flags{std::get<parser::OmpDirectiveSpecification::Flags>(beginSpec.t)};
301+
if (flags.test(parser::OmpDirectiveSpecification::Flag::CrossesLabelDo)) {
302+
if (auto &endSpec{x.EndDir()}) {
303+
parser::CharBlock beginSource{beginSpec.DirName().source};
304+
context_
305+
.Say(endSpec->DirName().source,
306+
"END %s directive is not allowed when the construct does not contain all loops that share a loop-terminating statement"_err_en_US,
307+
parser::ToUpperCaseLetters(beginSource.ToString()))
308+
.Attach(beginSource, "The construct starts here"_en_US);
309+
}
310+
}
311+
293312
auto &body{std::get<parser::Block>(x.t)};
294313
if (body.empty()) {
295314
context_.Say(x.source,

flang/test/Parser/OpenMP/atomic-label-do.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ subroutine f
2929
!PARSE-TREE: | | | OmpBeginDirective
3030
!PARSE-TREE: | | | | OmpDirectiveName -> llvm::omp::Directive = atomic
3131
!PARSE-TREE: | | | | OmpClauseList -> OmpClause -> Write
32-
!PARSE-TREE: | | | | Flags = {}
32+
!PARSE-TREE: | | | | Flags = {CrossesLabelDo}
3333
!PARSE-TREE: | | | Block
3434
!PARSE-TREE: | | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'x=i'
3535
!PARSE-TREE: | | | | | Variable = 'x'

flang/test/Parser/OpenMP/cross-label-do.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ subroutine f00
3232
!PARSE-TREE: | | | OmpBeginLoopDirective
3333
!PARSE-TREE: | | | | OmpDirectiveName -> llvm::omp::Directive = do
3434
!PARSE-TREE: | | | | OmpClauseList ->
35-
!PARSE-TREE: | | | | Flags = {}
35+
!PARSE-TREE: | | | | Flags = {CrossesLabelDo}
3636
!PARSE-TREE: | | | Block
3737
!PARSE-TREE: | | | | ExecutionPartConstruct -> ExecutableConstruct -> DoConstruct
3838
!PARSE-TREE: | | | | | NonLabelDoStmt

flang/test/Semantics/OpenMP/loop-association.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
do 100 j=1, N
6565
a = 3.14
6666
100 continue
67+
!ERROR: END DO directive is not allowed when the construct does not contain all loops that share a loop-terminating statement
6768
!$omp enddo
6869

6970
!ERROR: Non-THREADPRIVATE object 'a' in COPYIN clause

0 commit comments

Comments
 (0)