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