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 "llvm/Frontend/OpenMP/OMP.h"
20#include <list>
21#include <map>
22#include <optional>
23#include <set>
24#include <string>
25
26namespace llvm {
27class raw_ostream;
28}
29
30namespace Fortran::semantics {
31
32using namespace parser::literals;
33
34using common::ConstantSubscript;
35
37
38// An equivalence object is represented by a symbol for the variable name,
39// the indices for an array element, and the lower bound for a substring.
40struct EquivalenceObject {
41 EquivalenceObject(Symbol &symbol, std::vector<ConstantSubscript> subscripts,
42 std::optional<ConstantSubscript> substringStart, parser::CharBlock source)
43 : symbol{symbol}, subscripts{subscripts},
44 substringStart{substringStart}, source{source} {}
45 explicit EquivalenceObject(Symbol &symbol)
46 : symbol{symbol}, source{symbol.name()} {}
47
48 bool operator==(const EquivalenceObject &) const;
49 bool operator<(const EquivalenceObject &) const;
50 std::string AsFortran() const;
51
52 Symbol &symbol;
53 std::vector<ConstantSubscript> subscripts; // for array elem
54 std::optional<ConstantSubscript> substringStart;
55 parser::CharBlock source;
56};
57using EquivalenceSet = std::vector<EquivalenceObject>;
58
59// Preserved USE statement information for debug info generation.
60struct PreservedUseStmt {
61 std::string moduleName;
62 std::vector<std::string> onlyNames; // For USE ONLY
63 std::vector<std::string> renames; // local_name (resolved via GetUltimate)
64 bool hasOnlyWithRenames{false}; // true if there are renames in an ONLY clause
65
66 PreservedUseStmt(std::string modName) : moduleName(std::move(modName)) {}
67};
68
69class Scope {
70 using mapType = std::map<SourceName, MutableSymbolRef>;
71
72public:
73 ENUM_CLASS(Kind, Global, IntrinsicModules, Module, MainProgram, Subprogram,
74 BlockData, DerivedType, BlockConstruct, Forall, OtherConstruct,
75 OpenACCConstruct, ImpliedDos, OtherClause)
76 using ImportKind = common::ImportKind;
77
78 // Create the Global scope -- the root of the scope tree
79 explicit Scope(SemanticsContext &context)
80 : Scope{*this, Kind::Global, nullptr, context} {}
81 Scope(Scope &parent, Kind kind, Symbol *symbol, SemanticsContext &context)
82 : parent_{&parent}, kind_{kind}, symbol_{symbol}, context_{context} {
83 if (symbol) {
84 symbol->set_scope(this);
85 }
86 }
87 Scope(const Scope &) = delete;
88
89 bool operator==(const Scope &that) const { return this == &that; }
90 bool operator!=(const Scope &that) const { return this != &that; }
91
92 Scope &parent() {
93 CHECK(parent_ != this);
94 return *parent_;
95 }
96 const Scope &parent() const {
97 CHECK(parent_ != this);
98 return *parent_;
99 }
100
101 mapType &commonBlocks() { return commonBlocks_; }
102 const mapType &commonBlocks() const { return commonBlocks_; }
103
104 mapType &commonBlockUses() { return commonBlockUses_; }
105 const mapType &commonBlockUses() const { return commonBlockUses_; }
106
107 Kind kind() const { return kind_; }
108 bool IsGlobal() const { return kind_ == Kind::Global; }
109 bool IsIntrinsicModules() const { return kind_ == Kind::IntrinsicModules; }
110 bool IsTopLevel() const {
111 return kind_ == Kind::Global || kind_ == Kind::IntrinsicModules;
112 }
113 bool IsModule() const {
114 return kind_ == Kind::Module &&
115 !symbol_->get<ModuleDetails>().isSubmodule();
116 }
117 bool IsSubmodule() const {
118 return kind_ == Kind::Module && symbol_->get<ModuleDetails>().isSubmodule();
119 }
120 bool IsDerivedType() const { return kind_ == Kind::DerivedType; }
121 bool IsStmtFunction() const;
122 bool IsParameterizedDerivedType() const;
123 bool IsParameterizedDerivedTypeInstantiation() const {
124 return kind_ == Kind::DerivedType && !symbol_;
125 }
130 Symbol *symbol() { return symbol_; }
131 const Symbol *symbol() const { return symbol_; }
132 SemanticsContext &context() const { return context_; }
133
134 inline const Symbol *GetSymbol() const;
135 const Scope *GetDerivedTypeParent() const;
136 const Scope &GetDerivedTypeBase() const;
137 inline std::optional<SourceName> GetName() const;
138 // Returns true if this scope contains, or is, another scope.
139 bool Contains(const Scope &) const;
141 Scope &MakeScope(Kind kind, Symbol *symbol = nullptr);
142
143 SemanticsContext &GetMutableSemanticsContext() const {
144 return const_cast<SemanticsContext &>(context());
145 }
146
147 using size_type = mapType::size_type;
148 using iterator = mapType::iterator;
149 using const_iterator = mapType::const_iterator;
150
151 iterator begin() { return symbols_.begin(); }
152 iterator end() { return symbols_.end(); }
153 const_iterator begin() const { return symbols_.begin(); }
154 const_iterator end() const { return symbols_.end(); }
155 const_iterator cbegin() const { return symbols_.cbegin(); }
156 const_iterator cend() const { return symbols_.cend(); }
157
158 // Return symbols in declaration order (the iterators above are in name order)
159 // When a generic procedure interface shadows a derived type or specific
160 // procedure, only the generic's symbol appears in the output.
161 SymbolVector GetSymbols() const;
162 MutableSymbolVector GetSymbols();
163
164 iterator find(const SourceName &name);
165 const_iterator find(const SourceName &name) const {
166 return symbols_.find(name);
167 }
168 size_type erase(const SourceName &);
169 bool empty() const { return symbols_.empty(); }
170
171 // Look for symbol by name in this scope and host (depending on imports).
172 Symbol *FindSymbol(const SourceName &) const;
173
174 // Look for component symbol by name in a derived type's scope and
175 // parents'.
176 Symbol *FindComponent(SourceName) const;
177
179 std::pair<iterator, bool> try_emplace(
180 const SourceName &name, Attrs attrs = Attrs()) {
181 return try_emplace(name, attrs, UnknownDetails());
182 }
183
184 template <typename D>
185 common::IfNoLvalue<std::pair<iterator, bool>, D> try_emplace(
186 const SourceName &name, D &&details) {
187 return try_emplace(name, Attrs(), std::move(details));
188 }
189
190 template <typename D>
191 common::IfNoLvalue<std::pair<iterator, bool>, D> try_emplace(
192 const SourceName &name, Attrs attrs, D &&details) {
193 Symbol &symbol{MakeSymbol(name, attrs, std::move(details))};
194 return symbols_.emplace(name, symbol);
195 }
196 // Make a copy of a symbol in this scope; nullptr if one is already there
197 Symbol *CopySymbol(const Symbol &);
198
199 std::list<EquivalenceSet> &equivalenceSets() { return equivalenceSets_; }
200 const std::list<EquivalenceSet> &equivalenceSets() const {
201 return equivalenceSets_;
202 }
203 void add_equivalenceSet(EquivalenceSet &&);
204 // Cray pointers are saved as map of pointee name -> pointer symbol
205 const mapType &crayPointers() const { return crayPointers_; }
206 void add_crayPointer(const SourceName &, Symbol &);
207 Symbol &MakeCommonBlock(SourceName, SourceName location);
208 bool AddCommonBlockUse(
209 const SourceName &name, Attrs attrs, Symbol &cbUltimate);
210
211 // Find COMMON block that is declared in the current scope
212 Symbol *FindCommonBlock(const SourceName &name) const;
213
214 // Find USE-associated COMMON block in the current scope
215 Symbol *FindCommonBlockUse(const SourceName &name) const;
216
217 // Find COMMON block in current and surrounding scopes, follow USE
218 // associations
219 Symbol *FindCommonBlockInVisibleScopes(const SourceName &) const;
220
222 template <typename D>
223 common::IfNoLvalue<Symbol &, D> MakeSymbol(
224 const SourceName &name, Attrs attrs, D &&details) {
225 return allSymbols.Make(*this, name, attrs, std::move(details));
226 }
227
228 std::list<Scope> &children() { return children_; }
229 const std::list<Scope> &children() const { return children_; }
230
231 // For Module scope, maintain a mapping of all submodule scopes with this
232 // module as its ancestor module. AddSubmodule returns false if already there.
233 Scope *FindSubmodule(const SourceName &) const;
234 bool AddSubmodule(const SourceName &, Scope &);
235
236 const DeclTypeSpec *FindType(const DeclTypeSpec &) const;
237 const DeclTypeSpec &MakeNumericType(TypeCategory, KindExpr &&kind);
238 const DeclTypeSpec &MakeLogicalType(KindExpr &&kind);
239 const DeclTypeSpec &MakeCharacterType(ParamValue &&length, KindExpr &&kind);
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 const std::set<llvm::omp::Directive> &ompAssumesAbsent() const {
279 return ompAssumesAbsent_;
280 }
281 void add_ompAssumesAbsent(llvm::omp::Directive directive) {
282 ompAssumesAbsent_.insert(directive);
283 }
284
285 // The range of the source of this and nested scopes.
286 const parser::CharBlock &sourceRange() const { return sourceRange_; }
287 void AddSourceRange(parser::CharBlock);
288
289 // Record objects that have a device mapping in this OpenACC construct.
290 // Unlike a CUDA data attribute, this does not change the storage denoted by
291 // ordinary references to the object in the construct.
292 void AddOpenACCMappedSymbol(const Symbol &symbol) {
293 openACCMappedSymbols_.insert(symbol.GetUltimate());
294 }
295 bool IsOpenACCMappedSymbol(const Symbol &symbol) const {
296 return openACCMappedSymbols_.count(symbol.GetUltimate()) != 0;
297 }
298
299 // Attempts to find a match for a derived type instance
300 const DeclTypeSpec *FindInstantiatedDerivedType(const DerivedTypeSpec &,
301 DeclTypeSpec::Category = DeclTypeSpec::TypeDerived) const;
302
303 bool IsModuleFile() const {
304 return kind_ == Kind::Module && symbol_ &&
305 symbol_->test(Symbol::Flag::ModFile);
306 }
307
308 void InstantiateDerivedTypes();
309
310 const Symbol *runtimeDerivedTypeDescription() const {
311 return runtimeDerivedTypeDescription_;
312 }
313 void set_runtimeDerivedTypeDescription(const Symbol &symbol) {
314 runtimeDerivedTypeDescription_ = &symbol;
315 }
316
317private:
318 Scope *parent_{
319 nullptr}; // this is enclosing scope, not extended derived type base
320 const Kind kind_;
321 std::size_t size_{0}; // size in bytes
322 std::optional<std::size_t> alignment_; // required alignment in bytes
323 parser::CharBlock sourceRange_;
324 const parser::CookedSource *cookedSource_{nullptr};
325 Symbol *const symbol_; // if not null, symbol_->scope() == this
326 std::list<Scope> children_;
327 mapType symbols_;
328 mapType commonBlocks_;
329 mapType commonBlockUses_; // USE-assocated COMMON blocks
330 std::list<EquivalenceSet> equivalenceSets_;
331 mapType crayPointers_;
332 std::map<SourceName, common::Reference<Scope>> submodules_;
333 std::list<DeclTypeSpec> declTypeSpecs_;
334 std::optional<ImportKind> importKind_;
335 std::set<SourceName> importNames_;
336 UnorderedSymbolSet openACCMappedSymbols_;
337 std::set<llvm::omp::Directive> ompAssumesAbsent_;
338 DerivedTypeSpec *derivedTypeSpec_{nullptr}; // dTS->scope() == this
339 parser::Message::Reference instantiationContext_;
340 bool hasSAVE_{false}; // scope has a bare SAVE statement
341 const Symbol *runtimeDerivedTypeDescription_{nullptr};
342 SemanticsContext &context_;
343 // When additional data members are added to Scope, remember to
344 // copy them, if appropriate, in FindOrInstantiateDerivedType().
345
346 // Storage for all Symbols. Every Symbol is in allSymbols and every Symbol*
347 // or Symbol& points to one in there.
348 static Symbols<1024> allSymbols;
349
350 const DeclTypeSpec &MakeLengthlessType(DeclTypeSpec &&);
351
352 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Scope &);
353};
354
355// Inline so that it can be called from Evaluate without a link-time dependency.
356
357inline const Symbol *Scope::GetSymbol() const {
358 return symbol_ ? symbol_
359 : derivedTypeSpec_ ? &derivedTypeSpec_->typeSymbol()
360 : nullptr;
361}
362
363inline std::optional<SourceName> Scope::GetName() const {
364 if (const auto *sym{GetSymbol()}) {
365 return sym->name();
366 } else {
367 return std::nullopt;
368 }
369}
370
371} // namespace Fortran::semantics
372#endif // FORTRAN_SEMANTICS_SCOPE_H_
Definition char-block.h:27
Definition symbol.h:126
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:191
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:185
Scope & MakeScope(Kind kind, Symbol *symbol=nullptr)
Make a scope nested in this one.
Definition scope.cpp:51
std::pair< iterator, bool > try_emplace(const SourceName &name, Attrs attrs=Attrs())
Make a Symbol with unknown details.
Definition scope.h:179
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:223
bool IsDerivedTypeWithLengthParameter() const
Does this derived type have at least one length parameter ?
Definition scope.cpp:475
Definition semantics.h:71
Definition symbol.h:918
Definition symbol.h:907