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