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 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const AssocEntityDetails &);
159
160 // An entity known to be an object.
161 class ObjectEntityDetails : public EntityDetails {
162 public:
163 explicit ObjectEntityDetails(EntityDetails &&);
164 ObjectEntityDetails(const ObjectEntityDetails &) = default;
165 ObjectEntityDetails &operator=(const ObjectEntityDetails &) = default;
EntityDetails(isDummy)166 ObjectEntityDetails(bool isDummy = false) : EntityDetails(isDummy) {}
init()167 MaybeExpr &init() { return init_; }
init()168 const MaybeExpr &init() const { return init_; }
set_init(MaybeExpr && expr)169 void set_init(MaybeExpr &&expr) { init_ = std::move(expr); }
shape()170 ArraySpec &shape() { return shape_; }
shape()171 const ArraySpec &shape() const { return shape_; }
coshape()172 ArraySpec &coshape() { return coshape_; }
coshape()173 const ArraySpec &coshape() const { return coshape_; }
174 void set_shape(const ArraySpec &);
175 void set_coshape(const ArraySpec &);
commonBlock()176 const Symbol *commonBlock() const { return commonBlock_; }
set_commonBlock(const Symbol & commonBlock)177 void set_commonBlock(const Symbol &commonBlock) {
178 commonBlock_ = &commonBlock;
179 }
IsArray()180 bool IsArray() const { return !shape_.empty(); }
IsCoarray()181 bool IsCoarray() const { return !coshape_.empty(); }
IsAssumedShape()182 bool IsAssumedShape() const { return isDummy() && shape_.IsAssumedShape(); }
IsDeferredShape()183 bool IsDeferredShape() const {
184 return !isDummy() && shape_.IsDeferredShape();
185 }
IsAssumedSize()186 bool IsAssumedSize() const { return isDummy() && shape_.IsAssumedSize(); }
IsAssumedRank()187 bool IsAssumedRank() const { return isDummy() && shape_.IsAssumedRank(); }
188
189 private:
190 MaybeExpr init_;
191 ArraySpec shape_;
192 ArraySpec coshape_;
193 const Symbol *commonBlock_{nullptr}; // common block this object is in
194 friend llvm::raw_ostream &operator<<(
195 llvm::raw_ostream &, const ObjectEntityDetails &);
196 };
197
198 // Mixin for details with passed-object dummy argument.
199 // If a procedure pointer component or type-bound procedure does not have
200 // the NOPASS attribute on its symbol, then PASS is assumed; the name
201 // is optional; if it is missing, the first dummy argument of the procedure's
202 // interface is the passed-object dummy argument.
203 class WithPassArg {
204 public:
passName()205 std::optional<SourceName> passName() const { return passName_; }
set_passName(const SourceName & passName)206 void set_passName(const SourceName &passName) { passName_ = passName; }
207
208 private:
209 std::optional<SourceName> passName_;
210 };
211
212 // A procedure pointer, dummy procedure, or external procedure
213 class ProcEntityDetails : public EntityDetails, public WithPassArg {
214 public:
215 ProcEntityDetails() = default;
216 explicit ProcEntityDetails(EntityDetails &&d);
217
interface()218 const ProcInterface &interface() const { return interface_; }
interface()219 ProcInterface &interface() { return interface_; }
set_interface(const ProcInterface & interface)220 void set_interface(const ProcInterface &interface) { interface_ = interface; }
IsInterfaceSet()221 bool IsInterfaceSet() {
222 return interface_.symbol() != nullptr || interface_.type() != nullptr;
223 }
224 inline bool HasExplicitInterface() const;
225
226 // Be advised: !init().has_value() => uninitialized pointer,
227 // while *init() == nullptr => explicit NULL() initialization.
init()228 std::optional<const Symbol *> init() const { return init_; }
set_init(const Symbol & symbol)229 void set_init(const Symbol &symbol) { init_ = &symbol; }
set_init(std::nullptr_t)230 void set_init(std::nullptr_t) { init_ = nullptr; }
231
232 private:
233 ProcInterface interface_;
234 std::optional<const Symbol *> init_;
235 friend llvm::raw_ostream &operator<<(
236 llvm::raw_ostream &, const ProcEntityDetails &);
237 };
238
239 // These derived type details represent the characteristics of a derived
240 // type definition that are shared by all instantiations of that type.
241 // The DerivedTypeSpec instances whose type symbols share these details
242 // each own a scope into which the components' symbols have been cloned
243 // and specialized for each distinct set of type parameter values.
244 class DerivedTypeDetails {
245 public:
paramNames()246 const std::list<SourceName> ¶mNames() const { return paramNames_; }
paramDecls()247 const SymbolVector ¶mDecls() const { return paramDecls_; }
sequence()248 bool sequence() const { return sequence_; }
finals()249 std::map<SourceName, SymbolRef> &finals() { return finals_; }
finals()250 const std::map<SourceName, SymbolRef> &finals() const { return finals_; }
isForwardReferenced()251 bool isForwardReferenced() const { return isForwardReferenced_; }
add_paramName(const SourceName & name)252 void add_paramName(const SourceName &name) { paramNames_.push_back(name); }
add_paramDecl(const Symbol & symbol)253 void add_paramDecl(const Symbol &symbol) { paramDecls_.push_back(symbol); }
254 void add_component(const Symbol &);
255 void set_sequence(bool x = true) { sequence_ = x; }
set_isForwardReferenced()256 void set_isForwardReferenced() { isForwardReferenced_ = true; }
componentNames()257 const std::list<SourceName> &componentNames() const {
258 return componentNames_;
259 }
260
261 // If this derived type extends another, locate the parent component's symbol.
262 const Symbol *GetParentComponent(const Scope &) const;
263
GetParentComponentName()264 std::optional<SourceName> GetParentComponentName() const {
265 if (componentNames_.empty()) {
266 return std::nullopt;
267 } else {
268 return componentNames_.front();
269 }
270 }
271
272 const Symbol *GetFinalForRank(int) const;
273
274 private:
275 // These are (1) the names of the derived type parameters in the order
276 // in which they appear on the type definition statement(s), and (2) the
277 // symbols that correspond to those names in the order in which their
278 // declarations appear in the derived type definition(s).
279 std::list<SourceName> paramNames_;
280 SymbolVector paramDecls_;
281 // These are the names of the derived type's components in component
282 // order. A parent component, if any, appears first in this list.
283 std::list<SourceName> componentNames_;
284 std::map<SourceName, SymbolRef> finals_; // FINAL :: subr
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 MiscDetails {
329 public:
330 ENUM_CLASS(Kind, None, ConstructName, ScopeName, PassName, ComplexPartRe,
331 ComplexPartIm, KindParamInquiry, LenParamInquiry, SelectRankAssociateName,
332 SelectTypeAssociateName, TypeBoundDefinedOp);
MiscDetails(Kind kind)333 MiscDetails(Kind kind) : kind_{kind} {}
kind()334 Kind kind() const { return kind_; }
335
336 private:
337 Kind kind_;
338 };
339
340 class TypeParamDetails {
341 public:
TypeParamDetails(common::TypeParamAttr attr)342 explicit TypeParamDetails(common::TypeParamAttr attr) : attr_{attr} {}
343 TypeParamDetails(const TypeParamDetails &) = default;
attr()344 common::TypeParamAttr attr() const { return attr_; }
init()345 MaybeIntExpr &init() { return init_; }
init()346 const MaybeIntExpr &init() const { return init_; }
set_init(MaybeIntExpr && expr)347 void set_init(MaybeIntExpr &&expr) { init_ = std::move(expr); }
type()348 const DeclTypeSpec *type() const { return type_; }
349 void set_type(const DeclTypeSpec &);
350 void ReplaceType(const DeclTypeSpec &);
351
352 private:
353 common::TypeParamAttr attr_;
354 MaybeIntExpr init_;
355 const DeclTypeSpec *type_{nullptr};
356 };
357
358 // Record the USE of a symbol: location is where (USE statement or renaming);
359 // symbol is the USEd module.
360 class UseDetails {
361 public:
UseDetails(const SourceName & location,const Symbol & symbol)362 UseDetails(const SourceName &location, const Symbol &symbol)
363 : location_{location}, symbol_{symbol} {}
location()364 const SourceName &location() const { return location_; }
symbol()365 const Symbol &symbol() const { return symbol_; }
366
367 private:
368 SourceName location_;
369 SymbolRef symbol_;
370 };
371
372 // A symbol with ambiguous use-associations. Record where they were so
373 // we can report the error if it is used.
374 class UseErrorDetails {
375 public:
376 UseErrorDetails(const UseDetails &);
377 UseErrorDetails &add_occurrence(const SourceName &, const Scope &);
378 using listType = std::list<std::pair<SourceName, const Scope *>>;
occurrences()379 const listType occurrences() const { return occurrences_; };
380
381 private:
382 listType occurrences_;
383 };
384
385 // A symbol host-associated from an enclosing scope.
386 class HostAssocDetails {
387 public:
HostAssocDetails(const Symbol & symbol)388 HostAssocDetails(const Symbol &symbol) : symbol_{symbol} {}
symbol()389 const Symbol &symbol() const { return symbol_; }
390 bool implicitOrSpecExprError{false};
391 bool implicitOrExplicitTypeError{false};
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);
uses()433 const SymbolVector &uses() const { return uses_; }
434
435 // specific and derivedType indicate a specific procedure or derived type
436 // with the same name as this generic. Only one of them may be set.
specific()437 Symbol *specific() { return specific_; }
specific()438 const Symbol *specific() const { return specific_; }
439 void set_specific(Symbol &specific);
derivedType()440 Symbol *derivedType() { return derivedType_; }
derivedType()441 const Symbol *derivedType() const { return derivedType_; }
442 void set_derivedType(Symbol &derivedType);
443 void AddUse(const Symbol &);
444
445 // Copy in specificProcs, specific, and derivedType from another generic
446 void CopyFrom(const GenericDetails &);
447
448 // Check that specific is one of the specificProcs. If not, return the
449 // specific as a raw pointer.
450 const Symbol *CheckSpecific() const;
451 Symbol *CheckSpecific();
452
453 private:
454 GenericKind kind_;
455 // all of the specific procedures for this generic
456 SymbolVector specificProcs_;
457 std::vector<SourceName> bindingNames_;
458 // Symbols used from other modules merged into this one
459 SymbolVector uses_;
460 // a specific procedure with the same name as this generic, if any
461 Symbol *specific_{nullptr};
462 // a derived type with the same name as this generic, if any
463 Symbol *derivedType_{nullptr};
464 };
465 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const GenericDetails &);
466
467 class UnknownDetails {};
468
469 using Details = std::variant<UnknownDetails, MainProgramDetails, ModuleDetails,
470 SubprogramDetails, SubprogramNameDetails, EntityDetails,
471 ObjectEntityDetails, ProcEntityDetails, AssocEntityDetails,
472 DerivedTypeDetails, UseDetails, UseErrorDetails, HostAssocDetails,
473 GenericDetails, ProcBindingDetails, NamelistDetails, CommonBlockDetails,
474 TypeParamDetails, MiscDetails>;
475 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Details &);
476 std::string DetailsToString(const Details &);
477
478 class Symbol {
479 public:
480 ENUM_CLASS(Flag,
481 Function, // symbol is a function
482 Subroutine, // symbol is a subroutine
483 StmtFunction, // symbol is a statement function (Function is set too)
484 Implicit, // symbol is implicitly typed
485 ImplicitOrError, // symbol must be implicitly typed or it's an error
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 InNamelist, // flag is set if the symbol is in Namelist statement
494 // OpenACC data-sharing attribute
495 AccPrivate, AccFirstPrivate, AccShared,
496 // OpenACC data-mapping attribute
497 AccCopyIn, AccCopyOut, AccCreate, AccDelete, AccPresent,
498 // OpenACC miscellaneous flags
499 AccCommonBlock, AccThreadPrivate, AccReduction, AccNone, AccPreDetermined,
500 // OpenMP data-sharing attribute
501 OmpShared, OmpPrivate, OmpLinear, OmpFirstPrivate, OmpLastPrivate,
502 // OpenMP data-mapping attribute
503 OmpMapTo, OmpMapFrom, OmpMapAlloc, OmpMapRelease, OmpMapDelete,
504 // OpenMP data-copying attribute
505 OmpCopyIn,
506 // OpenMP miscellaneous flags
507 OmpCommonBlock, OmpReduction, OmpAllocate, OmpDeclareSimd,
508 OmpDeclareTarget, OmpThreadprivate, OmpDeclareReduction, OmpFlushed,
509 OmpCriticalLock, OmpIfSpecified, OmpNone, OmpPreDetermined, OmpAligned);
510 using Flags = common::EnumSet<Flag, Flag_enumSize>;
511
owner()512 const Scope &owner() const { return *owner_; }
name()513 const SourceName &name() const { return name_; }
attrs()514 Attrs &attrs() { return attrs_; }
attrs()515 const Attrs &attrs() const { return attrs_; }
flags()516 Flags &flags() { return flags_; }
flags()517 const Flags &flags() const { return flags_; }
test(Flag flag)518 bool test(Flag flag) const { return flags_.test(flag); }
519 void set(Flag flag, bool value = true) { flags_.set(flag, value); }
520 // The Scope introduced by this symbol, if any.
scope()521 Scope *scope() { return scope_; }
scope()522 const Scope *scope() const { return scope_; }
set_scope(Scope * scope)523 void set_scope(Scope *scope) { scope_ = scope; }
size()524 std::size_t size() const { return size_; }
set_size(std::size_t size)525 void set_size(std::size_t size) { size_ = size; }
offset()526 std::size_t offset() const { return offset_; }
set_offset(std::size_t offset)527 void set_offset(std::size_t offset) { offset_ = offset; }
528 // Give the symbol a name with a different source location but same chars.
529 void ReplaceName(const SourceName &);
530
531 // Does symbol have this type of details?
has()532 template <typename D> bool has() const {
533 return std::holds_alternative<D>(details_);
534 }
535
536 // Return a non-owning pointer to details if it is type D, else nullptr.
detailsIf()537 template <typename D> D *detailsIf() { return std::get_if<D>(&details_); }
detailsIf()538 template <typename D> const D *detailsIf() const {
539 return std::get_if<D>(&details_);
540 }
541
542 // Return a reference to the details which must be of type D.
get()543 template <typename D> D &get() {
544 return const_cast<D &>(const_cast<const Symbol *>(this)->get<D>());
545 }
get()546 template <typename D> const D &get() const {
547 const auto *p{detailsIf<D>()};
548 CHECK(p);
549 return *p;
550 }
551
details()552 Details &details() { return details_; }
details()553 const Details &details() const { return details_; }
554 // Assign the details of the symbol from one of the variants.
555 // Only allowed in certain cases.
556 void set_details(Details &&);
557
558 // Can the details of this symbol be replaced with the given details?
559 bool CanReplaceDetails(const Details &details) const;
560
561 // Follow use-associations and host-associations to get the ultimate entity.
562 inline Symbol &GetUltimate();
563 inline const Symbol &GetUltimate() const;
564
565 inline DeclTypeSpec *GetType();
566 inline const DeclTypeSpec *GetType() const;
567
568 void SetType(const DeclTypeSpec &);
569 bool IsFuncResult() const;
570 bool IsObjectArray() const;
571 bool IsSubprogram() const;
572 bool IsFromModFile() const;
HasExplicitInterface()573 bool HasExplicitInterface() const {
574 return std::visit(common::visitors{
575 [](const SubprogramDetails &) { return true; },
576 [](const SubprogramNameDetails &) { return true; },
577 [&](const ProcEntityDetails &x) {
578 return attrs_.test(Attr::INTRINSIC) ||
579 x.HasExplicitInterface();
580 },
581 [](const ProcBindingDetails &x) {
582 return x.symbol().HasExplicitInterface();
583 },
584 [](const UseDetails &x) {
585 return x.symbol().HasExplicitInterface();
586 },
587 [](const HostAssocDetails &x) {
588 return x.symbol().HasExplicitInterface();
589 },
590 [](const auto &) { return false; },
591 },
592 details_);
593 }
594
595 bool operator==(const Symbol &that) const { return this == &that; }
596 bool operator!=(const Symbol &that) const { return !(*this == that); }
597 bool operator<(const Symbol &that) const {
598 // For sets of symbols: collate them by source location
599 return name_.begin() < that.name_.begin();
600 }
601
Rank()602 int Rank() const {
603 return std::visit(
604 common::visitors{
605 [](const SubprogramDetails &sd) {
606 return sd.isFunction() ? sd.result().Rank() : 0;
607 },
608 [](const GenericDetails &) {
609 return 0; /*TODO*/
610 },
611 [](const ProcBindingDetails &x) { return x.symbol().Rank(); },
612 [](const UseDetails &x) { return x.symbol().Rank(); },
613 [](const HostAssocDetails &x) { return x.symbol().Rank(); },
614 [](const ObjectEntityDetails &oed) { return oed.shape().Rank(); },
615 [](const AssocEntityDetails &aed) {
616 if (const auto &expr{aed.expr()}) {
617 if (auto assocRank{aed.rank()}) {
618 return *assocRank;
619 } else {
620 return expr->Rank();
621 }
622 } else {
623 return 0;
624 }
625 },
626 [](const auto &) { return 0; },
627 },
628 details_);
629 }
630
Corank()631 int Corank() const {
632 return std::visit(
633 common::visitors{
634 [](const SubprogramDetails &sd) {
635 return sd.isFunction() ? sd.result().Corank() : 0;
636 },
637 [](const GenericDetails &) {
638 return 0; /*TODO*/
639 },
640 [](const UseDetails &x) { return x.symbol().Corank(); },
641 [](const HostAssocDetails &x) { return x.symbol().Corank(); },
642 [](const ObjectEntityDetails &oed) { return oed.coshape().Rank(); },
643 [](const auto &) { return 0; },
644 },
645 details_);
646 }
647
648 // If there is a parent component, return a pointer to its derived type spec.
649 // The Scope * argument defaults to this->scope_ but should be overridden
650 // for a parameterized derived type instantiation with the instance's scope.
651 const DerivedTypeSpec *GetParentTypeSpec(const Scope * = nullptr) const;
652
653 private:
654 const Scope *owner_;
655 SourceName name_;
656 Attrs attrs_;
657 Flags flags_;
658 Scope *scope_{nullptr};
659 std::size_t size_{0}; // size in bytes
660 std::size_t offset_{0}; // byte offset in scope or common block
661 Details details_;
662
Symbol()663 Symbol() {} // only created in class Symbols
664 const std::string GetDetailsName() const;
665 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Symbol &);
666 friend llvm::raw_ostream &DumpForUnparse(
667 llvm::raw_ostream &, const Symbol &, bool);
668
669 // If a derived type's symbol refers to an extended derived type,
670 // return the parent component's symbol. The scope of the derived type
671 // can be overridden.
672 const Symbol *GetParentComponent(const Scope * = nullptr) const;
673
674 template <std::size_t> friend class Symbols;
675 template <class, std::size_t> friend struct std::array;
676 };
677
678 llvm::raw_ostream &operator<<(llvm::raw_ostream &, Symbol::Flag);
679
680 // Manage memory for all symbols. BLOCK_SIZE symbols at a time are allocated.
681 // Make() returns a reference to the next available one. They are never
682 // deleted.
683 template <std::size_t BLOCK_SIZE> class Symbols {
684 public:
Make(const Scope & owner,const SourceName & name,const Attrs & attrs,Details && details)685 Symbol &Make(const Scope &owner, const SourceName &name, const Attrs &attrs,
686 Details &&details) {
687 Symbol &symbol = Get();
688 symbol.owner_ = &owner;
689 symbol.name_ = name;
690 symbol.attrs_ = attrs;
691 symbol.details_ = std::move(details);
692 return symbol;
693 }
694
695 private:
696 using blockType = std::array<Symbol, BLOCK_SIZE>;
697 std::list<blockType *> blocks_;
698 std::size_t nextIndex_{0};
699 blockType *currBlock_{nullptr};
700
Get()701 Symbol &Get() {
702 if (nextIndex_ == 0) {
703 blocks_.push_back(new blockType());
704 currBlock_ = blocks_.back();
705 }
706 Symbol &result = (*currBlock_)[nextIndex_];
707 if (++nextIndex_ >= BLOCK_SIZE) {
708 nextIndex_ = 0; // allocate a new block next time
709 }
710 return result;
711 }
712 };
713
714 // Define a few member functions here in the header so that they
715 // can be used by lib/Evaluate without inducing a dependence cycle
716 // between the two shared libraries.
717
HasExplicitInterface()718 inline bool ProcEntityDetails::HasExplicitInterface() const {
719 if (auto *symbol{interface_.symbol()}) {
720 return symbol->HasExplicitInterface();
721 }
722 return false;
723 }
724
GetUltimate()725 inline Symbol &Symbol::GetUltimate() {
726 return const_cast<Symbol &>(const_cast<const Symbol *>(this)->GetUltimate());
727 }
GetUltimate()728 inline const Symbol &Symbol::GetUltimate() const {
729 if (const auto *details{detailsIf<UseDetails>()}) {
730 return details->symbol().GetUltimate();
731 } else if (const auto *details{detailsIf<HostAssocDetails>()}) {
732 return details->symbol().GetUltimate();
733 } else {
734 return *this;
735 }
736 }
737
GetType()738 inline DeclTypeSpec *Symbol::GetType() {
739 return const_cast<DeclTypeSpec *>(
740 const_cast<const Symbol *>(this)->GetType());
741 }
GetType()742 inline const DeclTypeSpec *Symbol::GetType() const {
743 return std::visit(
744 common::visitors{
745 [](const EntityDetails &x) { return x.type(); },
746 [](const ObjectEntityDetails &x) { return x.type(); },
747 [](const AssocEntityDetails &x) { return x.type(); },
748 [](const SubprogramDetails &x) {
749 return x.isFunction() ? x.result().GetType() : nullptr;
750 },
751 [](const ProcEntityDetails &x) {
752 const Symbol *symbol{x.interface().symbol()};
753 return symbol ? symbol->GetType() : x.interface().type();
754 },
755 [](const ProcBindingDetails &x) { return x.symbol().GetType(); },
756 [](const TypeParamDetails &x) { return x.type(); },
757 [](const UseDetails &x) { return x.symbol().GetType(); },
758 [](const HostAssocDetails &x) { return x.symbol().GetType(); },
759 [](const auto &) -> const DeclTypeSpec * { return nullptr; },
760 },
761 details_);
762 }
763
764 inline bool operator<(SymbolRef x, SymbolRef y) { return *x < *y; }
765 inline bool operator<(MutableSymbolRef x, MutableSymbolRef y) {
766 return *x < *y;
767 }
768 using SymbolSet = std::set<SymbolRef>;
769
770 } // namespace Fortran::semantics
771
772 // Define required info so that SymbolRef can be used inside llvm::DenseMap.
773 namespace llvm {
774 template <> struct DenseMapInfo<Fortran::semantics::SymbolRef> {
775 static inline Fortran::semantics::SymbolRef getEmptyKey() {
776 auto ptr = DenseMapInfo<const Fortran::semantics::Symbol *>::getEmptyKey();
777 return *reinterpret_cast<Fortran::semantics::SymbolRef *>(&ptr);
778 }
779
780 static inline Fortran::semantics::SymbolRef getTombstoneKey() {
781 auto ptr =
782 DenseMapInfo<const Fortran::semantics::Symbol *>::getTombstoneKey();
783 return *reinterpret_cast<Fortran::semantics::SymbolRef *>(&ptr);
784 }
785
786 static unsigned getHashValue(const Fortran::semantics::SymbolRef &sym) {
787 return DenseMapInfo<const Fortran::semantics::Symbol *>::getHashValue(
788 &sym.get());
789 }
790
791 static bool isEqual(const Fortran::semantics::SymbolRef &LHS,
792 const Fortran::semantics::SymbolRef &RHS) {
793 return LHS == RHS;
794 }
795 };
796 } // namespace llvm
797 #endif // FORTRAN_SEMANTICS_SYMBOL_H_
798