Warning: This file is not a C or C++ file. It does not have highlighting.

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

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of flang/include/flang/Semantics/scope.h