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/idioms.h"
15#include "flang/Common/reference.h"
16#include "flang/Parser/message.h"
17#include "flang/Parser/provenance.h"
18#include "flang/Support/Fortran.h"
19#include <list>
20#include <map>
21#include <optional>
22#include <set>
23#include <string>
24
25namespace llvm {
26class raw_ostream;
27}
28
29namespace Fortran::semantics {
30
31using namespace parser::literals;
32
33using common::ConstantSubscript;
34
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.
39struct 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 explicit EquivalenceObject(Symbol &symbol)
45 : symbol{symbol}, source{symbol.name()} {}
46
47 bool operator==(const EquivalenceObject &) const;
48 bool operator<(const EquivalenceObject &) const;
49 std::string AsFortran() const;
50
51 Symbol &symbol;
52 std::vector<ConstantSubscript> subscripts; // for array elem
53 std::optional<ConstantSubscript> substringStart;
54 parser::CharBlock source;
55};
56using EquivalenceSet = std::vector<EquivalenceObject>;
57
58// Preserved USE statement information for debug info generation.
59struct PreservedUseStmt {
60 std::string moduleName;
61 std::vector<std::string> onlyNames; // For USE ONLY
62 std::vector<std::string> renames; // local_name (resolved via GetUltimate)
63
64 PreservedUseStmt(std::string modName) : moduleName(std::move(modName)) {}
65};
66
67class Scope {
68 using mapType = std::map<SourceName, MutableSymbolRef>;
69
70public:
71 ENUM_CLASS(Kind, Global, IntrinsicModules, Module, MainProgram, Subprogram,
72 BlockData, DerivedType, BlockConstruct, Forall, OtherConstruct,
73 OpenACCConstruct, ImpliedDos, OtherClause)
74 using ImportKind = common::ImportKind;
75
76 // Create the Global scope -- the root of the scope tree
77 explicit Scope(SemanticsContext &context)
78 : Scope{*this, Kind::Global, nullptr, context} {}
79 Scope(Scope &parent, Kind kind, Symbol *symbol, SemanticsContext &context)
80 : parent_{&parent}, kind_{kind}, symbol_{symbol}, context_{context} {
81 if (symbol) {
82 symbol->set_scope(this);
83 }
84 }
85 Scope(const Scope &) = delete;
86
87 bool operator==(const Scope &that) const { return this == &that; }
88 bool operator!=(const Scope &that) const { return this != &that; }
89
90 Scope &parent() {
91 CHECK(parent_ != this);
92 return *parent_;
93 }
94 const Scope &parent() const {
95 CHECK(parent_ != this);
96 return *parent_;
97 }
98
99 mapType &commonBlocks() { return commonBlocks_; }
100 const mapType &commonBlocks() const { return commonBlocks_; }
101
102 mapType &commonBlockUses() { return commonBlockUses_; }
103 const mapType &commonBlockUses() const { return commonBlockUses_; }
104
105 Kind kind() const { return kind_; }
106 bool IsGlobal() const { return kind_ == Kind::Global; }
107 bool IsIntrinsicModules() const { return kind_ == Kind::IntrinsicModules; }
108 bool IsTopLevel() const {
109 return kind_ == Kind::Global || kind_ == Kind::IntrinsicModules;
110 }
111 bool IsModule() const {
112 return kind_ == Kind::Module &&
113 !symbol_->get<ModuleDetails>().isSubmodule();
114 }
115 bool IsSubmodule() const {
116 return kind_ == Kind::Module && symbol_->get<ModuleDetails>().isSubmodule();
117 }
118 bool IsDerivedType() const { return kind_ == Kind::DerivedType; }
119 bool IsStmtFunction() const;
120 bool IsParameterizedDerivedType() const;
121 bool IsParameterizedDerivedTypeInstantiation() const {
122 return kind_ == Kind::DerivedType && !symbol_;
123 }
128 Symbol *symbol() { return symbol_; }
129 const Symbol *symbol() const { return symbol_; }
130 SemanticsContext &context() const { return context_; }
131
132 inline const Symbol *GetSymbol() const;
133 const Scope *GetDerivedTypeParent() const;
134 const Scope &GetDerivedTypeBase() const;
135 inline std::optional<SourceName> GetName() const;
136 // Returns true if this scope contains, or is, another scope.
137 bool Contains(const Scope &) const;
139 Scope &MakeScope(Kind kind, Symbol *symbol = nullptr);
140
141 SemanticsContext &GetMutableSemanticsContext() const {
142 return const_cast<SemanticsContext &>(context());
143 }
144
145 using size_type = mapType::size_type;
146 using iterator = mapType::iterator;
147 using const_iterator = mapType::const_iterator;
148
149 iterator begin() { return symbols_.begin(); }
150 iterator end() { return symbols_.end(); }
151 const_iterator begin() const { return symbols_.begin(); }
152 const_iterator end() const { return symbols_.end(); }
153 const_iterator cbegin() const { return symbols_.cbegin(); }
154 const_iterator cend() const { return symbols_.cend(); }
155
156 // Return symbols in declaration order (the iterators above are in name order)
157 // When a generic procedure interface shadows a derived type or specific
158 // procedure, only the generic's symbol appears in the output.
159 SymbolVector GetSymbols() const;
160 MutableSymbolVector GetSymbols();
161
162 iterator find(const SourceName &name);
163 const_iterator find(const SourceName &name) const {
164 return symbols_.find(name);
165 }
166 size_type erase(const SourceName &);
167 bool empty() const { return symbols_.empty(); }
168
169 // Look for symbol by name in this scope and host (depending on imports).
170 Symbol *FindSymbol(const SourceName &) const;
171
172 // Look for component symbol by name in a derived type's scope and
173 // parents'.
174 Symbol *FindComponent(SourceName) const;
175
177 std::pair<iterator, bool> try_emplace(
178 const SourceName &name, Attrs attrs = Attrs()) {
179 return try_emplace(name, attrs, UnknownDetails());
180 }
181
182 template <typename D>
183 common::IfNoLvalue<std::pair<iterator, bool>, D> try_emplace(
184 const SourceName &name, D &&details) {
185 return try_emplace(name, Attrs(), std::move(details));
186 }
187
188 template <typename D>
189 common::IfNoLvalue<std::pair<iterator, bool>, D> try_emplace(
190 const SourceName &name, Attrs attrs, D &&details) {
191 Symbol &symbol{MakeSymbol(name, attrs, std::move(details))};
192 return symbols_.emplace(name, symbol);
193 }
194 // Make a copy of a symbol in this scope; nullptr if one is already there
195 Symbol *CopySymbol(const Symbol &);
196
197 std::list<EquivalenceSet> &equivalenceSets() { return equivalenceSets_; }
198 const std::list<EquivalenceSet> &equivalenceSets() const {
199 return equivalenceSets_;
200 }
201 void add_equivalenceSet(EquivalenceSet &&);
202 // Cray pointers are saved as map of pointee name -> pointer symbol
203 const mapType &crayPointers() const { return crayPointers_; }
204 void add_crayPointer(const SourceName &, Symbol &);
205 Symbol &MakeCommonBlock(SourceName, SourceName location);
206 bool AddCommonBlockUse(
207 const SourceName &name, Attrs attrs, Symbol &cbUltimate);
208
209 // Find COMMON block that is declared in the current scope
210 Symbol *FindCommonBlock(const SourceName &name) const;
211
212 // Find USE-associated COMMON block in the current scope
213 Symbol *FindCommonBlockUse(const SourceName &name) const;
214
215 // Find COMMON block in current and surrounding scopes, follow USE
216 // associations
217 Symbol *FindCommonBlockInVisibleScopes(const SourceName &) const;
218
220 template <typename D>
221 common::IfNoLvalue<Symbol &, D> MakeSymbol(
222 const SourceName &name, Attrs attrs, D &&details) {
223 return allSymbols.Make(*this, name, attrs, std::move(details));
224 }
225
226 std::list<Scope> &children() { return children_; }
227 const std::list<Scope> &children() const { return children_; }
228
229 // For Module scope, maintain a mapping of all submodule scopes with this
230 // module as its ancestor module. AddSubmodule returns false if already there.
231 Scope *FindSubmodule(const SourceName &) const;
232 bool AddSubmodule(const SourceName &, Scope &);
233
234 const DeclTypeSpec *FindType(const DeclTypeSpec &) const;
235 const DeclTypeSpec &MakeNumericType(TypeCategory, KindExpr &&kind);
236 const DeclTypeSpec &MakeLogicalType(KindExpr &&kind);
237 const DeclTypeSpec &MakeCharacterType(
238 ParamValue &&length, KindExpr &&kind = KindExpr{0});
239 DeclTypeSpec &MakeDerivedType(DeclTypeSpec::Category, DerivedTypeSpec &&);
240 const DeclTypeSpec &MakeTypeStarType();
241 const DeclTypeSpec &MakeClassStarType();
242 const DeclTypeSpec *GetType(const SomeExpr &);
243
244 std::size_t size() const { return size_; }
245 void set_size(std::size_t size) { size_ = size; }
246 std::optional<std::size_t> alignment() const { return alignment_; }
247
248 void SetAlignment(std::size_t n) {
249 alignment_ = std::max(alignment_.value_or(0), n);
250 }
251
252 ImportKind GetImportKind() const;
253 // Names appearing in IMPORT statements in this scope
254 std::set<SourceName> importNames() const { return importNames_; }
255 bool CanImport(const SourceName &) const;
256
257 // Set the kind of imports from host into this scope.
258 // Return an error message for incompatible kinds.
259 std::optional<parser::MessageFixedText> SetImportKind(ImportKind);
260
261 void add_importName(const SourceName &);
262
263 // These members pertain to instantiations of parameterized derived types.
264 const DerivedTypeSpec *derivedTypeSpec() const { return derivedTypeSpec_; }
265 DerivedTypeSpec *derivedTypeSpec() { return derivedTypeSpec_; }
266 void set_derivedTypeSpec(DerivedTypeSpec &spec) { derivedTypeSpec_ = &spec; }
267 parser::Message::Reference instantiationContext() const {
268 return instantiationContext_;
269 };
270 void set_instantiationContext(parser::Message::Reference &&mref) {
271 instantiationContext_ = std::move(mref);
272 }
273
274 bool hasSAVE() const { return hasSAVE_; }
275 void set_hasSAVE(bool yes = true) { hasSAVE_ = yes; }
276
277 // The range of the source of this and nested scopes.
278 const parser::CharBlock &sourceRange() const { return sourceRange_; }
279 void AddSourceRange(parser::CharBlock);
280
281 // Attempts to find a match for a derived type instance
282 const DeclTypeSpec *FindInstantiatedDerivedType(const DerivedTypeSpec &,
283 DeclTypeSpec::Category = DeclTypeSpec::TypeDerived) const;
284
285 bool IsModuleFile() const {
286 return kind_ == Kind::Module && symbol_ &&
287 symbol_->test(Symbol::Flag::ModFile);
288 }
289
290 void InstantiateDerivedTypes();
291
292 const Symbol *runtimeDerivedTypeDescription() const {
293 return runtimeDerivedTypeDescription_;
294 }
295 void set_runtimeDerivedTypeDescription(const Symbol &symbol) {
296 runtimeDerivedTypeDescription_ = &symbol;
297 }
298
299private:
300 Scope *parent_{
301 nullptr}; // this is enclosing scope, not extended derived type base
302 const Kind kind_;
303 std::size_t size_{0}; // size in bytes
304 std::optional<std::size_t> alignment_; // required alignment in bytes
305 parser::CharBlock sourceRange_;
306 const parser::CookedSource *cookedSource_{nullptr};
307 Symbol *const symbol_; // if not null, symbol_->scope() == this
308 std::list<Scope> children_;
309 mapType symbols_;
310 mapType commonBlocks_;
311 mapType commonBlockUses_; // USE-assocated COMMON blocks
312 std::list<EquivalenceSet> equivalenceSets_;
313 mapType crayPointers_;
314 std::map<SourceName, common::Reference<Scope>> submodules_;
315 std::list<DeclTypeSpec> declTypeSpecs_;
316 std::optional<ImportKind> importKind_;
317 std::set<SourceName> importNames_;
318 DerivedTypeSpec *derivedTypeSpec_{nullptr}; // dTS->scope() == this
319 parser::Message::Reference instantiationContext_;
320 bool hasSAVE_{false}; // scope has a bare SAVE statement
321 const Symbol *runtimeDerivedTypeDescription_{nullptr};
322 SemanticsContext &context_;
323 // When additional data members are added to Scope, remember to
324 // copy them, if appropriate, in FindOrInstantiateDerivedType().
325
326 // Storage for all Symbols. Every Symbol is in allSymbols and every Symbol*
327 // or Symbol& points to one in there.
328 static Symbols<1024> allSymbols;
329
330 const DeclTypeSpec &MakeLengthlessType(DeclTypeSpec &&);
331
332 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Scope &);
333};
334
335// Inline so that it can be called from Evaluate without a link-time dependency.
336
337inline const Symbol *Scope::GetSymbol() const {
338 return symbol_ ? symbol_
339 : derivedTypeSpec_ ? &derivedTypeSpec_->typeSymbol()
340 : nullptr;
341}
342
343inline std::optional<SourceName> Scope::GetName() const {
344 if (const auto *sym{GetSymbol()}) {
345 return sym->name();
346 } else {
347 return std::nullopt;
348 }
349}
350
351} // namespace Fortran::semantics
352#endif // FORTRAN_SEMANTICS_SCOPE_H_
Definition char-block.h:28
Definition symbol.h:85
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:189
bool IsDerivedTypeWithKindParameter() const
Does this derived type have at least one kind parameter ?
Definition scope.cpp:478
common::IfNoLvalue< std::pair< iterator, bool >, D > try_emplace(const SourceName &name, D &&details)
Make a Symbol with provided details.
Definition scope.h:183
Scope & MakeScope(Kind kind, Symbol *symbol=nullptr)
Make a scope nested in this one.
Definition scope.cpp:53
std::pair< iterator, bool > try_emplace(const SourceName &name, Attrs attrs=Attrs())
Make a Symbol with unknown details.
Definition scope.h:177
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:221
bool IsDerivedTypeWithLengthParameter() const
Does this derived type have at least one length parameter ?
Definition scope.cpp:475
Definition semantics.h:67
Definition symbol.h:809
Definition symbol.h:798