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