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 ¬ifyVar{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