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 | |
27 | namespace llvm { |
28 | class raw_ostream; |
29 | } |
30 | namespace Fortran::parser { |
31 | struct Expr; |
32 | } |
33 | |
34 | namespace 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 | |
40 | class Scope; |
41 | class Symbol; |
42 | class ProgramTree; |
43 | |
44 | using SymbolRef = common::Reference<const Symbol>; |
45 | using SymbolVector = std::vector<SymbolRef>; |
46 | using MutableSymbolRef = common::Reference<Symbol>; |
47 | using MutableSymbolVector = std::vector<MutableSymbolRef>; |
48 | |
49 | // Mixin for details with OpenMP declarative constructs. |
50 | class WithOmpDeclarative { |
51 | using OmpAtomicOrderType = common::OmpAtomicDefaultMemOrderType; |
52 | |
53 | public: |
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 | |
74 | private: |
75 | std::optional<RequiresFlags> ompRequires_; |
76 | std::optional<OmpAtomicOrderType> ompAtomicDefaultMemOrder_; |
77 | }; |
78 | |
79 | // A module or submodule. |
80 | class ModuleDetails : public WithOmpDeclarative { |
81 | public: |
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 | |
97 | private: |
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 | |
105 | class MainProgramDetails : public WithOmpDeclarative { |
106 | public: |
107 | private: |
108 | }; |
109 | |
110 | class WithBindName { |
111 | public: |
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 | |
119 | private: |
120 | std::optional<std::string> bindName_; |
121 | bool isExplicitBindName_{false}; |
122 | }; |
123 | |
124 | // Device type specific OpenACC routine information |
125 | class OpenACCRoutineDeviceTypeInfo { |
126 | public: |
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 | |
146 | private: |
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. |
160 | class OpenACCRoutineInfo : public OpenACCRoutineDeviceTypeInfo { |
161 | public: |
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 | |
171 | private: |
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). |
179 | class SubprogramDetails : public WithBindName, public WithOmpDeclarative { |
180 | public: |
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 | |
238 | private: |
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. |
263 | ENUM_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. |
269 | class SubprogramNameDetails { |
270 | public: |
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 | |
277 | private: |
278 | SubprogramKind kind_; |
279 | common::Reference<ProgramTree> node_; |
280 | }; |
281 | |
282 | // A name from an entity-decl -- could be object or function. |
283 | class EntityDetails : public WithBindName { |
284 | public: |
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 | |
294 | private: |
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. |
304 | class AssocEntityDetails : public EntityDetails { |
305 | public: |
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 | |
333 | private: |
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 | }; |
341 | llvm::raw_ostream &operator<<(llvm::raw_ostream &, const AssocEntityDetails &); |
342 | |
343 | // An entity known to be an object. |
344 | class ObjectEntityDetails : public EntityDetails { |
345 | public: |
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 | |
386 | private: |
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. |
403 | class WithPassArg { |
404 | public: |
405 | std::optional<SourceName> passName() const { return passName_; } |
406 | void set_passName(const SourceName &passName) { passName_ = passName; } |
407 | |
408 | private: |
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. |
415 | class ProcEntityDetails : public EntityDetails, public WithPassArg { |
416 | public: |
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 | |
443 | private: |
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. |
458 | class DerivedTypeDetails { |
459 | public: |
460 | const std::list<SourceName> ¶mNames() const { return paramNames_; } |
461 | const SymbolVector ¶mDecls() 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 | |
490 | private: |
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 | |
508 | class ProcBindingDetails : public WithPassArg { |
509 | public: |
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 | |
516 | private: |
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 | |
522 | class NamelistDetails { |
523 | public: |
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 | |
530 | private: |
531 | SymbolVector objects_; |
532 | }; |
533 | |
534 | class CommonBlockDetails : public WithBindName { |
535 | public: |
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 | |
546 | private: |
547 | MutableSymbolVector objects_; |
548 | std::size_t alignment_{0}; // required alignment in bytes |
549 | }; |
550 | |
551 | class MiscDetails { |
552 | public: |
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 | |
559 | private: |
560 | Kind kind_; |
561 | }; |
562 | |
563 | class TypeParamDetails { |
564 | public: |
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 | |
575 | private: |
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. |
583 | class UseDetails { |
584 | public: |
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 | |
590 | private: |
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. |
597 | class UseErrorDetails { |
598 | public: |
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 | |
604 | private: |
605 | listType occurrences_; |
606 | }; |
607 | |
608 | // A symbol host-associated from an enclosing scope. |
609 | class HostAssocDetails { |
610 | public: |
611 | HostAssocDetails(const Symbol &symbol) : symbol_{symbol} {} |
612 | const Symbol &symbol() const { return symbol_; } |
613 | bool implicitOrSpecExprError{false}; |
614 | bool implicitOrExplicitTypeError{false}; |
615 | |
616 | private: |
617 | SymbolRef symbol_; |
618 | }; |
619 | |
620 | // A GenericKind is one of: generic name, defined operator, |
621 | // defined assignment, intrinsic operator, or defined I/O. |
622 | struct 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 | |
637 | private: |
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. |
645 | class GenericDetails { |
646 | public: |
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 | |
679 | private: |
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 | }; |
691 | llvm::raw_ostream &operator<<(llvm::raw_ostream &, const GenericDetails &); |
692 | |
693 | class UnknownDetails {}; |
694 | |
695 | using 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>; |
701 | llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Details &); |
702 | std::string DetailsToString(const Details &); |
703 | |
704 | class Symbol { |
705 | public: |
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 | |
884 | private: |
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 | |
949 | llvm::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. |
954 | template <std::size_t BLOCK_SIZE> class Symbols { |
955 | public: |
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 | |
966 | private: |
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 | |
989 | inline bool ProcEntityDetails::HasExplicitInterface() const { |
990 | return procInterface_ && procInterface_->HasExplicitInterface(); |
991 | } |
992 | |
993 | inline Symbol &Symbol::GetUltimate() { |
994 | return const_cast<Symbol &>(const_cast<const Symbol *>(this)->GetUltimate()); |
995 | } |
996 | inline 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 | |
1006 | inline DeclTypeSpec *Symbol::GetType() { |
1007 | return const_cast<DeclTypeSpec *>( |
1008 | const_cast<const Symbol *>(this)->GetType()); |
1009 | } |
1010 | |
1011 | inline 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 | |
1040 | inline const DeclTypeSpec *Symbol::GetType() const { return GetTypeImpl(); } |
1041 | |
1042 | // Sets and maps keyed by Symbols |
1043 | |
1044 | struct 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(). |
1058 | struct 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 | |
1065 | struct SymbolOffsetCompare { |
1066 | bool operator()(const SymbolRef &, const SymbolRef &) const; |
1067 | bool operator()(const MutableSymbolRef &, const MutableSymbolRef &) const; |
1068 | }; |
1069 | |
1070 | using UnorderedSymbolSet = std::set<SymbolRef, SymbolAddressCompare>; |
1071 | using SourceOrderedSymbolSet = std::set<SymbolRef, SymbolSourcePositionCompare>; |
1072 | |
1073 | template <typename A> |
1074 | SourceOrderedSymbolSet 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. |
1085 | namespace llvm { |
1086 | template <> 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.