1 //===-- lib/Semantics/check-coarray.cpp -----------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "check-coarray.h"
10 #include "flang/Common/indirection.h"
11 #include "flang/Evaluate/expression.h"
12 #include "flang/Parser/message.h"
13 #include "flang/Parser/parse-tree.h"
14 #include "flang/Parser/tools.h"
15 #include "flang/Semantics/expression.h"
16 #include "flang/Semantics/tools.h"
18 namespace Fortran::semantics
{
20 class CriticalBodyEnforce
{
23 SemanticsContext
&context
, parser::CharBlock criticalSourcePosition
)
24 : context_
{context
}, criticalSourcePosition_
{criticalSourcePosition
} {}
25 std::set
<parser::Label
> labels() { return labels_
; }
26 template <typename T
> bool Pre(const T
&) { return true; }
27 template <typename T
> void Post(const T
&) {}
29 template <typename T
> bool Pre(const parser::Statement
<T
> &statement
) {
30 currentStatementSourcePosition_
= statement
.source
;
31 if (statement
.label
.has_value()) {
32 labels_
.insert(*statement
.label
);
38 void Post(const parser::ReturnStmt
&) {
40 .Say(currentStatementSourcePosition_
,
41 "RETURN statement is not allowed in a CRITICAL construct"_err_en_US
)
42 .Attach(criticalSourcePosition_
, GetEnclosingMsg());
44 void Post(const parser::ExecutableConstruct
&construct
) {
45 if (IsImageControlStmt(construct
)) {
47 .Say(currentStatementSourcePosition_
,
48 "An image control statement is not allowed in a CRITICAL"
49 " construct"_err_en_US
)
50 .Attach(criticalSourcePosition_
, GetEnclosingMsg());
55 parser::MessageFixedText
GetEnclosingMsg() {
56 return "Enclosing CRITICAL statement"_en_US
;
59 SemanticsContext
&context_
;
60 std::set
<parser::Label
> labels_
;
61 parser::CharBlock currentStatementSourcePosition_
;
62 parser::CharBlock criticalSourcePosition_
;
66 static void CheckTeamType(SemanticsContext
&context
, const T
&x
) {
67 if (const auto *expr
{GetExpr(context
, x
)}) {
68 if (!IsTeamType(evaluate::GetDerivedTypeSpec(expr
->GetType()))) {
69 context
.Say(parser::FindSourceLocation(x
), // C1114
70 "Team value must be of type TEAM_TYPE from module ISO_FORTRAN_ENV"_err_en_US
);
75 static void CheckTeamStat(
76 SemanticsContext
&context
, const parser::ImageSelectorSpec::Stat
&stat
) {
77 const parser::Variable
&var
{stat
.v
.thing
.thing
.value()};
78 if (parser::GetCoindexedNamedObject(var
)) {
79 context
.Say(parser::FindSourceLocation(var
), // C931
80 "Image selector STAT variable must not be a coindexed "
85 static void CheckCoindexedStatOrErrmsg(SemanticsContext
&context
,
86 const parser::StatOrErrmsg
&statOrErrmsg
, const std::string
&listName
) {
87 auto CoindexedCheck
{[&](const auto &statOrErrmsg
) {
88 if (const auto *expr
{GetExpr(context
, statOrErrmsg
)}) {
89 if (ExtractCoarrayRef(expr
)) {
90 context
.Say(parser::FindSourceLocation(statOrErrmsg
), // C1173
91 "The stat-variable or errmsg-variable in a %s may not be a coindexed object"_err_en_US
,
96 Fortran::common::visit(CoindexedCheck
, statOrErrmsg
.u
);
99 static void CheckSyncStatList(
100 SemanticsContext
&context
, const std::list
<parser::StatOrErrmsg
> &list
) {
101 bool gotStat
{false}, gotMsg
{false};
103 for (const parser::StatOrErrmsg
&statOrErrmsg
: list
) {
106 [&](const parser::StatVariable
&stat
) {
108 context
.Say( // C1172
109 "The stat-variable in a sync-stat-list may not be repeated"_err_en_US
);
113 [&](const parser::MsgVariable
&var
) {
114 WarnOnDeferredLengthCharacterScalar(context
,
115 GetExpr(context
, var
), var
.v
.thing
.thing
.GetSource(),
118 context
.Say( // C1172
119 "The errmsg-variable in a sync-stat-list may not be repeated"_err_en_US
);
126 CheckCoindexedStatOrErrmsg(context
, statOrErrmsg
, "sync-stat-list");
130 static void CheckEventVariable(
131 SemanticsContext
&context
, const parser::EventVariable
&eventVar
) {
132 if (const auto *expr
{GetExpr(context
, eventVar
)}) {
133 if (!IsEventType(evaluate::GetDerivedTypeSpec(expr
->GetType()))) { // C1176
134 context
.Say(parser::FindSourceLocation(eventVar
),
135 "The event-variable must be of type EVENT_TYPE from module ISO_FORTRAN_ENV"_err_en_US
);
140 void CoarrayChecker::Leave(const parser::ChangeTeamStmt
&x
) {
141 CheckNamesAreDistinct(std::get
<std::list
<parser::CoarrayAssociation
>>(x
.t
));
142 CheckTeamType(context_
, std::get
<parser::TeamValue
>(x
.t
));
143 CheckSyncStatList(context_
, std::get
<std::list
<parser::StatOrErrmsg
>>(x
.t
));
146 void CoarrayChecker::Leave(const parser::EndChangeTeamStmt
&x
) {
147 CheckSyncStatList(context_
, std::get
<std::list
<parser::StatOrErrmsg
>>(x
.t
));
150 void CoarrayChecker::Leave(const parser::SyncAllStmt
&x
) {
151 CheckSyncStatList(context_
, x
.v
);
154 void CoarrayChecker::Leave(const parser::SyncImagesStmt
&x
) {
155 CheckSyncStatList(context_
, std::get
<std::list
<parser::StatOrErrmsg
>>(x
.t
));
157 const auto &imageSet
{std::get
<parser::SyncImagesStmt::ImageSet
>(x
.t
)};
158 if (const auto *intExpr
{std::get_if
<parser::IntExpr
>(&imageSet
.u
)}) {
159 if (const auto *expr
{GetExpr(context_
, *intExpr
)}) {
160 if (expr
->Rank() > 1) {
161 context_
.Say(parser::FindSourceLocation(imageSet
), // C1174
162 "An image-set that is an int-expr must be a scalar or a rank-one array"_err_en_US
);
168 void CoarrayChecker::Leave(const parser::SyncMemoryStmt
&x
) {
169 CheckSyncStatList(context_
, x
.v
);
172 void CoarrayChecker::Leave(const parser::SyncTeamStmt
&x
) {
173 CheckTeamType(context_
, std::get
<parser::TeamValue
>(x
.t
));
174 CheckSyncStatList(context_
, std::get
<std::list
<parser::StatOrErrmsg
>>(x
.t
));
177 static void CheckEventWaitSpecList(SemanticsContext
&context
,
178 const std::list
<parser::EventWaitSpec
> &eventWaitSpecList
) {
179 bool gotStat
{false}, gotMsg
{false}, gotUntil
{false};
180 for (const parser::EventWaitSpec
&eventWaitSpec
: eventWaitSpecList
) {
183 [&](const parser::ScalarIntExpr
&untilCount
) {
185 context
.Say( // C1178
186 "Until-spec in a event-wait-spec-list may not be repeated"_err_en_US
);
190 [&](const parser::StatOrErrmsg
&statOrErrmsg
) {
193 [&](const parser::StatVariable
&stat
) {
195 context
.Say( // C1178
196 "A stat-variable in a event-wait-spec-list may not be repeated"_err_en_US
);
200 [&](const parser::MsgVariable
&var
) {
201 WarnOnDeferredLengthCharacterScalar(context
,
202 GetExpr(context
, var
),
203 var
.v
.thing
.thing
.GetSource(), "ERRMSG=");
205 context
.Say( // C1178
206 "A errmsg-variable in a event-wait-spec-list may not be repeated"_err_en_US
);
212 CheckCoindexedStatOrErrmsg(
213 context
, statOrErrmsg
, "event-wait-spec-list");
221 void CoarrayChecker::Leave(const parser::NotifyWaitStmt
&x
) {
222 const auto ¬ifyVar
{std::get
<parser::Scalar
<parser::Variable
>>(x
.t
)};
224 if (const auto *expr
{GetExpr(context_
, notifyVar
)}) {
225 if (ExtractCoarrayRef(expr
)) {
226 context_
.Say(parser::FindSourceLocation(notifyVar
), // F2023 - C1178
227 "A notify-variable in a NOTIFY WAIT statement may not be a coindexed object"_err_en_US
);
228 } else if (!IsNotifyType(evaluate::GetDerivedTypeSpec(
229 expr
->GetType()))) { // F2023 - C1177
230 context_
.Say(parser::FindSourceLocation(notifyVar
),
231 "The notify-variable must be of type NOTIFY_TYPE from module ISO_FORTRAN_ENV"_err_en_US
);
232 } else if (!evaluate::IsCoarray(*expr
)) { // F2023 - C1612
233 context_
.Say(parser::FindSourceLocation(notifyVar
),
234 "The notify-variable must be a coarray"_err_en_US
);
238 CheckEventWaitSpecList(
239 context_
, std::get
<std::list
<parser::EventWaitSpec
>>(x
.t
));
242 void CoarrayChecker::Leave(const parser::EventPostStmt
&x
) {
243 CheckSyncStatList(context_
, std::get
<std::list
<parser::StatOrErrmsg
>>(x
.t
));
244 CheckEventVariable(context_
, std::get
<parser::EventVariable
>(x
.t
));
247 void CoarrayChecker::Leave(const parser::EventWaitStmt
&x
) {
248 const auto &eventVar
{std::get
<parser::EventVariable
>(x
.t
)};
250 if (const auto *expr
{GetExpr(context_
, eventVar
)}) {
251 if (ExtractCoarrayRef(expr
)) {
252 context_
.Say(parser::FindSourceLocation(eventVar
), // C1177
253 "A event-variable in a EVENT WAIT statement may not be a coindexed object"_err_en_US
);
255 CheckEventVariable(context_
, eventVar
);
259 CheckEventWaitSpecList(
260 context_
, std::get
<std::list
<parser::EventWaitSpec
>>(x
.t
));
263 void CoarrayChecker::Leave(const parser::UnlockStmt
&x
) {
264 CheckSyncStatList(context_
, std::get
<std::list
<parser::StatOrErrmsg
>>(x
.t
));
267 void CoarrayChecker::Leave(const parser::CriticalStmt
&x
) {
268 CheckSyncStatList(context_
, std::get
<std::list
<parser::StatOrErrmsg
>>(x
.t
));
271 void CoarrayChecker::Leave(const parser::ImageSelector
&imageSelector
) {
274 haveTeamNumber_
= false;
275 for (const auto &imageSelectorSpec
:
276 std::get
<std::list
<parser::ImageSelectorSpec
>>(imageSelector
.t
)) {
277 if (const auto *team
{
278 std::get_if
<parser::TeamValue
>(&imageSelectorSpec
.u
)}) {
280 context_
.Say(parser::FindSourceLocation(imageSelectorSpec
), // C929
281 "TEAM value can only be specified once"_err_en_US
);
283 CheckTeamType(context_
, *team
);
286 if (const auto *stat
{std::get_if
<parser::ImageSelectorSpec::Stat
>(
287 &imageSelectorSpec
.u
)}) {
289 context_
.Say(parser::FindSourceLocation(imageSelectorSpec
), // C929
290 "STAT variable can only be specified once"_err_en_US
);
292 CheckTeamStat(context_
, *stat
);
295 if (std::get_if
<parser::ImageSelectorSpec::Team_Number
>(
296 &imageSelectorSpec
.u
)) {
297 if (haveTeamNumber_
) {
298 context_
.Say(parser::FindSourceLocation(imageSelectorSpec
), // C929
299 "TEAM_NUMBER value can only be specified once"_err_en_US
);
301 haveTeamNumber_
= true;
304 if (haveTeam_
&& haveTeamNumber_
) {
305 context_
.Say(parser::FindSourceLocation(imageSelector
), // C930
306 "Cannot specify both TEAM and TEAM_NUMBER"_err_en_US
);
310 void CoarrayChecker::Leave(const parser::FormTeamStmt
&x
) {
311 CheckTeamType(context_
, std::get
<parser::TeamVariable
>(x
.t
));
314 void CoarrayChecker::Enter(const parser::CriticalConstruct
&x
) {
315 auto &criticalStmt
{std::get
<parser::Statement
<parser::CriticalStmt
>>(x
.t
)};
317 const parser::Block
&block
{std::get
<parser::Block
>(x
.t
)};
318 CriticalBodyEnforce criticalBodyEnforce
{context_
, criticalStmt
.source
};
319 parser::Walk(block
, criticalBodyEnforce
);
322 LabelEnforce criticalLabelEnforce
{
323 context_
, criticalBodyEnforce
.labels(), criticalStmt
.source
, "CRITICAL"};
324 parser::Walk(block
, criticalLabelEnforce
);
327 // Check that coarray names and selector names are all distinct.
328 void CoarrayChecker::CheckNamesAreDistinct(
329 const std::list
<parser::CoarrayAssociation
> &list
) {
330 std::set
<parser::CharBlock
> names
;
332 [&](const parser::Name
&name
) -> const parser::CharBlock
* {
333 auto pair
{names
.insert(name
.source
)};
334 return !pair
.second
? &*pair
.first
: nullptr;
336 for (const auto &assoc
: list
) {
337 const auto &decl
{std::get
<parser::CodimensionDecl
>(assoc
.t
)};
338 const auto &selector
{std::get
<parser::Selector
>(assoc
.t
)};
339 const auto &declName
{std::get
<parser::Name
>(decl
.t
)};
340 if (context_
.HasError(declName
)) {
341 continue; // already reported an error about this name
343 if (auto *prev
{getPreviousUse(declName
)}) {
344 Say2(declName
.source
, // C1113
345 "Coarray '%s' was already used as a selector or coarray in this statement"_err_en_US
,
346 *prev
, "Previous use of '%s'"_en_US
);
348 // ResolveNames verified the selector is a simple name
349 const parser::Name
*name
{parser::Unwrap
<parser::Name
>(selector
)};
351 if (auto *prev
{getPreviousUse(*name
)}) {
352 Say2(name
->source
, // C1113, C1115
353 "Selector '%s' was already used as a selector or coarray in this statement"_err_en_US
,
354 *prev
, "Previous use of '%s'"_en_US
);
360 void CoarrayChecker::Say2(const parser::CharBlock
&name1
,
361 parser::MessageFixedText
&&msg1
, const parser::CharBlock
&name2
,
362 parser::MessageFixedText
&&msg2
) {
363 context_
.Say(name1
, std::move(msg1
), name1
)
364 .Attach(name2
, std::move(msg2
), name2
);
366 } // namespace Fortran::semantics