xref: /llvm-project/flang/lib/Semantics/check-coarray.cpp (revision 2625510ef8094457413661ef0ce2651844f584d2)
164ab3302SCarolineConcatto //===-- lib/Semantics/check-coarray.cpp -----------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto 
964ab3302SCarolineConcatto #include "check-coarray.h"
1064ab3302SCarolineConcatto #include "flang/Common/indirection.h"
1164ab3302SCarolineConcatto #include "flang/Evaluate/expression.h"
1264ab3302SCarolineConcatto #include "flang/Parser/message.h"
1364ab3302SCarolineConcatto #include "flang/Parser/parse-tree.h"
1464ab3302SCarolineConcatto #include "flang/Parser/tools.h"
1564ab3302SCarolineConcatto #include "flang/Semantics/expression.h"
1664ab3302SCarolineConcatto #include "flang/Semantics/tools.h"
1764ab3302SCarolineConcatto 
1864ab3302SCarolineConcatto namespace Fortran::semantics {
1964ab3302SCarolineConcatto 
2064ab3302SCarolineConcatto class CriticalBodyEnforce {
2164ab3302SCarolineConcatto public:
2264ab3302SCarolineConcatto   CriticalBodyEnforce(
2364ab3302SCarolineConcatto       SemanticsContext &context, parser::CharBlock criticalSourcePosition)
2464ab3302SCarolineConcatto       : context_{context}, criticalSourcePosition_{criticalSourcePosition} {}
2564ab3302SCarolineConcatto   std::set<parser::Label> labels() { return labels_; }
2664ab3302SCarolineConcatto   template <typename T> bool Pre(const T &) { return true; }
2764ab3302SCarolineConcatto   template <typename T> void Post(const T &) {}
2864ab3302SCarolineConcatto 
2964ab3302SCarolineConcatto   template <typename T> bool Pre(const parser::Statement<T> &statement) {
3064ab3302SCarolineConcatto     currentStatementSourcePosition_ = statement.source;
3164ab3302SCarolineConcatto     if (statement.label.has_value()) {
3264ab3302SCarolineConcatto       labels_.insert(*statement.label);
3364ab3302SCarolineConcatto     }
3464ab3302SCarolineConcatto     return true;
3564ab3302SCarolineConcatto   }
3664ab3302SCarolineConcatto 
3764ab3302SCarolineConcatto   // C1118
3864ab3302SCarolineConcatto   void Post(const parser::ReturnStmt &) {
3964ab3302SCarolineConcatto     context_
4064ab3302SCarolineConcatto         .Say(currentStatementSourcePosition_,
4164ab3302SCarolineConcatto             "RETURN statement is not allowed in a CRITICAL construct"_err_en_US)
4264ab3302SCarolineConcatto         .Attach(criticalSourcePosition_, GetEnclosingMsg());
4364ab3302SCarolineConcatto   }
4464ab3302SCarolineConcatto   void Post(const parser::ExecutableConstruct &construct) {
4564ab3302SCarolineConcatto     if (IsImageControlStmt(construct)) {
4664ab3302SCarolineConcatto       context_
4764ab3302SCarolineConcatto           .Say(currentStatementSourcePosition_,
4864ab3302SCarolineConcatto               "An image control statement is not allowed in a CRITICAL"
4964ab3302SCarolineConcatto               " construct"_err_en_US)
5064ab3302SCarolineConcatto           .Attach(criticalSourcePosition_, GetEnclosingMsg());
5164ab3302SCarolineConcatto     }
5264ab3302SCarolineConcatto   }
5364ab3302SCarolineConcatto 
5464ab3302SCarolineConcatto private:
5564ab3302SCarolineConcatto   parser::MessageFixedText GetEnclosingMsg() {
5664ab3302SCarolineConcatto     return "Enclosing CRITICAL statement"_en_US;
5764ab3302SCarolineConcatto   }
5864ab3302SCarolineConcatto 
5964ab3302SCarolineConcatto   SemanticsContext &context_;
6064ab3302SCarolineConcatto   std::set<parser::Label> labels_;
6164ab3302SCarolineConcatto   parser::CharBlock currentStatementSourcePosition_;
6264ab3302SCarolineConcatto   parser::CharBlock criticalSourcePosition_;
6364ab3302SCarolineConcatto };
6464ab3302SCarolineConcatto 
6564ab3302SCarolineConcatto template <typename T>
6664ab3302SCarolineConcatto static void CheckTeamType(SemanticsContext &context, const T &x) {
677e225423SPeter Klausler   if (const auto *expr{GetExpr(context, x)}) {
6864ab3302SCarolineConcatto     if (!IsTeamType(evaluate::GetDerivedTypeSpec(expr->GetType()))) {
6964ab3302SCarolineConcatto       context.Say(parser::FindSourceLocation(x), // C1114
7064ab3302SCarolineConcatto           "Team value must be of type TEAM_TYPE from module ISO_FORTRAN_ENV"_err_en_US);
7164ab3302SCarolineConcatto     }
7264ab3302SCarolineConcatto   }
7364ab3302SCarolineConcatto }
7464ab3302SCarolineConcatto 
7515fa287bSPete Steinfeld static void CheckTeamStat(
7615fa287bSPete Steinfeld     SemanticsContext &context, const parser::ImageSelectorSpec::Stat &stat) {
7715fa287bSPete Steinfeld   const parser::Variable &var{stat.v.thing.thing.value()};
7815fa287bSPete Steinfeld   if (parser::GetCoindexedNamedObject(var)) {
7915fa287bSPete Steinfeld     context.Say(parser::FindSourceLocation(var), // C931
8015fa287bSPete Steinfeld         "Image selector STAT variable must not be a coindexed "
8115fa287bSPete Steinfeld         "object"_err_en_US);
8215fa287bSPete Steinfeld   }
8315fa287bSPete Steinfeld }
8415fa287bSPete Steinfeld 
85f770b1e9SKatherine Rasmussen static void CheckCoindexedStatOrErrmsg(SemanticsContext &context,
86f770b1e9SKatherine Rasmussen     const parser::StatOrErrmsg &statOrErrmsg, const std::string &listName) {
87f770b1e9SKatherine Rasmussen   auto CoindexedCheck{[&](const auto &statOrErrmsg) {
88f770b1e9SKatherine Rasmussen     if (const auto *expr{GetExpr(context, statOrErrmsg)}) {
89f770b1e9SKatherine Rasmussen       if (ExtractCoarrayRef(expr)) {
90f770b1e9SKatherine Rasmussen         context.Say(parser::FindSourceLocation(statOrErrmsg), // C1173
91f770b1e9SKatherine Rasmussen             "The stat-variable or errmsg-variable in a %s may not be a coindexed object"_err_en_US,
92f770b1e9SKatherine Rasmussen             listName);
93f770b1e9SKatherine Rasmussen       }
94f770b1e9SKatherine Rasmussen     }
95f770b1e9SKatherine Rasmussen   }};
96*77d8cfb3SAlexander Shaposhnikov   Fortran::common::visit(CoindexedCheck, statOrErrmsg.u);
97f770b1e9SKatherine Rasmussen }
98f770b1e9SKatherine Rasmussen 
99f770b1e9SKatherine Rasmussen static void CheckSyncStatList(
100f770b1e9SKatherine Rasmussen     SemanticsContext &context, const std::list<parser::StatOrErrmsg> &list) {
101f770b1e9SKatherine Rasmussen   bool gotStat{false}, gotMsg{false};
102f770b1e9SKatherine Rasmussen 
103f770b1e9SKatherine Rasmussen   for (const parser::StatOrErrmsg &statOrErrmsg : list) {
104f770b1e9SKatherine Rasmussen     common::visit(
105f770b1e9SKatherine Rasmussen         common::visitors{
106f770b1e9SKatherine Rasmussen             [&](const parser::StatVariable &stat) {
107f770b1e9SKatherine Rasmussen               if (gotStat) {
108f770b1e9SKatherine Rasmussen                 context.Say( // C1172
109f770b1e9SKatherine Rasmussen                     "The stat-variable in a sync-stat-list may not be repeated"_err_en_US);
110f770b1e9SKatherine Rasmussen               }
111f770b1e9SKatherine Rasmussen               gotStat = true;
112f770b1e9SKatherine Rasmussen             },
1137871deb8SPeter Klausler             [&](const parser::MsgVariable &var) {
1147871deb8SPeter Klausler               WarnOnDeferredLengthCharacterScalar(context,
1157871deb8SPeter Klausler                   GetExpr(context, var), var.v.thing.thing.GetSource(),
1167871deb8SPeter Klausler                   "ERRMSG=");
117f770b1e9SKatherine Rasmussen               if (gotMsg) {
118f770b1e9SKatherine Rasmussen                 context.Say( // C1172
119f770b1e9SKatherine Rasmussen                     "The errmsg-variable in a sync-stat-list may not be repeated"_err_en_US);
120f770b1e9SKatherine Rasmussen               }
121f770b1e9SKatherine Rasmussen               gotMsg = true;
122f770b1e9SKatherine Rasmussen             },
123f770b1e9SKatherine Rasmussen         },
124f770b1e9SKatherine Rasmussen         statOrErrmsg.u);
125f770b1e9SKatherine Rasmussen 
126f770b1e9SKatherine Rasmussen     CheckCoindexedStatOrErrmsg(context, statOrErrmsg, "sync-stat-list");
127f770b1e9SKatherine Rasmussen   }
128f770b1e9SKatherine Rasmussen }
129f770b1e9SKatherine Rasmussen 
130e0320016SKatherine Rasmussen static void CheckEventVariable(
131e0320016SKatherine Rasmussen     SemanticsContext &context, const parser::EventVariable &eventVar) {
132e0320016SKatherine Rasmussen   if (const auto *expr{GetExpr(context, eventVar)}) {
133e0320016SKatherine Rasmussen     if (!IsEventType(evaluate::GetDerivedTypeSpec(expr->GetType()))) { // C1176
134e0320016SKatherine Rasmussen       context.Say(parser::FindSourceLocation(eventVar),
135e0320016SKatherine Rasmussen           "The event-variable must be of type EVENT_TYPE from module ISO_FORTRAN_ENV"_err_en_US);
136e0320016SKatherine Rasmussen     }
137e0320016SKatherine Rasmussen   }
138e0320016SKatherine Rasmussen }
139e0320016SKatherine Rasmussen 
14064ab3302SCarolineConcatto void CoarrayChecker::Leave(const parser::ChangeTeamStmt &x) {
14164ab3302SCarolineConcatto   CheckNamesAreDistinct(std::get<std::list<parser::CoarrayAssociation>>(x.t));
14264ab3302SCarolineConcatto   CheckTeamType(context_, std::get<parser::TeamValue>(x.t));
1432d5ef391SKatherine Rasmussen   CheckSyncStatList(context_, std::get<std::list<parser::StatOrErrmsg>>(x.t));
1442d5ef391SKatherine Rasmussen }
1452d5ef391SKatherine Rasmussen 
1462d5ef391SKatherine Rasmussen void CoarrayChecker::Leave(const parser::EndChangeTeamStmt &x) {
1472d5ef391SKatherine Rasmussen   CheckSyncStatList(context_, std::get<std::list<parser::StatOrErrmsg>>(x.t));
14864ab3302SCarolineConcatto }
14964ab3302SCarolineConcatto 
150f770b1e9SKatherine Rasmussen void CoarrayChecker::Leave(const parser::SyncAllStmt &x) {
151f770b1e9SKatherine Rasmussen   CheckSyncStatList(context_, x.v);
152f770b1e9SKatherine Rasmussen }
153f770b1e9SKatherine Rasmussen 
154f770b1e9SKatherine Rasmussen void CoarrayChecker::Leave(const parser::SyncImagesStmt &x) {
155f770b1e9SKatherine Rasmussen   CheckSyncStatList(context_, std::get<std::list<parser::StatOrErrmsg>>(x.t));
156f770b1e9SKatherine Rasmussen 
157f770b1e9SKatherine Rasmussen   const auto &imageSet{std::get<parser::SyncImagesStmt::ImageSet>(x.t)};
158f770b1e9SKatherine Rasmussen   if (const auto *intExpr{std::get_if<parser::IntExpr>(&imageSet.u)}) {
159f770b1e9SKatherine Rasmussen     if (const auto *expr{GetExpr(context_, *intExpr)}) {
160f770b1e9SKatherine Rasmussen       if (expr->Rank() > 1) {
161f770b1e9SKatherine Rasmussen         context_.Say(parser::FindSourceLocation(imageSet), // C1174
162f770b1e9SKatherine Rasmussen             "An image-set that is an int-expr must be a scalar or a rank-one array"_err_en_US);
163f770b1e9SKatherine Rasmussen       }
164f770b1e9SKatherine Rasmussen     }
165f770b1e9SKatherine Rasmussen   }
166f770b1e9SKatherine Rasmussen }
167f770b1e9SKatherine Rasmussen 
168f770b1e9SKatherine Rasmussen void CoarrayChecker::Leave(const parser::SyncMemoryStmt &x) {
169f770b1e9SKatherine Rasmussen   CheckSyncStatList(context_, x.v);
170f770b1e9SKatherine Rasmussen }
171f770b1e9SKatherine Rasmussen 
17264ab3302SCarolineConcatto void CoarrayChecker::Leave(const parser::SyncTeamStmt &x) {
17364ab3302SCarolineConcatto   CheckTeamType(context_, std::get<parser::TeamValue>(x.t));
174f770b1e9SKatherine Rasmussen   CheckSyncStatList(context_, std::get<std::list<parser::StatOrErrmsg>>(x.t));
17564ab3302SCarolineConcatto }
17664ab3302SCarolineConcatto 
177a2d7af75SKatherine Rasmussen static void CheckEventWaitSpecList(SemanticsContext &context,
178a2d7af75SKatherine Rasmussen     const std::list<parser::EventWaitSpec> &eventWaitSpecList) {
179a2d7af75SKatherine Rasmussen   bool gotStat{false}, gotMsg{false}, gotUntil{false};
180a2d7af75SKatherine Rasmussen   for (const parser::EventWaitSpec &eventWaitSpec : eventWaitSpecList) {
181a2d7af75SKatherine Rasmussen     common::visit(
182a2d7af75SKatherine Rasmussen         common::visitors{
183a2d7af75SKatherine Rasmussen             [&](const parser::ScalarIntExpr &untilCount) {
184a2d7af75SKatherine Rasmussen               if (gotUntil) {
185a2d7af75SKatherine Rasmussen                 context.Say( // C1178
186a2d7af75SKatherine Rasmussen                     "Until-spec in a event-wait-spec-list may not be repeated"_err_en_US);
187a2d7af75SKatherine Rasmussen               }
188a2d7af75SKatherine Rasmussen               gotUntil = true;
189a2d7af75SKatherine Rasmussen             },
190a2d7af75SKatherine Rasmussen             [&](const parser::StatOrErrmsg &statOrErrmsg) {
191a2d7af75SKatherine Rasmussen               common::visit(
192a2d7af75SKatherine Rasmussen                   common::visitors{
193a2d7af75SKatherine Rasmussen                       [&](const parser::StatVariable &stat) {
194a2d7af75SKatherine Rasmussen                         if (gotStat) {
195a2d7af75SKatherine Rasmussen                           context.Say( // C1178
196a2d7af75SKatherine Rasmussen                               "A stat-variable in a event-wait-spec-list may not be repeated"_err_en_US);
197a2d7af75SKatherine Rasmussen                         }
198a2d7af75SKatherine Rasmussen                         gotStat = true;
199a2d7af75SKatherine Rasmussen                       },
200a2d7af75SKatherine Rasmussen                       [&](const parser::MsgVariable &var) {
201a2d7af75SKatherine Rasmussen                         WarnOnDeferredLengthCharacterScalar(context,
202a2d7af75SKatherine Rasmussen                             GetExpr(context, var),
203a2d7af75SKatherine Rasmussen                             var.v.thing.thing.GetSource(), "ERRMSG=");
204a2d7af75SKatherine Rasmussen                         if (gotMsg) {
205a2d7af75SKatherine Rasmussen                           context.Say( // C1178
206a2d7af75SKatherine Rasmussen                               "A errmsg-variable in a event-wait-spec-list may not be repeated"_err_en_US);
207a2d7af75SKatherine Rasmussen                         }
208a2d7af75SKatherine Rasmussen                         gotMsg = true;
209a2d7af75SKatherine Rasmussen                       },
210a2d7af75SKatherine Rasmussen                   },
211a2d7af75SKatherine Rasmussen                   statOrErrmsg.u);
212a2d7af75SKatherine Rasmussen               CheckCoindexedStatOrErrmsg(
213a2d7af75SKatherine Rasmussen                   context, statOrErrmsg, "event-wait-spec-list");
214a2d7af75SKatherine Rasmussen             },
215a2d7af75SKatherine Rasmussen 
216a2d7af75SKatherine Rasmussen         },
217a2d7af75SKatherine Rasmussen         eventWaitSpec.u);
218a2d7af75SKatherine Rasmussen   }
219a2d7af75SKatherine Rasmussen }
220a2d7af75SKatherine Rasmussen 
221a2d7af75SKatherine Rasmussen void CoarrayChecker::Leave(const parser::NotifyWaitStmt &x) {
222a2d7af75SKatherine Rasmussen   const auto &notifyVar{std::get<parser::Scalar<parser::Variable>>(x.t)};
223a2d7af75SKatherine Rasmussen 
224a2d7af75SKatherine Rasmussen   if (const auto *expr{GetExpr(context_, notifyVar)}) {
225a2d7af75SKatherine Rasmussen     if (ExtractCoarrayRef(expr)) {
226a2d7af75SKatherine Rasmussen       context_.Say(parser::FindSourceLocation(notifyVar), // F2023 - C1178
227a2d7af75SKatherine Rasmussen           "A notify-variable in a NOTIFY WAIT statement may not be a coindexed object"_err_en_US);
228a2d7af75SKatherine Rasmussen     } else if (!IsNotifyType(evaluate::GetDerivedTypeSpec(
229a2d7af75SKatherine Rasmussen                    expr->GetType()))) { // F2023 - C1177
230a2d7af75SKatherine Rasmussen       context_.Say(parser::FindSourceLocation(notifyVar),
231a2d7af75SKatherine Rasmussen           "The notify-variable must be of type NOTIFY_TYPE from module ISO_FORTRAN_ENV"_err_en_US);
232a2d7af75SKatherine Rasmussen     } else if (!evaluate::IsCoarray(*expr)) { // F2023 - C1612
233a2d7af75SKatherine Rasmussen       context_.Say(parser::FindSourceLocation(notifyVar),
234a2d7af75SKatherine Rasmussen           "The notify-variable must be a coarray"_err_en_US);
235a2d7af75SKatherine Rasmussen     }
236a2d7af75SKatherine Rasmussen   }
237a2d7af75SKatherine Rasmussen 
238a2d7af75SKatherine Rasmussen   CheckEventWaitSpecList(
239a2d7af75SKatherine Rasmussen       context_, std::get<std::list<parser::EventWaitSpec>>(x.t));
240a2d7af75SKatherine Rasmussen }
241a2d7af75SKatherine Rasmussen 
242e0320016SKatherine Rasmussen void CoarrayChecker::Leave(const parser::EventPostStmt &x) {
243e0320016SKatherine Rasmussen   CheckSyncStatList(context_, std::get<std::list<parser::StatOrErrmsg>>(x.t));
244e0320016SKatherine Rasmussen   CheckEventVariable(context_, std::get<parser::EventVariable>(x.t));
245e0320016SKatherine Rasmussen }
246e0320016SKatherine Rasmussen 
247e0320016SKatherine Rasmussen void CoarrayChecker::Leave(const parser::EventWaitStmt &x) {
248e0320016SKatherine Rasmussen   const auto &eventVar{std::get<parser::EventVariable>(x.t)};
249e0320016SKatherine Rasmussen 
250e0320016SKatherine Rasmussen   if (const auto *expr{GetExpr(context_, eventVar)}) {
251e0320016SKatherine Rasmussen     if (ExtractCoarrayRef(expr)) {
252e0320016SKatherine Rasmussen       context_.Say(parser::FindSourceLocation(eventVar), // C1177
253e0320016SKatherine Rasmussen           "A event-variable in a EVENT WAIT statement may not be a coindexed object"_err_en_US);
254e0320016SKatherine Rasmussen     } else {
255e0320016SKatherine Rasmussen       CheckEventVariable(context_, eventVar);
256e0320016SKatherine Rasmussen     }
257e0320016SKatherine Rasmussen   }
258e0320016SKatherine Rasmussen 
259a2d7af75SKatherine Rasmussen   CheckEventWaitSpecList(
260a2d7af75SKatherine Rasmussen       context_, std::get<std::list<parser::EventWaitSpec>>(x.t));
261e0320016SKatherine Rasmussen }
262e0320016SKatherine Rasmussen 
2632d5ef391SKatherine Rasmussen void CoarrayChecker::Leave(const parser::UnlockStmt &x) {
2642d5ef391SKatherine Rasmussen   CheckSyncStatList(context_, std::get<std::list<parser::StatOrErrmsg>>(x.t));
2652d5ef391SKatherine Rasmussen }
2662d5ef391SKatherine Rasmussen 
2672d5ef391SKatherine Rasmussen void CoarrayChecker::Leave(const parser::CriticalStmt &x) {
2682d5ef391SKatherine Rasmussen   CheckSyncStatList(context_, std::get<std::list<parser::StatOrErrmsg>>(x.t));
2692d5ef391SKatherine Rasmussen }
2702d5ef391SKatherine Rasmussen 
27115fa287bSPete Steinfeld void CoarrayChecker::Leave(const parser::ImageSelector &imageSelector) {
27215fa287bSPete Steinfeld   haveStat_ = false;
27315fa287bSPete Steinfeld   haveTeam_ = false;
27415fa287bSPete Steinfeld   haveTeamNumber_ = false;
27515fa287bSPete Steinfeld   for (const auto &imageSelectorSpec :
27615fa287bSPete Steinfeld       std::get<std::list<parser::ImageSelectorSpec>>(imageSelector.t)) {
27715fa287bSPete Steinfeld     if (const auto *team{
27815fa287bSPete Steinfeld             std::get_if<parser::TeamValue>(&imageSelectorSpec.u)}) {
27915fa287bSPete Steinfeld       if (haveTeam_) {
28015fa287bSPete Steinfeld         context_.Say(parser::FindSourceLocation(imageSelectorSpec), // C929
28115fa287bSPete Steinfeld             "TEAM value can only be specified once"_err_en_US);
28215fa287bSPete Steinfeld       }
28364ab3302SCarolineConcatto       CheckTeamType(context_, *team);
28415fa287bSPete Steinfeld       haveTeam_ = true;
28515fa287bSPete Steinfeld     }
28615fa287bSPete Steinfeld     if (const auto *stat{std::get_if<parser::ImageSelectorSpec::Stat>(
28715fa287bSPete Steinfeld             &imageSelectorSpec.u)}) {
28815fa287bSPete Steinfeld       if (haveStat_) {
28915fa287bSPete Steinfeld         context_.Say(parser::FindSourceLocation(imageSelectorSpec), // C929
29015fa287bSPete Steinfeld             "STAT variable can only be specified once"_err_en_US);
29115fa287bSPete Steinfeld       }
29215fa287bSPete Steinfeld       CheckTeamStat(context_, *stat);
29315fa287bSPete Steinfeld       haveStat_ = true;
29415fa287bSPete Steinfeld     }
29515fa287bSPete Steinfeld     if (std::get_if<parser::ImageSelectorSpec::Team_Number>(
29615fa287bSPete Steinfeld             &imageSelectorSpec.u)) {
29715fa287bSPete Steinfeld       if (haveTeamNumber_) {
29815fa287bSPete Steinfeld         context_.Say(parser::FindSourceLocation(imageSelectorSpec), // C929
29915fa287bSPete Steinfeld             "TEAM_NUMBER value can only be specified once"_err_en_US);
30015fa287bSPete Steinfeld       }
30115fa287bSPete Steinfeld       haveTeamNumber_ = true;
30215fa287bSPete Steinfeld     }
30315fa287bSPete Steinfeld   }
30415fa287bSPete Steinfeld   if (haveTeam_ && haveTeamNumber_) {
30515fa287bSPete Steinfeld     context_.Say(parser::FindSourceLocation(imageSelector), // C930
30615fa287bSPete Steinfeld         "Cannot specify both TEAM and TEAM_NUMBER"_err_en_US);
30764ab3302SCarolineConcatto   }
30864ab3302SCarolineConcatto }
30964ab3302SCarolineConcatto 
31064ab3302SCarolineConcatto void CoarrayChecker::Leave(const parser::FormTeamStmt &x) {
31164ab3302SCarolineConcatto   CheckTeamType(context_, std::get<parser::TeamVariable>(x.t));
31264ab3302SCarolineConcatto }
31364ab3302SCarolineConcatto 
31464ab3302SCarolineConcatto void CoarrayChecker::Enter(const parser::CriticalConstruct &x) {
31564ab3302SCarolineConcatto   auto &criticalStmt{std::get<parser::Statement<parser::CriticalStmt>>(x.t)};
31664ab3302SCarolineConcatto 
31764ab3302SCarolineConcatto   const parser::Block &block{std::get<parser::Block>(x.t)};
31864ab3302SCarolineConcatto   CriticalBodyEnforce criticalBodyEnforce{context_, criticalStmt.source};
31964ab3302SCarolineConcatto   parser::Walk(block, criticalBodyEnforce);
32064ab3302SCarolineConcatto 
32164ab3302SCarolineConcatto   // C1119
32264ab3302SCarolineConcatto   LabelEnforce criticalLabelEnforce{
32364ab3302SCarolineConcatto       context_, criticalBodyEnforce.labels(), criticalStmt.source, "CRITICAL"};
32464ab3302SCarolineConcatto   parser::Walk(block, criticalLabelEnforce);
32564ab3302SCarolineConcatto }
32664ab3302SCarolineConcatto 
32764ab3302SCarolineConcatto // Check that coarray names and selector names are all distinct.
32864ab3302SCarolineConcatto void CoarrayChecker::CheckNamesAreDistinct(
32964ab3302SCarolineConcatto     const std::list<parser::CoarrayAssociation> &list) {
33064ab3302SCarolineConcatto   std::set<parser::CharBlock> names;
33164ab3302SCarolineConcatto   auto getPreviousUse{
33264ab3302SCarolineConcatto       [&](const parser::Name &name) -> const parser::CharBlock * {
33364ab3302SCarolineConcatto         auto pair{names.insert(name.source)};
33464ab3302SCarolineConcatto         return !pair.second ? &*pair.first : nullptr;
33564ab3302SCarolineConcatto       }};
33664ab3302SCarolineConcatto   for (const auto &assoc : list) {
33764ab3302SCarolineConcatto     const auto &decl{std::get<parser::CodimensionDecl>(assoc.t)};
33864ab3302SCarolineConcatto     const auto &selector{std::get<parser::Selector>(assoc.t)};
33964ab3302SCarolineConcatto     const auto &declName{std::get<parser::Name>(decl.t)};
34064ab3302SCarolineConcatto     if (context_.HasError(declName)) {
34164ab3302SCarolineConcatto       continue; // already reported an error about this name
34264ab3302SCarolineConcatto     }
34364ab3302SCarolineConcatto     if (auto *prev{getPreviousUse(declName)}) {
34464ab3302SCarolineConcatto       Say2(declName.source, // C1113
34564ab3302SCarolineConcatto           "Coarray '%s' was already used as a selector or coarray in this statement"_err_en_US,
34664ab3302SCarolineConcatto           *prev, "Previous use of '%s'"_en_US);
34764ab3302SCarolineConcatto     }
34864ab3302SCarolineConcatto     // ResolveNames verified the selector is a simple name
34964ab3302SCarolineConcatto     const parser::Name *name{parser::Unwrap<parser::Name>(selector)};
35064ab3302SCarolineConcatto     if (name) {
35164ab3302SCarolineConcatto       if (auto *prev{getPreviousUse(*name)}) {
35264ab3302SCarolineConcatto         Say2(name->source, // C1113, C1115
35364ab3302SCarolineConcatto             "Selector '%s' was already used as a selector or coarray in this statement"_err_en_US,
35464ab3302SCarolineConcatto             *prev, "Previous use of '%s'"_en_US);
35564ab3302SCarolineConcatto       }
35664ab3302SCarolineConcatto     }
35764ab3302SCarolineConcatto   }
35864ab3302SCarolineConcatto }
35964ab3302SCarolineConcatto 
36064ab3302SCarolineConcatto void CoarrayChecker::Say2(const parser::CharBlock &name1,
36164ab3302SCarolineConcatto     parser::MessageFixedText &&msg1, const parser::CharBlock &name2,
36264ab3302SCarolineConcatto     parser::MessageFixedText &&msg2) {
36364ab3302SCarolineConcatto   context_.Say(name1, std::move(msg1), name1)
36464ab3302SCarolineConcatto       .Attach(name2, std::move(msg2), name2);
36564ab3302SCarolineConcatto }
3661f879005STim Keith } // namespace Fortran::semantics
367