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