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