xref: /llvm-project/flang/include/flang/Semantics/scope.h (revision 973fa983afbd769a847f3b2ca564b8a53b7ff4b1)
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 {
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 };
56 using EquivalenceSet = std::vector<EquivalenceObject>;
57 
58 class Scope {
59   using mapType = std::map<SourceName, MutableSymbolRef>;
60 
61 public:
62   ENUM_CLASS(Kind, Global, IntrinsicModules, Module, MainProgram, Subprogram,
63       BlockData, DerivedType, BlockConstruct, Forall, OtherConstruct,
64       OpenACCConstruct, ImpliedDos, OtherClause)
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   // When a generic procedure interface shadows a derived type or specific
142   // procedure, only the generic's symbol appears in the output.
143   SymbolVector GetSymbols() const;
144   MutableSymbolVector GetSymbols();
145 
146   iterator find(const SourceName &name);
147   const_iterator find(const SourceName &name) const {
148     return symbols_.find(name);
149   }
150   size_type erase(const SourceName &);
151   bool empty() const { return symbols_.empty(); }
152 
153   // Look for symbol by name in this scope and host (depending on imports).
154   Symbol *FindSymbol(const SourceName &) const;
155 
156   // Look for component symbol by name in a derived type's scope and
157   // parents'.
158   Symbol *FindComponent(SourceName) const;
159 
160   /// Make a Symbol with unknown details.
161   std::pair<iterator, bool> try_emplace(
162       const SourceName &name, Attrs attrs = Attrs()) {
163     return try_emplace(name, attrs, UnknownDetails());
164   }
165   /// Make a Symbol with provided details.
166   template <typename D>
167   common::IfNoLvalue<std::pair<iterator, bool>, D> try_emplace(
168       const SourceName &name, D &&details) {
169     return try_emplace(name, Attrs(), std::move(details));
170   }
171   /// Make a Symbol with attrs and details
172   template <typename D>
173   common::IfNoLvalue<std::pair<iterator, bool>, D> try_emplace(
174       const SourceName &name, Attrs attrs, D &&details) {
175     Symbol &symbol{MakeSymbol(name, attrs, std::move(details))};
176     return symbols_.emplace(name, symbol);
177   }
178   // Make a copy of a symbol in this scope; nullptr if one is already there
179   Symbol *CopySymbol(const Symbol &);
180 
181   std::list<EquivalenceSet> &equivalenceSets() { return equivalenceSets_; }
182   const std::list<EquivalenceSet> &equivalenceSets() const {
183     return equivalenceSets_;
184   }
185   void add_equivalenceSet(EquivalenceSet &&);
186   // Cray pointers are saved as map of pointee name -> pointer symbol
187   const mapType &crayPointers() const { return crayPointers_; }
188   void add_crayPointer(const SourceName &, Symbol &);
189   mapType &commonBlocks() { return commonBlocks_; }
190   const mapType &commonBlocks() const { return commonBlocks_; }
191   Symbol &MakeCommonBlock(const SourceName &);
192   Symbol *FindCommonBlock(const SourceName &) const;
193 
194   /// Make a Symbol but don't add it to the scope.
195   template <typename D>
196   common::IfNoLvalue<Symbol &, D> MakeSymbol(
197       const SourceName &name, Attrs attrs, D &&details) {
198     return allSymbols.Make(*this, name, attrs, std::move(details));
199   }
200 
201   std::list<Scope> &children() { return children_; }
202   const std::list<Scope> &children() const { return children_; }
203 
204   // For Module scope, maintain a mapping of all submodule scopes with this
205   // module as its ancestor module. AddSubmodule returns false if already there.
206   Scope *FindSubmodule(const SourceName &) const;
207   bool AddSubmodule(const SourceName &, Scope &);
208 
209   const DeclTypeSpec *FindType(const DeclTypeSpec &) const;
210   const DeclTypeSpec &MakeNumericType(TypeCategory, KindExpr &&kind);
211   const DeclTypeSpec &MakeLogicalType(KindExpr &&kind);
212   const DeclTypeSpec &MakeCharacterType(
213       ParamValue &&length, KindExpr &&kind = KindExpr{0});
214   DeclTypeSpec &MakeDerivedType(DeclTypeSpec::Category, DerivedTypeSpec &&);
215   const DeclTypeSpec &MakeTypeStarType();
216   const DeclTypeSpec &MakeClassStarType();
217   const DeclTypeSpec *GetType(const SomeExpr &);
218 
219   std::size_t size() const { return size_; }
220   void set_size(std::size_t size) { size_ = size; }
221   std::optional<std::size_t> alignment() const { return alignment_; }
222 
223   void SetAlignment(std::size_t n) {
224     alignment_ = std::max(alignment_.value_or(0), n);
225   }
226 
227   ImportKind GetImportKind() const;
228   // Names appearing in IMPORT statements in this scope
229   std::set<SourceName> importNames() const { return importNames_; }
230   bool CanImport(const SourceName &) const;
231 
232   // Set the kind of imports from host into this scope.
233   // Return an error message for incompatible kinds.
234   std::optional<parser::MessageFixedText> SetImportKind(ImportKind);
235 
236   void add_importName(const SourceName &);
237 
238   // These members pertain to instantiations of parameterized derived types.
239   const DerivedTypeSpec *derivedTypeSpec() const { return derivedTypeSpec_; }
240   DerivedTypeSpec *derivedTypeSpec() { return derivedTypeSpec_; }
241   void set_derivedTypeSpec(DerivedTypeSpec &spec) { derivedTypeSpec_ = &spec; }
242   parser::Message::Reference instantiationContext() const {
243     return instantiationContext_;
244   };
245   void set_instantiationContext(parser::Message::Reference &&mref) {
246     instantiationContext_ = std::move(mref);
247   }
248 
249   bool hasSAVE() const { return hasSAVE_; }
250   void set_hasSAVE(bool yes = true) { hasSAVE_ = yes; }
251 
252   // The range of the source of this and nested scopes.
253   const parser::CharBlock &sourceRange() const { return sourceRange_; }
254   void AddSourceRange(parser::CharBlock);
255 
256   // Attempts to find a match for a derived type instance
257   const DeclTypeSpec *FindInstantiatedDerivedType(const DerivedTypeSpec &,
258       DeclTypeSpec::Category = DeclTypeSpec::TypeDerived) const;
259 
260   bool IsModuleFile() const {
261     return kind_ == Kind::Module && symbol_ &&
262         symbol_->test(Symbol::Flag::ModFile);
263   }
264 
265   void InstantiateDerivedTypes();
266 
267   const Symbol *runtimeDerivedTypeDescription() const {
268     return runtimeDerivedTypeDescription_;
269   }
270   void set_runtimeDerivedTypeDescription(const Symbol &symbol) {
271     runtimeDerivedTypeDescription_ = &symbol;
272   }
273 
274 private:
275   Scope *parent_{
276       nullptr}; // this is enclosing scope, not extended derived type base
277   const Kind kind_;
278   std::size_t size_{0}; // size in bytes
279   std::optional<std::size_t> alignment_; // required alignment in bytes
280   parser::CharBlock sourceRange_;
281   const parser::CookedSource *cookedSource_{nullptr};
282   Symbol *const symbol_; // if not null, symbol_->scope() == this
283   std::list<Scope> children_;
284   mapType symbols_;
285   mapType commonBlocks_;
286   std::list<EquivalenceSet> equivalenceSets_;
287   mapType crayPointers_;
288   std::map<SourceName, common::Reference<Scope>> submodules_;
289   std::list<DeclTypeSpec> declTypeSpecs_;
290   std::optional<ImportKind> importKind_;
291   std::set<SourceName> importNames_;
292   DerivedTypeSpec *derivedTypeSpec_{nullptr}; // dTS->scope() == this
293   parser::Message::Reference instantiationContext_;
294   bool hasSAVE_{false}; // scope has a bare SAVE statement
295   const Symbol *runtimeDerivedTypeDescription_{nullptr};
296   SemanticsContext &context_;
297   // When additional data members are added to Scope, remember to
298   // copy them, if appropriate, in FindOrInstantiateDerivedType().
299 
300   // Storage for all Symbols. Every Symbol is in allSymbols and every Symbol*
301   // or Symbol& points to one in there.
302   static Symbols<1024> allSymbols;
303 
304   const DeclTypeSpec &MakeLengthlessType(DeclTypeSpec &&);
305 
306   friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Scope &);
307 };
308 
309 // Inline so that it can be called from Evaluate without a link-time dependency.
310 
311 inline const Symbol *Scope::GetSymbol() const {
312   return symbol_         ? symbol_
313       : derivedTypeSpec_ ? &derivedTypeSpec_->typeSymbol()
314                          : nullptr;
315 }
316 
317 inline std::optional<SourceName> Scope::GetName() const {
318   if (const auto *sym{GetSymbol()}) {
319     return sym->name();
320   } else {
321     return std::nullopt;
322   }
323 }
324 
325 } // namespace Fortran::semantics
326 #endif // FORTRAN_SEMANTICS_SCOPE_H_
327