1 //===-- lib/Semantics/resolve-names-utils.h ---------------------*- C++ -*-===//
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 #ifndef FORTRAN_SEMANTICS_RESOLVE_NAMES_UTILS_H_
10 #define FORTRAN_SEMANTICS_RESOLVE_NAMES_UTILS_H_
11
12 // Utility functions and class for use in resolve-names.cpp.
13
14 #include "flang/Evaluate/fold.h"
15 #include "flang/Parser/message.h"
16 #include "flang/Parser/tools.h"
17 #include "flang/Semantics/expression.h"
18 #include "flang/Semantics/scope.h"
19 #include "flang/Semantics/semantics.h"
20 #include "flang/Semantics/symbol.h"
21 #include "flang/Semantics/type.h"
22 #include <forward_list>
23
24 namespace Fortran::parser {
25 class CharBlock;
26 struct ArraySpec;
27 struct CoarraySpec;
28 struct ComponentArraySpec;
29 struct DataRef;
30 struct DefinedOpName;
31 struct Designator;
32 struct Expr;
33 struct GenericSpec;
34 struct Name;
35 } // namespace Fortran::parser
36
37 namespace Fortran::semantics {
38
39 using SourceName = parser::CharBlock;
40 class SemanticsContext;
41
42 // Record that a Name has been resolved to a Symbol
43 Symbol &Resolve(const parser::Name &, Symbol &);
44 Symbol *Resolve(const parser::Name &, Symbol *);
45
46 // Create a copy of msg with a new isFatal value.
47 parser::MessageFixedText WithIsFatal(
48 const parser::MessageFixedText &msg, bool isFatal);
49
50 bool IsIntrinsicOperator(const SemanticsContext &, const SourceName &);
51 bool IsLogicalConstant(const SemanticsContext &, const SourceName &);
52
53 template <typename T>
EvaluateIntExpr(SemanticsContext & context,const T & expr)54 MaybeIntExpr EvaluateIntExpr(SemanticsContext &context, const T &expr) {
55 if (MaybeExpr maybeExpr{
56 Fold(context.foldingContext(), AnalyzeExpr(context, expr))}) {
57 if (auto *intExpr{evaluate::UnwrapExpr<SomeIntExpr>(*maybeExpr)}) {
58 return std::move(*intExpr);
59 }
60 }
61 return std::nullopt;
62 }
63
64 template <typename T>
EvaluateInt64(SemanticsContext & context,const T & expr)65 std::optional<std::int64_t> EvaluateInt64(
66 SemanticsContext &context, const T &expr) {
67 return evaluate::ToInt64(EvaluateIntExpr(context, expr));
68 }
69
70 // Analyze a generic-spec and generate a symbol name and GenericKind for it.
71 class GenericSpecInfo {
72 public:
GenericSpecInfo(const parser::DefinedOpName & x)73 GenericSpecInfo(const parser::DefinedOpName &x) { Analyze(x); }
GenericSpecInfo(const parser::GenericSpec & x)74 GenericSpecInfo(const parser::GenericSpec &x) { Analyze(x); }
75
kind()76 GenericKind kind() const { return kind_; }
symbolName()77 const SourceName &symbolName() const { return symbolName_.value(); }
78 // Some intrinsic operators have more than one name (e.g. `operator(.eq.)` and
79 // `operator(==)`). GetAllNames() returns them all, including symbolName.
80 std::forward_list<std::string> GetAllNames(SemanticsContext &) const;
81 // Set the GenericKind in this symbol and resolve the corresponding
82 // name if there is one
83 void Resolve(Symbol *) const;
84 Symbol *FindInScope(SemanticsContext &, const Scope &) const;
85
86 private:
87 GenericKind kind_;
88 const parser::Name *parseName_{nullptr};
89 std::optional<SourceName> symbolName_;
90
91 void Analyze(const parser::DefinedOpName &);
92 void Analyze(const parser::GenericSpec &);
93 };
94
95 // Analyze a parser::ArraySpec or parser::CoarraySpec
96 ArraySpec AnalyzeArraySpec(SemanticsContext &, const parser::ArraySpec &);
97 ArraySpec AnalyzeArraySpec(
98 SemanticsContext &, const parser::ComponentArraySpec &);
99 ArraySpec AnalyzeCoarraySpec(
100 SemanticsContext &context, const parser::CoarraySpec &);
101
102 // Perform consistency checks on equivalence sets
103 class EquivalenceSets {
104 public:
EquivalenceSets(SemanticsContext & context)105 EquivalenceSets(SemanticsContext &context) : context_{context} {}
sets()106 std::vector<EquivalenceSet> &sets() { return sets_; };
107 // Resolve this designator and add to the current equivalence set
108 void AddToSet(const parser::Designator &);
109 // Finish the current equivalence set: determine if it overlaps
110 // with any of the others and perform necessary merges if it does.
111 void FinishSet(const parser::CharBlock &);
112
113 private:
114 bool CheckCanEquivalence(
115 const parser::CharBlock &, const Symbol &, const Symbol &);
116 void MergeInto(const parser::CharBlock &, EquivalenceSet &, std::size_t);
117 const EquivalenceObject *Find(const EquivalenceSet &, const Symbol &);
118 bool CheckDesignator(const parser::Designator &);
119 bool CheckDataRef(const parser::CharBlock &, const parser::DataRef &);
120 bool CheckObject(const parser::Name &);
121 bool CheckArrayBound(const parser::Expr &);
122 bool CheckSubstringBound(const parser::Expr &, bool);
123 bool IsCharacterSequenceType(const DeclTypeSpec *);
124 bool IsDefaultKindNumericType(const IntrinsicTypeSpec &);
125 bool IsNumericSequenceType(const DeclTypeSpec *);
126 bool IsSequenceType(
127 const DeclTypeSpec *, std::function<bool(const IntrinsicTypeSpec &)>);
128
129 SemanticsContext &context_;
130 std::vector<EquivalenceSet> sets_; // all equivalence sets in this scope
131 // Map object to index of set it is in
132 std::map<EquivalenceObject, std::size_t> objectToSet_;
133 EquivalenceSet currSet_; // equivalence set currently being constructed
134 struct {
135 Symbol *symbol{nullptr};
136 std::vector<ConstantSubscript> subscripts;
137 std::optional<ConstantSubscript> substringStart;
138 } currObject_; // equivalence object currently being constructed
139 };
140
141 } // namespace Fortran::semantics
142 #endif // FORTRAN_SEMANTICS_RESOLVE_NAMES_H_
143