1//===-- lib/Semantics/symbol.cpp ------------------------------------------===//
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#include "flang/Semantics/symbol.h"
10#include "flang/Common/idioms.h"
11#include "flang/Evaluate/expression.h"
12#include "flang/Semantics/scope.h"
13#include "flang/Semantics/semantics.h"
14#include "flang/Semantics/tools.h"
15#include "llvm/Support/raw_ostream.h"
16#include <cstring>
17#include <string>
18#include <type_traits>
19
20namespace Fortran::semantics {
21
22template <typename T>
23static void DumpOptional(llvm::raw_ostream &os, const char *label, const T &x) {
24 if (x) {
25 os << ' ' << label << ':' << *x;
26 }
27}
28template <typename T>
29static void DumpExpr(llvm::raw_ostream &os, const char *label,
30 const std::optional<evaluate::Expr<T>> &x) {
31 if (x) {
32 x->AsFortran(os << ' ' << label << ':');
33 }
34}
35
36static void DumpBool(llvm::raw_ostream &os, const char *label, bool x) {
37 if (x) {
38 os << ' ' << label;
39 }
40}
41
42static void DumpSymbolVector(llvm::raw_ostream &os, const SymbolVector &list) {
43 char sep{' '};
44 for (const Symbol &elem : list) {
45 os << sep << elem.name();
46 sep = ',';
47 }
48}
49
50static void DumpType(llvm::raw_ostream &os, const Symbol &symbol) {
51 if (const auto *type{symbol.GetType()}) {
52 os << *type << ' ';
53 }
54}
55static void DumpType(llvm::raw_ostream &os, const DeclTypeSpec *type) {
56 if (type) {
57 os << ' ' << *type;
58 }
59}
60
61template <typename T>
62static void DumpList(llvm::raw_ostream &os, const char *label, const T &list) {
63 if (!list.empty()) {
64 os << ' ' << label << ':';
65 char sep{' '};
66 for (const auto &elem : list) {
67 os << sep << elem;
68 sep = ',';
69 }
70 }
71}
72
73void SubprogramDetails::set_moduleInterface(Symbol &symbol) {
74 CHECK(!moduleInterface_);
75 moduleInterface_ = &symbol;
76}
77
78const Scope *ModuleDetails::parent() const {
79 return isSubmodule_ && scope_ ? &scope_->parent() : nullptr;
80}
81const Scope *ModuleDetails::ancestor() const {
82 return isSubmodule_ && scope_ ? FindModuleContaining(*scope_) : nullptr;
83}
84void ModuleDetails::set_scope(const Scope *scope) {
85 CHECK(!scope_);
86 bool scopeIsSubmodule{scope->parent().kind() == Scope::Kind::Module};
87 CHECK(isSubmodule_ == scopeIsSubmodule);
88 scope_ = scope;
89}
90
91llvm::raw_ostream &operator<<(
92 llvm::raw_ostream &os, const SubprogramDetails &x) {
93 DumpBool(os, "isInterface", x.isInterface_);
94 DumpBool(os, "dummy", x.isDummy_);
95 DumpOptional(os, "bindName", x.bindName());
96 if (x.result_) {
97 DumpType(os << " result:", x.result());
98 os << x.result_->name();
99 if (!x.result_->attrs().empty()) {
100 os << ", " << x.result_->attrs();
101 }
102 }
103 if (x.entryScope_) {
104 os << " entry";
105 if (x.entryScope_->symbol()) {
106 os << " in " << x.entryScope_->symbol()->name();
107 }
108 }
109 char sep{'('};
110 os << ' ';
111 for (const Symbol *arg : x.dummyArgs_) {
112 os << sep;
113 sep = ',';
114 if (arg) {
115 DumpType(os, *arg);
116 os << arg->name();
117 } else {
118 os << '*';
119 }
120 }
121 os << (sep == '(' ? "()" : ")");
122 if (x.stmtFunction_) {
123 os << " -> " << x.stmtFunction_->AsFortran();
124 }
125 if (x.moduleInterface_) {
126 os << " moduleInterface: " << *x.moduleInterface_;
127 }
128 if (x.defaultIgnoreTKR_) {
129 os << " defaultIgnoreTKR";
130 }
131 if (x.cudaSubprogramAttrs_) {
132 os << " cudaSubprogramAttrs: "
133 << common::EnumToString(*x.cudaSubprogramAttrs_);
134 }
135 if (!x.cudaLaunchBounds_.empty()) {
136 os << " cudaLaunchBounds:";
137 for (auto x : x.cudaLaunchBounds_) {
138 os << ' ' << x;
139 }
140 }
141 if (!x.cudaClusterDims_.empty()) {
142 os << " cudaClusterDims:";
143 for (auto x : x.cudaClusterDims_) {
144 os << ' ' << x;
145 }
146 }
147 return os;
148}
149
150void EntityDetails::set_type(const DeclTypeSpec &type) {
151 CHECK(!type_);
152 type_ = &type;
153}
154
155void AssocEntityDetails::set_rank(int rank) { rank_ = rank; }
156void AssocEntityDetails::set_IsAssumedSize() { rank_ = isAssumedSize; }
157void AssocEntityDetails::set_IsAssumedRank() { rank_ = isAssumedRank; }
158void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; }
159
160ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d)
161 : EntityDetails(std::move(d)) {}
162
163void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
164 CHECK(shape_.empty());
165 for (const auto &shapeSpec : shape) {
166 shape_.push_back(shapeSpec);
167 }
168}
169void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) {
170 CHECK(coshape_.empty());
171 for (const auto &shapeSpec : coshape) {
172 coshape_.push_back(shapeSpec);
173 }
174}
175
176ProcEntityDetails::ProcEntityDetails(EntityDetails &&d)
177 : EntityDetails(std::move(d)) {}
178
179UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) {
180 add_occurrence(useDetails.location(), *GetUsedModule(useDetails).scope());
181}
182UseErrorDetails &UseErrorDetails::add_occurrence(
183 const SourceName &location, const Scope &module) {
184 occurrences_.push_back(std::make_pair(location, &module));
185 return *this;
186}
187
188void GenericDetails::AddSpecificProc(
189 const Symbol &proc, SourceName bindingName) {
190 specificProcs_.push_back(proc);
191 bindingNames_.push_back(bindingName);
192}
193void GenericDetails::set_specific(Symbol &specific) {
194 CHECK(!specific_);
195 specific_ = &specific;
196}
197void GenericDetails::clear_specific() { specific_ = nullptr; }
198void GenericDetails::set_derivedType(Symbol &derivedType) {
199 CHECK(!derivedType_);
200 derivedType_ = &derivedType;
201}
202void GenericDetails::clear_derivedType() { derivedType_ = nullptr; }
203void GenericDetails::AddUse(const Symbol &use) {
204 CHECK(use.has<UseDetails>());
205 uses_.push_back(use);
206}
207
208const Symbol *GenericDetails::CheckSpecific() const {
209 return const_cast<GenericDetails *>(this)->CheckSpecific();
210}
211Symbol *GenericDetails::CheckSpecific() {
212 if (specific_ && !specific_->has<UseErrorDetails>()) {
213 for (const Symbol &proc : specificProcs_) {
214 if (&proc == specific_) {
215 return nullptr;
216 }
217 }
218 return specific_;
219 } else {
220 return nullptr;
221 }
222}
223
224void GenericDetails::CopyFrom(const GenericDetails &from) {
225 CHECK(specificProcs_.size() == bindingNames_.size());
226 CHECK(from.specificProcs_.size() == from.bindingNames_.size());
227 kind_ = from.kind_;
228 if (from.derivedType_) {
229 CHECK(!derivedType_ || derivedType_ == from.derivedType_);
230 derivedType_ = from.derivedType_;
231 }
232 for (std::size_t i{0}; i < from.specificProcs_.size(); ++i) {
233 if (std::find_if(specificProcs_.begin(), specificProcs_.end(),
234 [&](const Symbol &mySymbol) {
235 return &mySymbol.GetUltimate() ==
236 &from.specificProcs_[i]->GetUltimate();
237 }) == specificProcs_.end()) {
238 specificProcs_.push_back(from.specificProcs_[i]);
239 bindingNames_.push_back(from.bindingNames_[i]);
240 }
241 }
242}
243
244// The name of the kind of details for this symbol.
245// This is primarily for debugging.
246std::string DetailsToString(const Details &details) {
247 return common::visit(
248 common::visitors{
249 [](const UnknownDetails &) { return "Unknown"; },
250 [](const MainProgramDetails &) { return "MainProgram"; },
251 [](const ModuleDetails &) { return "Module"; },
252 [](const SubprogramDetails &) { return "Subprogram"; },
253 [](const SubprogramNameDetails &) { return "SubprogramName"; },
254 [](const EntityDetails &) { return "Entity"; },
255 [](const ObjectEntityDetails &) { return "ObjectEntity"; },
256 [](const ProcEntityDetails &) { return "ProcEntity"; },
257 [](const DerivedTypeDetails &) { return "DerivedType"; },
258 [](const UseDetails &) { return "Use"; },
259 [](const UseErrorDetails &) { return "UseError"; },
260 [](const HostAssocDetails &) { return "HostAssoc"; },
261 [](const GenericDetails &) { return "Generic"; },
262 [](const ProcBindingDetails &) { return "ProcBinding"; },
263 [](const NamelistDetails &) { return "Namelist"; },
264 [](const CommonBlockDetails &) { return "CommonBlockDetails"; },
265 [](const TypeParamDetails &) { return "TypeParam"; },
266 [](const MiscDetails &) { return "Misc"; },
267 [](const AssocEntityDetails &) { return "AssocEntity"; },
268 },
269 details);
270}
271
272std::string Symbol::GetDetailsName() const { return DetailsToString(details_); }
273
274void Symbol::set_details(Details &&details) {
275 CHECK(CanReplaceDetails(details));
276 details_ = std::move(details);
277}
278
279bool Symbol::CanReplaceDetails(const Details &details) const {
280 if (has<UnknownDetails>()) {
281 return true; // can always replace UnknownDetails
282 } else {
283 return common::visit(
284 common::visitors{
285 [](const UseErrorDetails &) { return true; },
286 [&](const ObjectEntityDetails &) { return has<EntityDetails>(); },
287 [&](const ProcEntityDetails &) { return has<EntityDetails>(); },
288 [&](const SubprogramDetails &) {
289 return has<SubprogramNameDetails>() || has<EntityDetails>();
290 },
291 [&](const DerivedTypeDetails &) {
292 const auto *derived{this->detailsIf<DerivedTypeDetails>()};
293 return derived && derived->isForwardReferenced();
294 },
295 [&](const UseDetails &x) {
296 const auto *use{this->detailsIf<UseDetails>()};
297 return use && use->symbol() == x.symbol();
298 },
299 [&](const HostAssocDetails &) {
300 return this->has<HostAssocDetails>();
301 },
302 [](const auto &) { return false; },
303 },
304 details);
305 }
306}
307
308// Usually a symbol's name is the first occurrence in the source, but sometimes
309// we want to replace it with one at a different location (but same characters).
310void Symbol::ReplaceName(const SourceName &name) {
311 CHECK(name == name_);
312 name_ = name;
313}
314
315void Symbol::SetType(const DeclTypeSpec &type) {
316 common::visit(common::visitors{
317 [&](EntityDetails &x) { x.set_type(type); },
318 [&](ObjectEntityDetails &x) { x.set_type(type); },
319 [&](AssocEntityDetails &x) { x.set_type(type); },
320 [&](ProcEntityDetails &x) { x.set_type(type); },
321 [&](TypeParamDetails &x) { x.set_type(type); },
322 [](auto &) {},
323 },
324 details_);
325}
326
327template <typename T>
328constexpr bool HasBindName{std::is_convertible_v<T, const WithBindName *>};
329
330const std::string *Symbol::GetBindName() const {
331 return common::visit(
332 [&](auto &x) -> const std::string * {
333 if constexpr (HasBindName<decltype(&x)>) {
334 return x.bindName();
335 } else {
336 return nullptr;
337 }
338 },
339 details_);
340}
341
342void Symbol::SetBindName(std::string &&name) {
343 common::visit(
344 [&](auto &x) {
345 if constexpr (HasBindName<decltype(&x)>) {
346 x.set_bindName(std::move(name));
347 } else {
348 DIE("bind name not allowed on this kind of symbol");
349 }
350 },
351 details_);
352}
353
354bool Symbol::GetIsExplicitBindName() const {
355 return common::visit(
356 [&](auto &x) -> bool {
357 if constexpr (HasBindName<decltype(&x)>) {
358 return x.isExplicitBindName();
359 } else {
360 return false;
361 }
362 },
363 details_);
364}
365
366void Symbol::SetIsExplicitBindName(bool yes) {
367 common::visit(
368 [&](auto &x) {
369 if constexpr (HasBindName<decltype(&x)>) {
370 x.set_isExplicitBindName(yes);
371 } else {
372 DIE("bind name not allowed on this kind of symbol");
373 }
374 },
375 details_);
376}
377
378bool Symbol::IsFuncResult() const {
379 return common::visit(
380 common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); },
381 [](const ObjectEntityDetails &x) { return x.isFuncResult(); },
382 [](const ProcEntityDetails &x) { return x.isFuncResult(); },
383 [](const HostAssocDetails &x) { return x.symbol().IsFuncResult(); },
384 [](const auto &) { return false; }},
385 details_);
386}
387
388bool Symbol::IsObjectArray() const {
389 const auto *details{std::get_if<ObjectEntityDetails>(&details_)};
390 return details && details->IsArray();
391}
392
393bool Symbol::IsSubprogram() const {
394 return common::visit(
395 common::visitors{
396 [](const SubprogramDetails &) { return true; },
397 [](const SubprogramNameDetails &) { return true; },
398 [](const GenericDetails &) { return true; },
399 [](const UseDetails &x) { return x.symbol().IsSubprogram(); },
400 [](const auto &) { return false; },
401 },
402 details_);
403}
404
405bool Symbol::IsFromModFile() const {
406 return test(Flag::ModFile) ||
407 (!owner_->IsTopLevel() && owner_->symbol()->IsFromModFile());
408}
409
410llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) {
411 DumpBool(os, "dummy", x.isDummy());
412 DumpBool(os, "funcResult", x.isFuncResult());
413 if (x.type()) {
414 os << " type: " << *x.type();
415 }
416 DumpOptional(os, "bindName", x.bindName());
417 return os;
418}
419
420llvm::raw_ostream &operator<<(
421 llvm::raw_ostream &os, const ObjectEntityDetails &x) {
422 os << *static_cast<const EntityDetails *>(&x);
423 DumpList(os, "shape", x.shape());
424 DumpList(os, "coshape", x.coshape());
425 DumpExpr(os, "init", x.init_);
426 if (x.unanalyzedPDTComponentInit()) {
427 os << " (has unanalyzedPDTComponentInit)";
428 }
429 if (!x.ignoreTKR_.empty()) {
430 x.ignoreTKR_.Dump(os << ' ', common::EnumToString);
431 }
432 if (x.cudaDataAttr()) {
433 os << " cudaDataAttr: " << common::EnumToString(*x.cudaDataAttr());
434 }
435 return os;
436}
437
438llvm::raw_ostream &operator<<(
439 llvm::raw_ostream &os, const AssocEntityDetails &x) {
440 os << *static_cast<const EntityDetails *>(&x);
441 if (x.IsAssumedSize()) {
442 os << " RANK(*)";
443 } else if (x.IsAssumedRank()) {
444 os << " RANK DEFAULT";
445 } else if (auto assocRank{x.rank()}) {
446 os << " RANK(" << *assocRank << ')';
447 }
448 DumpExpr(os, "expr", x.expr());
449 return os;
450}
451
452llvm::raw_ostream &operator<<(
453 llvm::raw_ostream &os, const ProcEntityDetails &x) {
454 if (x.procInterface_) {
455 if (x.rawProcInterface_ != x.procInterface_) {
456 os << ' ' << x.rawProcInterface_->name() << " ->";
457 }
458 os << ' ' << x.procInterface_->name();
459 } else {
460 DumpType(os, x.type());
461 }
462 DumpOptional(os, "bindName", x.bindName());
463 DumpOptional(os, "passName", x.passName());
464 if (x.init()) {
465 if (const Symbol * target{*x.init()}) {
466 os << " => " << target->name();
467 } else {
468 os << " => NULL()";
469 }
470 }
471 if (x.isCUDAKernel()) {
472 os << " isCUDAKernel";
473 }
474 return os;
475}
476
477llvm::raw_ostream &operator<<(
478 llvm::raw_ostream &os, const DerivedTypeDetails &x) {
479 DumpBool(os, "sequence", x.sequence_);
480 DumpList(os, "components", x.componentNames_);
481 return os;
482}
483
484llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const GenericDetails &x) {
485 os << ' ' << x.kind().ToString();
486 DumpBool(os, "(specific)", x.specific() != nullptr);
487 DumpBool(os, "(derivedType)", x.derivedType() != nullptr);
488 if (const auto &uses{x.uses()}; !uses.empty()) {
489 os << " (uses:";
490 char sep{' '};
491 for (const Symbol &use : uses) {
492 const Symbol &ultimate{use.GetUltimate()};
493 os << sep << ultimate.name() << "->"
494 << ultimate.owner().GetName().value();
495 sep = ',';
496 }
497 os << ')';
498 }
499 os << " procs:";
500 DumpSymbolVector(os, x.specificProcs());
501 return os;
502}
503
504llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
505 os << DetailsToString(details);
506 common::visit( //
507 common::visitors{
508 [&](const UnknownDetails &) {},
509 [&](const MainProgramDetails &) {},
510 [&](const ModuleDetails &x) {
511 if (x.isSubmodule()) {
512 os << " (";
513 if (x.ancestor()) {
514 auto ancestor{x.ancestor()->GetName().value()};
515 os << ancestor;
516 if (x.parent()) {
517 auto parent{x.parent()->GetName().value()};
518 if (ancestor != parent) {
519 os << ':' << parent;
520 }
521 }
522 }
523 os << ")";
524 }
525 if (x.isDefaultPrivate()) {
526 os << " isDefaultPrivate";
527 }
528 },
529 [&](const SubprogramNameDetails &x) {
530 os << ' ' << EnumToString(x.kind());
531 },
532 [&](const UseDetails &x) {
533 os << " from " << x.symbol().name() << " in "
534 << GetUsedModule(x).name();
535 },
536 [&](const UseErrorDetails &x) {
537 os << " uses:";
538 char sep{':'};
539 for (const auto &[location, module] : x.occurrences()) {
540 os << sep << " from " << module->GetName().value() << " at "
541 << location;
542 sep = ',';
543 }
544 },
545 [](const HostAssocDetails &) {},
546 [&](const ProcBindingDetails &x) {
547 os << " => " << x.symbol().name();
548 DumpOptional(os, "passName", x.passName());
549 if (x.numPrivatesNotOverridden() > 0) {
550 os << " numPrivatesNotOverridden: "
551 << x.numPrivatesNotOverridden();
552 }
553 },
554 [&](const NamelistDetails &x) {
555 os << ':';
556 DumpSymbolVector(os, x.objects());
557 },
558 [&](const CommonBlockDetails &x) {
559 DumpOptional(os, "bindName", x.bindName());
560 if (x.alignment()) {
561 os << " alignment=" << x.alignment();
562 }
563 os << ':';
564 for (const auto &object : x.objects()) {
565 os << ' ' << object->name();
566 }
567 },
568 [&](const TypeParamDetails &x) {
569 DumpOptional(os, "type", x.type());
570 os << ' ' << common::EnumToString(x.attr());
571 DumpExpr(os, "init", x.init());
572 },
573 [&](const MiscDetails &x) {
574 os << ' ' << MiscDetails::EnumToString(x.kind());
575 },
576 [&](const auto &x) { os << x; },
577 },
578 details);
579 return os;
580}
581
582llvm::raw_ostream &operator<<(llvm::raw_ostream &o, Symbol::Flag flag) {
583 return o << Symbol::EnumToString(flag);
584}
585
586llvm::raw_ostream &operator<<(
587 llvm::raw_ostream &o, const Symbol::Flags &flags) {
588 std::size_t n{flags.count()};
589 std::size_t seen{0};
590 for (std::size_t j{0}; seen < n; ++j) {
591 Symbol::Flag flag{static_cast<Symbol::Flag>(j)};
592 if (flags.test(flag)) {
593 if (seen++ > 0) {
594 o << ", ";
595 }
596 o << flag;
597 }
598 }
599 return o;
600}
601
602llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Symbol &symbol) {
603 os << symbol.name();
604 if (!symbol.attrs().empty()) {
605 os << ", " << symbol.attrs();
606 }
607 if (!symbol.flags().empty()) {
608 os << " (" << symbol.flags() << ')';
609 }
610 if (symbol.size_) {
611 os << " size=" << symbol.size_ << " offset=" << symbol.offset_;
612 }
613 os << ": " << symbol.details_;
614 return os;
615}
616
617#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
618void Symbol::dump() const { llvm::errs() << *this << '\n'; }
619#endif
620
621// Output a unique name for a scope by qualifying it with the names of
622// parent scopes. For scopes without corresponding symbols, use the kind
623// with an index (e.g. Block1, Block2, etc.).
624static void DumpUniqueName(llvm::raw_ostream &os, const Scope &scope) {
625 if (!scope.IsTopLevel()) {
626 DumpUniqueName(os, scope.parent());
627 os << '/';
628 if (auto *scopeSymbol{scope.symbol()};
629 scopeSymbol && !scopeSymbol->name().empty()) {
630 os << scopeSymbol->name();
631 } else {
632 int index{1};
633 for (auto &child : scope.parent().children()) {
634 if (child == scope) {
635 break;
636 }
637 if (child.kind() == scope.kind()) {
638 ++index;
639 }
640 }
641 os << Scope::EnumToString(scope.kind()) << index;
642 }
643 }
644}
645
646// Dump a symbol for UnparseWithSymbols. This will be used for tests so the
647// format should be reasonably stable.
648llvm::raw_ostream &DumpForUnparse(
649 llvm::raw_ostream &os, const Symbol &symbol, bool isDef) {
650 DumpUniqueName(os, symbol.owner());
651 os << '/' << symbol.name();
652 if (isDef) {
653 if (!symbol.attrs().empty()) {
654 os << ' ' << symbol.attrs();
655 }
656 if (!symbol.flags().empty()) {
657 os << " (" << symbol.flags() << ')';
658 }
659 os << ' ' << symbol.GetDetailsName();
660 DumpType(os, symbol.GetType());
661 }
662 return os;
663}
664
665const DerivedTypeSpec *Symbol::GetParentTypeSpec(const Scope *scope) const {
666 if (const Symbol * parentComponent{GetParentComponent(scope)}) {
667 const auto &object{parentComponent->get<ObjectEntityDetails>()};
668 return &object.type()->derivedTypeSpec();
669 } else {
670 return nullptr;
671 }
672}
673
674const Symbol *Symbol::GetParentComponent(const Scope *scope) const {
675 if (const auto *dtDetails{detailsIf<DerivedTypeDetails>()}) {
676 if (const Scope * localScope{scope ? scope : scope_}) {
677 return dtDetails->GetParentComponent(DEREF(localScope));
678 }
679 }
680 return nullptr;
681}
682
683void DerivedTypeDetails::add_component(const Symbol &symbol) {
684 if (symbol.test(Symbol::Flag::ParentComp)) {
685 CHECK(componentNames_.empty());
686 }
687 componentNames_.push_back(symbol.name());
688}
689
690const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const {
691 if (auto extends{GetParentComponentName()}) {
692 if (auto iter{scope.find(*extends)}; iter != scope.cend()) {
693 if (const Symbol & symbol{*iter->second};
694 symbol.test(Symbol::Flag::ParentComp)) {
695 return &symbol;
696 }
697 }
698 }
699 return nullptr;
700}
701
702const Symbol *DerivedTypeDetails::GetFinalForRank(int rank) const {
703 for (const auto &pair : finals_) {
704 const Symbol &symbol{*pair.second};
705 if (const auto *details{symbol.detailsIf<SubprogramDetails>()}) {
706 if (details->dummyArgs().size() == 1) {
707 if (const Symbol * arg{details->dummyArgs().at(0)}) {
708 if (const auto *object{arg->detailsIf<ObjectEntityDetails>()}) {
709 if (rank == object->shape().Rank() || object->IsAssumedRank() ||
710 IsElementalProcedure(symbol)) {
711 return &symbol;
712 }
713 }
714 }
715 }
716 }
717 }
718 return nullptr;
719}
720
721void TypeParamDetails::set_type(const DeclTypeSpec &type) {
722 CHECK(!type_);
723 type_ = &type;
724}
725
726bool GenericKind::IsIntrinsicOperator() const {
727 return Is(OtherKind::Concat) || Has<common::LogicalOperator>() ||
728 Has<common::NumericOperator>() || Has<common::RelationalOperator>();
729}
730
731bool GenericKind::IsOperator() const {
732 return IsDefinedOperator() || IsIntrinsicOperator();
733}
734
735std::string GenericKind::ToString() const {
736 return common::visit(
737 common::visitors{
738 [](const OtherKind &x) { return std::string{EnumToString(x)}; },
739 [](const common::DefinedIo &x) { return AsFortran(x).ToString(); },
740 [](const auto &x) { return std::string{common::EnumToString(x)}; },
741 },
742 u);
743}
744
745SourceName GenericKind::AsFortran(common::DefinedIo x) {
746 const char *name{common::AsFortran(x)};
747 return {name, std::strlen(name)};
748}
749
750bool GenericKind::Is(GenericKind::OtherKind x) const {
751 const OtherKind *y{std::get_if<OtherKind>(&u)};
752 return y && *y == x;
753}
754
755std::string Symbol::OmpFlagToClauseName(Symbol::Flag ompFlag) {
756 std::string clauseName;
757 switch (ompFlag) {
758 case Symbol::Flag::OmpShared:
759 clauseName = "SHARED";
760 break;
761 case Symbol::Flag::OmpPrivate:
762 clauseName = "PRIVATE";
763 break;
764 case Symbol::Flag::OmpLinear:
765 clauseName = "LINEAR";
766 break;
767 case Symbol::Flag::OmpFirstPrivate:
768 clauseName = "FIRSTPRIVATE";
769 break;
770 case Symbol::Flag::OmpLastPrivate:
771 clauseName = "LASTPRIVATE";
772 break;
773 case Symbol::Flag::OmpMapTo:
774 case Symbol::Flag::OmpMapFrom:
775 case Symbol::Flag::OmpMapToFrom:
776 case Symbol::Flag::OmpMapAlloc:
777 case Symbol::Flag::OmpMapRelease:
778 case Symbol::Flag::OmpMapDelete:
779 clauseName = "MAP";
780 break;
781 case Symbol::Flag::OmpUseDevicePtr:
782 clauseName = "USE_DEVICE_PTR";
783 break;
784 case Symbol::Flag::OmpUseDeviceAddr:
785 clauseName = "USE_DEVICE_ADDR";
786 break;
787 case Symbol::Flag::OmpCopyIn:
788 clauseName = "COPYIN";
789 break;
790 case Symbol::Flag::OmpCopyPrivate:
791 clauseName = "COPYPRIVATE";
792 break;
793 case Symbol::Flag::OmpIsDevicePtr:
794 clauseName = "IS_DEVICE_PTR";
795 break;
796 case Symbol::Flag::OmpHasDeviceAddr:
797 clauseName = "HAS_DEVICE_ADDR";
798 break;
799 default:
800 clauseName = "";
801 break;
802 }
803 return clauseName;
804}
805
806bool SymbolOffsetCompare::operator()(
807 const SymbolRef &x, const SymbolRef &y) const {
808 const Symbol *xCommon{FindCommonBlockContaining(*x)};
809 const Symbol *yCommon{FindCommonBlockContaining(*y)};
810 if (xCommon) {
811 if (yCommon) {
812 const SymbolSourcePositionCompare sourceCmp;
813 if (sourceCmp(*xCommon, *yCommon)) {
814 return true;
815 } else if (sourceCmp(*yCommon, *xCommon)) {
816 return false;
817 } else if (x->offset() == y->offset()) {
818 return x->size() > y->size();
819 } else {
820 return x->offset() < y->offset();
821 }
822 } else {
823 return false;
824 }
825 } else if (yCommon) {
826 return true;
827 } else if (x->offset() == y->offset()) {
828 return x->size() > y->size();
829 } else {
830 return x->offset() < y->offset();
831 }
832 return x->GetSemanticsContext().allCookedSources().Precedes(
833 x->name(), y->name());
834}
835
836bool SymbolOffsetCompare::operator()(
837 const MutableSymbolRef &x, const MutableSymbolRef &y) const {
838 return (*this)(SymbolRef{*x}, SymbolRef{*y});
839}
840
841} // namespace Fortran::semantics
842

source code of flang/lib/Semantics/symbol.cpp