xref: /llvm-project/flang/lib/Semantics/resolve-names-utils.cpp (revision 2ab9990c9eb79682a4d4b183dfbc7612d3e55328)
1 //===-- lib/Semantics/resolve-names-utils.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 "resolve-names-utils.h"
10 #include "flang/Common/Fortran-features.h"
11 #include "flang/Common/Fortran.h"
12 #include "flang/Common/idioms.h"
13 #include "flang/Common/indirection.h"
14 #include "flang/Evaluate/fold.h"
15 #include "flang/Evaluate/tools.h"
16 #include "flang/Evaluate/type.h"
17 #include "flang/Parser/char-block.h"
18 #include "flang/Parser/parse-tree.h"
19 #include "flang/Semantics/expression.h"
20 #include "flang/Semantics/semantics.h"
21 #include "flang/Semantics/tools.h"
22 #include <initializer_list>
23 #include <variant>
24 
25 namespace Fortran::semantics {
26 
27 using common::LanguageFeature;
28 using common::LogicalOperator;
29 using common::NumericOperator;
30 using common::RelationalOperator;
31 using IntrinsicOperator = parser::DefinedOperator::IntrinsicOperator;
32 
33 static constexpr const char *operatorPrefix{"operator("};
34 
35 static GenericKind MapIntrinsicOperator(IntrinsicOperator);
36 
37 Symbol *Resolve(const parser::Name &name, Symbol *symbol) {
38   if (symbol && !name.symbol) {
39     name.symbol = symbol;
40   }
41   return symbol;
42 }
43 Symbol &Resolve(const parser::Name &name, Symbol &symbol) {
44   return *Resolve(name, &symbol);
45 }
46 
47 parser::MessageFixedText WithSeverity(
48     const parser::MessageFixedText &msg, parser::Severity severity) {
49   return parser::MessageFixedText{
50       msg.text().begin(), msg.text().size(), severity};
51 }
52 
53 bool IsIntrinsicOperator(
54     const SemanticsContext &context, const SourceName &name) {
55   std::string str{name.ToString()};
56   for (int i{0}; i != common::LogicalOperator_enumSize; ++i) {
57     auto names{context.languageFeatures().GetNames(LogicalOperator{i})};
58     if (std::find(names.begin(), names.end(), str) != names.end()) {
59       return true;
60     }
61   }
62   for (int i{0}; i != common::RelationalOperator_enumSize; ++i) {
63     auto names{context.languageFeatures().GetNames(RelationalOperator{i})};
64     if (std::find(names.begin(), names.end(), str) != names.end()) {
65       return true;
66     }
67   }
68   return false;
69 }
70 
71 template <typename E>
72 std::forward_list<std::string> GetOperatorNames(
73     const SemanticsContext &context, E opr) {
74   std::forward_list<std::string> result;
75   for (const char *name : context.languageFeatures().GetNames(opr)) {
76     result.emplace_front(std::string{operatorPrefix} + name + ')');
77   }
78   return result;
79 }
80 
81 std::forward_list<std::string> GetAllNames(
82     const SemanticsContext &context, const SourceName &name) {
83   std::string str{name.ToString()};
84   if (!name.empty() && name.end()[-1] == ')' &&
85       name.ToString().rfind(std::string{operatorPrefix}, 0) == 0) {
86     for (int i{0}; i != common::LogicalOperator_enumSize; ++i) {
87       auto names{GetOperatorNames(context, LogicalOperator{i})};
88       if (std::find(names.begin(), names.end(), str) != names.end()) {
89         return names;
90       }
91     }
92     for (int i{0}; i != common::RelationalOperator_enumSize; ++i) {
93       auto names{GetOperatorNames(context, RelationalOperator{i})};
94       if (std::find(names.begin(), names.end(), str) != names.end()) {
95         return names;
96       }
97     }
98   }
99   return {str};
100 }
101 
102 bool IsLogicalConstant(
103     const SemanticsContext &context, const SourceName &name) {
104   std::string str{name.ToString()};
105   return str == ".true." || str == ".false." ||
106       (context.IsEnabled(LanguageFeature::LogicalAbbreviations) &&
107           (str == ".t" || str == ".f."));
108 }
109 
110 void GenericSpecInfo::Resolve(Symbol *symbol) const {
111   if (symbol) {
112     if (auto *details{symbol->detailsIf<GenericDetails>()}) {
113       details->set_kind(kind_);
114     }
115     if (parseName_) {
116       semantics::Resolve(*parseName_, symbol);
117     }
118   }
119 }
120 
121 void GenericSpecInfo::Analyze(const parser::DefinedOpName &name) {
122   kind_ = GenericKind::OtherKind::DefinedOp;
123   parseName_ = &name.v;
124   symbolName_ = name.v.source;
125 }
126 
127 void GenericSpecInfo::Analyze(const parser::GenericSpec &x) {
128   symbolName_ = x.source;
129   kind_ = common::visit(
130       common::visitors{
131           [&](const parser::Name &y) -> GenericKind {
132             parseName_ = &y;
133             symbolName_ = y.source;
134             return GenericKind::OtherKind::Name;
135           },
136           [&](const parser::DefinedOperator &y) {
137             return common::visit(
138                 common::visitors{
139                     [&](const parser::DefinedOpName &z) -> GenericKind {
140                       Analyze(z);
141                       return GenericKind::OtherKind::DefinedOp;
142                     },
143                     [&](const IntrinsicOperator &z) {
144                       return MapIntrinsicOperator(z);
145                     },
146                 },
147                 y.u);
148           },
149           [&](const parser::GenericSpec::Assignment &) -> GenericKind {
150             return GenericKind::OtherKind::Assignment;
151           },
152           [&](const parser::GenericSpec::ReadFormatted &) -> GenericKind {
153             return GenericKind::DefinedIo::ReadFormatted;
154           },
155           [&](const parser::GenericSpec::ReadUnformatted &) -> GenericKind {
156             return GenericKind::DefinedIo::ReadUnformatted;
157           },
158           [&](const parser::GenericSpec::WriteFormatted &) -> GenericKind {
159             return GenericKind::DefinedIo::WriteFormatted;
160           },
161           [&](const parser::GenericSpec::WriteUnformatted &) -> GenericKind {
162             return GenericKind::DefinedIo::WriteUnformatted;
163           },
164       },
165       x.u);
166 }
167 
168 llvm::raw_ostream &operator<<(
169     llvm::raw_ostream &os, const GenericSpecInfo &info) {
170   os << "GenericSpecInfo: kind=" << info.kind_.ToString();
171   os << " parseName="
172      << (info.parseName_ ? info.parseName_->ToString() : "null");
173   os << " symbolName="
174      << (info.symbolName_ ? info.symbolName_->ToString() : "null");
175   return os;
176 }
177 
178 // parser::DefinedOperator::IntrinsicOperator -> GenericKind
179 static GenericKind MapIntrinsicOperator(IntrinsicOperator op) {
180   switch (op) {
181     SWITCH_COVERS_ALL_CASES
182   case IntrinsicOperator::Concat:
183     return GenericKind::OtherKind::Concat;
184   case IntrinsicOperator::Power:
185     return NumericOperator::Power;
186   case IntrinsicOperator::Multiply:
187     return NumericOperator::Multiply;
188   case IntrinsicOperator::Divide:
189     return NumericOperator::Divide;
190   case IntrinsicOperator::Add:
191     return NumericOperator::Add;
192   case IntrinsicOperator::Subtract:
193     return NumericOperator::Subtract;
194   case IntrinsicOperator::AND:
195     return LogicalOperator::And;
196   case IntrinsicOperator::OR:
197     return LogicalOperator::Or;
198   case IntrinsicOperator::EQV:
199     return LogicalOperator::Eqv;
200   case IntrinsicOperator::NEQV:
201     return LogicalOperator::Neqv;
202   case IntrinsicOperator::NOT:
203     return LogicalOperator::Not;
204   case IntrinsicOperator::LT:
205     return RelationalOperator::LT;
206   case IntrinsicOperator::LE:
207     return RelationalOperator::LE;
208   case IntrinsicOperator::EQ:
209     return RelationalOperator::EQ;
210   case IntrinsicOperator::NE:
211     return RelationalOperator::NE;
212   case IntrinsicOperator::GE:
213     return RelationalOperator::GE;
214   case IntrinsicOperator::GT:
215     return RelationalOperator::GT;
216   }
217 }
218 
219 class ArraySpecAnalyzer {
220 public:
221   ArraySpecAnalyzer(SemanticsContext &context) : context_{context} {}
222   ArraySpec Analyze(const parser::ArraySpec &);
223   ArraySpec AnalyzeDeferredShapeSpecList(const parser::DeferredShapeSpecList &);
224   ArraySpec Analyze(const parser::ComponentArraySpec &);
225   ArraySpec Analyze(const parser::CoarraySpec &);
226 
227 private:
228   SemanticsContext &context_;
229   ArraySpec arraySpec_;
230 
231   template <typename T> void Analyze(const std::list<T> &list) {
232     for (const auto &elem : list) {
233       Analyze(elem);
234     }
235   }
236   void Analyze(const parser::AssumedShapeSpec &);
237   void Analyze(const parser::ExplicitShapeSpec &);
238   void Analyze(const parser::AssumedImpliedSpec &);
239   void Analyze(const parser::DeferredShapeSpecList &);
240   void Analyze(const parser::AssumedRankSpec &);
241   void MakeExplicit(const std::optional<parser::SpecificationExpr> &,
242       const parser::SpecificationExpr &);
243   void MakeImplied(const std::optional<parser::SpecificationExpr> &);
244   void MakeDeferred(int);
245   Bound GetBound(const std::optional<parser::SpecificationExpr> &);
246   Bound GetBound(const parser::SpecificationExpr &);
247 };
248 
249 ArraySpec AnalyzeArraySpec(
250     SemanticsContext &context, const parser::ArraySpec &arraySpec) {
251   return ArraySpecAnalyzer{context}.Analyze(arraySpec);
252 }
253 ArraySpec AnalyzeArraySpec(
254     SemanticsContext &context, const parser::ComponentArraySpec &arraySpec) {
255   return ArraySpecAnalyzer{context}.Analyze(arraySpec);
256 }
257 ArraySpec AnalyzeDeferredShapeSpecList(SemanticsContext &context,
258     const parser::DeferredShapeSpecList &deferredShapeSpecs) {
259   return ArraySpecAnalyzer{context}.AnalyzeDeferredShapeSpecList(
260       deferredShapeSpecs);
261 }
262 ArraySpec AnalyzeCoarraySpec(
263     SemanticsContext &context, const parser::CoarraySpec &coarraySpec) {
264   return ArraySpecAnalyzer{context}.Analyze(coarraySpec);
265 }
266 
267 ArraySpec ArraySpecAnalyzer::Analyze(const parser::ComponentArraySpec &x) {
268   common::visit([this](const auto &y) { Analyze(y); }, x.u);
269   CHECK(!arraySpec_.empty());
270   return arraySpec_;
271 }
272 ArraySpec ArraySpecAnalyzer::Analyze(const parser::ArraySpec &x) {
273   common::visit(common::visitors{
274                     [&](const parser::AssumedSizeSpec &y) {
275                       Analyze(
276                           std::get<std::list<parser::ExplicitShapeSpec>>(y.t));
277                       Analyze(std::get<parser::AssumedImpliedSpec>(y.t));
278                     },
279                     [&](const parser::ImpliedShapeSpec &y) { Analyze(y.v); },
280                     [&](const auto &y) { Analyze(y); },
281                 },
282       x.u);
283   CHECK(!arraySpec_.empty());
284   return arraySpec_;
285 }
286 ArraySpec ArraySpecAnalyzer::AnalyzeDeferredShapeSpecList(
287     const parser::DeferredShapeSpecList &x) {
288   Analyze(x);
289   CHECK(!arraySpec_.empty());
290   return arraySpec_;
291 }
292 ArraySpec ArraySpecAnalyzer::Analyze(const parser::CoarraySpec &x) {
293   common::visit(
294       common::visitors{
295           [&](const parser::DeferredCoshapeSpecList &y) { MakeDeferred(y.v); },
296           [&](const parser::ExplicitCoshapeSpec &y) {
297             Analyze(std::get<std::list<parser::ExplicitShapeSpec>>(y.t));
298             MakeImplied(
299                 std::get<std::optional<parser::SpecificationExpr>>(y.t));
300           },
301       },
302       x.u);
303   CHECK(!arraySpec_.empty());
304   return arraySpec_;
305 }
306 
307 void ArraySpecAnalyzer::Analyze(const parser::AssumedShapeSpec &x) {
308   arraySpec_.push_back(ShapeSpec::MakeAssumedShape(GetBound(x.v)));
309 }
310 void ArraySpecAnalyzer::Analyze(const parser::ExplicitShapeSpec &x) {
311   MakeExplicit(std::get<std::optional<parser::SpecificationExpr>>(x.t),
312       std::get<parser::SpecificationExpr>(x.t));
313 }
314 void ArraySpecAnalyzer::Analyze(const parser::AssumedImpliedSpec &x) {
315   MakeImplied(x.v);
316 }
317 void ArraySpecAnalyzer::Analyze(const parser::DeferredShapeSpecList &x) {
318   MakeDeferred(x.v);
319 }
320 void ArraySpecAnalyzer::Analyze(const parser::AssumedRankSpec &) {
321   arraySpec_.push_back(ShapeSpec::MakeAssumedRank());
322 }
323 
324 void ArraySpecAnalyzer::MakeExplicit(
325     const std::optional<parser::SpecificationExpr> &lb,
326     const parser::SpecificationExpr &ub) {
327   arraySpec_.push_back(ShapeSpec::MakeExplicit(GetBound(lb), GetBound(ub)));
328 }
329 void ArraySpecAnalyzer::MakeImplied(
330     const std::optional<parser::SpecificationExpr> &lb) {
331   arraySpec_.push_back(ShapeSpec::MakeImplied(GetBound(lb)));
332 }
333 void ArraySpecAnalyzer::MakeDeferred(int n) {
334   for (int i = 0; i < n; ++i) {
335     arraySpec_.push_back(ShapeSpec::MakeDeferred());
336   }
337 }
338 
339 Bound ArraySpecAnalyzer::GetBound(
340     const std::optional<parser::SpecificationExpr> &x) {
341   return x ? GetBound(*x) : Bound{1};
342 }
343 Bound ArraySpecAnalyzer::GetBound(const parser::SpecificationExpr &x) {
344   MaybeSubscriptIntExpr expr;
345   if (MaybeExpr maybeExpr{AnalyzeExpr(context_, x.v)}) {
346     if (auto *intExpr{evaluate::UnwrapExpr<SomeIntExpr>(*maybeExpr)}) {
347       expr = evaluate::Fold(context_.foldingContext(),
348           evaluate::ConvertToType<evaluate::SubscriptInteger>(
349               std::move(*intExpr)));
350     }
351   }
352   return Bound{std::move(expr)};
353 }
354 
355 // If SAVE is set on src, set it on all members of dst
356 static void PropagateSaveAttr(
357     const EquivalenceObject &src, EquivalenceSet &dst) {
358   if (src.symbol.attrs().test(Attr::SAVE)) {
359     for (auto &obj : dst) {
360       obj.symbol.attrs().set(Attr::SAVE);
361     }
362   }
363 }
364 static void PropagateSaveAttr(const EquivalenceSet &src, EquivalenceSet &dst) {
365   if (!src.empty()) {
366     PropagateSaveAttr(src.front(), dst);
367   }
368 }
369 
370 void EquivalenceSets::AddToSet(const parser::Designator &designator) {
371   if (CheckDesignator(designator)) {
372     Symbol &symbol{*currObject_.symbol};
373     if (!currSet_.empty()) {
374       // check this symbol against first of set for compatibility
375       Symbol &first{currSet_.front().symbol};
376       CheckCanEquivalence(designator.source, first, symbol) &&
377           CheckCanEquivalence(designator.source, symbol, first);
378     }
379     auto subscripts{currObject_.subscripts};
380     if (subscripts.empty() && symbol.IsObjectArray()) {
381       // record a whole array as its first element
382       for (const ShapeSpec &spec : symbol.get<ObjectEntityDetails>().shape()) {
383         auto &lbound{spec.lbound().GetExplicit().value()};
384         subscripts.push_back(evaluate::ToInt64(lbound).value());
385       }
386     }
387     auto substringStart{currObject_.substringStart};
388     currSet_.emplace_back(
389         symbol, subscripts, substringStart, designator.source);
390     PropagateSaveAttr(currSet_.back(), currSet_);
391   }
392   currObject_ = {};
393 }
394 
395 void EquivalenceSets::FinishSet(const parser::CharBlock &source) {
396   std::set<std::size_t> existing; // indices of sets intersecting this one
397   for (auto &obj : currSet_) {
398     auto it{objectToSet_.find(obj)};
399     if (it != objectToSet_.end()) {
400       existing.insert(it->second); // symbol already in this set
401     }
402   }
403   if (existing.empty()) {
404     sets_.push_back({}); // create a new equivalence set
405     MergeInto(source, currSet_, sets_.size() - 1);
406   } else {
407     auto it{existing.begin()};
408     std::size_t dstIndex{*it};
409     MergeInto(source, currSet_, dstIndex);
410     while (++it != existing.end()) {
411       MergeInto(source, sets_[*it], dstIndex);
412     }
413   }
414   currSet_.clear();
415 }
416 
417 // Report an error or warning if sym1 and sym2 cannot be in the same equivalence
418 // set.
419 bool EquivalenceSets::CheckCanEquivalence(
420     const parser::CharBlock &source, const Symbol &sym1, const Symbol &sym2) {
421   std::optional<parser::MessageFixedText> msg;
422   const DeclTypeSpec *type1{sym1.GetType()};
423   const DeclTypeSpec *type2{sym2.GetType()};
424   bool isDefaultNum1{IsDefaultNumericSequenceType(type1)};
425   bool isAnyNum1{IsAnyNumericSequenceType(type1)};
426   bool isDefaultNum2{IsDefaultNumericSequenceType(type2)};
427   bool isAnyNum2{IsAnyNumericSequenceType(type2)};
428   bool isChar1{IsCharacterSequenceType(type1)};
429   bool isChar2{IsCharacterSequenceType(type2)};
430   if (sym1.attrs().test(Attr::PROTECTED) &&
431       !sym2.attrs().test(Attr::PROTECTED)) { // C8114
432     msg = "Equivalence set cannot contain '%s'"
433           " with PROTECTED attribute and '%s' without"_err_en_US;
434   } else if ((isDefaultNum1 && isDefaultNum2) || (isChar1 && isChar2)) {
435     // ok & standard conforming
436   } else if (!(isAnyNum1 || isChar1) &&
437       !(isAnyNum2 || isChar2)) { // C8110 - C8113
438     if (AreTkCompatibleTypes(type1, type2)) {
439       if (context_.ShouldWarn(LanguageFeature::EquivalenceSameNonSequence)) {
440         msg =
441             "nonstandard: Equivalence set contains '%s' and '%s' with same "
442             "type that is neither numeric nor character sequence type"_port_en_US;
443       }
444     } else {
445       msg = "Equivalence set cannot contain '%s' and '%s' with distinct types "
446             "that are not both numeric or character sequence types"_err_en_US;
447     }
448   } else if (isAnyNum1) {
449     if (isChar2) {
450       if (context_.ShouldWarn(
451               LanguageFeature::EquivalenceNumericWithCharacter)) {
452         msg = "nonstandard: Equivalence set contains '%s' that is numeric "
453               "sequence type and '%s' that is character"_port_en_US;
454       }
455     } else if (isAnyNum2 &&
456         context_.ShouldWarn(LanguageFeature::EquivalenceNonDefaultNumeric)) {
457       if (isDefaultNum1) {
458         msg =
459             "nonstandard: Equivalence set contains '%s' that is a default "
460             "numeric sequence type and '%s' that is numeric with non-default kind"_port_en_US;
461       } else if (!isDefaultNum2) {
462         msg = "nonstandard: Equivalence set contains '%s' and '%s' that are "
463               "numeric sequence types with non-default kinds"_port_en_US;
464       }
465     }
466   }
467   if (msg) {
468     context_.Say(source, std::move(*msg), sym1.name(), sym2.name());
469     return false;
470   }
471   return true;
472 }
473 
474 // Move objects from src to sets_[dstIndex]
475 void EquivalenceSets::MergeInto(const parser::CharBlock &source,
476     EquivalenceSet &src, std::size_t dstIndex) {
477   EquivalenceSet &dst{sets_[dstIndex]};
478   PropagateSaveAttr(dst, src);
479   for (const auto &obj : src) {
480     dst.push_back(obj);
481     objectToSet_[obj] = dstIndex;
482   }
483   PropagateSaveAttr(src, dst);
484   src.clear();
485 }
486 
487 // If set has an object with this symbol, return it.
488 const EquivalenceObject *EquivalenceSets::Find(
489     const EquivalenceSet &set, const Symbol &symbol) {
490   for (const auto &obj : set) {
491     if (obj.symbol == symbol) {
492       return &obj;
493     }
494   }
495   return nullptr;
496 }
497 
498 bool EquivalenceSets::CheckDesignator(const parser::Designator &designator) {
499   return common::visit(
500       common::visitors{
501           [&](const parser::DataRef &x) {
502             return CheckDataRef(designator.source, x);
503           },
504           [&](const parser::Substring &x) {
505             const auto &dataRef{std::get<parser::DataRef>(x.t)};
506             const auto &range{std::get<parser::SubstringRange>(x.t)};
507             bool ok{CheckDataRef(designator.source, dataRef)};
508             if (const auto &lb{std::get<0>(range.t)}) {
509               ok &= CheckSubstringBound(lb->thing.thing.value(), true);
510             } else {
511               currObject_.substringStart = 1;
512             }
513             if (const auto &ub{std::get<1>(range.t)}) {
514               ok &= CheckSubstringBound(ub->thing.thing.value(), false);
515             }
516             return ok;
517           },
518       },
519       designator.u);
520 }
521 
522 bool EquivalenceSets::CheckDataRef(
523     const parser::CharBlock &source, const parser::DataRef &x) {
524   return common::visit(
525       common::visitors{
526           [&](const parser::Name &name) { return CheckObject(name); },
527           [&](const common::Indirection<parser::StructureComponent> &) {
528             context_.Say(source, // C8107
529                 "Derived type component '%s' is not allowed in an equivalence set"_err_en_US,
530                 source);
531             return false;
532           },
533           [&](const common::Indirection<parser::ArrayElement> &elem) {
534             bool ok{CheckDataRef(source, elem.value().base)};
535             for (const auto &subscript : elem.value().subscripts) {
536               ok &= common::visit(
537                   common::visitors{
538                       [&](const parser::SubscriptTriplet &) {
539                         context_.Say(source, // C924, R872
540                             "Array section '%s' is not allowed in an equivalence set"_err_en_US,
541                             source);
542                         return false;
543                       },
544                       [&](const parser::IntExpr &y) {
545                         return CheckArrayBound(y.thing.value());
546                       },
547                   },
548                   subscript.u);
549             }
550             return ok;
551           },
552           [&](const common::Indirection<parser::CoindexedNamedObject> &) {
553             context_.Say(source, // C924 (R872)
554                 "Coindexed object '%s' is not allowed in an equivalence set"_err_en_US,
555                 source);
556             return false;
557           },
558       },
559       x.u);
560 }
561 
562 static bool InCommonWithBind(const Symbol &symbol) {
563   if (const auto *details{symbol.detailsIf<ObjectEntityDetails>()}) {
564     const Symbol *commonBlock{details->commonBlock()};
565     return commonBlock && commonBlock->attrs().test(Attr::BIND_C);
566   } else {
567     return false;
568   }
569 }
570 
571 // If symbol can't be in equivalence set report error and return false;
572 bool EquivalenceSets::CheckObject(const parser::Name &name) {
573   if (!name.symbol) {
574     return false; // an error has already occurred
575   }
576   currObject_.symbol = name.symbol;
577   parser::MessageFixedText msg;
578   const Symbol &symbol{*name.symbol};
579   if (symbol.owner().IsDerivedType()) { // C8107
580     msg = "Derived type component '%s'"
581           " is not allowed in an equivalence set"_err_en_US;
582   } else if (IsDummy(symbol)) { // C8106
583     msg = "Dummy argument '%s' is not allowed in an equivalence set"_err_en_US;
584   } else if (symbol.IsFuncResult()) { // C8106
585     msg = "Function result '%s' is not allow in an equivalence set"_err_en_US;
586   } else if (IsPointer(symbol)) { // C8106
587     msg = "Pointer '%s' is not allowed in an equivalence set"_err_en_US;
588   } else if (IsAllocatable(symbol)) { // C8106
589     msg = "Allocatable variable '%s'"
590           " is not allowed in an equivalence set"_err_en_US;
591   } else if (symbol.Corank() > 0) { // C8106
592     msg = "Coarray '%s' is not allowed in an equivalence set"_err_en_US;
593   } else if (symbol.has<UseDetails>()) { // C8115
594     msg = "Use-associated variable '%s'"
595           " is not allowed in an equivalence set"_err_en_US;
596   } else if (symbol.attrs().test(Attr::BIND_C)) { // C8106
597     msg = "Variable '%s' with BIND attribute"
598           " is not allowed in an equivalence set"_err_en_US;
599   } else if (symbol.attrs().test(Attr::TARGET)) { // C8108
600     msg = "Variable '%s' with TARGET attribute"
601           " is not allowed in an equivalence set"_err_en_US;
602   } else if (IsNamedConstant(symbol)) { // C8106
603     msg = "Named constant '%s' is not allowed in an equivalence set"_err_en_US;
604   } else if (InCommonWithBind(symbol)) { // C8106
605     msg = "Variable '%s' in common block with BIND attribute"
606           " is not allowed in an equivalence set"_err_en_US;
607   } else if (const auto *type{symbol.GetType()}) {
608     if (const auto *derived{type->AsDerived()}) {
609       if (const auto *comp{FindUltimateComponent(
610               *derived, IsAllocatableOrPointer)}) { // C8106
611         msg = IsPointer(*comp)
612             ? "Derived type object '%s' with pointer ultimate component"
613               " is not allowed in an equivalence set"_err_en_US
614             : "Derived type object '%s' with allocatable ultimate component"
615               " is not allowed in an equivalence set"_err_en_US;
616       } else if (!derived->typeSymbol().get<DerivedTypeDetails>().sequence()) {
617         msg = "Nonsequence derived type object '%s'"
618               " is not allowed in an equivalence set"_err_en_US;
619       }
620     } else if (IsAutomatic(symbol)) {
621       msg = "Automatic object '%s'"
622             " is not allowed in an equivalence set"_err_en_US;
623     }
624   }
625   if (!msg.text().empty()) {
626     context_.Say(name.source, std::move(msg), name.source);
627     return false;
628   }
629   return true;
630 }
631 
632 bool EquivalenceSets::CheckArrayBound(const parser::Expr &bound) {
633   MaybeExpr expr{
634       evaluate::Fold(context_.foldingContext(), AnalyzeExpr(context_, bound))};
635   if (!expr) {
636     return false;
637   }
638   if (expr->Rank() > 0) {
639     context_.Say(bound.source, // C924, R872
640         "Array with vector subscript '%s' is not allowed in an equivalence set"_err_en_US,
641         bound.source);
642     return false;
643   }
644   auto subscript{evaluate::ToInt64(*expr)};
645   if (!subscript) {
646     context_.Say(bound.source, // C8109
647         "Array with nonconstant subscript '%s' is not allowed in an equivalence set"_err_en_US,
648         bound.source);
649     return false;
650   }
651   currObject_.subscripts.push_back(*subscript);
652   return true;
653 }
654 
655 bool EquivalenceSets::CheckSubstringBound(
656     const parser::Expr &bound, bool isStart) {
657   MaybeExpr expr{
658       evaluate::Fold(context_.foldingContext(), AnalyzeExpr(context_, bound))};
659   if (!expr) {
660     return false;
661   }
662   auto subscript{evaluate::ToInt64(*expr)};
663   if (!subscript) {
664     context_.Say(bound.source, // C8109
665         "Substring with nonconstant bound '%s' is not allowed in an equivalence set"_err_en_US,
666         bound.source);
667     return false;
668   }
669   if (!isStart) {
670     auto start{currObject_.substringStart};
671     if (*subscript < (start ? *start : 1)) {
672       context_.Say(bound.source, // C8116
673           "Substring with zero length is not allowed in an equivalence set"_err_en_US);
674       return false;
675     }
676   } else if (*subscript != 1) {
677     currObject_.substringStart = *subscript;
678   }
679   return true;
680 }
681 
682 bool EquivalenceSets::IsCharacterSequenceType(const DeclTypeSpec *type) {
683   return IsSequenceType(type, [&](const IntrinsicTypeSpec &type) {
684     auto kind{evaluate::ToInt64(type.kind())};
685     return type.category() == TypeCategory::Character && kind &&
686         kind.value() == context_.GetDefaultKind(TypeCategory::Character);
687   });
688 }
689 
690 // Numeric or logical type of default kind or DOUBLE PRECISION or DOUBLE COMPLEX
691 bool EquivalenceSets::IsDefaultKindNumericType(const IntrinsicTypeSpec &type) {
692   if (auto kind{evaluate::ToInt64(type.kind())}) {
693     switch (type.category()) {
694     case TypeCategory::Integer:
695     case TypeCategory::Logical:
696       return *kind == context_.GetDefaultKind(TypeCategory::Integer);
697     case TypeCategory::Real:
698     case TypeCategory::Complex:
699       return *kind == context_.GetDefaultKind(TypeCategory::Real) ||
700           *kind == context_.doublePrecisionKind();
701     default:
702       return false;
703     }
704   }
705   return false;
706 }
707 
708 bool EquivalenceSets::IsDefaultNumericSequenceType(const DeclTypeSpec *type) {
709   return IsSequenceType(type, [&](const IntrinsicTypeSpec &type) {
710     return IsDefaultKindNumericType(type);
711   });
712 }
713 
714 bool EquivalenceSets::IsAnyNumericSequenceType(const DeclTypeSpec *type) {
715   return IsSequenceType(type, [&](const IntrinsicTypeSpec &type) {
716     return type.category() == TypeCategory::Logical ||
717         common::IsNumericTypeCategory(type.category());
718   });
719 }
720 
721 // Is type an intrinsic type that satisfies predicate or a sequence type
722 // whose components do.
723 bool EquivalenceSets::IsSequenceType(const DeclTypeSpec *type,
724     std::function<bool(const IntrinsicTypeSpec &)> predicate) {
725   if (!type) {
726     return false;
727   } else if (const IntrinsicTypeSpec * intrinsic{type->AsIntrinsic()}) {
728     return predicate(*intrinsic);
729   } else if (const DerivedTypeSpec * derived{type->AsDerived()}) {
730     for (const auto &pair : *derived->typeSymbol().scope()) {
731       const Symbol &component{*pair.second};
732       if (IsAllocatableOrPointer(component) ||
733           !IsSequenceType(component.GetType(), predicate)) {
734         return false;
735       }
736     }
737     return true;
738   } else {
739     return false;
740   }
741 }
742 
743 } // namespace Fortran::semantics
744