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