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 
159 // An entity known to be an object.
160 class ObjectEntityDetails : public EntityDetails {
161 public:
162   explicit ObjectEntityDetails(EntityDetails &&);
163   ObjectEntityDetails(const ObjectEntityDetails &) = default;
164   ObjectEntityDetails &operator=(const ObjectEntityDetails &) = default;
EntityDetails(isDummy)165   ObjectEntityDetails(bool isDummy = false) : EntityDetails(isDummy) {}
init()166   MaybeExpr &init() { return init_; }
init()167   const MaybeExpr &init() const { return init_; }
set_init(MaybeExpr && expr)168   void set_init(MaybeExpr &&expr) { init_ = std::move(expr); }
initWasValidated()169   bool initWasValidated() const { return initWasValidated_; }
170   void set_initWasValidated(bool yes = true) { initWasValidated_ = yes; }
shape()171   ArraySpec &shape() { return shape_; }
shape()172   const ArraySpec &shape() const { return shape_; }
coshape()173   ArraySpec &coshape() { return coshape_; }
coshape()174   const ArraySpec &coshape() const { return coshape_; }
175   void set_shape(const ArraySpec &);
176   void set_coshape(const ArraySpec &);
commonBlock()177   const Symbol *commonBlock() const { return commonBlock_; }
set_commonBlock(const Symbol & commonBlock)178   void set_commonBlock(const Symbol &commonBlock) {
179     commonBlock_ = &commonBlock;
180   }
IsArray()181   bool IsArray() const { return !shape_.empty(); }
IsCoarray()182   bool IsCoarray() const { return !coshape_.empty(); }
IsAssumedShape()183   bool IsAssumedShape() const { return isDummy() && shape_.IsAssumedShape(); }
IsDeferredShape()184   bool IsDeferredShape() const {
185     return !isDummy() && shape_.IsDeferredShape();
186   }
IsAssumedSize()187   bool IsAssumedSize() const { return isDummy() && shape_.IsAssumedSize(); }
IsAssumedRank()188   bool IsAssumedRank() const { return isDummy() && shape_.IsAssumedRank(); }
189 
190 private:
191   MaybeExpr init_;
192   bool initWasValidated_{false};
193   ArraySpec shape_;
194   ArraySpec coshape_;
195   const Symbol *commonBlock_{nullptr}; // common block this object is in
196   friend llvm::raw_ostream &operator<<(
197       llvm::raw_ostream &, const ObjectEntityDetails &);
198 };
199 
200 // Mixin for details with passed-object dummy argument.
201 // If a procedure pointer component or type-bound procedure does not have
202 // the NOPASS attribute on its symbol, then PASS is assumed; the name
203 // is optional; if it is missing, the first dummy argument of the procedure's
204 // interface is the passed-object dummy argument.
205 class WithPassArg {
206 public:
passName()207   std::optional<SourceName> passName() const { return passName_; }
set_passName(const SourceName & passName)208   void set_passName(const SourceName &passName) { passName_ = passName; }
209 
210 private:
211   std::optional<SourceName> passName_;
212 };
213 
214 // A procedure pointer, dummy procedure, or external procedure
215 class ProcEntityDetails : public EntityDetails, public WithPassArg {
216 public:
217   ProcEntityDetails() = default;
218   explicit ProcEntityDetails(EntityDetails &&d);
219 
interface()220   const ProcInterface &interface() const { return interface_; }
interface()221   ProcInterface &interface() { return interface_; }
set_interface(const ProcInterface & interface)222   void set_interface(const ProcInterface &interface) {
223     CHECK(!IsInterfaceSet());
224     interface_ = interface;
225   }
IsInterfaceSet()226   bool IsInterfaceSet() {
227     return interface_.symbol() != nullptr || interface_.type() != nullptr;
228   }
229   inline bool HasExplicitInterface() const;
230 
231   // Be advised: !init().has_value() => uninitialized pointer,
232   // while *init() == nullptr => explicit NULL() initialization.
init()233   std::optional<const Symbol *> init() const { return init_; }
set_init(const Symbol & symbol)234   void set_init(const Symbol &symbol) { init_ = &symbol; }
set_init(std::nullptr_t)235   void set_init(std::nullptr_t) { init_ = nullptr; }
236 
237 private:
238   ProcInterface interface_;
239   std::optional<const Symbol *> init_;
240   friend llvm::raw_ostream &operator<<(
241       llvm::raw_ostream &, const ProcEntityDetails &);
242 };
243 
244 // These derived type details represent the characteristics of a derived
245 // type definition that are shared by all instantiations of that type.
246 // The DerivedTypeSpec instances whose type symbols share these details
247 // each own a scope into which the components' symbols have been cloned
248 // and specialized for each distinct set of type parameter values.
249 class DerivedTypeDetails {
250 public:
paramNames()251   const std::list<SourceName> &paramNames() const { return paramNames_; }
paramDecls()252   const SymbolVector &paramDecls() const { return paramDecls_; }
sequence()253   bool sequence() const { return sequence_; }
isForwardReferenced()254   bool isForwardReferenced() const { return isForwardReferenced_; }
add_paramName(const SourceName & name)255   void add_paramName(const SourceName &name) { paramNames_.push_back(name); }
add_paramDecl(const Symbol & symbol)256   void add_paramDecl(const Symbol &symbol) { paramDecls_.push_back(symbol); }
257   void add_component(const Symbol &);
258   void set_sequence(bool x = true) { sequence_ = x; }
set_isForwardReferenced()259   void set_isForwardReferenced() { isForwardReferenced_ = true; }
componentNames()260   const std::list<SourceName> &componentNames() const {
261     return componentNames_;
262   }
263 
264   // If this derived type extends another, locate the parent component's symbol.
265   const Symbol *GetParentComponent(const Scope &) const;
266 
GetParentComponentName()267   std::optional<SourceName> GetParentComponentName() const {
268     if (componentNames_.empty()) {
269       return std::nullopt;
270     } else {
271       return componentNames_.front();
272     }
273   }
274 
275 private:
276   // These are (1) the names of the derived type parameters in the order
277   // in which they appear on the type definition statement(s), and (2) the
278   // symbols that correspond to those names in the order in which their
279   // declarations appear in the derived type definition(s).
280   std::list<SourceName> paramNames_;
281   SymbolVector paramDecls_;
282   // These are the names of the derived type's components in component
283   // order.  A parent component, if any, appears first in this list.
284   std::list<SourceName> componentNames_;
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 FinalProcDetails {}; // TODO
329 
330 class MiscDetails {
331 public:
332   ENUM_CLASS(Kind, None, ConstructName, ScopeName, PassName, ComplexPartRe,
333       ComplexPartIm, KindParamInquiry, LenParamInquiry, SelectRankAssociateName,
334       SelectTypeAssociateName, TypeBoundDefinedOp);
MiscDetails(Kind kind)335   MiscDetails(Kind kind) : kind_{kind} {}
kind()336   Kind kind() const { return kind_; }
337 
338 private:
339   Kind kind_;
340 };
341 
342 class TypeParamDetails {
343 public:
TypeParamDetails(common::TypeParamAttr attr)344   explicit TypeParamDetails(common::TypeParamAttr attr) : attr_{attr} {}
345   TypeParamDetails(const TypeParamDetails &) = default;
attr()346   common::TypeParamAttr attr() const { return attr_; }
init()347   MaybeIntExpr &init() { return init_; }
init()348   const MaybeIntExpr &init() const { return init_; }
set_init(MaybeIntExpr && expr)349   void set_init(MaybeIntExpr &&expr) { init_ = std::move(expr); }
type()350   const DeclTypeSpec *type() const { return type_; }
351   void set_type(const DeclTypeSpec &);
352   void ReplaceType(const DeclTypeSpec &);
353 
354 private:
355   common::TypeParamAttr attr_;
356   MaybeIntExpr init_;
357   const DeclTypeSpec *type_{nullptr};
358 };
359 
360 // Record the USE of a symbol: location is where (USE statement or renaming);
361 // symbol is the USEd module.
362 class UseDetails {
363 public:
UseDetails(const SourceName & location,const Symbol & symbol)364   UseDetails(const SourceName &location, const Symbol &symbol)
365       : location_{location}, symbol_{symbol} {}
location()366   const SourceName &location() const { return location_; }
symbol()367   const Symbol &symbol() const { return symbol_; }
368 
369 private:
370   SourceName location_;
371   SymbolRef symbol_;
372 };
373 
374 // A symbol with ambiguous use-associations. Record where they were so
375 // we can report the error if it is used.
376 class UseErrorDetails {
377 public:
378   UseErrorDetails(const UseDetails &);
379   UseErrorDetails &add_occurrence(const SourceName &, const Scope &);
380   using listType = std::list<std::pair<SourceName, const Scope *>>;
occurrences()381   const listType occurrences() const { return occurrences_; };
382 
383 private:
384   listType occurrences_;
385 };
386 
387 // A symbol host-associated from an enclosing scope.
388 class HostAssocDetails {
389 public:
HostAssocDetails(const Symbol & symbol)390   HostAssocDetails(const Symbol &symbol) : symbol_{symbol} {}
symbol()391   const Symbol &symbol() const { return symbol_; }
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);
433 
434   // specific and derivedType indicate a specific procedure or derived type
435   // with the same name as this generic. Only one of them may be set.
specific()436   Symbol *specific() { return specific_; }
specific()437   const Symbol *specific() const { return specific_; }
438   void set_specific(Symbol &specific);
derivedType()439   Symbol *derivedType() { return derivedType_; }
derivedType()440   const Symbol *derivedType() const { return derivedType_; }
441   void set_derivedType(Symbol &derivedType);
442 
443   // Copy in specificProcs, specific, and derivedType from another generic
444   void CopyFrom(const GenericDetails &);
445 
446   // Check that specific is one of the specificProcs. If not, return the
447   // specific as a raw pointer.
448   const Symbol *CheckSpecific() const;
449   Symbol *CheckSpecific();
450 
useDetails()451   const std::optional<UseDetails> &useDetails() const { return useDetails_; }
set_useDetails(const UseDetails & details)452   void set_useDetails(const UseDetails &details) { useDetails_ = details; }
453 
454 private:
455   GenericKind kind_;
456   // all of the specific procedures for this generic
457   SymbolVector specificProcs_;
458   std::vector<SourceName> bindingNames_;
459   // a specific procedure with the same name as this generic, if any
460   Symbol *specific_{nullptr};
461   // a derived type with the same name as this generic, if any
462   Symbol *derivedType_{nullptr};
463   // If two USEs of generics were merged to form this one, this is the
464   // UseDetails for one of them. Used for reporting USE errors.
465   std::optional<UseDetails> useDetails_;
466 };
467 
468 class UnknownDetails {};
469 
470 using Details = std::variant<UnknownDetails, MainProgramDetails, ModuleDetails,
471     SubprogramDetails, SubprogramNameDetails, EntityDetails,
472     ObjectEntityDetails, ProcEntityDetails, AssocEntityDetails,
473     DerivedTypeDetails, UseDetails, UseErrorDetails, HostAssocDetails,
474     GenericDetails, ProcBindingDetails, NamelistDetails, CommonBlockDetails,
475     FinalProcDetails, TypeParamDetails, MiscDetails>;
476 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Details &);
477 std::string DetailsToString(const Details &);
478 
479 class Symbol {
480 public:
481   ENUM_CLASS(Flag,
482       Error, // an error has been reported on this symbol
483       Function, // symbol is a function
484       Subroutine, // symbol is a subroutine
485       Implicit, // symbol is implicitly typed
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 
494       // OpenMP data-sharing attribute
495       OmpShared, OmpPrivate, OmpLinear, OmpFirstPrivate, OmpLastPrivate,
496       // OpenMP data-mapping attribute
497       OmpMapTo, OmpMapFrom, OmpMapAlloc, OmpMapRelease, OmpMapDelete,
498       // OpenMP miscellaneous flags
499       OmpCommonBlock, OmpReduction, OmpDeclareSimd, OmpDeclareTarget,
500       OmpThreadprivate, OmpDeclareReduction, OmpFlushed, OmpCriticalLock,
501       OmpIfSpecified, OmpNone, OmpPreDetermined);
502   using Flags = common::EnumSet<Flag, Flag_enumSize>;
503 
owner()504   const Scope &owner() const { return *owner_; }
name()505   const SourceName &name() const { return name_; }
attrs()506   Attrs &attrs() { return attrs_; }
attrs()507   const Attrs &attrs() const { return attrs_; }
flags()508   Flags &flags() { return flags_; }
flags()509   const Flags &flags() const { return flags_; }
test(Flag flag)510   bool test(Flag flag) const { return flags_.test(flag); }
511   void set(Flag flag, bool value = true) { flags_.set(flag, value); }
512   // The Scope introduced by this symbol, if any.
scope()513   Scope *scope() { return scope_; }
scope()514   const Scope *scope() const { return scope_; }
set_scope(Scope * scope)515   void set_scope(Scope *scope) { scope_ = scope; }
size()516   std::size_t size() const { return size_; }
set_size(std::size_t size)517   void set_size(std::size_t size) { size_ = size; }
offset()518   std::size_t offset() const { return offset_; }
set_offset(std::size_t offset)519   void set_offset(std::size_t offset) { offset_ = offset; }
520   // Give the symbol a name with a different source location but same chars.
521   void ReplaceName(const SourceName &);
522 
523   // Does symbol have this type of details?
has()524   template <typename D> bool has() const {
525     return std::holds_alternative<D>(details_);
526   }
527 
528   // Return a non-owning pointer to details if it is type D, else nullptr.
detailsIf()529   template <typename D> D *detailsIf() { return std::get_if<D>(&details_); }
detailsIf()530   template <typename D> const D *detailsIf() const {
531     return std::get_if<D>(&details_);
532   }
533 
534   // Return a reference to the details which must be of type D.
get()535   template <typename D> D &get() {
536     return const_cast<D &>(const_cast<const Symbol *>(this)->get<D>());
537   }
get()538   template <typename D> const D &get() const {
539     const auto *p{detailsIf<D>()};
540     CHECK(p);
541     return *p;
542   }
543 
details()544   Details &details() { return details_; }
details()545   const Details &details() const { return details_; }
546   // Assign the details of the symbol from one of the variants.
547   // Only allowed in certain cases.
548   void set_details(Details &&);
549 
550   // Can the details of this symbol be replaced with the given details?
551   bool CanReplaceDetails(const Details &details) const;
552 
553   // Follow use-associations and host-associations to get the ultimate entity.
554   inline Symbol &GetUltimate();
555   inline const Symbol &GetUltimate() const;
556 
557   inline DeclTypeSpec *GetType();
558   inline const DeclTypeSpec *GetType() const;
559 
560   void SetType(const DeclTypeSpec &);
561   bool IsFuncResult() const;
562   bool IsObjectArray() const;
563   bool IsSubprogram() const;
564   bool IsFromModFile() const;
HasExplicitInterface()565   bool HasExplicitInterface() const {
566     return std::visit(common::visitors{
567                           [](const SubprogramDetails &) { return true; },
568                           [](const SubprogramNameDetails &) { return true; },
569                           [&](const ProcEntityDetails &x) {
570                             return attrs_.test(Attr::INTRINSIC) ||
571                                 x.HasExplicitInterface();
572                           },
573                           [](const ProcBindingDetails &x) {
574                             return x.symbol().HasExplicitInterface();
575                           },
576                           [](const UseDetails &x) {
577                             return x.symbol().HasExplicitInterface();
578                           },
579                           [](const HostAssocDetails &x) {
580                             return x.symbol().HasExplicitInterface();
581                           },
582                           [](const auto &) { return false; },
583                       },
584         details_);
585   }
586 
587   bool operator==(const Symbol &that) const { return this == &that; }
588   bool operator!=(const Symbol &that) const { return !(*this == that); }
589   bool operator<(const Symbol &that) const {
590     // For sets of symbols: collate them by source location
591     return name_.begin() < that.name_.begin();
592   }
593 
Rank()594   int Rank() const {
595     return std::visit(
596         common::visitors{
597             [](const SubprogramDetails &sd) {
598               return sd.isFunction() ? sd.result().Rank() : 0;
599             },
600             [](const GenericDetails &) {
601               return 0; /*TODO*/
602             },
603             [](const ProcBindingDetails &x) { return x.symbol().Rank(); },
604             [](const UseDetails &x) { return x.symbol().Rank(); },
605             [](const HostAssocDetails &x) { return x.symbol().Rank(); },
606             [](const ObjectEntityDetails &oed) { return oed.shape().Rank(); },
607             [](const AssocEntityDetails &aed) {
608               if (const auto &expr{aed.expr()}) {
609                 if (auto assocRank{aed.rank()}) {
610                   return *assocRank;
611                 } else {
612                   return expr->Rank();
613                 }
614               } else {
615                 return 0;
616               }
617             },
618             [](const auto &) { return 0; },
619         },
620         details_);
621   }
622 
Corank()623   int Corank() const {
624     return std::visit(
625         common::visitors{
626             [](const SubprogramDetails &sd) {
627               return sd.isFunction() ? sd.result().Corank() : 0;
628             },
629             [](const GenericDetails &) {
630               return 0; /*TODO*/
631             },
632             [](const UseDetails &x) { return x.symbol().Corank(); },
633             [](const HostAssocDetails &x) { return x.symbol().Corank(); },
634             [](const ObjectEntityDetails &oed) { return oed.coshape().Rank(); },
635             [](const auto &) { return 0; },
636         },
637         details_);
638   }
639 
640   // If there is a parent component, return a pointer to its derived type spec.
641   // The Scope * argument defaults to this->scope_ but should be overridden
642   // for a parameterized derived type instantiation with the instance's scope.
643   const DerivedTypeSpec *GetParentTypeSpec(const Scope * = nullptr) const;
644 
645 private:
646   const Scope *owner_;
647   SourceName name_;
648   Attrs attrs_;
649   Flags flags_;
650   Scope *scope_{nullptr};
651   std::size_t size_{0}; // size in bytes
652   std::size_t offset_{0}; // byte offset in scope or common block
653   Details details_;
654 
Symbol()655   Symbol() {} // only created in class Symbols
656   const std::string GetDetailsName() const;
657   friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Symbol &);
658   friend llvm::raw_ostream &DumpForUnparse(
659       llvm::raw_ostream &, const Symbol &, bool);
660 
661   // If a derived type's symbol refers to an extended derived type,
662   // return the parent component's symbol.  The scope of the derived type
663   // can be overridden.
664   const Symbol *GetParentComponent(const Scope * = nullptr) const;
665 
666   template <std::size_t> friend class Symbols;
667   template <class, std::size_t> friend struct std::array;
668 };
669 
670 llvm::raw_ostream &operator<<(llvm::raw_ostream &, Symbol::Flag);
671 
672 // Manage memory for all symbols. BLOCK_SIZE symbols at a time are allocated.
673 // Make() returns a reference to the next available one. They are never
674 // deleted.
675 template <std::size_t BLOCK_SIZE> class Symbols {
676 public:
Make(const Scope & owner,const SourceName & name,const Attrs & attrs,Details && details)677   Symbol &Make(const Scope &owner, const SourceName &name, const Attrs &attrs,
678       Details &&details) {
679     Symbol &symbol = Get();
680     symbol.owner_ = &owner;
681     symbol.name_ = name;
682     symbol.attrs_ = attrs;
683     symbol.details_ = std::move(details);
684     return symbol;
685   }
686 
687 private:
688   using blockType = std::array<Symbol, BLOCK_SIZE>;
689   std::list<blockType *> blocks_;
690   std::size_t nextIndex_{0};
691   blockType *currBlock_{nullptr};
692 
Get()693   Symbol &Get() {
694     if (nextIndex_ == 0) {
695       blocks_.push_back(new blockType());
696       currBlock_ = blocks_.back();
697     }
698     Symbol &result = (*currBlock_)[nextIndex_];
699     if (++nextIndex_ >= BLOCK_SIZE) {
700       nextIndex_ = 0; // allocate a new block next time
701     }
702     return result;
703   }
704 };
705 
706 // Define a few member functions here in the header so that they
707 // can be used by lib/Evaluate without inducing a dependence cycle
708 // between the two shared libraries.
709 
HasExplicitInterface()710 inline bool ProcEntityDetails::HasExplicitInterface() const {
711   if (auto *symbol{interface_.symbol()}) {
712     return symbol->HasExplicitInterface();
713   }
714   return false;
715 }
716 
GetUltimate()717 inline Symbol &Symbol::GetUltimate() {
718   return const_cast<Symbol &>(const_cast<const Symbol *>(this)->GetUltimate());
719 }
GetUltimate()720 inline const Symbol &Symbol::GetUltimate() const {
721   if (const auto *details{detailsIf<UseDetails>()}) {
722     return details->symbol().GetUltimate();
723   } else if (const auto *details{detailsIf<HostAssocDetails>()}) {
724     return details->symbol().GetUltimate();
725   } else {
726     return *this;
727   }
728 }
729 
GetType()730 inline DeclTypeSpec *Symbol::GetType() {
731   return const_cast<DeclTypeSpec *>(
732       const_cast<const Symbol *>(this)->GetType());
733 }
GetType()734 inline const DeclTypeSpec *Symbol::GetType() const {
735   return std::visit(
736       common::visitors{
737           [](const EntityDetails &x) { return x.type(); },
738           [](const ObjectEntityDetails &x) { return x.type(); },
739           [](const AssocEntityDetails &x) { return x.type(); },
740           [](const SubprogramDetails &x) {
741             return x.isFunction() ? x.result().GetType() : nullptr;
742           },
743           [](const ProcEntityDetails &x) {
744             const Symbol *symbol{x.interface().symbol()};
745             return symbol ? symbol->GetType() : x.interface().type();
746           },
747           [](const ProcBindingDetails &x) { return x.symbol().GetType(); },
748           [](const TypeParamDetails &x) { return x.type(); },
749           [](const UseDetails &x) { return x.symbol().GetType(); },
750           [](const HostAssocDetails &x) { return x.symbol().GetType(); },
751           [](const auto &) -> const DeclTypeSpec * { return nullptr; },
752       },
753       details_);
754 }
755 
756 inline bool operator<(SymbolRef x, SymbolRef y) { return *x < *y; }
757 inline bool operator<(MutableSymbolRef x, MutableSymbolRef y) {
758   return *x < *y;
759 }
760 using SymbolSet = std::set<SymbolRef>;
761 
762 } // namespace Fortran::semantics
763 
764 // Define required  info so that SymbolRef can be used inside llvm::DenseMap.
765 namespace llvm {
766 template <> struct DenseMapInfo<Fortran::semantics::SymbolRef> {
767   static inline Fortran::semantics::SymbolRef getEmptyKey() {
768     auto ptr = DenseMapInfo<const Fortran::semantics::Symbol *>::getEmptyKey();
769     return *reinterpret_cast<Fortran::semantics::SymbolRef *>(&ptr);
770   }
771 
772   static inline Fortran::semantics::SymbolRef getTombstoneKey() {
773     auto ptr =
774         DenseMapInfo<const Fortran::semantics::Symbol *>::getTombstoneKey();
775     return *reinterpret_cast<Fortran::semantics::SymbolRef *>(&ptr);
776   }
777 
778   static unsigned getHashValue(const Fortran::semantics::SymbolRef &sym) {
779     return DenseMapInfo<const Fortran::semantics::Symbol *>::getHashValue(
780         &sym.get());
781   }
782 
783   static bool isEqual(const Fortran::semantics::SymbolRef &LHS,
784       const Fortran::semantics::SymbolRef &RHS) {
785     return LHS == RHS;
786   }
787 };
788 } // namespace llvm
789 #endif // FORTRAN_SEMANTICS_SYMBOL_H_
790