FLANG

scope.h
1 //===-- include/flang/Semantics/scope.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_SCOPE_H_
10 #define FORTRAN_SEMANTICS_SCOPE_H_
11
12 #include "attr.h"
13 #include "symbol.h"
14 #include "flang/Common/Fortran.h"
15 #include "flang/Common/idioms.h"
16 #include "flang/Common/reference.h"
17 #include "flang/Parser/message.h"
18 #include "flang/Parser/provenance.h"
19 #include <list>
20 #include <map>
21 #include <optional>
22 #include <set>
23 #include <string>
24
25 namespace llvm {
26 class raw_ostream;
27 }
28
29 namespace Fortran::semantics {
30
31 using namespace parser::literals;
32
33 using common::ConstantSubscript;
34
35 class SemanticsContext;
36
37 // An equivalence object is represented by a symbol for the variable name,
38 // the indices for an array element, and the lower bound for a substring.
39 struct EquivalenceObject {
40 EquivalenceObject(Symbol &symbol, std::vector<ConstantSubscript> subscripts,
41 std::optional<ConstantSubscript> substringStart, parser::CharBlock source)
42 : symbol{symbol}, subscripts{subscripts},
43 substringStart{substringStart}, source{source} {}
44
45 bool operator==(const EquivalenceObject &) const;
46 bool operator<(const EquivalenceObject &) const;
47 std::string AsFortran() const;
48
49 Symbol &symbol;
50 std::vector<ConstantSubscript> subscripts; // for array elem
51 std::optional<ConstantSubscript> substringStart;
52 parser::CharBlock source;
53 };
54 using EquivalenceSet = std::vector<EquivalenceObject>;
55
56 class Scope {
57 using mapType = std::map<SourceName, MutableSymbolRef>;
58
59 public:
60 ENUM_CLASS(Kind, Global, Module, MainProgram, Subprogram, BlockData,
61 DerivedType, Block, Forall, ImpliedDos)
62 using ImportKind = common::ImportKind;
63
64 // Create the Global scope -- the root of the scope tree
65 Scope() : Scope{*this, Kind::Global, nullptr} {}
66 Scope(Scope &parent, Kind kind, Symbol *symbol)
67 : parent_{parent}, kind_{kind}, symbol_{symbol} {
68 if (symbol) {
69 symbol->set_scope(this);
70 }
71 }
72 Scope(const Scope &) = delete;
73
74 bool operator==(const Scope &that) const { return this == &that; }
75 bool operator!=(const Scope &that) const { return this != &that; }
76
77 Scope &parent() {
78 CHECK(&parent_ != this);
79 return parent_;
80 }
81 const Scope &parent() const {
82 CHECK(&parent_ != this);
83 return parent_;
84 }
85 Kind kind() const { return kind_; }
86 bool IsGlobal() const { return kind_ == Kind::Global; }
87 bool IsModule() const; // only module, not submodule
88 bool IsSubmodule() const;
89 bool IsDerivedType() const { return kind_ == Kind::DerivedType; }
90 bool IsParameterizedDerivedType() const;
91 Symbol *symbol() { return symbol_; }
92 const Symbol *symbol() const { return symbol_; }
93
94 inline const Symbol *GetSymbol() const;
95 const Scope *GetDerivedTypeParent() const;
96 const Scope &GetDerivedTypeBase() const;
97 std::optional<SourceName> GetName() const;
98 bool Contains(const Scope &) const;
100 Scope &MakeScope(Kind kind, Symbol *symbol = nullptr);
101
102 using size_type = mapType::size_type;
103 using iterator = mapType::iterator;
104 using const_iterator = mapType::const_iterator;
105
106 iterator begin() { return symbols_.begin(); }
107 iterator end() { return symbols_.end(); }
108 const_iterator begin() const { return symbols_.begin(); }
109 const_iterator end() const { return symbols_.end(); }
110 const_iterator cbegin() const { return symbols_.cbegin(); }
111 const_iterator cend() const { return symbols_.cend(); }
112
113 // Return symbols in declaration order (the iterators above are in name order)
114 SymbolVector GetSymbols() const;
115 MutableSymbolVector GetSymbols();
116
117 iterator find(const SourceName &name);
118 const_iterator find(const SourceName &name) const {
119 return symbols_.find(name);
120 }
121 size_type erase(const SourceName &);
122 bool empty() const { return symbols_.empty(); }
123
124 // Look for symbol by name in this scope and host (depending on imports).
125 Symbol *FindSymbol(const SourceName &) const;
126
127 // Look for component symbol by name in a derived type's scope and
128 // parents'.
129 Symbol *FindComponent(SourceName) const;
130
132 std::pair<iterator, bool> try_emplace(
133 const SourceName &name, Attrs attrs = Attrs()) {
134 return try_emplace(name, attrs, UnknownDetails());
135 }
137 template <typename D>
138 common::IfNoLvalue<std::pair<iterator, bool>, D> try_emplace(
139 const SourceName &name, D &&details) {
140 return try_emplace(name, Attrs(), std::move(details));
141 }
143 template <typename D>
144 common::IfNoLvalue<std::pair<iterator, bool>, D> try_emplace(
145 const SourceName &name, Attrs attrs, D &&details) {
146 Symbol &symbol{MakeSymbol(name, attrs, std::move(details))};
147 return symbols_.emplace(name, symbol);
148 }
149 // Make a copy of a symbol in this scope; nullptr if one is already there
150 Symbol *CopySymbol(const Symbol &);
151
152 std::list<EquivalenceSet> &equivalenceSets() { return equivalenceSets_; }
153 const std::list<EquivalenceSet> &equivalenceSets() const {
154 return equivalenceSets_;
155 }
156 void add_equivalenceSet(EquivalenceSet &&);
157 // Cray pointers are saved as map of pointee name -> pointer symbol
158 const mapType &crayPointers() const { return crayPointers_; }
159 void add_crayPointer(const SourceName &, Symbol &);
160 mapType &commonBlocks() { return commonBlocks_; }
161 const mapType &commonBlocks() const { return commonBlocks_; }
162 Symbol &MakeCommonBlock(const SourceName &);
163 Symbol *FindCommonBlock(const SourceName &);
164
166 template <typename D>
167 common::IfNoLvalue<Symbol &, D> MakeSymbol(
168 const SourceName &name, Attrs attrs, D &&details) {
169 return allSymbols.Make(*this, name, attrs, std::move(details));
170 }
171
172 std::list<Scope> &children() { return children_; }
173 const std::list<Scope> &children() const { return children_; }
174
175 // For Module scope, maintain a mapping of all submodule scopes with this
176 // module as its ancestor module. AddSubmodule returns false if already there.
177 Scope *FindSubmodule(const SourceName &) const;
178 bool AddSubmodule(const SourceName &, Scope &);
179
180 const DeclTypeSpec *FindType(const DeclTypeSpec &) const;
181 const DeclTypeSpec &MakeNumericType(TypeCategory, KindExpr &&kind);
182 const DeclTypeSpec &MakeLogicalType(KindExpr &&kind);
183 const DeclTypeSpec &MakeCharacterType(
184 ParamValue &&length, KindExpr &&kind = KindExpr{0});
185 DeclTypeSpec &MakeDerivedType(DeclTypeSpec::Category, DerivedTypeSpec &&);
186 const DeclTypeSpec &MakeTypeStarType();
187 const DeclTypeSpec &MakeClassStarType();
188
189 // For modules read from module files, this is the stream of characters
190 // that are referenced by SourceName objects.
191 void set_chars(parser::CookedSource &);
192
193 std::size_t size() const { return size_; }
194 void set_size(std::size_t size) { size_ = size; }
195 std::size_t alignment() const { return alignment_; }
196 void set_alignment(std::size_t alignment) { alignment_ = alignment; }
197
198 ImportKind GetImportKind() const;
199 // Names appearing in IMPORT statements in this scope
200 std::set<SourceName> importNames() const { return importNames_; }
201
202 // Set the kind of imports from host into this scope.
203 // Return an error message for incompatible kinds.
204 std::optional<parser::MessageFixedText> SetImportKind(ImportKind);
205
206 void add_importName(const SourceName &);
207
208 const DerivedTypeSpec *derivedTypeSpec() const { return derivedTypeSpec_; }
209 DerivedTypeSpec *derivedTypeSpec() { return derivedTypeSpec_; }
210 void set_derivedTypeSpec(DerivedTypeSpec &spec) { derivedTypeSpec_ = &spec; }
211
212 bool hasSAVE() const { return hasSAVE_; }
213 void set_hasSAVE(bool yes = true) { hasSAVE_ = yes; }
214
215 // The range of the source of this and nested scopes.
216 const parser::CharBlock &sourceRange() const { return sourceRange_; }
217 void AddSourceRange(const parser::CharBlock &);
218 // Find the smallest scope under this one that contains source
219 const Scope *FindScope(parser::CharBlock) const;
220 Scope *FindScope(parser::CharBlock);
221
222 // Attempts to find a match for a derived type instance
223 const DeclTypeSpec *FindInstantiatedDerivedType(const DerivedTypeSpec &,
224 DeclTypeSpec::Category = DeclTypeSpec::TypeDerived) const;
225
226 bool IsModuleFile() const {
227 return kind_ == Kind::Module && symbol_ &&
228 symbol_->test(Symbol::Flag::ModFile);
229 }
230
231 void InstantiateDerivedTypes(SemanticsContext &);
232
233 private:
234 Scope &parent_; // this is enclosing scope, not extended derived type base
235 const Kind kind_;
236 std::size_t size_{0}; // size in bytes
237 std::size_t alignment_{0}; // required alignment in bytes
238 parser::CharBlock sourceRange_;
239 Symbol *const symbol_; // if not null, symbol_->scope() == this
240 std::list<Scope> children_;
241 mapType symbols_;
242 mapType commonBlocks_;
243 std::list<EquivalenceSet> equivalenceSets_;
244 mapType crayPointers_;
245 std::map<SourceName, common::Reference<Scope>> submodules_;
246 std::list<DeclTypeSpec> declTypeSpecs_;
247 std::string chars_;
248 std::optional<ImportKind> importKind_;
249 std::set<SourceName> importNames_;
250 DerivedTypeSpec *derivedTypeSpec_{nullptr}; // dTS->scope() == this
251 bool hasSAVE_{false}; // scope has a bare SAVE statement
252 // When additional data members are added to Scope, remember to
253 // copy them, if appropriate, in InstantiateDerivedType().
254
255 // Storage for all Symbols. Every Symbol is in allSymbols and every Symbol*
256 // or Symbol& points to one in there.
257 static Symbols<1024> allSymbols;
258
259 bool CanImport(const SourceName &) const;
260 const DeclTypeSpec &MakeLengthlessType(DeclTypeSpec &&);
261
262 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Scope &);
263 };
264
265 // Inline so that it can be called from Evaluate without a link-time dependency.
266
267 inline const Symbol *Scope::GetSymbol() const {
268 return symbol_ ? symbol_
269 : derivedTypeSpec_ ? &derivedTypeSpec_->typeSymbol()
270 : nullptr;
271 }
272
273 } // namespace Fortran::semantics
274 #endif // FORTRAN_SEMANTICS_SCOPE_H_
Fortran::semantics::UnknownDetails
Definition: symbol.h:468
Fortran::semantics::Symbol
Definition: symbol.h:479
Fortran::semantics::Scope::try_emplace
common::IfNoLvalue< std::pair< iterator, bool >, D > try_emplace(const SourceName &name, D &&details)
Make a Symbol with provided details.
Definition: scope.h:138
Fortran::semantics::Scope::MakeSymbol
common::IfNoLvalue< Symbol &, D > MakeSymbol(const SourceName &name, Attrs attrs, D &&details)
Make a Symbol but don't add it to the scope.
Definition: scope.h:167
Fortran::semantics::Scope::try_emplace
common::IfNoLvalue< std::pair< iterator, bool >, D > try_emplace(const SourceName &name, Attrs attrs, D &&details)
Make a Symbol with attrs and details.
Definition: scope.h:144
Fortran::semantics::Scope::try_emplace
std::pair< iterator, bool > try_emplace(const SourceName &name, Attrs attrs=Attrs())
Make a Symbol with unknown details.
Definition: scope.h:132
Fortran::parser::CharBlock
Definition: char-block.h:28
Fortran::semantics::Scope
Definition: scope.h:56
Fortran::semantics::EquivalenceObject
Definition: scope.h:39