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 "llvm/Support/raw_ostream.h" |
23 | #include <forward_list> |
24 | |
25 | namespace Fortran::parser { |
26 | class CharBlock; |
27 | struct ArraySpec; |
28 | struct CoarraySpec; |
29 | struct ComponentArraySpec; |
30 | struct DataRef; |
31 | struct DefinedOpName; |
32 | struct Designator; |
33 | struct Expr; |
34 | struct GenericSpec; |
35 | struct Name; |
36 | } // namespace Fortran::parser |
37 | |
38 | namespace Fortran::semantics { |
39 | |
40 | using SourceName = parser::CharBlock; |
41 | class SemanticsContext; |
42 | |
43 | // Record that a Name has been resolved to a Symbol |
44 | Symbol &Resolve(const parser::Name &, Symbol &); |
45 | Symbol *Resolve(const parser::Name &, Symbol *); |
46 | |
47 | // Create a copy of msg with a new severity. |
48 | parser::MessageFixedText WithSeverity( |
49 | const parser::MessageFixedText &msg, parser::Severity); |
50 | |
51 | bool IsIntrinsicOperator(const SemanticsContext &, const SourceName &); |
52 | bool IsLogicalConstant(const SemanticsContext &, const SourceName &); |
53 | |
54 | // Some intrinsic operators have more than one name (e.g. `operator(.eq.)` and |
55 | // `operator(==)`). GetAllNames() returns them all, including symbolName. |
56 | std::forward_list<std::string> GetAllNames( |
57 | const SemanticsContext &, const SourceName &); |
58 | |
59 | template <typename T> |
60 | MaybeIntExpr EvaluateIntExpr(SemanticsContext &context, const T &expr) { |
61 | if (MaybeExpr maybeExpr{ |
62 | Fold(context.foldingContext(), AnalyzeExpr(context, expr))}) { |
63 | if (auto *intExpr{evaluate::UnwrapExpr<SomeIntExpr>(*maybeExpr)}) { |
64 | return std::move(*intExpr); |
65 | } |
66 | } |
67 | return std::nullopt; |
68 | } |
69 | |
70 | template <typename T> |
71 | std::optional<std::int64_t> EvaluateInt64( |
72 | SemanticsContext &context, const T &expr) { |
73 | return evaluate::ToInt64(EvaluateIntExpr(context, expr)); |
74 | } |
75 | |
76 | // Analyze a generic-spec and generate a symbol name and GenericKind for it. |
77 | class GenericSpecInfo { |
78 | public: |
79 | explicit GenericSpecInfo(const parser::DefinedOpName &x) { Analyze(x); } |
80 | explicit GenericSpecInfo(const parser::GenericSpec &x) { Analyze(x); } |
81 | |
82 | GenericKind kind() const { return kind_; } |
83 | const SourceName &symbolName() const { return symbolName_.value(); } |
84 | // Set the GenericKind in this symbol and resolve the corresponding |
85 | // name if there is one |
86 | void Resolve(Symbol *) const; |
87 | friend llvm::raw_ostream &operator<<( |
88 | llvm::raw_ostream &, const GenericSpecInfo &); |
89 | |
90 | private: |
91 | void Analyze(const parser::DefinedOpName &); |
92 | void Analyze(const parser::GenericSpec &); |
93 | |
94 | GenericKind kind_; |
95 | const parser::Name *parseName_{nullptr}; |
96 | std::optional<SourceName> symbolName_; |
97 | }; |
98 | |
99 | // Analyze a parser::ArraySpec or parser::CoarraySpec |
100 | ArraySpec AnalyzeArraySpec(SemanticsContext &, const parser::ArraySpec &); |
101 | ArraySpec AnalyzeArraySpec( |
102 | SemanticsContext &, const parser::ComponentArraySpec &); |
103 | ArraySpec AnalyzeDeferredShapeSpecList( |
104 | SemanticsContext &, const parser::DeferredShapeSpecList &); |
105 | ArraySpec AnalyzeCoarraySpec( |
106 | SemanticsContext &context, const parser::CoarraySpec &); |
107 | |
108 | // Perform consistency checks on equivalence sets |
109 | class EquivalenceSets { |
110 | public: |
111 | EquivalenceSets(SemanticsContext &context) : context_{context} {} |
112 | std::vector<EquivalenceSet> &sets() { return sets_; }; |
113 | // Resolve this designator and add to the current equivalence set |
114 | void AddToSet(const parser::Designator &); |
115 | // Finish the current equivalence set: determine if it overlaps |
116 | // with any of the others and perform necessary merges if it does. |
117 | void FinishSet(const parser::CharBlock &); |
118 | |
119 | private: |
120 | bool CheckCanEquivalence( |
121 | const parser::CharBlock &, const Symbol &, const Symbol &); |
122 | void MergeInto(const parser::CharBlock &, EquivalenceSet &, std::size_t); |
123 | const EquivalenceObject *Find(const EquivalenceSet &, const Symbol &); |
124 | bool CheckDesignator(const parser::Designator &); |
125 | bool CheckDataRef(const parser::CharBlock &, const parser::DataRef &); |
126 | bool CheckObject(const parser::Name &); |
127 | bool CheckArrayBound(const parser::Expr &); |
128 | bool CheckSubstringBound(const parser::Expr &, bool); |
129 | bool IsCharacterSequenceType(const DeclTypeSpec *); |
130 | bool IsDefaultKindNumericType(const IntrinsicTypeSpec &); |
131 | bool IsDefaultNumericSequenceType(const DeclTypeSpec *); |
132 | static bool IsAnyNumericSequenceType(const DeclTypeSpec *); |
133 | static bool IsSequenceType( |
134 | const DeclTypeSpec *, std::function<bool(const IntrinsicTypeSpec &)>); |
135 | |
136 | SemanticsContext &context_; |
137 | std::vector<EquivalenceSet> sets_; // all equivalence sets in this scope |
138 | // Map object to index of set it is in |
139 | std::map<EquivalenceObject, std::size_t> objectToSet_; |
140 | EquivalenceSet currSet_; // equivalence set currently being constructed |
141 | struct { |
142 | Symbol *symbol{nullptr}; |
143 | std::vector<ConstantSubscript> subscripts; |
144 | std::optional<ConstantSubscript> substringStart; |
145 | } currObject_; // equivalence object currently being constructed |
146 | }; |
147 | |
148 | // Duplicates a subprogram's dummy arguments and result, if any, and |
149 | // maps all of the symbols in their expressions. |
150 | struct SymbolAndTypeMappings; |
151 | void MapSubprogramToNewSymbols(const Symbol &oldSymbol, Symbol &newSymbol, |
152 | Scope &newScope, SymbolAndTypeMappings * = nullptr); |
153 | |
154 | } // namespace Fortran::semantics |
155 | #endif // FORTRAN_SEMANTICS_RESOLVE_NAMES_H_ |
156 | |