Warning: This file is not a C or C++ file. It does not have highlighting.

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 "flang/Semantics/module-dependences.h"
18#include "llvm/ADT/DenseMapInfo.h"
19
20#include <array>
21#include <functional>
22#include <list>
23#include <optional>
24#include <set>
25#include <vector>
26
27namespace llvm {
28class raw_ostream;
29}
30namespace Fortran::parser {
31struct Expr;
32}
33
34namespace Fortran::semantics {
35
36/// A Symbol consists of common information (name, owner, and attributes)
37/// and details information specific to the kind of symbol, represented by the
38/// *Details classes.
39
40class Scope;
41class Symbol;
42class ProgramTree;
43
44using SymbolRef = common::Reference<const Symbol>;
45using SymbolVector = std::vector<SymbolRef>;
46using MutableSymbolRef = common::Reference<Symbol>;
47using MutableSymbolVector = std::vector<MutableSymbolRef>;
48
49// Mixin for details with OpenMP declarative constructs.
50class WithOmpDeclarative {
51 using OmpAtomicOrderType = common::OmpAtomicDefaultMemOrderType;
52
53public:
54 ENUM_CLASS(RequiresFlag, ReverseOffload, UnifiedAddress, UnifiedSharedMemory,
55 DynamicAllocators);
56 using RequiresFlags = common::EnumSet<RequiresFlag, RequiresFlag_enumSize>;
57
58 bool has_ompRequires() const { return ompRequires_.has_value(); }
59 const RequiresFlags *ompRequires() const {
60 return ompRequires_ ? &*ompRequires_ : nullptr;
61 }
62 void set_ompRequires(RequiresFlags flags) { ompRequires_ = flags; }
63
64 bool has_ompAtomicDefaultMemOrder() const {
65 return ompAtomicDefaultMemOrder_.has_value();
66 }
67 const OmpAtomicOrderType *ompAtomicDefaultMemOrder() const {
68 return ompAtomicDefaultMemOrder_ ? &*ompAtomicDefaultMemOrder_ : nullptr;
69 }
70 void set_ompAtomicDefaultMemOrder(OmpAtomicOrderType flags) {
71 ompAtomicDefaultMemOrder_ = flags;
72 }
73
74private:
75 std::optional<RequiresFlags> ompRequires_;
76 std::optional<OmpAtomicOrderType> ompAtomicDefaultMemOrder_;
77};
78
79// A module or submodule.
80class ModuleDetails : public WithOmpDeclarative {
81public:
82 ModuleDetails(bool isSubmodule = false) : isSubmodule_{isSubmodule} {}
83 bool isSubmodule() const { return isSubmodule_; }
84 const Scope *scope() const { return scope_; }
85 const Scope *ancestor() const; // for submodule; nullptr for module
86 const Scope *parent() const; // for submodule; nullptr for module
87 void set_scope(const Scope *);
88 bool isDefaultPrivate() const { return isDefaultPrivate_; }
89 void set_isDefaultPrivate(bool yes = true) { isDefaultPrivate_ = yes; }
90 std::optional<ModuleCheckSumType> moduleFileHash() const {
91 return moduleFileHash_;
92 }
93 void set_moduleFileHash(ModuleCheckSumType x) { moduleFileHash_ = x; }
94 const Symbol *previous() const { return previous_; }
95 void set_previous(const Symbol *p) { previous_ = p; }
96
97private:
98 bool isSubmodule_;
99 bool isDefaultPrivate_{false};
100 const Scope *scope_{nullptr};
101 std::optional<ModuleCheckSumType> moduleFileHash_;
102 const Symbol *previous_{nullptr}; // same name, different module file hash
103};
104
105class MainProgramDetails : public WithOmpDeclarative {
106public:
107private:
108};
109
110class WithBindName {
111public:
112 const std::string *bindName() const {
113 return bindName_ ? &*bindName_ : nullptr;
114 }
115 bool isExplicitBindName() const { return isExplicitBindName_; }
116 void set_bindName(std::string &&name) { bindName_ = std::move(name); }
117 void set_isExplicitBindName(bool yes) { isExplicitBindName_ = yes; }
118
119private:
120 std::optional<std::string> bindName_;
121 bool isExplicitBindName_{false};
122};
123
124// Device type specific OpenACC routine information
125class OpenACCRoutineDeviceTypeInfo {
126public:
127 bool isSeq() const { return isSeq_; }
128 void set_isSeq(bool value = true) { isSeq_ = value; }
129 bool isVector() const { return isVector_; }
130 void set_isVector(bool value = true) { isVector_ = value; }
131 bool isWorker() const { return isWorker_; }
132 void set_isWorker(bool value = true) { isWorker_ = value; }
133 bool isGang() const { return isGang_; }
134 void set_isGang(bool value = true) { isGang_ = value; }
135 unsigned gangDim() const { return gangDim_; }
136 void set_gangDim(unsigned value) { gangDim_ = value; }
137 const std::string *bindName() const {
138 return bindName_ ? &*bindName_ : nullptr;
139 }
140 void set_bindName(std::string &&name) { bindName_ = std::move(name); }
141 void set_dType(Fortran::common::OpenACCDeviceType dType) {
142 deviceType_ = dType;
143 }
144 Fortran::common::OpenACCDeviceType dType() const { return deviceType_; }
145
146private:
147 bool isSeq_{false};
148 bool isVector_{false};
149 bool isWorker_{false};
150 bool isGang_{false};
151 unsigned gangDim_{0};
152 std::optional<std::string> bindName_;
153 Fortran::common::OpenACCDeviceType deviceType_{
154 Fortran::common::OpenACCDeviceType::None};
155};
156
157// OpenACC routine information. Device independent info are stored on the
158// OpenACCRoutineInfo instance while device dependent info are stored
159// in as objects in the OpenACCRoutineDeviceTypeInfo list.
160class OpenACCRoutineInfo : public OpenACCRoutineDeviceTypeInfo {
161public:
162 bool isNohost() const { return isNohost_; }
163 void set_isNohost(bool value = true) { isNohost_ = value; }
164 std::list<OpenACCRoutineDeviceTypeInfo> &deviceTypeInfos() {
165 return deviceTypeInfos_;
166 }
167 void add_deviceTypeInfo(OpenACCRoutineDeviceTypeInfo &info) {
168 deviceTypeInfos_.push_back(info);
169 }
170
171private:
172 std::list<OpenACCRoutineDeviceTypeInfo> deviceTypeInfos_;
173 bool isNohost_{false};
174};
175
176// A subroutine or function definition, or a subprogram interface defined
177// in an INTERFACE block as part of the definition of a dummy procedure
178// or a procedure pointer (with just POINTER).
179class SubprogramDetails : public WithBindName, public WithOmpDeclarative {
180public:
181 bool isFunction() const { return result_ != nullptr; }
182 bool isInterface() const { return isInterface_; }
183 void set_isInterface(bool value = true) { isInterface_ = value; }
184 bool isDummy() const { return isDummy_; }
185 void set_isDummy(bool value = true) { isDummy_ = value; }
186 Scope *entryScope() { return entryScope_; }
187 const Scope *entryScope() const { return entryScope_; }
188 void set_entryScope(Scope &scope) { entryScope_ = &scope; }
189 const Symbol &result() const {
190 CHECK(isFunction());
191 return *result_;
192 }
193 void set_result(Symbol &result) {
194 CHECK(!result_);
195 result_ = &result;
196 }
197 const std::vector<Symbol *> &dummyArgs() const { return dummyArgs_; }
198 void add_dummyArg(Symbol &symbol) { dummyArgs_.push_back(&symbol); }
199 void add_alternateReturn() { dummyArgs_.push_back(nullptr); }
200 const MaybeExpr &stmtFunction() const { return stmtFunction_; }
201 void set_stmtFunction(SomeExpr &&expr) { stmtFunction_ = std::move(expr); }
202 Symbol *moduleInterface() { return moduleInterface_; }
203 const Symbol *moduleInterface() const { return moduleInterface_; }
204 void set_moduleInterface(Symbol &);
205 void ReplaceResult(Symbol &result) {
206 CHECK(result_ != nullptr);
207 result_ = &result;
208 }
209 bool defaultIgnoreTKR() const { return defaultIgnoreTKR_; }
210 void set_defaultIgnoreTKR(bool yes) { defaultIgnoreTKR_ = yes; }
211 std::optional<common::CUDASubprogramAttrs> cudaSubprogramAttrs() const {
212 return cudaSubprogramAttrs_;
213 }
214 void set_cudaSubprogramAttrs(common::CUDASubprogramAttrs csas) {
215 cudaSubprogramAttrs_ = csas;
216 }
217 std::vector<std::int64_t> &cudaLaunchBounds() { return cudaLaunchBounds_; }
218 const std::vector<std::int64_t> &cudaLaunchBounds() const {
219 return cudaLaunchBounds_;
220 }
221 void set_cudaLaunchBounds(std::vector<std::int64_t> &&x) {
222 cudaLaunchBounds_ = std::move(x);
223 }
224 std::vector<std::int64_t> &cudaClusterDims() { return cudaClusterDims_; }
225 const std::vector<std::int64_t> &cudaClusterDims() const {
226 return cudaClusterDims_;
227 }
228 void set_cudaClusterDims(std::vector<std::int64_t> &&x) {
229 cudaClusterDims_ = std::move(x);
230 }
231 const std::vector<OpenACCRoutineInfo> &openACCRoutineInfos() const {
232 return openACCRoutineInfos_;
233 }
234 void add_openACCRoutineInfo(OpenACCRoutineInfo info) {
235 openACCRoutineInfos_.push_back(info);
236 }
237
238private:
239 bool isInterface_{false}; // true if this represents an interface-body
240 bool isDummy_{false}; // true when interface of dummy procedure
241 std::vector<Symbol *> dummyArgs_; // nullptr -> alternate return indicator
242 Symbol *result_{nullptr};
243 Scope *entryScope_{nullptr}; // if ENTRY, points to subprogram's scope
244 MaybeExpr stmtFunction_;
245 // For MODULE FUNCTION or SUBROUTINE, this is the symbol of its declared
246 // interface. For MODULE PROCEDURE, this is the declared interface if it
247 // appeared in an ancestor (sub)module.
248 Symbol *moduleInterface_{nullptr};
249 bool defaultIgnoreTKR_{false};
250 // CUDA ATTRIBUTES(...) from subroutine/function prefix
251 std::optional<common::CUDASubprogramAttrs> cudaSubprogramAttrs_;
252 // CUDA LAUNCH_BOUNDS(...) & CLUSTER_DIMS(...) from prefix
253 std::vector<std::int64_t> cudaLaunchBounds_, cudaClusterDims_;
254 // OpenACC routine information
255 std::vector<OpenACCRoutineInfo> openACCRoutineInfos_;
256
257 friend llvm::raw_ostream &operator<<(
258 llvm::raw_ostream &, const SubprogramDetails &);
259};
260
261// For SubprogramNameDetails, the kind indicates whether it is the name
262// of a module subprogram or an internal subprogram or ENTRY.
263ENUM_CLASS(SubprogramKind, Module, Internal)
264
265// Symbol with SubprogramNameDetails is created when we scan for module and
266// internal procedure names, to record that there is a subprogram with this
267// name. Later they are replaced by SubprogramDetails with dummy and result
268// type information.
269class SubprogramNameDetails {
270public:
271 SubprogramNameDetails(SubprogramKind kind, ProgramTree &node)
272 : kind_{kind}, node_{node} {}
273 SubprogramNameDetails() = delete;
274 SubprogramKind kind() const { return kind_; }
275 ProgramTree &node() const { return *node_; }
276
277private:
278 SubprogramKind kind_;
279 common::Reference<ProgramTree> node_;
280};
281
282// A name from an entity-decl -- could be object or function.
283class EntityDetails : public WithBindName {
284public:
285 explicit EntityDetails(bool isDummy = false) : isDummy_{isDummy} {}
286 const DeclTypeSpec *type() const { return type_; }
287 void set_type(const DeclTypeSpec &);
288 void ReplaceType(const DeclTypeSpec &);
289 bool isDummy() const { return isDummy_; }
290 void set_isDummy(bool value = true) { isDummy_ = value; }
291 bool isFuncResult() const { return isFuncResult_; }
292 void set_funcResult(bool x) { isFuncResult_ = x; }
293
294private:
295 bool isDummy_{false};
296 bool isFuncResult_{false};
297 const DeclTypeSpec *type_{nullptr};
298 friend llvm::raw_ostream &operator<<(
299 llvm::raw_ostream &, const EntityDetails &);
300};
301
302// Symbol is associated with a name or expression in an ASSOCIATE,
303// SELECT TYPE, or SELECT RANK construct.
304class AssocEntityDetails : public EntityDetails {
305public:
306 AssocEntityDetails() {}
307 explicit AssocEntityDetails(SomeExpr &&expr) : expr_{std::move(expr)} {}
308 AssocEntityDetails(const AssocEntityDetails &) = default;
309 AssocEntityDetails(AssocEntityDetails &&) = default;
310 AssocEntityDetails &operator=(const AssocEntityDetails &) = default;
311 AssocEntityDetails &operator=(AssocEntityDetails &&) = default;
312 const MaybeExpr &expr() const { return expr_; }
313
314 // SELECT RANK's rank cases will return a populated result for
315 // RANK(n) and RANK(*), and IsAssumedRank() will be true for
316 // RANK DEFAULT.
317 std::optional<int> rank() const {
318 int r{rank_.value_or(0)};
319 if (r == isAssumedSize) {
320 return 1; // RANK(*)
321 } else if (r == isAssumedRank) {
322 return std::nullopt; // RANK DEFAULT
323 } else {
324 return rank_;
325 }
326 }
327 bool IsAssumedSize() const { return rank_.value_or(0) == isAssumedSize; }
328 bool IsAssumedRank() const { return rank_.value_or(0) == isAssumedRank; }
329 void set_rank(int rank);
330 void set_IsAssumedSize();
331 void set_IsAssumedRank();
332
333private:
334 MaybeExpr expr_;
335 // Populated for SELECT RANK with rank (n>=0) for RANK(n),
336 // isAssumedSize for RANK(*), or isAssumedRank for RANK DEFAULT.
337 static constexpr int isAssumedSize{-1}; // RANK(*)
338 static constexpr int isAssumedRank{-2}; // RANK DEFAULT
339 std::optional<int> rank_;
340};
341llvm::raw_ostream &operator<<(llvm::raw_ostream &, const AssocEntityDetails &);
342
343// An entity known to be an object.
344class ObjectEntityDetails : public EntityDetails {
345public:
346 explicit ObjectEntityDetails(EntityDetails &&);
347 ObjectEntityDetails(const ObjectEntityDetails &) = default;
348 ObjectEntityDetails(ObjectEntityDetails &&) = default;
349 ObjectEntityDetails &operator=(const ObjectEntityDetails &) = default;
350 ObjectEntityDetails(bool isDummy = false) : EntityDetails(isDummy) {}
351 MaybeExpr &init() { return init_; }
352 const MaybeExpr &init() const { return init_; }
353 void set_init(MaybeExpr &&expr) { init_ = std::move(expr); }
354 const parser::Expr *unanalyzedPDTComponentInit() const {
355 return unanalyzedPDTComponentInit_;
356 }
357 void set_unanalyzedPDTComponentInit(const parser::Expr *expr) {
358 unanalyzedPDTComponentInit_ = expr;
359 }
360 ArraySpec &shape() { return shape_; }
361 const ArraySpec &shape() const { return shape_; }
362 ArraySpec &coshape() { return coshape_; }
363 const ArraySpec &coshape() const { return coshape_; }
364 void set_shape(const ArraySpec &);
365 void set_coshape(const ArraySpec &);
366 const Symbol *commonBlock() const { return commonBlock_; }
367 void set_commonBlock(const Symbol &commonBlock) {
368 commonBlock_ = &commonBlock;
369 }
370 common::IgnoreTKRSet ignoreTKR() const { return ignoreTKR_; }
371 void set_ignoreTKR(common::IgnoreTKRSet set) { ignoreTKR_ = set; }
372 bool IsArray() const { return !shape_.empty(); }
373 bool IsCoarray() const { return !coshape_.empty(); }
374 bool IsAssumedShape() const {
375 return isDummy() && shape_.CanBeAssumedShape();
376 }
377 bool CanBeDeferredShape() const { return shape_.CanBeDeferredShape(); }
378 bool IsAssumedRank() const { return isDummy() && shape_.IsAssumedRank(); }
379 std::optional<common::CUDADataAttr> cudaDataAttr() const {
380 return cudaDataAttr_;
381 }
382 void set_cudaDataAttr(std::optional<common::CUDADataAttr> attr) {
383 cudaDataAttr_ = attr;
384 }
385
386private:
387 MaybeExpr init_;
388 const parser::Expr *unanalyzedPDTComponentInit_{nullptr};
389 ArraySpec shape_;
390 ArraySpec coshape_;
391 common::IgnoreTKRSet ignoreTKR_;
392 const Symbol *commonBlock_{nullptr}; // common block this object is in
393 std::optional<common::CUDADataAttr> cudaDataAttr_;
394 friend llvm::raw_ostream &operator<<(
395 llvm::raw_ostream &, const ObjectEntityDetails &);
396};
397
398// Mixin for details with passed-object dummy argument.
399// If a procedure pointer component or type-bound procedure does not have
400// the NOPASS attribute on its symbol, then PASS is assumed; the name
401// is optional; if it is missing, the first dummy argument of the procedure's
402// interface is the passed-object dummy argument.
403class WithPassArg {
404public:
405 std::optional<SourceName> passName() const { return passName_; }
406 void set_passName(const SourceName &passName) { passName_ = passName; }
407
408private:
409 std::optional<SourceName> passName_;
410};
411
412// A procedure pointer (other than one defined with POINTER and an
413// INTERFACE block), a dummy procedure (without an INTERFACE but with
414// EXTERNAL or use in a procedure reference), or external procedure.
415class ProcEntityDetails : public EntityDetails, public WithPassArg {
416public:
417 ProcEntityDetails() = default;
418 explicit ProcEntityDetails(EntityDetails &&);
419 ProcEntityDetails(const ProcEntityDetails &) = default;
420 ProcEntityDetails(ProcEntityDetails &&) = default;
421 ProcEntityDetails &operator=(const ProcEntityDetails &) = default;
422
423 const Symbol *rawProcInterface() const { return rawProcInterface_; }
424 const Symbol *procInterface() const { return procInterface_; }
425 void set_procInterfaces(const Symbol &raw, const Symbol &resolved) {
426 rawProcInterface_ = &raw;
427 procInterface_ = &resolved;
428 }
429 inline bool HasExplicitInterface() const;
430
431 // Be advised: !init().has_value() => uninitialized pointer,
432 // while *init() == nullptr => explicit NULL() initialization.
433 std::optional<const Symbol *> init() const { return init_; }
434 void set_init(const Symbol &symbol) { init_ = &symbol; }
435 void set_init(std::nullptr_t) { init_ = nullptr; }
436 bool isCUDAKernel() const { return isCUDAKernel_; }
437 void set_isCUDAKernel(bool yes = true) { isCUDAKernel_ = yes; }
438 std::optional<SourceName> usedAsProcedureHere() const {
439 return usedAsProcedureHere_;
440 }
441 void set_usedAsProcedureHere(SourceName here) { usedAsProcedureHere_ = here; }
442
443private:
444 const Symbol *rawProcInterface_{nullptr};
445 const Symbol *procInterface_{nullptr};
446 std::optional<const Symbol *> init_;
447 bool isCUDAKernel_{false};
448 std::optional<SourceName> usedAsProcedureHere_;
449 friend llvm::raw_ostream &operator<<(
450 llvm::raw_ostream &, const ProcEntityDetails &);
451};
452
453// These derived type details represent the characteristics of a derived
454// type definition that are shared by all instantiations of that type.
455// The DerivedTypeSpec instances whose type symbols share these details
456// each own a scope into which the components' symbols have been cloned
457// and specialized for each distinct set of type parameter values.
458class DerivedTypeDetails {
459public:
460 const std::list<SourceName> &paramNames() const { return paramNames_; }
461 const SymbolVector &paramDecls() const { return paramDecls_; }
462 bool sequence() const { return sequence_; }
463 bool isDECStructure() const { return isDECStructure_; }
464 std::map<SourceName, SymbolRef> &finals() { return finals_; }
465 const std::map<SourceName, SymbolRef> &finals() const { return finals_; }
466 bool isForwardReferenced() const { return isForwardReferenced_; }
467 void add_paramName(const SourceName &name) { paramNames_.push_back(name); }
468 void add_paramDecl(const Symbol &symbol) { paramDecls_.push_back(symbol); }
469 void add_component(const Symbol &);
470 void set_sequence(bool x = true) { sequence_ = x; }
471 void set_isDECStructure(bool x = true) { isDECStructure_ = x; }
472 void set_isForwardReferenced(bool value) { isForwardReferenced_ = value; }
473 const std::list<SourceName> &componentNames() const {
474 return componentNames_;
475 }
476
477 // If this derived type extends another, locate the parent component's symbol.
478 const Symbol *GetParentComponent(const Scope &) const;
479
480 std::optional<SourceName> GetParentComponentName() const {
481 if (componentNames_.empty()) {
482 return std::nullopt;
483 } else {
484 return componentNames_.front();
485 }
486 }
487
488 const Symbol *GetFinalForRank(int) const;
489
490private:
491 // These are (1) the names of the derived type parameters in the order
492 // in which they appear on the type definition statement(s), and (2) the
493 // symbols that correspond to those names in the order in which their
494 // declarations appear in the derived type definition(s).
495 std::list<SourceName> paramNames_;
496 SymbolVector paramDecls_;
497 // These are the names of the derived type's components in component
498 // order. A parent component, if any, appears first in this list.
499 std::list<SourceName> componentNames_;
500 std::map<SourceName, SymbolRef> finals_; // FINAL :: subr
501 bool sequence_{false};
502 bool isDECStructure_{false};
503 bool isForwardReferenced_{false};
504 friend llvm::raw_ostream &operator<<(
505 llvm::raw_ostream &, const DerivedTypeDetails &);
506};
507
508class ProcBindingDetails : public WithPassArg {
509public:
510 explicit ProcBindingDetails(const Symbol &symbol) : symbol_{symbol} {}
511 const Symbol &symbol() const { return symbol_; }
512 void ReplaceSymbol(const Symbol &symbol) { symbol_ = symbol; }
513 int numPrivatesNotOverridden() const { return numPrivatesNotOverridden_; }
514 void set_numPrivatesNotOverridden(int n) { numPrivatesNotOverridden_ = n; }
515
516private:
517 SymbolRef symbol_; // procedure bound to; may be forward
518 // Homonymous private bindings in ancestor types from other modules
519 int numPrivatesNotOverridden_{0};
520};
521
522class NamelistDetails {
523public:
524 const SymbolVector &objects() const { return objects_; }
525 void add_object(const Symbol &object) { objects_.push_back(object); }
526 void add_objects(const SymbolVector &objects) {
527 objects_.insert(objects_.end(), objects.begin(), objects.end());
528 }
529
530private:
531 SymbolVector objects_;
532};
533
534class CommonBlockDetails : public WithBindName {
535public:
536 MutableSymbolVector &objects() { return objects_; }
537 const MutableSymbolVector &objects() const { return objects_; }
538 void add_object(Symbol &object) { objects_.emplace_back(object); }
539 void replace_object(Symbol &object, unsigned index) {
540 CHECK(index < (unsigned)objects_.size());
541 objects_[index] = object;
542 }
543 std::size_t alignment() const { return alignment_; }
544 void set_alignment(std::size_t alignment) { alignment_ = alignment; }
545
546private:
547 MutableSymbolVector objects_;
548 std::size_t alignment_{0}; // required alignment in bytes
549};
550
551class MiscDetails {
552public:
553 ENUM_CLASS(Kind, None, ConstructName, ScopeName, PassName, ComplexPartRe,
554 ComplexPartIm, KindParamInquiry, LenParamInquiry, SelectRankAssociateName,
555 SelectTypeAssociateName, TypeBoundDefinedOp);
556 MiscDetails(Kind kind) : kind_{kind} {}
557 Kind kind() const { return kind_; }
558
559private:
560 Kind kind_;
561};
562
563class TypeParamDetails {
564public:
565 explicit TypeParamDetails(common::TypeParamAttr attr) : attr_{attr} {}
566 TypeParamDetails(const TypeParamDetails &) = default;
567 common::TypeParamAttr attr() const { return attr_; }
568 MaybeIntExpr &init() { return init_; }
569 const MaybeIntExpr &init() const { return init_; }
570 void set_init(MaybeIntExpr &&expr) { init_ = std::move(expr); }
571 const DeclTypeSpec *type() const { return type_; }
572 void set_type(const DeclTypeSpec &);
573 void ReplaceType(const DeclTypeSpec &);
574
575private:
576 common::TypeParamAttr attr_;
577 MaybeIntExpr init_;
578 const DeclTypeSpec *type_{nullptr};
579};
580
581// Record the USE of a symbol: location is where (USE statement or renaming);
582// symbol is in the USEd module.
583class UseDetails {
584public:
585 UseDetails(const SourceName &location, const Symbol &symbol)
586 : location_{location}, symbol_{symbol} {}
587 const SourceName &location() const { return location_; }
588 const Symbol &symbol() const { return symbol_; }
589
590private:
591 SourceName location_;
592 SymbolRef symbol_;
593};
594
595// A symbol with ambiguous use-associations. Record where they were so
596// we can report the error if it is used.
597class UseErrorDetails {
598public:
599 UseErrorDetails(const UseDetails &);
600 UseErrorDetails &add_occurrence(const SourceName &, const Scope &);
601 using listType = std::list<std::pair<SourceName, const Scope *>>;
602 const listType occurrences() const { return occurrences_; };
603
604private:
605 listType occurrences_;
606};
607
608// A symbol host-associated from an enclosing scope.
609class HostAssocDetails {
610public:
611 HostAssocDetails(const Symbol &symbol) : symbol_{symbol} {}
612 const Symbol &symbol() const { return symbol_; }
613 bool implicitOrSpecExprError{false};
614 bool implicitOrExplicitTypeError{false};
615
616private:
617 SymbolRef symbol_;
618};
619
620// A GenericKind is one of: generic name, defined operator,
621// defined assignment, intrinsic operator, or defined I/O.
622struct GenericKind {
623 ENUM_CLASS(OtherKind, Name, DefinedOp, Assignment, Concat)
624 GenericKind() : u{OtherKind::Name} {}
625 template <typename T> GenericKind(const T &x) { u = x; }
626 bool IsName() const { return Is(OtherKind::Name); }
627 bool IsAssignment() const { return Is(OtherKind::Assignment); }
628 bool IsDefinedOperator() const { return Is(OtherKind::DefinedOp); }
629 bool IsIntrinsicOperator() const;
630 bool IsOperator() const;
631 std::string ToString() const;
632 static SourceName AsFortran(common::DefinedIo);
633 std::variant<OtherKind, common::NumericOperator, common::LogicalOperator,
634 common::RelationalOperator, common::DefinedIo>
635 u;
636
637private:
638 template <typename T> bool Has() const {
639 return std::holds_alternative<T>(u);
640 }
641 bool Is(OtherKind) const;
642};
643
644// A generic interface or type-bound generic.
645class GenericDetails {
646public:
647 GenericDetails() {}
648
649 GenericKind kind() const { return kind_; }
650 void set_kind(GenericKind kind) { kind_ = kind; }
651
652 const SymbolVector &specificProcs() const { return specificProcs_; }
653 const std::vector<SourceName> &bindingNames() const { return bindingNames_; }
654 void AddSpecificProc(const Symbol &, SourceName bindingName);
655 const SymbolVector &uses() const { return uses_; }
656
657 // specific and derivedType indicate a specific procedure or derived type
658 // with the same name as this generic. Only one of them may be set in
659 // a scope that declares them, but both can be set during USE association
660 // when generics are combined.
661 Symbol *specific() { return specific_; }
662 const Symbol *specific() const { return specific_; }
663 void set_specific(Symbol &specific);
664 void clear_specific();
665 Symbol *derivedType() { return derivedType_; }
666 const Symbol *derivedType() const { return derivedType_; }
667 void set_derivedType(Symbol &derivedType);
668 void clear_derivedType();
669 void AddUse(const Symbol &);
670
671 // Copy in specificProcs, specific, and derivedType from another generic
672 void CopyFrom(const GenericDetails &);
673
674 // Check that specific is one of the specificProcs. If not, return the
675 // specific as a raw pointer.
676 const Symbol *CheckSpecific() const;
677 Symbol *CheckSpecific();
678
679private:
680 GenericKind kind_;
681 // all of the specific procedures for this generic
682 SymbolVector specificProcs_;
683 std::vector<SourceName> bindingNames_;
684 // Symbols used from other modules merged into this one
685 SymbolVector uses_;
686 // a specific procedure with the same name as this generic, if any
687 Symbol *specific_{nullptr};
688 // a derived type with the same name as this generic, if any
689 Symbol *derivedType_{nullptr};
690};
691llvm::raw_ostream &operator<<(llvm::raw_ostream &, const GenericDetails &);
692
693class UnknownDetails {};
694
695using Details = std::variant<UnknownDetails, MainProgramDetails, ModuleDetails,
696 SubprogramDetails, SubprogramNameDetails, EntityDetails,
697 ObjectEntityDetails, ProcEntityDetails, AssocEntityDetails,
698 DerivedTypeDetails, UseDetails, UseErrorDetails, HostAssocDetails,
699 GenericDetails, ProcBindingDetails, NamelistDetails, CommonBlockDetails,
700 TypeParamDetails, MiscDetails>;
701llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Details &);
702std::string DetailsToString(const Details &);
703
704class Symbol {
705public:
706 ENUM_CLASS(Flag,
707 Function, // symbol is a function or statement function
708 Subroutine, // symbol is a subroutine
709 StmtFunction, // symbol is a statement function or result
710 Implicit, // symbol is implicitly typed
711 ImplicitOrError, // symbol must be implicitly typed or it's an error
712 ModFile, // symbol came from .mod file
713 ParentComp, // symbol is the "parent component" of an extended type
714 CrayPointer, CrayPointee,
715 LocalityLocal, // named in LOCAL locality-spec
716 LocalityLocalInit, // named in LOCAL_INIT locality-spec
717 LocalityShared, // named in SHARED locality-spec
718 InDataStmt, // initialized in a DATA statement, =>object, or /init/
719 InNamelist, // in a Namelist group
720 EntryDummyArgument,
721 CompilerCreated, // A compiler created symbol
722 // For compiler created symbols that are constant but cannot legally have
723 // the PARAMETER attribute.
724 ReadOnly,
725 // OpenACC data-sharing attribute
726 AccPrivate, AccFirstPrivate, AccShared,
727 // OpenACC data-mapping attribute
728 AccCopy, AccCopyIn, AccCopyInReadOnly, AccCopyOut, AccCreate, AccDelete,
729 AccPresent, AccLink, AccDeviceResident, AccDevicePtr,
730 // OpenACC declare
731 AccDeclare,
732 // OpenACC data-movement attribute
733 AccDevice, AccHost, AccSelf,
734 // OpenACC miscellaneous flags
735 AccCommonBlock, AccThreadPrivate, AccReduction, AccNone, AccPreDetermined,
736 // OpenMP data-sharing attribute
737 OmpShared, OmpPrivate, OmpLinear, OmpFirstPrivate, OmpLastPrivate,
738 // OpenMP data-mapping attribute
739 OmpMapTo, OmpMapFrom, OmpMapToFrom, OmpMapAlloc, OmpMapRelease,
740 OmpMapDelete, OmpUseDevicePtr, OmpUseDeviceAddr, OmpIsDevicePtr,
741 OmpHasDeviceAddr,
742 // OpenMP data-copying attribute
743 OmpCopyIn, OmpCopyPrivate,
744 // OpenMP miscellaneous flags
745 OmpCommonBlock, OmpReduction, OmpAligned, OmpNontemporal, OmpAllocate,
746 OmpDeclarativeAllocateDirective, OmpExecutableAllocateDirective,
747 OmpDeclareSimd, OmpDeclareTarget, OmpThreadprivate, OmpDeclareReduction,
748 OmpFlushed, OmpCriticalLock, OmpIfSpecified, OmpNone, OmpPreDetermined);
749 using Flags = common::EnumSet<Flag, Flag_enumSize>;
750
751 const Scope &owner() const { return *owner_; }
752 const SourceName &name() const { return name_; }
753 Attrs &attrs() { return attrs_; }
754 const Attrs &attrs() const { return attrs_; }
755 Attrs &implicitAttrs() { return implicitAttrs_; }
756 const Attrs &implicitAttrs() const { return implicitAttrs_; }
757 Flags &flags() { return flags_; }
758 const Flags &flags() const { return flags_; }
759 bool test(Flag flag) const { return flags_.test(flag); }
760 void set(Flag flag, bool value = true) { flags_.set(flag, value); }
761 // The Scope introduced by this symbol, if any.
762 Scope *scope() { return scope_; }
763 const Scope *scope() const { return scope_; }
764 void set_scope(Scope *scope) { scope_ = scope; }
765 std::size_t size() const { return size_; }
766 void set_size(std::size_t size) { size_ = size; }
767 std::size_t offset() const { return offset_; }
768 void set_offset(std::size_t offset) { offset_ = offset; }
769 // Give the symbol a name with a different source location but same chars.
770 void ReplaceName(const SourceName &);
771 std::string OmpFlagToClauseName(Flag ompFlag);
772
773 // Does symbol have this type of details?
774 template <typename D> bool has() const {
775 return std::holds_alternative<D>(details_);
776 }
777
778 // Return a non-owning pointer to details if it is type D, else nullptr.
779 template <typename D> D *detailsIf() { return std::get_if<D>(&details_); }
780 template <typename D> const D *detailsIf() const {
781 return std::get_if<D>(&details_);
782 }
783
784 // Return a reference to the details which must be of type D.
785 template <typename D> D &get() {
786 return const_cast<D &>(const_cast<const Symbol *>(this)->get<D>());
787 }
788 template <typename D> const D &get() const {
789 const auto *p{detailsIf<D>()};
790 CHECK(p);
791 return *p;
792 }
793
794 Details &details() { return details_; }
795 const Details &details() const { return details_; }
796 // Assign the details of the symbol from one of the variants.
797 // Only allowed in certain cases.
798 void set_details(Details &&);
799
800 // Can the details of this symbol be replaced with the given details?
801 bool CanReplaceDetails(const Details &details) const;
802
803 // Follow use-associations and host-associations to get the ultimate entity.
804 inline Symbol &GetUltimate();
805 inline const Symbol &GetUltimate() const;
806
807 inline DeclTypeSpec *GetType();
808 inline const DeclTypeSpec *GetType() const;
809 void SetType(const DeclTypeSpec &);
810
811 const std::string *GetBindName() const;
812 void SetBindName(std::string &&);
813 bool GetIsExplicitBindName() const;
814 void SetIsExplicitBindName(bool);
815 bool IsFuncResult() const;
816 bool IsObjectArray() const;
817 bool IsSubprogram() const;
818 bool IsFromModFile() const;
819 bool HasExplicitInterface() const {
820 return common::visit(
821 common::visitors{
822 [](const SubprogramDetails &) { return true; },
823 [](const SubprogramNameDetails &) { return true; },
824 [&](const ProcEntityDetails &x) {
825 return attrs_.test(Attr::INTRINSIC) || x.HasExplicitInterface();
826 },
827 [](const ProcBindingDetails &x) {
828 return x.symbol().HasExplicitInterface();
829 },
830 [](const UseDetails &x) {
831 return x.symbol().HasExplicitInterface();
832 },
833 [](const HostAssocDetails &x) {
834 return x.symbol().HasExplicitInterface();
835 },
836 [](const GenericDetails &x) {
837 return x.specific() && x.specific()->HasExplicitInterface();
838 },
839 [](const auto &) { return false; },
840 },
841 details_);
842 }
843 bool HasLocalLocality() const {
844 return test(Flag::LocalityLocal) || test(Flag::LocalityLocalInit);
845 }
846
847 bool operator==(const Symbol &that) const { return this == &that; }
848 bool operator!=(const Symbol &that) const { return !(*this == that); }
849
850 int Rank() const { return RankImpl(); }
851
852 int Corank() const {
853 return common::visit(
854 common::visitors{
855 [](const SubprogramDetails &sd) {
856 return sd.isFunction() ? sd.result().Corank() : 0;
857 },
858 [](const GenericDetails &) {
859 return 0; /*TODO*/
860 },
861 [](const UseDetails &x) { return x.symbol().Corank(); },
862 [](const HostAssocDetails &x) { return x.symbol().Corank(); },
863 [](const ObjectEntityDetails &oed) { return oed.coshape().Rank(); },
864 [](const auto &) { return 0; },
865 },
866 details_);
867 }
868
869 // If there is a parent component, return a pointer to its derived type spec.
870 // The Scope * argument defaults to this->scope_ but should be overridden
871 // for a parameterized derived type instantiation with the instance's scope.
872 const DerivedTypeSpec *GetParentTypeSpec(const Scope * = nullptr) const;
873
874 // If a derived type's symbol refers to an extended derived type,
875 // return the parent component's symbol. The scope of the derived type
876 // can be overridden.
877 const Symbol *GetParentComponent(const Scope * = nullptr) const;
878
879 SemanticsContext &GetSemanticsContext() const;
880#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
881 LLVM_DUMP_METHOD void dump() const;
882#endif
883
884private:
885 const Scope *owner_;
886 SourceName name_;
887 Attrs attrs_;
888 Attrs implicitAttrs_; // subset of attrs_ that were not explicit
889 Flags flags_;
890 Scope *scope_{nullptr};
891 std::size_t size_{0}; // size in bytes
892 std::size_t offset_{0}; // byte offset in scope or common block
893 Details details_;
894
895 Symbol() {} // only created in class Symbols
896 std::string GetDetailsName() const;
897 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Symbol &);
898 friend llvm::raw_ostream &DumpForUnparse(
899 llvm::raw_ostream &, const Symbol &, bool);
900
901 static constexpr int startRecursionDepth{100};
902
903 inline const DeclTypeSpec *GetTypeImpl(int depth = startRecursionDepth) const;
904 inline int RankImpl(int depth = startRecursionDepth) const {
905 if (depth-- == 0) {
906 return 0;
907 }
908 return common::visit(
909 common::visitors{
910 [&](const SubprogramDetails &sd) {
911 return sd.isFunction() ? sd.result().RankImpl(depth) : 0;
912 },
913 [](const GenericDetails &) {
914 return 0; /*TODO*/
915 },
916 [&](const ProcBindingDetails &x) {
917 return x.symbol().RankImpl(depth);
918 },
919 [&](const UseDetails &x) { return x.symbol().RankImpl(depth); },
920 [&](const HostAssocDetails &x) {
921 return x.symbol().RankImpl(depth);
922 },
923 [](const ObjectEntityDetails &oed) { return oed.shape().Rank(); },
924 [&](const ProcEntityDetails &ped) {
925 const Symbol *iface{ped.procInterface()};
926 return iface ? iface->RankImpl(depth) : 0;
927 },
928 [](const AssocEntityDetails &aed) {
929 if (auto assocRank{aed.rank()}) {
930 // RANK(n) & RANK(*)
931 return *assocRank;
932 } else if (aed.IsAssumedRank()) {
933 // RANK DEFAULT
934 return 0;
935 } else if (const auto &expr{aed.expr()}) {
936 return expr->Rank();
937 } else {
938 return 0;
939 }
940 },
941 [](const auto &) { return 0; },
942 },
943 details_);
944 }
945 template <std::size_t> friend class Symbols;
946 template <class, std::size_t> friend class std::array;
947};
948
949llvm::raw_ostream &operator<<(llvm::raw_ostream &, Symbol::Flag);
950
951// Manage memory for all symbols. BLOCK_SIZE symbols at a time are allocated.
952// Make() returns a reference to the next available one. They are never
953// deleted.
954template <std::size_t BLOCK_SIZE> class Symbols {
955public:
956 Symbol &Make(const Scope &owner, const SourceName &name, const Attrs &attrs,
957 Details &&details) {
958 Symbol &symbol = Get();
959 symbol.owner_ = &owner;
960 symbol.name_ = name;
961 symbol.attrs_ = attrs;
962 symbol.details_ = std::move(details);
963 return symbol;
964 }
965
966private:
967 using blockType = std::array<Symbol, BLOCK_SIZE>;
968 std::list<blockType *> blocks_;
969 std::size_t nextIndex_{0};
970 blockType *currBlock_{nullptr};
971
972 Symbol &Get() {
973 if (nextIndex_ == 0) {
974 blocks_.push_back(new blockType());
975 currBlock_ = blocks_.back();
976 }
977 Symbol &result = (*currBlock_)[nextIndex_];
978 if (++nextIndex_ >= BLOCK_SIZE) {
979 nextIndex_ = 0; // allocate a new block next time
980 }
981 return result;
982 }
983};
984
985// Define a few member functions here in the header so that they
986// can be used by lib/Evaluate without inducing a dependence cycle
987// between the two shared libraries.
988
989inline bool ProcEntityDetails::HasExplicitInterface() const {
990 return procInterface_ && procInterface_->HasExplicitInterface();
991}
992
993inline Symbol &Symbol::GetUltimate() {
994 return const_cast<Symbol &>(const_cast<const Symbol *>(this)->GetUltimate());
995}
996inline const Symbol &Symbol::GetUltimate() const {
997 if (const auto *details{detailsIf<UseDetails>()}) {
998 return details->symbol().GetUltimate();
999 } else if (const auto *details{detailsIf<HostAssocDetails>()}) {
1000 return details->symbol().GetUltimate();
1001 } else {
1002 return *this;
1003 }
1004}
1005
1006inline DeclTypeSpec *Symbol::GetType() {
1007 return const_cast<DeclTypeSpec *>(
1008 const_cast<const Symbol *>(this)->GetType());
1009}
1010
1011inline const DeclTypeSpec *Symbol::GetTypeImpl(int depth) const {
1012 if (depth-- == 0) {
1013 return nullptr;
1014 }
1015 return common::visit(
1016 common::visitors{
1017 [](const EntityDetails &x) { return x.type(); },
1018 [](const ObjectEntityDetails &x) { return x.type(); },
1019 [](const AssocEntityDetails &x) { return x.type(); },
1020 [&](const SubprogramDetails &x) {
1021 return x.isFunction() ? x.result().GetTypeImpl(depth) : nullptr;
1022 },
1023 [&](const ProcEntityDetails &x) {
1024 const Symbol *symbol{x.procInterface()};
1025 return symbol ? symbol->GetTypeImpl(depth) : x.type();
1026 },
1027 [&](const ProcBindingDetails &x) {
1028 return x.symbol().GetTypeImpl(depth);
1029 },
1030 [](const TypeParamDetails &x) { return x.type(); },
1031 [&](const UseDetails &x) { return x.symbol().GetTypeImpl(depth); },
1032 [&](const HostAssocDetails &x) {
1033 return x.symbol().GetTypeImpl(depth);
1034 },
1035 [](const auto &) -> const DeclTypeSpec * { return nullptr; },
1036 },
1037 details_);
1038}
1039
1040inline const DeclTypeSpec *Symbol::GetType() const { return GetTypeImpl(); }
1041
1042// Sets and maps keyed by Symbols
1043
1044struct SymbolAddressCompare {
1045 bool operator()(const SymbolRef &x, const SymbolRef &y) const {
1046 return &*x < &*y;
1047 }
1048 bool operator()(const MutableSymbolRef &x, const MutableSymbolRef &y) const {
1049 return &*x < &*y;
1050 }
1051};
1052
1053// Symbol comparison is usually based on the order of cooked source
1054// stream creation and, when both are from the same cooked source,
1055// their positions in that cooked source stream.
1056// Don't use this comparator or SourceOrderedSymbolSet to hold
1057// Symbols that might be subject to ReplaceName().
1058struct SymbolSourcePositionCompare {
1059 // These functions are implemented in Evaluate/tools.cpp to
1060 // satisfy complicated shared library interdependency.
1061 bool operator()(const SymbolRef &, const SymbolRef &) const;
1062 bool operator()(const MutableSymbolRef &, const MutableSymbolRef &) const;
1063};
1064
1065struct SymbolOffsetCompare {
1066 bool operator()(const SymbolRef &, const SymbolRef &) const;
1067 bool operator()(const MutableSymbolRef &, const MutableSymbolRef &) const;
1068};
1069
1070using UnorderedSymbolSet = std::set<SymbolRef, SymbolAddressCompare>;
1071using SourceOrderedSymbolSet = std::set<SymbolRef, SymbolSourcePositionCompare>;
1072
1073template <typename A>
1074SourceOrderedSymbolSet OrderBySourcePosition(const A &container) {
1075 SourceOrderedSymbolSet result;
1076 for (SymbolRef x : container) {
1077 result.emplace(x);
1078 }
1079 return result;
1080}
1081
1082} // namespace Fortran::semantics
1083
1084// Define required info so that SymbolRef can be used inside llvm::DenseMap.
1085namespace llvm {
1086template <> struct DenseMapInfo<Fortran::semantics::SymbolRef> {
1087 static inline Fortran::semantics::SymbolRef getEmptyKey() {
1088 auto ptr = DenseMapInfo<const Fortran::semantics::Symbol *>::getEmptyKey();
1089 return *reinterpret_cast<Fortran::semantics::SymbolRef *>(&ptr);
1090 }
1091
1092 static inline Fortran::semantics::SymbolRef getTombstoneKey() {
1093 auto ptr =
1094 DenseMapInfo<const Fortran::semantics::Symbol *>::getTombstoneKey();
1095 return *reinterpret_cast<Fortran::semantics::SymbolRef *>(&ptr);
1096 }
1097
1098 static unsigned getHashValue(const Fortran::semantics::SymbolRef &sym) {
1099 return DenseMapInfo<const Fortran::semantics::Symbol *>::getHashValue(
1100 &sym.get());
1101 }
1102
1103 static bool isEqual(const Fortran::semantics::SymbolRef &LHS,
1104 const Fortran::semantics::SymbolRef &RHS) {
1105 return LHS == RHS;
1106 }
1107};
1108} // namespace llvm
1109#endif // FORTRAN_SEMANTICS_SYMBOL_H_
1110

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of flang/include/flang/Semantics/symbol.h