Skip to content

Commit 746bf29

Browse files
[Flang][OpenMP] Add checks for EXIT from associated loops (#91315)
Extend the checker that deals with CYCLE to handle EXIT also. The difference for EXIT is that it is not allowed to EXIT from the innermost associated loops while it is OK to CYCLE in the innermost associated loop. Also add an incrementer on leaving the DO loop for EXIT checks.
1 parent 57b9c15 commit 746bf29

File tree

2 files changed

+63
-15
lines changed

2 files changed

+63
-15
lines changed

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

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,52 +84,69 @@ class OmpWorkshareBlockChecker {
8484
parser::CharBlock source_;
8585
};
8686

87-
class OmpCycleChecker {
87+
class OmpCycleAndExitChecker {
8888
public:
89-
OmpCycleChecker(SemanticsContext &context, std::int64_t cycleLevel)
90-
: context_{context}, cycleLevel_{cycleLevel} {}
89+
OmpCycleAndExitChecker(SemanticsContext &context, std::int64_t level)
90+
: context_{context}, level_{level} {}
9191

9292
template <typename T> bool Pre(const T &) { return true; }
9393
template <typename T> void Post(const T &) {}
9494

9595
bool Pre(const parser::DoConstruct &dc) {
96-
cycleLevel_--;
96+
level_--;
9797
const auto &constructName{std::get<0>(std::get<0>(dc.t).statement.t)};
9898
if (constructName) {
9999
constructNamesAndLevels_.emplace(
100-
constructName.value().ToString(), cycleLevel_);
100+
constructName.value().ToString(), level_);
101101
}
102102
return true;
103103
}
104104

105+
void Post(const parser::DoConstruct &dc) { level_++; }
106+
105107
bool Pre(const parser::CycleStmt &cyclestmt) {
106108
std::map<std::string, std::int64_t>::iterator it;
107109
bool err{false};
108110
if (cyclestmt.v) {
109111
it = constructNamesAndLevels_.find(cyclestmt.v->source.ToString());
110112
err = (it != constructNamesAndLevels_.end() && it->second > 0);
111-
} else {
112-
// If there is no label then the cycle statement is associated with the
113-
// closest enclosing DO. Use its level for the checks.
114-
err = cycleLevel_ > 0;
113+
} else { // If there is no label then use the level of the last enclosing DO
114+
err = level_ > 0;
115115
}
116116
if (err) {
117-
context_.Say(*cycleSource_,
117+
context_.Say(*source_,
118118
"CYCLE statement to non-innermost associated loop of an OpenMP DO "
119119
"construct"_err_en_US);
120120
}
121121
return true;
122122
}
123123

124+
bool Pre(const parser::ExitStmt &exitStmt) {
125+
std::map<std::string, std::int64_t>::iterator it;
126+
bool err{false};
127+
if (exitStmt.v) {
128+
it = constructNamesAndLevels_.find(exitStmt.v->source.ToString());
129+
err = (it != constructNamesAndLevels_.end() && it->second >= 0);
130+
} else { // If there is no label then use the level of the last enclosing DO
131+
err = level_ >= 0;
132+
}
133+
if (err) {
134+
context_.Say(*source_,
135+
"EXIT statement terminates associated loop of an OpenMP DO "
136+
"construct"_err_en_US);
137+
}
138+
return true;
139+
}
140+
124141
bool Pre(const parser::Statement<parser::ActionStmt> &actionstmt) {
125-
cycleSource_ = &actionstmt.source;
142+
source_ = &actionstmt.source;
126143
return true;
127144
}
128145

129146
private:
130147
SemanticsContext &context_;
131-
const parser::CharBlock *cycleSource_;
132-
std::int64_t cycleLevel_;
148+
const parser::CharBlock *source_;
149+
std::int64_t level_;
133150
std::map<std::string, std::int64_t> constructNamesAndLevels_;
134151
};
135152

@@ -657,8 +674,8 @@ std::int64_t OmpStructureChecker::GetOrdCollapseLevel(
657674
void OmpStructureChecker::CheckCycleConstraints(
658675
const parser::OpenMPLoopConstruct &x) {
659676
std::int64_t ordCollapseLevel{GetOrdCollapseLevel(x)};
660-
OmpCycleChecker ompCycleChecker{context_, ordCollapseLevel};
661-
parser::Walk(x, ompCycleChecker);
677+
OmpCycleAndExitChecker checker{context_, ordCollapseLevel};
678+
parser::Walk(x, checker);
662679
}
663680

664681
void OmpStructureChecker::CheckDistLinear(

flang/test/Semantics/OpenMP/do08.f90

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
program omp
66
integer i, j, k
7+
logical cond(10,10,10)
8+
cond = .false.
79

810
!ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
911
!$omp do collapse(3)
@@ -135,4 +137,33 @@ program omp
135137
end do foo
136138
!$omp end do
137139

140+
!$omp do collapse(3)
141+
loopk: do k=1,10
142+
loopj: do j=1,10
143+
loopi: do i=1,10
144+
ifi : if (.true.) then
145+
!ERROR: EXIT statement terminates associated loop of an OpenMP DO construct
146+
if (cond(i,j,k)) exit
147+
if (cond(i,j,k)) exit ifi
148+
!ERROR: EXIT statement terminates associated loop of an OpenMP DO construct
149+
if (cond(i,j,k)) exit loopi
150+
!ERROR: EXIT statement terminates associated loop of an OpenMP DO construct
151+
if (cond(i,j,k)) exit loopj
152+
end if ifi
153+
end do loopi
154+
end do loopj
155+
end do loopk
156+
!$omp end do
157+
158+
!$omp do collapse(2)
159+
loopk: do k=1,10
160+
loopj: do j=1,10
161+
do i=1,10
162+
end do
163+
!ERROR: EXIT statement terminates associated loop of an OpenMP DO construct
164+
if (cond(i,j,k)) exit
165+
end do loopj
166+
end do loopk
167+
!$omp end do
168+
138169
end program omp

0 commit comments

Comments
 (0)