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:
CriticalBodyEnforce(SemanticsContext & context,parser::CharBlock criticalSourcePosition)2264ab3302SCarolineConcatto CriticalBodyEnforce(
2364ab3302SCarolineConcatto SemanticsContext &context, parser::CharBlock criticalSourcePosition)
2464ab3302SCarolineConcatto : context_{context}, criticalSourcePosition_{criticalSourcePosition} {}
labels()2564ab3302SCarolineConcatto std::set<parser::Label> labels() { return labels_; }
Pre(const T &)2664ab3302SCarolineConcatto template <typename T> bool Pre(const T &) { return true; }
Post(const T &)2764ab3302SCarolineConcatto template <typename T> void Post(const T &) {}
2864ab3302SCarolineConcatto
Pre(const parser::Statement<T> & statement)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
Post(const parser::ReturnStmt &)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 }
Post(const parser::ExecutableConstruct & construct)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:
GetEnclosingMsg()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>
CheckTeamType(SemanticsContext & context,const T & x)6664ab3302SCarolineConcatto static void CheckTeamType(SemanticsContext &context, const T &x) {
67*7e225423SPeter 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
CheckTeamStat(SemanticsContext & context,const parser::ImageSelectorSpec::Stat & stat)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
Leave(const parser::ChangeTeamStmt & x)8564ab3302SCarolineConcatto void CoarrayChecker::Leave(const parser::ChangeTeamStmt &x) {
8664ab3302SCarolineConcatto CheckNamesAreDistinct(std::get<std::list<parser::CoarrayAssociation>>(x.t));
8764ab3302SCarolineConcatto CheckTeamType(context_, std::get<parser::TeamValue>(x.t));
8864ab3302SCarolineConcatto }
8964ab3302SCarolineConcatto
Leave(const parser::SyncTeamStmt & x)9064ab3302SCarolineConcatto void CoarrayChecker::Leave(const parser::SyncTeamStmt &x) {
9164ab3302SCarolineConcatto CheckTeamType(context_, std::get<parser::TeamValue>(x.t));
9264ab3302SCarolineConcatto }
9364ab3302SCarolineConcatto
Leave(const parser::ImageSelector & imageSelector)9415fa287bSPete Steinfeld void CoarrayChecker::Leave(const parser::ImageSelector &imageSelector) {
9515fa287bSPete Steinfeld haveStat_ = false;
9615fa287bSPete Steinfeld haveTeam_ = false;
9715fa287bSPete Steinfeld haveTeamNumber_ = false;
9815fa287bSPete Steinfeld for (const auto &imageSelectorSpec :
9915fa287bSPete Steinfeld std::get<std::list<parser::ImageSelectorSpec>>(imageSelector.t)) {
10015fa287bSPete Steinfeld if (const auto *team{
10115fa287bSPete Steinfeld std::get_if<parser::TeamValue>(&imageSelectorSpec.u)}) {
10215fa287bSPete Steinfeld if (haveTeam_) {
10315fa287bSPete Steinfeld context_.Say(parser::FindSourceLocation(imageSelectorSpec), // C929
10415fa287bSPete Steinfeld "TEAM value can only be specified once"_err_en_US);
10515fa287bSPete Steinfeld }
10664ab3302SCarolineConcatto CheckTeamType(context_, *team);
10715fa287bSPete Steinfeld haveTeam_ = true;
10815fa287bSPete Steinfeld }
10915fa287bSPete Steinfeld if (const auto *stat{std::get_if<parser::ImageSelectorSpec::Stat>(
11015fa287bSPete Steinfeld &imageSelectorSpec.u)}) {
11115fa287bSPete Steinfeld if (haveStat_) {
11215fa287bSPete Steinfeld context_.Say(parser::FindSourceLocation(imageSelectorSpec), // C929
11315fa287bSPete Steinfeld "STAT variable can only be specified once"_err_en_US);
11415fa287bSPete Steinfeld }
11515fa287bSPete Steinfeld CheckTeamStat(context_, *stat);
11615fa287bSPete Steinfeld haveStat_ = true;
11715fa287bSPete Steinfeld }
11815fa287bSPete Steinfeld if (std::get_if<parser::ImageSelectorSpec::Team_Number>(
11915fa287bSPete Steinfeld &imageSelectorSpec.u)) {
12015fa287bSPete Steinfeld if (haveTeamNumber_) {
12115fa287bSPete Steinfeld context_.Say(parser::FindSourceLocation(imageSelectorSpec), // C929
12215fa287bSPete Steinfeld "TEAM_NUMBER value can only be specified once"_err_en_US);
12315fa287bSPete Steinfeld }
12415fa287bSPete Steinfeld haveTeamNumber_ = true;
12515fa287bSPete Steinfeld }
12615fa287bSPete Steinfeld }
12715fa287bSPete Steinfeld if (haveTeam_ && haveTeamNumber_) {
12815fa287bSPete Steinfeld context_.Say(parser::FindSourceLocation(imageSelector), // C930
12915fa287bSPete Steinfeld "Cannot specify both TEAM and TEAM_NUMBER"_err_en_US);
13064ab3302SCarolineConcatto }
13164ab3302SCarolineConcatto }
13264ab3302SCarolineConcatto
Leave(const parser::FormTeamStmt & x)13364ab3302SCarolineConcatto void CoarrayChecker::Leave(const parser::FormTeamStmt &x) {
13464ab3302SCarolineConcatto CheckTeamType(context_, std::get<parser::TeamVariable>(x.t));
13564ab3302SCarolineConcatto }
13664ab3302SCarolineConcatto
Enter(const parser::CriticalConstruct & x)13764ab3302SCarolineConcatto void CoarrayChecker::Enter(const parser::CriticalConstruct &x) {
13864ab3302SCarolineConcatto auto &criticalStmt{std::get<parser::Statement<parser::CriticalStmt>>(x.t)};
13964ab3302SCarolineConcatto
14064ab3302SCarolineConcatto const parser::Block &block{std::get<parser::Block>(x.t)};
14164ab3302SCarolineConcatto CriticalBodyEnforce criticalBodyEnforce{context_, criticalStmt.source};
14264ab3302SCarolineConcatto parser::Walk(block, criticalBodyEnforce);
14364ab3302SCarolineConcatto
14464ab3302SCarolineConcatto // C1119
14564ab3302SCarolineConcatto LabelEnforce criticalLabelEnforce{
14664ab3302SCarolineConcatto context_, criticalBodyEnforce.labels(), criticalStmt.source, "CRITICAL"};
14764ab3302SCarolineConcatto parser::Walk(block, criticalLabelEnforce);
14864ab3302SCarolineConcatto }
14964ab3302SCarolineConcatto
15064ab3302SCarolineConcatto // Check that coarray names and selector names are all distinct.
CheckNamesAreDistinct(const std::list<parser::CoarrayAssociation> & list)15164ab3302SCarolineConcatto void CoarrayChecker::CheckNamesAreDistinct(
15264ab3302SCarolineConcatto const std::list<parser::CoarrayAssociation> &list) {
15364ab3302SCarolineConcatto std::set<parser::CharBlock> names;
15464ab3302SCarolineConcatto auto getPreviousUse{
15564ab3302SCarolineConcatto [&](const parser::Name &name) -> const parser::CharBlock * {
15664ab3302SCarolineConcatto auto pair{names.insert(name.source)};
15764ab3302SCarolineConcatto return !pair.second ? &*pair.first : nullptr;
15864ab3302SCarolineConcatto }};
15964ab3302SCarolineConcatto for (const auto &assoc : list) {
16064ab3302SCarolineConcatto const auto &decl{std::get<parser::CodimensionDecl>(assoc.t)};
16164ab3302SCarolineConcatto const auto &selector{std::get<parser::Selector>(assoc.t)};
16264ab3302SCarolineConcatto const auto &declName{std::get<parser::Name>(decl.t)};
16364ab3302SCarolineConcatto if (context_.HasError(declName)) {
16464ab3302SCarolineConcatto continue; // already reported an error about this name
16564ab3302SCarolineConcatto }
16664ab3302SCarolineConcatto if (auto *prev{getPreviousUse(declName)}) {
16764ab3302SCarolineConcatto Say2(declName.source, // C1113
16864ab3302SCarolineConcatto "Coarray '%s' was already used as a selector or coarray in this statement"_err_en_US,
16964ab3302SCarolineConcatto *prev, "Previous use of '%s'"_en_US);
17064ab3302SCarolineConcatto }
17164ab3302SCarolineConcatto // ResolveNames verified the selector is a simple name
17264ab3302SCarolineConcatto const parser::Name *name{parser::Unwrap<parser::Name>(selector)};
17364ab3302SCarolineConcatto if (name) {
17464ab3302SCarolineConcatto if (auto *prev{getPreviousUse(*name)}) {
17564ab3302SCarolineConcatto Say2(name->source, // C1113, C1115
17664ab3302SCarolineConcatto "Selector '%s' was already used as a selector or coarray in this statement"_err_en_US,
17764ab3302SCarolineConcatto *prev, "Previous use of '%s'"_en_US);
17864ab3302SCarolineConcatto }
17964ab3302SCarolineConcatto }
18064ab3302SCarolineConcatto }
18164ab3302SCarolineConcatto }
18264ab3302SCarolineConcatto
Say2(const parser::CharBlock & name1,parser::MessageFixedText && msg1,const parser::CharBlock & name2,parser::MessageFixedText && msg2)18364ab3302SCarolineConcatto void CoarrayChecker::Say2(const parser::CharBlock &name1,
18464ab3302SCarolineConcatto parser::MessageFixedText &&msg1, const parser::CharBlock &name2,
18564ab3302SCarolineConcatto parser::MessageFixedText &&msg2) {
18664ab3302SCarolineConcatto context_.Say(name1, std::move(msg1), name1)
18764ab3302SCarolineConcatto .Attach(name2, std::move(msg2), name2);
18864ab3302SCarolineConcatto }
1891f879005STim Keith } // namespace Fortran::semantics
190