1 //===-- include/flang/Semantics/symbol.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_SYMBOL_H_
10 #define FORTRAN_SEMANTICS_SYMBOL_H_
11 
12 #include "type.h"
13 #include "flang/Common/Fortran.h"
14 #include "flang/Common/enum-set.h"
15 #include "flang/Common/reference.h"
16 #include "llvm/ADT/DenseMapInfo.h"
17 #include <array>
18 #include <list>
19 #include <optional>
20 #include <set>
21 #include <vector>
22 
23 namespace llvm {
24 class raw_ostream;
25 }
26 
27 namespace Fortran::semantics {
28 
29 /// A Symbol consists of common information (name, owner, and attributes)
30 /// and details information specific to the kind of symbol, represented by the
31 /// *Details classes.
32 
33 class Scope;
34 class Symbol;
35 class ProgramTree;
36 
37 using SymbolRef = common::Reference<const Symbol>;
38 using SymbolVector = std::vector<SymbolRef>;
39 using MutableSymbolRef = common::Reference<Symbol>;
40 using MutableSymbolVector = std::vector<MutableSymbolRef>;
41 
42 // A module or submodule.
43 class ModuleDetails {
44 public:
45   ModuleDetails(bool isSubmodule = false) : isSubmodule_{isSubmodule} {}
isSubmodule()46   bool isSubmodule() const { return isSubmodule_; }
scope()47   const Scope *scope() const { return scope_; }
48   const Scope *ancestor() const; // for submodule; nullptr for module
49   const Scope *parent() const; // for submodule; nullptr for module
50   void set_scope(const Scope *);
51 
52 private:
53   bool isSubmodule_;
54   const Scope *scope_{nullptr};
55 };
56 
57 class MainProgramDetails {
58 public:
59 private:
60 };
61 
62 class SubprogramDetails {
63 public:
isFunction()64   bool isFunction() const { return result_ != nullptr; }
isInterface()65   bool isInterface() const { return isInterface_; }
66   void set_isInterface(bool value = true) { isInterface_ = value; }
entryScope()67   Scope *entryScope() { return entryScope_; }
entryScope()68   const Scope *entryScope() const { return entryScope_; }
set_entryScope(Scope & scope)69   void set_entryScope(Scope &scope) { entryScope_ = &scope; }
bindName()70   MaybeExpr bindName() const { return bindName_; }
set_bindName(MaybeExpr && expr)71   void set_bindName(MaybeExpr &&expr) { bindName_ = std::move(expr); }
result()72   const Symbol &result() const {
73     CHECK(isFunction());
74     return *result_;
75   }
set_result(Symbol & result)76   void set_result(Symbol &result) {
77     CHECK(!result_);
78     result_ = &result;
79   }
dummyArgs()80   const std::vector<Symbol *> &dummyArgs() const { return dummyArgs_; }
add_dummyArg(Symbol & symbol)81   void add_dummyArg(Symbol &symbol) { dummyArgs_.push_back(&symbol); }
add_alternateReturn()82   void add_alternateReturn() { dummyArgs_.push_back(nullptr); }
stmtFunction()83   const MaybeExpr &stmtFunction() const { return stmtFunction_; }
set_stmtFunction(SomeExpr && expr)84   void set_stmtFunction(SomeExpr &&expr) { stmtFunction_ = std::move(expr); }
85 
86 private:
87   bool isInterface_{false}; // true if this represents an interface-body
88   MaybeExpr bindName_;
89   std::vector<Symbol *> dummyArgs_; // nullptr -> alternate return indicator
90   Symbol *result_{nullptr};
91   Scope *entryScope_{nullptr}; // if ENTRY, points to subprogram's scope
92   MaybeExpr stmtFunction_;
93   friend llvm::raw_ostream &operator<<(
94       llvm::raw_ostream &, const SubprogramDetails &);
95 };
96 
97 // For SubprogramNameDetails, the kind indicates whether it is the name
98 // of a module subprogram or internal subprogram.
ENUM_CLASS(SubprogramKind,Module,Internal)99 ENUM_CLASS(SubprogramKind, Module, Internal)
100 
101 // Symbol with SubprogramNameDetails is created when we scan for module and
102 // internal procedure names, to record that there is a subprogram with this
103 // name. Later they are replaced by SubprogramDetails with dummy and result
104 // type information.
105 class SubprogramNameDetails {
106 public:
107   SubprogramNameDetails(SubprogramKind kind, ProgramTree &node)
108       : kind_{kind}, node_{node} {}
109   SubprogramNameDetails() = delete;
110   SubprogramKind kind() const { return kind_; }
111   ProgramTree &node() const { return *node_; }
112 
113 private:
114   SubprogramKind kind_;
115   common::Reference<ProgramTree> node_;
116 };
117 
118 // A name from an entity-decl -- could be object or function.
119 class EntityDetails {
120 public:
121   explicit EntityDetails(bool isDummy = false) : isDummy_{isDummy} {}
type()122   const DeclTypeSpec *type() const { return type_; }
123   void set_type(const DeclTypeSpec &);
124   void ReplaceType(const DeclTypeSpec &);
isDummy()125   bool isDummy() const { return isDummy_; }
126   void set_isDummy(bool value = true) { isDummy_ = value; }
isFuncResult()127   bool isFuncResult() const { return isFuncResult_; }
set_funcResult(bool x)128   void set_funcResult(bool x) { isFuncResult_ = x; }
bindName()129   MaybeExpr bindName() const { return bindName_; }
set_bindName(MaybeExpr && expr)130   void set_bindName(MaybeExpr &&expr) { bindName_ = std::move(expr); }
131 
132 private:
133   bool isDummy_{false};
134   bool isFuncResult_{false};
135   const DeclTypeSpec *type_{nullptr};
136   MaybeExpr bindName_;
137   friend llvm::raw_ostream &operator<<(
138       llvm::raw_ostream &, const EntityDetails &);
139 };
140 
141 // Symbol is associated with a name or expression in a SELECT TYPE or ASSOCIATE.
142 class AssocEntityDetails : public EntityDetails {
143 public:
AssocEntityDetails()144   AssocEntityDetails() {}
AssocEntityDetails(SomeExpr && expr)145   explicit AssocEntityDetails(SomeExpr &&expr) : expr_{std::move(expr)} {}
146   AssocEntityDetails(const AssocEntityDetails &) = default;
147   AssocEntityDetails(AssocEntityDetails &&) = default;
148   AssocEntityDetails &operator=(const AssocEntityDetails &) = default;
149   AssocEntityDetails &operator=(AssocEntityDetails &&) = default;
expr()150   const MaybeExpr &expr() const { return expr_; }
151   void set_rank(int rank);
rank()152   std::optional<int> rank() const { return rank_; }
153 
154 private:
155   MaybeExpr expr_;
156   std::optional<int> rank_;
157 };
158 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const AssocEntityDetails &);
159 
160 // An entity known to be an object.
161 class ObjectEntityDetails : public EntityDetails {
162 public:
163   explicit ObjectEntityDetails(EntityDetails &&);
164   ObjectEntityDetails(const ObjectEntityDetails &) = default;
165   ObjectEntityDetails &operator=(const ObjectEntityDetails &) = default;
EntityDetails(isDummy)166   ObjectEntityDetails(bool isDummy = false) : EntityDetails(isDummy) {}
init()167   MaybeExpr &init() { return init_; }
init()168   const MaybeExpr &init() const { return init_; }
set_init(MaybeExpr && expr)169   void set_init(MaybeExpr &&expr) { init_ = std::move(expr); }
shape()170   ArraySpec &shape() { return shape_; }
shape()171   const ArraySpec &shape() const { return shape_; }
coshape()172   ArraySpec &coshape() { return coshape_; }
coshape()173   const ArraySpec &coshape() const { return coshape_; }
174   void set_shape(const ArraySpec &);
175   void set_coshape(const ArraySpec &);
commonBlock()176   const Symbol *commonBlock() const { return commonBlock_; }
set_commonBlock(const Symbol & commonBlock)177   void set_commonBlock(const Symbol &commonBlock) {
178     commonBlock_ = &commonBlock;
179   }
IsArray()180   bool IsArray() const { return !shape_.empty(); }
IsCoarray()181   bool IsCoarray() const { return !coshape_.empty(); }
IsAssumedShape()182   bool IsAssumedShape() const { return isDummy() && shape_.IsAssumedShape(); }
IsDeferredShape()183   bool IsDeferredShape() const {
184     return !isDummy() && shape_.IsDeferredShape();
185   }
IsAssumedSize()186   bool IsAssumedSize() const { return isDummy() && shape_.IsAssumedSize(); }
IsAssumedRank()187   bool IsAssumedRank() const { return isDummy() && shape_.IsAssumedRank(); }
188 
189 private:
190   MaybeExpr init_;
191   ArraySpec shape_;
192   ArraySpec coshape_;
193   const Symbol *commonBlock_{nullptr}; // common block this object is in
194   friend llvm::raw_ostream &operator<<(
195       llvm::raw_ostream &, const ObjectEntityDetails &);
196 };
197 
198 // Mixin for details with passed-object dummy argument.
199 // If a procedure pointer component or type-bound procedure does not have
200 // the NOPASS attribute on its symbol, then PASS is assumed; the name
201 // is optional; if it is missing, the first dummy argument of the procedure's
202 // interface is the passed-object dummy argument.
203 class WithPassArg {
204 public:
passName()205   std::optional<SourceName> passName() const { return passName_; }
set_passName(const SourceName & passName)206   void set_passName(const SourceName &passName) { passName_ = passName; }
207 
208 private:
209   std::optional<SourceName> passName_;
210 };
211 
212 // A procedure pointer, dummy procedure, or external procedure
213 class ProcEntityDetails : public EntityDetails, public WithPassArg {
214 public:
215   ProcEntityDetails() = default;
216   explicit ProcEntityDetails(EntityDetails &&d);
217 
interface()218   const ProcInterface &interface() const { return interface_; }
interface()219   ProcInterface &interface() { return interface_; }
set_interface(const ProcInterface & interface)220   void set_interface(const ProcInterface &interface) { interface_ = interface; }
IsInterfaceSet()221   bool IsInterfaceSet() {
222     return interface_.symbol() != nullptr || interface_.type() != nullptr;
223   }
224   inline bool HasExplicitInterface() const;
225 
226   // Be advised: !init().has_value() => uninitialized pointer,
227   // while *init() == nullptr => explicit NULL() initialization.
init()228   std::optional<const Symbol *> init() const { return init_; }
set_init(const Symbol & symbol)229   void set_init(const Symbol &symbol) { init_ = &symbol; }
set_init(std::nullptr_t)230   void set_init(std::nullptr_t) { init_ = nullptr; }
231 
232 private:
233   ProcInterface interface_;
234   std::optional<const Symbol *> init_;
235   friend llvm::raw_ostream &operator<<(
236       llvm::raw_ostream &, const ProcEntityDetails &);
237 };
238 
239 // These derived type details represent the characteristics of a derived
240 // type definition that are shared by all instantiations of that type.
241 // The DerivedTypeSpec instances whose type symbols share these details
242 // each own a scope into which the components' symbols have been cloned
243 // and specialized for each distinct set of type parameter values.
244 class DerivedTypeDetails {
245 public:
paramNames()246   const std::list<SourceName> &paramNames() const { return paramNames_; }
paramDecls()247   const SymbolVector &paramDecls() const { return paramDecls_; }
sequence()248   bool sequence() const { return sequence_; }
finals()249   std::map<SourceName, SymbolRef> &finals() { return finals_; }
finals()250   const std::map<SourceName, SymbolRef> &finals() const { return finals_; }
isForwardReferenced()251   bool isForwardReferenced() const { return isForwardReferenced_; }
add_paramName(const SourceName & name)252   void add_paramName(const SourceName &name) { paramNames_.push_back(name); }
add_paramDecl(const Symbol & symbol)253   void add_paramDecl(const Symbol &symbol) { paramDecls_.push_back(symbol); }
254   void add_component(const Symbol &);
255   void set_sequence(bool x = true) { sequence_ = x; }
set_isForwardReferenced()256   void set_isForwardReferenced() { isForwardReferenced_ = true; }
componentNames()257   const std::list<SourceName> &componentNames() const {
258     return componentNames_;
259   }
260 
261   // If this derived type extends another, locate the parent component's symbol.
262   const Symbol *GetParentComponent(const Scope &) const;
263 
GetParentComponentName()264   std::optional<SourceName> GetParentComponentName() const {
265     if (componentNames_.empty()) {
266       return std::nullopt;
267     } else {
268       return componentNames_.front();
269     }
270   }
271 
272   const Symbol *GetFinalForRank(int) const;
273 
274 private:
275   // These are (1) the names of the derived type parameters in the order
276   // in which they appear on the type definition statement(s), and (2) the
277   // symbols that correspond to those names in the order in which their
278   // declarations appear in the derived type definition(s).
279   std::list<SourceName> paramNames_;
280   SymbolVector paramDecls_;
281   // These are the names of the derived type's components in component
282   // order.  A parent component, if any, appears first in this list.
283   std::list<SourceName> componentNames_;
284   std::map<SourceName, SymbolRef> finals_; // FINAL :: subr
285   bool sequence_{false};
286   bool isForwardReferenced_{false};
287   friend llvm::raw_ostream &operator<<(
288       llvm::raw_ostream &, const DerivedTypeDetails &);
289 };
290 
291 class ProcBindingDetails : public WithPassArg {
292 public:
ProcBindingDetails(const Symbol & symbol)293   explicit ProcBindingDetails(const Symbol &symbol) : symbol_{symbol} {}
symbol()294   const Symbol &symbol() const { return symbol_; }
295 
296 private:
297   SymbolRef symbol_; // procedure bound to; may be forward
298 };
299 
300 class NamelistDetails {
301 public:
objects()302   const SymbolVector &objects() const { return objects_; }
add_object(const Symbol & object)303   void add_object(const Symbol &object) { objects_.push_back(object); }
add_objects(const SymbolVector & objects)304   void add_objects(const SymbolVector &objects) {
305     objects_.insert(objects_.end(), objects.begin(), objects.end());
306   }
307 
308 private:
309   SymbolVector objects_;
310 };
311 
312 class CommonBlockDetails {
313 public:
objects()314   MutableSymbolVector &objects() { return objects_; }
objects()315   const MutableSymbolVector &objects() const { return objects_; }
add_object(Symbol & object)316   void add_object(Symbol &object) { objects_.emplace_back(object); }
bindName()317   MaybeExpr bindName() const { return bindName_; }
set_bindName(MaybeExpr && expr)318   void set_bindName(MaybeExpr &&expr) { bindName_ = std::move(expr); }
alignment()319   std::size_t alignment() const { return alignment_; }
set_alignment(std::size_t alignment)320   void set_alignment(std::size_t alignment) { alignment_ = alignment; }
321 
322 private:
323   MutableSymbolVector objects_;
324   MaybeExpr bindName_;
325   std::size_t alignment_{0}; // required alignment in bytes
326 };
327 
328 class MiscDetails {
329 public:
330   ENUM_CLASS(Kind, None, ConstructName, ScopeName, PassName, ComplexPartRe,
331       ComplexPartIm, KindParamInquiry, LenParamInquiry, SelectRankAssociateName,
332       SelectTypeAssociateName, TypeBoundDefinedOp);
MiscDetails(Kind kind)333   MiscDetails(Kind kind) : kind_{kind} {}
kind()334   Kind kind() const { return kind_; }
335 
336 private:
337   Kind kind_;
338 };
339 
340 class TypeParamDetails {
341 public:
TypeParamDetails(common::TypeParamAttr attr)342   explicit TypeParamDetails(common::TypeParamAttr attr) : attr_{attr} {}
343   TypeParamDetails(const TypeParamDetails &) = default;
attr()344   common::TypeParamAttr attr() const { return attr_; }
init()345   MaybeIntExpr &init() { return init_; }
init()346   const MaybeIntExpr &init() const { return init_; }
set_init(MaybeIntExpr && expr)347   void set_init(MaybeIntExpr &&expr) { init_ = std::move(expr); }
type()348   const DeclTypeSpec *type() const { return type_; }
349   void set_type(const DeclTypeSpec &);
350   void ReplaceType(const DeclTypeSpec &);
351 
352 private:
353   common::TypeParamAttr attr_;
354   MaybeIntExpr init_;
355   const DeclTypeSpec *type_{nullptr};
356 };
357 
358 // Record the USE of a symbol: location is where (USE statement or renaming);
359 // symbol is the USEd module.
360 class UseDetails {
361 public:
UseDetails(const SourceName & location,const Symbol & symbol)362   UseDetails(const SourceName &location, const Symbol &symbol)
363       : location_{location}, symbol_{symbol} {}
location()364   const SourceName &location() const { return location_; }
symbol()365   const Symbol &symbol() const { return symbol_; }
366 
367 private:
368   SourceName location_;
369   SymbolRef symbol_;
370 };
371 
372 // A symbol with ambiguous use-associations. Record where they were so
373 // we can report the error if it is used.
374 class UseErrorDetails {
375 public:
376   UseErrorDetails(const UseDetails &);
377   UseErrorDetails &add_occurrence(const SourceName &, const Scope &);
378   using listType = std::list<std::pair<SourceName, const Scope *>>;
occurrences()379   const listType occurrences() const { return occurrences_; };
380 
381 private:
382   listType occurrences_;
383 };
384 
385 // A symbol host-associated from an enclosing scope.
386 class HostAssocDetails {
387 public:
HostAssocDetails(const Symbol & symbol)388   HostAssocDetails(const Symbol &symbol) : symbol_{symbol} {}
symbol()389   const Symbol &symbol() const { return symbol_; }
390   bool implicitOrSpecExprError{false};
391   bool implicitOrExplicitTypeError{false};
392 
393 private:
394   SymbolRef symbol_;
395 };
396 
397 // A GenericKind is one of: generic name, defined operator,
398 // defined assignment, intrinsic operator, or defined I/O.
399 struct GenericKind {
ENUM_CLASSGenericKind400   ENUM_CLASS(OtherKind, Name, DefinedOp, Assignment, Concat)
401   ENUM_CLASS(DefinedIo, // defined io
402       ReadFormatted, ReadUnformatted, WriteFormatted, WriteUnformatted)
403   GenericKind() : u{OtherKind::Name} {}
GenericKindGenericKind404   template <typename T> GenericKind(const T &x) { u = x; }
IsNameGenericKind405   bool IsName() const { return Is(OtherKind::Name); }
IsAssignmentGenericKind406   bool IsAssignment() const { return Is(OtherKind::Assignment); }
IsDefinedOperatorGenericKind407   bool IsDefinedOperator() const { return Is(OtherKind::DefinedOp); }
408   bool IsIntrinsicOperator() const;
409   bool IsOperator() const;
410   std::string ToString() const;
411   std::variant<OtherKind, common::NumericOperator, common::LogicalOperator,
412       common::RelationalOperator, DefinedIo>
413       u;
414 
415 private:
HasGenericKind416   template <typename T> bool Has() const {
417     return std::holds_alternative<T>(u);
418   }
419   bool Is(OtherKind) const;
420 };
421 
422 // A generic interface or type-bound generic.
423 class GenericDetails {
424 public:
GenericDetails()425   GenericDetails() {}
426 
kind()427   GenericKind kind() const { return kind_; }
set_kind(GenericKind kind)428   void set_kind(GenericKind kind) { kind_ = kind; }
429 
specificProcs()430   const SymbolVector &specificProcs() const { return specificProcs_; }
bindingNames()431   const std::vector<SourceName> &bindingNames() const { return bindingNames_; }
432   void AddSpecificProc(const Symbol &, SourceName bindingName);
uses()433   const SymbolVector &uses() const { return uses_; }
434 
435   // specific and derivedType indicate a specific procedure or derived type
436   // with the same name as this generic. Only one of them may be set.
specific()437   Symbol *specific() { return specific_; }
specific()438   const Symbol *specific() const { return specific_; }
439   void set_specific(Symbol &specific);
derivedType()440   Symbol *derivedType() { return derivedType_; }
derivedType()441   const Symbol *derivedType() const { return derivedType_; }
442   void set_derivedType(Symbol &derivedType);
443   void AddUse(const Symbol &);
444 
445   // Copy in specificProcs, specific, and derivedType from another generic
446   void CopyFrom(const GenericDetails &);
447 
448   // Check that specific is one of the specificProcs. If not, return the
449   // specific as a raw pointer.
450   const Symbol *CheckSpecific() const;
451   Symbol *CheckSpecific();
452 
453 private:
454   GenericKind kind_;
455   // all of the specific procedures for this generic
456   SymbolVector specificProcs_;
457   std::vector<SourceName> bindingNames_;
458   // Symbols used from other modules merged into this one
459   SymbolVector uses_;
460   // a specific procedure with the same name as this generic, if any
461   Symbol *specific_{nullptr};
462   // a derived type with the same name as this generic, if any
463   Symbol *derivedType_{nullptr};
464 };
465 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const GenericDetails &);
466 
467 class UnknownDetails {};
468 
469 using Details = std::variant<UnknownDetails, MainProgramDetails, ModuleDetails,
470     SubprogramDetails, SubprogramNameDetails, EntityDetails,
471     ObjectEntityDetails, ProcEntityDetails, AssocEntityDetails,
472     DerivedTypeDetails, UseDetails, UseErrorDetails, HostAssocDetails,
473     GenericDetails, ProcBindingDetails, NamelistDetails, CommonBlockDetails,
474     TypeParamDetails, MiscDetails>;
475 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Details &);
476 std::string DetailsToString(const Details &);
477 
478 class Symbol {
479 public:
480   ENUM_CLASS(Flag,
481       Function, // symbol is a function
482       Subroutine, // symbol is a subroutine
483       StmtFunction, // symbol is a statement function (Function is set too)
484       Implicit, // symbol is implicitly typed
485       ImplicitOrError, // symbol must be implicitly typed or it's an error
486       ModFile, // symbol came from .mod file
487       ParentComp, // symbol is the "parent component" of an extended type
488       CrayPointer, CrayPointee,
489       LocalityLocal, // named in LOCAL locality-spec
490       LocalityLocalInit, // named in LOCAL_INIT locality-spec
491       LocalityShared, // named in SHARED locality-spec
492       InDataStmt, // initialized in a DATA statement
493       InNamelist, // flag is set if the symbol is in Namelist statement
494       // OpenACC data-sharing attribute
495       AccPrivate, AccFirstPrivate, AccShared,
496       // OpenACC data-mapping attribute
497       AccCopyIn, AccCopyOut, AccCreate, AccDelete, AccPresent,
498       // OpenACC miscellaneous flags
499       AccCommonBlock, AccThreadPrivate, AccReduction, AccNone, AccPreDetermined,
500       // OpenMP data-sharing attribute
501       OmpShared, OmpPrivate, OmpLinear, OmpFirstPrivate, OmpLastPrivate,
502       // OpenMP data-mapping attribute
503       OmpMapTo, OmpMapFrom, OmpMapAlloc, OmpMapRelease, OmpMapDelete,
504       // OpenMP data-copying attribute
505       OmpCopyIn,
506       // OpenMP miscellaneous flags
507       OmpCommonBlock, OmpReduction, OmpAllocate, OmpDeclareSimd,
508       OmpDeclareTarget, OmpThreadprivate, OmpDeclareReduction, OmpFlushed,
509       OmpCriticalLock, OmpIfSpecified, OmpNone, OmpPreDetermined, OmpAligned);
510   using Flags = common::EnumSet<Flag, Flag_enumSize>;
511 
owner()512   const Scope &owner() const { return *owner_; }
name()513   const SourceName &name() const { return name_; }
attrs()514   Attrs &attrs() { return attrs_; }
attrs()515   const Attrs &attrs() const { return attrs_; }
flags()516   Flags &flags() { return flags_; }
flags()517   const Flags &flags() const { return flags_; }
test(Flag flag)518   bool test(Flag flag) const { return flags_.test(flag); }
519   void set(Flag flag, bool value = true) { flags_.set(flag, value); }
520   // The Scope introduced by this symbol, if any.
scope()521   Scope *scope() { return scope_; }
scope()522   const Scope *scope() const { return scope_; }
set_scope(Scope * scope)523   void set_scope(Scope *scope) { scope_ = scope; }
size()524   std::size_t size() const { return size_; }
set_size(std::size_t size)525   void set_size(std::size_t size) { size_ = size; }
offset()526   std::size_t offset() const { return offset_; }
set_offset(std::size_t offset)527   void set_offset(std::size_t offset) { offset_ = offset; }
528   // Give the symbol a name with a different source location but same chars.
529   void ReplaceName(const SourceName &);
530 
531   // Does symbol have this type of details?
has()532   template <typename D> bool has() const {
533     return std::holds_alternative<D>(details_);
534   }
535 
536   // Return a non-owning pointer to details if it is type D, else nullptr.
detailsIf()537   template <typename D> D *detailsIf() { return std::get_if<D>(&details_); }
detailsIf()538   template <typename D> const D *detailsIf() const {
539     return std::get_if<D>(&details_);
540   }
541 
542   // Return a reference to the details which must be of type D.
get()543   template <typename D> D &get() {
544     return const_cast<D &>(const_cast<const Symbol *>(this)->get<D>());
545   }
get()546   template <typename D> const D &get() const {
547     const auto *p{detailsIf<D>()};
548     CHECK(p);
549     return *p;
550   }
551 
details()552   Details &details() { return details_; }
details()553   const Details &details() const { return details_; }
554   // Assign the details of the symbol from one of the variants.
555   // Only allowed in certain cases.
556   void set_details(Details &&);
557 
558   // Can the details of this symbol be replaced with the given details?
559   bool CanReplaceDetails(const Details &details) const;
560 
561   // Follow use-associations and host-associations to get the ultimate entity.
562   inline Symbol &GetUltimate();
563   inline const Symbol &GetUltimate() const;
564 
565   inline DeclTypeSpec *GetType();
566   inline const DeclTypeSpec *GetType() const;
567 
568   void SetType(const DeclTypeSpec &);
569   bool IsFuncResult() const;
570   bool IsObjectArray() const;
571   bool IsSubprogram() const;
572   bool IsFromModFile() const;
HasExplicitInterface()573   bool HasExplicitInterface() const {
574     return std::visit(common::visitors{
575                           [](const SubprogramDetails &) { return true; },
576                           [](const SubprogramNameDetails &) { return true; },
577                           [&](const ProcEntityDetails &x) {
578                             return attrs_.test(Attr::INTRINSIC) ||
579                                 x.HasExplicitInterface();
580                           },
581                           [](const ProcBindingDetails &x) {
582                             return x.symbol().HasExplicitInterface();
583                           },
584                           [](const UseDetails &x) {
585                             return x.symbol().HasExplicitInterface();
586                           },
587                           [](const HostAssocDetails &x) {
588                             return x.symbol().HasExplicitInterface();
589                           },
590                           [](const auto &) { return false; },
591                       },
592         details_);
593   }
594 
595   bool operator==(const Symbol &that) const { return this == &that; }
596   bool operator!=(const Symbol &that) const { return !(*this == that); }
597   bool operator<(const Symbol &that) const {
598     // For sets of symbols: collate them by source location
599     return name_.begin() < that.name_.begin();
600   }
601 
Rank()602   int Rank() const {
603     return std::visit(
604         common::visitors{
605             [](const SubprogramDetails &sd) {
606               return sd.isFunction() ? sd.result().Rank() : 0;
607             },
608             [](const GenericDetails &) {
609               return 0; /*TODO*/
610             },
611             [](const ProcBindingDetails &x) { return x.symbol().Rank(); },
612             [](const UseDetails &x) { return x.symbol().Rank(); },
613             [](const HostAssocDetails &x) { return x.symbol().Rank(); },
614             [](const ObjectEntityDetails &oed) { return oed.shape().Rank(); },
615             [](const AssocEntityDetails &aed) {
616               if (const auto &expr{aed.expr()}) {
617                 if (auto assocRank{aed.rank()}) {
618                   return *assocRank;
619                 } else {
620                   return expr->Rank();
621                 }
622               } else {
623                 return 0;
624               }
625             },
626             [](const auto &) { return 0; },
627         },
628         details_);
629   }
630 
Corank()631   int Corank() const {
632     return std::visit(
633         common::visitors{
634             [](const SubprogramDetails &sd) {
635               return sd.isFunction() ? sd.result().Corank() : 0;
636             },
637             [](const GenericDetails &) {
638               return 0; /*TODO*/
639             },
640             [](const UseDetails &x) { return x.symbol().Corank(); },
641             [](const HostAssocDetails &x) { return x.symbol().Corank(); },
642             [](const ObjectEntityDetails &oed) { return oed.coshape().Rank(); },
643             [](const auto &) { return 0; },
644         },
645         details_);
646   }
647 
648   // If there is a parent component, return a pointer to its derived type spec.
649   // The Scope * argument defaults to this->scope_ but should be overridden
650   // for a parameterized derived type instantiation with the instance's scope.
651   const DerivedTypeSpec *GetParentTypeSpec(const Scope * = nullptr) const;
652 
653 private:
654   const Scope *owner_;
655   SourceName name_;
656   Attrs attrs_;
657   Flags flags_;
658   Scope *scope_{nullptr};
659   std::size_t size_{0}; // size in bytes
660   std::size_t offset_{0}; // byte offset in scope or common block
661   Details details_;
662 
Symbol()663   Symbol() {} // only created in class Symbols
664   const std::string GetDetailsName() const;
665   friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Symbol &);
666   friend llvm::raw_ostream &DumpForUnparse(
667       llvm::raw_ostream &, const Symbol &, bool);
668 
669   // If a derived type's symbol refers to an extended derived type,
670   // return the parent component's symbol.  The scope of the derived type
671   // can be overridden.
672   const Symbol *GetParentComponent(const Scope * = nullptr) const;
673 
674   template <std::size_t> friend class Symbols;
675   template <class, std::size_t> friend struct std::array;
676 };
677 
678 llvm::raw_ostream &operator<<(llvm::raw_ostream &, Symbol::Flag);
679 
680 // Manage memory for all symbols. BLOCK_SIZE symbols at a time are allocated.
681 // Make() returns a reference to the next available one. They are never
682 // deleted.
683 template <std::size_t BLOCK_SIZE> class Symbols {
684 public:
Make(const Scope & owner,const SourceName & name,const Attrs & attrs,Details && details)685   Symbol &Make(const Scope &owner, const SourceName &name, const Attrs &attrs,
686       Details &&details) {
687     Symbol &symbol = Get();
688     symbol.owner_ = &owner;
689     symbol.name_ = name;
690     symbol.attrs_ = attrs;
691     symbol.details_ = std::move(details);
692     return symbol;
693   }
694 
695 private:
696   using blockType = std::array<Symbol, BLOCK_SIZE>;
697   std::list<blockType *> blocks_;
698   std::size_t nextIndex_{0};
699   blockType *currBlock_{nullptr};
700 
Get()701   Symbol &Get() {
702     if (nextIndex_ == 0) {
703       blocks_.push_back(new blockType());
704       currBlock_ = blocks_.back();
705     }
706     Symbol &result = (*currBlock_)[nextIndex_];
707     if (++nextIndex_ >= BLOCK_SIZE) {
708       nextIndex_ = 0; // allocate a new block next time
709     }
710     return result;
711   }
712 };
713 
714 // Define a few member functions here in the header so that they
715 // can be used by lib/Evaluate without inducing a dependence cycle
716 // between the two shared libraries.
717 
HasExplicitInterface()718 inline bool ProcEntityDetails::HasExplicitInterface() const {
719   if (auto *symbol{interface_.symbol()}) {
720     return symbol->HasExplicitInterface();
721   }
722   return false;
723 }
724 
GetUltimate()725 inline Symbol &Symbol::GetUltimate() {
726   return const_cast<Symbol &>(const_cast<const Symbol *>(this)->GetUltimate());
727 }
GetUltimate()728 inline const Symbol &Symbol::GetUltimate() const {
729   if (const auto *details{detailsIf<UseDetails>()}) {
730     return details->symbol().GetUltimate();
731   } else if (const auto *details{detailsIf<HostAssocDetails>()}) {
732     return details->symbol().GetUltimate();
733   } else {
734     return *this;
735   }
736 }
737 
GetType()738 inline DeclTypeSpec *Symbol::GetType() {
739   return const_cast<DeclTypeSpec *>(
740       const_cast<const Symbol *>(this)->GetType());
741 }
GetType()742 inline const DeclTypeSpec *Symbol::GetType() const {
743   return std::visit(
744       common::visitors{
745           [](const EntityDetails &x) { return x.type(); },
746           [](const ObjectEntityDetails &x) { return x.type(); },
747           [](const AssocEntityDetails &x) { return x.type(); },
748           [](const SubprogramDetails &x) {
749             return x.isFunction() ? x.result().GetType() : nullptr;
750           },
751           [](const ProcEntityDetails &x) {
752             const Symbol *symbol{x.interface().symbol()};
753             return symbol ? symbol->GetType() : x.interface().type();
754           },
755           [](const ProcBindingDetails &x) { return x.symbol().GetType(); },
756           [](const TypeParamDetails &x) { return x.type(); },
757           [](const UseDetails &x) { return x.symbol().GetType(); },
758           [](const HostAssocDetails &x) { return x.symbol().GetType(); },
759           [](const auto &) -> const DeclTypeSpec * { return nullptr; },
760       },
761       details_);
762 }
763 
764 inline bool operator<(SymbolRef x, SymbolRef y) { return *x < *y; }
765 inline bool operator<(MutableSymbolRef x, MutableSymbolRef y) {
766   return *x < *y;
767 }
768 using SymbolSet = std::set<SymbolRef>;
769 
770 } // namespace Fortran::semantics
771 
772 // Define required  info so that SymbolRef can be used inside llvm::DenseMap.
773 namespace llvm {
774 template <> struct DenseMapInfo<Fortran::semantics::SymbolRef> {
775   static inline Fortran::semantics::SymbolRef getEmptyKey() {
776     auto ptr = DenseMapInfo<const Fortran::semantics::Symbol *>::getEmptyKey();
777     return *reinterpret_cast<Fortran::semantics::SymbolRef *>(&ptr);
778   }
779 
780   static inline Fortran::semantics::SymbolRef getTombstoneKey() {
781     auto ptr =
782         DenseMapInfo<const Fortran::semantics::Symbol *>::getTombstoneKey();
783     return *reinterpret_cast<Fortran::semantics::SymbolRef *>(&ptr);
784   }
785 
786   static unsigned getHashValue(const Fortran::semantics::SymbolRef &sym) {
787     return DenseMapInfo<const Fortran::semantics::Symbol *>::getHashValue(
788         &sym.get());
789   }
790 
791   static bool isEqual(const Fortran::semantics::SymbolRef &LHS,
792       const Fortran::semantics::SymbolRef &RHS) {
793     return LHS == RHS;
794   }
795 };
796 } // namespace llvm
797 #endif // FORTRAN_SEMANTICS_SYMBOL_H_
798