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