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