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