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