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