• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- lib/Semantics/check-select-rank.cpp -------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "check-select-rank.h"
10 #include "flang/Common/Fortran.h"
11 #include "flang/Common/idioms.h"
12 #include "flang/Parser/message.h"
13 #include "flang/Parser/tools.h"
14 #include "flang/Semantics/tools.h"
15 #include <list>
16 #include <optional>
17 #include <set>
18 #include <tuple>
19 #include <variant>
20 
21 namespace Fortran::semantics {
22 
Leave(const parser::SelectRankConstruct & selectRankConstruct)23 void SelectRankConstructChecker::Leave(
24     const parser::SelectRankConstruct &selectRankConstruct) {
25   const auto &selectRankStmt{
26       std::get<parser::Statement<parser::SelectRankStmt>>(
27           selectRankConstruct.t)};
28   const auto &selectRankStmtSel{
29       std::get<parser::Selector>(selectRankStmt.statement.t)};
30 
31   // R1149 select-rank-stmt checks
32   const Symbol *saveSelSymbol{nullptr};
33   if (const auto selExpr{GetExprFromSelector(selectRankStmtSel)}) {
34     if (const Symbol * sel{evaluate::UnwrapWholeSymbolDataRef(*selExpr)}) {
35       if (!IsAssumedRankArray(*sel)) { // C1150
36         context_.Say(parser::FindSourceLocation(selectRankStmtSel),
37             "Selector '%s' is not an assumed-rank array variable"_err_en_US,
38             sel->name().ToString());
39       } else {
40         saveSelSymbol = sel;
41       }
42     } else {
43       context_.Say(parser::FindSourceLocation(selectRankStmtSel),
44           "Selector '%s' is not an assumed-rank array variable"_err_en_US,
45           parser::FindSourceLocation(selectRankStmtSel).ToString());
46     }
47   }
48 
49   // R1150 select-rank-case-stmt checks
50   auto &rankCaseList{std::get<std::list<parser::SelectRankConstruct::RankCase>>(
51       selectRankConstruct.t)};
52   bool defaultRankFound{false};
53   bool starRankFound{false};
54   parser::CharBlock prevLocDefault;
55   parser::CharBlock prevLocStar;
56   std::optional<parser::CharBlock> caseForRank[common::maxRank + 1];
57 
58   for (const auto &rankCase : rankCaseList) {
59     const auto &rankCaseStmt{
60         std::get<parser::Statement<parser::SelectRankCaseStmt>>(rankCase.t)};
61     const auto &rank{
62         std::get<parser::SelectRankCaseStmt::Rank>(rankCaseStmt.statement.t)};
63     std::visit(
64         common::visitors{
65             [&](const parser::Default &) { // C1153
66               if (!defaultRankFound) {
67                 defaultRankFound = true;
68                 prevLocDefault = rankCaseStmt.source;
69               } else {
70                 context_
71                     .Say(rankCaseStmt.source,
72                         "Not more than one of the selectors of SELECT RANK "
73                         "statement may be DEFAULT"_err_en_US)
74                     .Attach(prevLocDefault, "Previous use"_err_en_US);
75               }
76             },
77             [&](const parser::Star &) { // C1153
78               if (!starRankFound) {
79                 starRankFound = true;
80                 prevLocStar = rankCaseStmt.source;
81               } else {
82                 context_
83                     .Say(rankCaseStmt.source,
84                         "Not more than one of the selectors of SELECT RANK "
85                         "statement may be '*'"_err_en_US)
86                     .Attach(prevLocStar, "Previous use"_err_en_US);
87               }
88               if (saveSelSymbol &&
89                   IsAllocatableOrPointer(*saveSelSymbol)) { // C1155
90                 context_.Say(parser::FindSourceLocation(selectRankStmtSel),
91                     "RANK (*) cannot be used when selector is "
92                     "POINTER or ALLOCATABLE"_err_en_US);
93               }
94             },
95             [&](const parser::ScalarIntConstantExpr &init) {
96               if (auto val{GetIntValue(init)}) {
97                 // If value is in valid range, then only show
98                 // value repeat error, else stack smashing occurs
99                 if (*val < 0 || *val > common::maxRank) { // C1151
100                   context_.Say(rankCaseStmt.source,
101                       "The value of the selector must be "
102                       "between zero and %d"_err_en_US,
103                       common::maxRank);
104 
105                 } else {
106                   if (!caseForRank[*val].has_value()) {
107                     caseForRank[*val] = rankCaseStmt.source;
108                   } else {
109                     auto prevloc{caseForRank[*val].value()};
110                     context_
111                         .Say(rankCaseStmt.source,
112                             "Same rank value (%d) not allowed more than once"_err_en_US,
113                             *val)
114                         .Attach(prevloc, "Previous use"_err_en_US);
115                   }
116                 }
117               }
118             },
119         },
120         rank.u);
121   }
122 }
123 
GetExprFromSelector(const parser::Selector & selector)124 const SomeExpr *SelectRankConstructChecker::GetExprFromSelector(
125     const parser::Selector &selector) {
126   return std::visit([](const auto &x) { return GetExpr(x); }, selector.u);
127 }
128 
129 } // namespace Fortran::semantics
130