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> ¶mNames() const { return paramNames_; }
paramDecls()253 const SymbolVector ¶mDecls() 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