[MemProf] Templatize CallStackRadixTreeBuilder (NFC) (#117014)
[llvm-project.git] / flang / lib / Semantics / symbol.cpp
blob14d6564664f2cc28115c60544500daf6727723aa
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 //===----------------------------------------------------------------------===//
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>
20 namespace Fortran::semantics {
22 template <typename T>
23 static void DumpOptional(llvm::raw_ostream &os, const char *label, const T &x) {
24 if (x) {
25 os << ' ' << label << ':' << *x;
28 template <typename T>
29 static 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 << ':');
36 static void DumpBool(llvm::raw_ostream &os, const char *label, bool x) {
37 if (x) {
38 os << ' ' << label;
42 static 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 = ',';
50 static void DumpType(llvm::raw_ostream &os, const Symbol &symbol) {
51 if (const auto *type{symbol.GetType()}) {
52 os << *type << ' ';
55 static void DumpType(llvm::raw_ostream &os, const DeclTypeSpec *type) {
56 if (type) {
57 os << ' ' << *type;
61 template <typename T>
62 static 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 = ',';
73 void SubprogramDetails::set_moduleInterface(Symbol &symbol) {
74 CHECK(!moduleInterface_);
75 moduleInterface_ = &symbol;
78 const Scope *ModuleDetails::parent() const {
79 return isSubmodule_ && scope_ ? &scope_->parent() : nullptr;
81 const Scope *ModuleDetails::ancestor() const {
82 return isSubmodule_ && scope_ ? FindModuleContaining(*scope_) : nullptr;
84 void 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;
91 llvm::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();
103 if (x.entryScope_) {
104 os << " entry";
105 if (x.entryScope_->symbol()) {
106 os << " in " << x.entryScope_->symbol()->name();
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 << '*';
121 os << (sep == '(' ? "()" : ")");
122 if (x.stmtFunction_) {
123 os << " -> " << x.stmtFunction_->AsFortran();
125 if (x.moduleInterface_) {
126 os << " moduleInterface: " << *x.moduleInterface_;
128 if (x.defaultIgnoreTKR_) {
129 os << " defaultIgnoreTKR";
131 if (x.cudaSubprogramAttrs_) {
132 os << " cudaSubprogramAttrs: "
133 << common::EnumToString(*x.cudaSubprogramAttrs_);
135 if (!x.cudaLaunchBounds_.empty()) {
136 os << " cudaLaunchBounds:";
137 for (auto x : x.cudaLaunchBounds_) {
138 os << ' ' << x;
141 if (!x.cudaClusterDims_.empty()) {
142 os << " cudaClusterDims:";
143 for (auto x : x.cudaClusterDims_) {
144 os << ' ' << x;
147 return os;
150 void EntityDetails::set_type(const DeclTypeSpec &type) {
151 CHECK(!type_);
152 type_ = &type;
155 void AssocEntityDetails::set_rank(int rank) { rank_ = rank; }
156 void AssocEntityDetails::set_IsAssumedSize() { rank_ = isAssumedSize; }
157 void AssocEntityDetails::set_IsAssumedRank() { rank_ = isAssumedRank; }
158 void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; }
160 ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d)
161 : EntityDetails(std::move(d)) {}
163 void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
164 CHECK(shape_.empty());
165 for (const auto &shapeSpec : shape) {
166 shape_.push_back(shapeSpec);
169 void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) {
170 CHECK(coshape_.empty());
171 for (const auto &shapeSpec : coshape) {
172 coshape_.push_back(shapeSpec);
176 ProcEntityDetails::ProcEntityDetails(EntityDetails &&d)
177 : EntityDetails(std::move(d)) {}
179 UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) {
180 add_occurrence(useDetails.location(), *GetUsedModule(useDetails).scope());
182 UseErrorDetails &UseErrorDetails::add_occurrence(
183 const SourceName &location, const Scope &module) {
184 occurrences_.push_back(std::make_pair(location, &module));
185 return *this;
188 void GenericDetails::AddSpecificProc(
189 const Symbol &proc, SourceName bindingName) {
190 specificProcs_.push_back(proc);
191 bindingNames_.push_back(bindingName);
193 void GenericDetails::set_specific(Symbol &specific) {
194 CHECK(!specific_);
195 specific_ = &specific;
197 void GenericDetails::clear_specific() { specific_ = nullptr; }
198 void GenericDetails::set_derivedType(Symbol &derivedType) {
199 CHECK(!derivedType_);
200 derivedType_ = &derivedType;
202 void GenericDetails::clear_derivedType() { derivedType_ = nullptr; }
203 void GenericDetails::AddUse(const Symbol &use) {
204 CHECK(use.has<UseDetails>());
205 uses_.push_back(use);
208 const Symbol *GenericDetails::CheckSpecific() const {
209 return const_cast<GenericDetails *>(this)->CheckSpecific();
211 Symbol *GenericDetails::CheckSpecific() {
212 if (specific_ && !specific_->has<UseErrorDetails>()) {
213 const Symbol &ultimate{specific_->GetUltimate()};
214 for (const Symbol &proc : specificProcs_) {
215 if (&proc.GetUltimate() == &ultimate) {
216 return nullptr;
219 return specific_;
220 } else {
221 return nullptr;
225 void GenericDetails::CopyFrom(const GenericDetails &from) {
226 CHECK(specificProcs_.size() == bindingNames_.size());
227 CHECK(from.specificProcs_.size() == from.bindingNames_.size());
228 kind_ = from.kind_;
229 if (from.derivedType_) {
230 CHECK(!derivedType_ || derivedType_ == from.derivedType_);
231 derivedType_ = from.derivedType_;
233 for (std::size_t i{0}; i < from.specificProcs_.size(); ++i) {
234 if (llvm::none_of(specificProcs_, [&](const Symbol &mySymbol) {
235 return &mySymbol.GetUltimate() ==
236 &from.specificProcs_[i]->GetUltimate();
237 })) {
238 specificProcs_.push_back(from.specificProcs_[i]);
239 bindingNames_.push_back(from.bindingNames_[i]);
244 // The name of the kind of details for this symbol.
245 // This is primarily for debugging.
246 std::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"; },
269 details);
272 std::string Symbol::GetDetailsName() const { return DetailsToString(details_); }
274 void Symbol::set_details(Details &&details) {
275 CHECK(CanReplaceDetails(details));
276 details_ = std::move(details);
279 bool 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>();
291 [&](const DerivedTypeDetails &) {
292 const auto *derived{this->detailsIf<DerivedTypeDetails>()};
293 return derived && derived->isForwardReferenced();
295 [&](const UseDetails &x) {
296 const auto *use{this->detailsIf<UseDetails>()};
297 return use && use->symbol() == x.symbol();
299 [&](const HostAssocDetails &) {
300 return this->has<HostAssocDetails>();
302 [](const auto &) { return false; },
304 details);
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).
310 void Symbol::ReplaceName(const SourceName &name) {
311 CHECK(name == name_);
312 name_ = name;
315 void 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 &) {},
324 details_);
327 template <typename T>
328 constexpr bool HasBindName{std::is_convertible_v<T, const WithBindName *>};
330 const 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;
339 details_);
342 void 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");
351 details_);
354 bool 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;
363 details_);
366 void 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");
375 details_);
378 void Symbol::SetIsCDefined(bool yes) {
379 common::visit(
380 [&](auto &x) {
381 if constexpr (HasBindName<decltype(&x)>) {
382 x.set_isCDefined(yes);
383 } else {
384 DIE("CDEFINED not allowed on this kind of symbol");
387 details_);
390 bool Symbol::IsFuncResult() const {
391 return common::visit(
392 common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); },
393 [](const ObjectEntityDetails &x) { return x.isFuncResult(); },
394 [](const ProcEntityDetails &x) { return x.isFuncResult(); },
395 [](const HostAssocDetails &x) { return x.symbol().IsFuncResult(); },
396 [](const auto &) { return false; }},
397 details_);
400 const ArraySpec *Symbol::GetShape() const {
401 if (const auto *details{std::get_if<ObjectEntityDetails>(&details_)}) {
402 return &details->shape();
403 } else {
404 return nullptr;
408 bool Symbol::IsObjectArray() const {
409 const ArraySpec *shape{GetShape()};
410 return shape && !shape->empty();
413 bool Symbol::IsSubprogram() const {
414 return common::visit(
415 common::visitors{
416 [](const SubprogramDetails &) { return true; },
417 [](const SubprogramNameDetails &) { return true; },
418 [](const GenericDetails &) { return true; },
419 [](const UseDetails &x) { return x.symbol().IsSubprogram(); },
420 [](const auto &) { return false; },
422 details_);
425 bool Symbol::IsFromModFile() const {
426 return test(Flag::ModFile) ||
427 (!owner_->IsTopLevel() && owner_->symbol()->IsFromModFile());
430 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) {
431 DumpBool(os, "dummy", x.isDummy());
432 DumpBool(os, "funcResult", x.isFuncResult());
433 if (x.type()) {
434 os << " type: " << *x.type();
436 DumpOptional(os, "bindName", x.bindName());
437 DumpBool(os, "CDEFINED", x.isCDefined());
438 return os;
441 llvm::raw_ostream &operator<<(
442 llvm::raw_ostream &os, const ObjectEntityDetails &x) {
443 os << *static_cast<const EntityDetails *>(&x);
444 DumpList(os, "shape", x.shape());
445 DumpList(os, "coshape", x.coshape());
446 DumpExpr(os, "init", x.init_);
447 if (x.unanalyzedPDTComponentInit()) {
448 os << " (has unanalyzedPDTComponentInit)";
450 if (!x.ignoreTKR_.empty()) {
451 x.ignoreTKR_.Dump(os << ' ', common::EnumToString);
453 if (x.cudaDataAttr()) {
454 os << " cudaDataAttr: " << common::EnumToString(*x.cudaDataAttr());
456 return os;
459 llvm::raw_ostream &operator<<(
460 llvm::raw_ostream &os, const AssocEntityDetails &x) {
461 os << *static_cast<const EntityDetails *>(&x);
462 if (x.IsAssumedSize()) {
463 os << " RANK(*)";
464 } else if (x.IsAssumedRank()) {
465 os << " RANK DEFAULT";
466 } else if (auto assocRank{x.rank()}) {
467 os << " RANK(" << *assocRank << ')';
469 DumpExpr(os, "expr", x.expr());
470 return os;
473 llvm::raw_ostream &operator<<(
474 llvm::raw_ostream &os, const ProcEntityDetails &x) {
475 if (x.procInterface_) {
476 if (x.rawProcInterface_ != x.procInterface_) {
477 os << ' ' << x.rawProcInterface_->name() << " ->";
479 os << ' ' << x.procInterface_->name();
480 } else {
481 DumpType(os, x.type());
483 DumpOptional(os, "bindName", x.bindName());
484 DumpOptional(os, "passName", x.passName());
485 if (x.init()) {
486 if (const Symbol * target{*x.init()}) {
487 os << " => " << target->name();
488 } else {
489 os << " => NULL()";
492 if (x.isCUDAKernel()) {
493 os << " isCUDAKernel";
495 return os;
498 llvm::raw_ostream &operator<<(
499 llvm::raw_ostream &os, const DerivedTypeDetails &x) {
500 DumpBool(os, "sequence", x.sequence_);
501 DumpList(os, "components", x.componentNames_);
502 return os;
505 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const GenericDetails &x) {
506 os << ' ' << x.kind().ToString();
507 DumpBool(os, "(specific)", x.specific() != nullptr);
508 DumpBool(os, "(derivedType)", x.derivedType() != nullptr);
509 if (const auto &uses{x.uses()}; !uses.empty()) {
510 os << " (uses:";
511 char sep{' '};
512 for (const Symbol &use : uses) {
513 const Symbol &ultimate{use.GetUltimate()};
514 os << sep << ultimate.name() << "->"
515 << ultimate.owner().GetName().value();
516 sep = ',';
518 os << ')';
520 os << " procs:";
521 DumpSymbolVector(os, x.specificProcs());
522 return os;
525 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
526 os << DetailsToString(details);
527 common::visit( //
528 common::visitors{
529 [&](const UnknownDetails &) {},
530 [&](const MainProgramDetails &) {},
531 [&](const ModuleDetails &x) {
532 if (x.isSubmodule()) {
533 os << " (";
534 if (x.ancestor()) {
535 auto ancestor{x.ancestor()->GetName().value()};
536 os << ancestor;
537 if (x.parent()) {
538 auto parent{x.parent()->GetName().value()};
539 if (ancestor != parent) {
540 os << ':' << parent;
544 os << ")";
546 if (x.isDefaultPrivate()) {
547 os << " isDefaultPrivate";
550 [&](const SubprogramNameDetails &x) {
551 os << ' ' << EnumToString(x.kind());
553 [&](const UseDetails &x) {
554 os << " from " << x.symbol().name() << " in "
555 << GetUsedModule(x).name();
557 [&](const UseErrorDetails &x) {
558 os << " uses:";
559 char sep{':'};
560 for (const auto &[location, module] : x.occurrences()) {
561 os << sep << " from " << module->GetName().value() << " at "
562 << location;
563 sep = ',';
566 [](const HostAssocDetails &) {},
567 [&](const ProcBindingDetails &x) {
568 os << " => " << x.symbol().name();
569 DumpOptional(os, "passName", x.passName());
570 if (x.numPrivatesNotOverridden() > 0) {
571 os << " numPrivatesNotOverridden: "
572 << x.numPrivatesNotOverridden();
575 [&](const NamelistDetails &x) {
576 os << ':';
577 DumpSymbolVector(os, x.objects());
579 [&](const CommonBlockDetails &x) {
580 DumpOptional(os, "bindName", x.bindName());
581 if (x.alignment()) {
582 os << " alignment=" << x.alignment();
584 os << ':';
585 for (const auto &object : x.objects()) {
586 os << ' ' << object->name();
589 [&](const TypeParamDetails &x) {
590 DumpOptional(os, "type", x.type());
591 if (auto attr{x.attr()}) {
592 os << ' ' << common::EnumToString(*attr);
593 } else {
594 os << " (no attr)";
596 DumpExpr(os, "init", x.init());
598 [&](const MiscDetails &x) {
599 os << ' ' << MiscDetails::EnumToString(x.kind());
601 [&](const auto &x) { os << x; },
603 details);
604 return os;
607 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, Symbol::Flag flag) {
608 return o << Symbol::EnumToString(flag);
611 llvm::raw_ostream &operator<<(
612 llvm::raw_ostream &o, const Symbol::Flags &flags) {
613 std::size_t n{flags.count()};
614 std::size_t seen{0};
615 for (std::size_t j{0}; seen < n; ++j) {
616 Symbol::Flag flag{static_cast<Symbol::Flag>(j)};
617 if (flags.test(flag)) {
618 if (seen++ > 0) {
619 o << ", ";
621 o << flag;
624 return o;
627 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Symbol &symbol) {
628 os << symbol.name();
629 if (!symbol.attrs().empty()) {
630 os << ", " << symbol.attrs();
632 if (!symbol.flags().empty()) {
633 os << " (" << symbol.flags() << ')';
635 if (symbol.size_) {
636 os << " size=" << symbol.size_ << " offset=" << symbol.offset_;
638 os << ": " << symbol.details_;
639 return os;
642 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
643 void Symbol::dump() const { llvm::errs() << *this << '\n'; }
644 #endif
646 // Output a unique name for a scope by qualifying it with the names of
647 // parent scopes. For scopes without corresponding symbols, use the kind
648 // with an index (e.g. Block1, Block2, etc.).
649 static void DumpUniqueName(llvm::raw_ostream &os, const Scope &scope) {
650 if (!scope.IsTopLevel()) {
651 DumpUniqueName(os, scope.parent());
652 os << '/';
653 if (auto *scopeSymbol{scope.symbol()};
654 scopeSymbol && !scopeSymbol->name().empty()) {
655 os << scopeSymbol->name();
656 } else {
657 int index{1};
658 for (auto &child : scope.parent().children()) {
659 if (child == scope) {
660 break;
662 if (child.kind() == scope.kind()) {
663 ++index;
666 os << Scope::EnumToString(scope.kind()) << index;
671 // Dump a symbol for UnparseWithSymbols. This will be used for tests so the
672 // format should be reasonably stable.
673 llvm::raw_ostream &DumpForUnparse(
674 llvm::raw_ostream &os, const Symbol &symbol, bool isDef) {
675 DumpUniqueName(os, symbol.owner());
676 os << '/' << symbol.name();
677 if (isDef) {
678 if (!symbol.attrs().empty()) {
679 os << ' ' << symbol.attrs();
681 if (!symbol.flags().empty()) {
682 os << " (" << symbol.flags() << ')';
684 os << ' ' << symbol.GetDetailsName();
685 DumpType(os, symbol.GetType());
687 return os;
690 const DerivedTypeSpec *Symbol::GetParentTypeSpec(const Scope *scope) const {
691 if (const Symbol * parentComponent{GetParentComponent(scope)}) {
692 const auto &object{parentComponent->get<ObjectEntityDetails>()};
693 return &object.type()->derivedTypeSpec();
694 } else {
695 return nullptr;
699 const Symbol *Symbol::GetParentComponent(const Scope *scope) const {
700 if (const auto *dtDetails{detailsIf<DerivedTypeDetails>()}) {
701 if (const Scope * localScope{scope ? scope : scope_}) {
702 return dtDetails->GetParentComponent(DEREF(localScope));
705 return nullptr;
708 void DerivedTypeDetails::add_component(const Symbol &symbol) {
709 if (symbol.test(Symbol::Flag::ParentComp)) {
710 CHECK(componentNames_.empty());
712 componentNames_.push_back(symbol.name());
715 const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const {
716 if (auto extends{GetParentComponentName()}) {
717 if (auto iter{scope.find(*extends)}; iter != scope.cend()) {
718 if (const Symbol & symbol{*iter->second};
719 symbol.test(Symbol::Flag::ParentComp)) {
720 return &symbol;
724 return nullptr;
727 const Symbol *DerivedTypeDetails::GetFinalForRank(int rank) const {
728 for (const auto &pair : finals_) {
729 const Symbol &symbol{*pair.second};
730 if (const auto *details{symbol.detailsIf<SubprogramDetails>()}) {
731 if (details->dummyArgs().size() == 1) {
732 if (const Symbol * arg{details->dummyArgs().at(0)}) {
733 if (const auto *object{arg->detailsIf<ObjectEntityDetails>()}) {
734 if (rank == object->shape().Rank() || object->IsAssumedRank() ||
735 IsElementalProcedure(symbol)) {
736 return &symbol;
743 return nullptr;
746 TypeParamDetails &TypeParamDetails::set_attr(common::TypeParamAttr attr) {
747 CHECK(!attr_);
748 attr_ = attr;
749 return *this;
752 TypeParamDetails &TypeParamDetails::set_type(const DeclTypeSpec &type) {
753 CHECK(!type_);
754 type_ = &type;
755 return *this;
758 bool GenericKind::IsIntrinsicOperator() const {
759 return Is(OtherKind::Concat) || Has<common::LogicalOperator>() ||
760 Has<common::NumericOperator>() || Has<common::RelationalOperator>();
763 bool GenericKind::IsOperator() const {
764 return IsDefinedOperator() || IsIntrinsicOperator();
767 std::string GenericKind::ToString() const {
768 return common::visit(
769 common::visitors{
770 [](const OtherKind &x) { return std::string{EnumToString(x)}; },
771 [](const common::DefinedIo &x) { return AsFortran(x).ToString(); },
772 [](const auto &x) { return std::string{common::EnumToString(x)}; },
777 SourceName GenericKind::AsFortran(common::DefinedIo x) {
778 const char *name{common::AsFortran(x)};
779 return {name, std::strlen(name)};
782 bool GenericKind::Is(GenericKind::OtherKind x) const {
783 const OtherKind *y{std::get_if<OtherKind>(&u)};
784 return y && *y == x;
787 std::string Symbol::OmpFlagToClauseName(Symbol::Flag ompFlag) {
788 std::string clauseName;
789 switch (ompFlag) {
790 case Symbol::Flag::OmpShared:
791 clauseName = "SHARED";
792 break;
793 case Symbol::Flag::OmpPrivate:
794 clauseName = "PRIVATE";
795 break;
796 case Symbol::Flag::OmpLinear:
797 clauseName = "LINEAR";
798 break;
799 case Symbol::Flag::OmpFirstPrivate:
800 clauseName = "FIRSTPRIVATE";
801 break;
802 case Symbol::Flag::OmpLastPrivate:
803 clauseName = "LASTPRIVATE";
804 break;
805 case Symbol::Flag::OmpMapTo:
806 case Symbol::Flag::OmpMapFrom:
807 case Symbol::Flag::OmpMapToFrom:
808 case Symbol::Flag::OmpMapAlloc:
809 case Symbol::Flag::OmpMapRelease:
810 case Symbol::Flag::OmpMapDelete:
811 clauseName = "MAP";
812 break;
813 case Symbol::Flag::OmpUseDevicePtr:
814 clauseName = "USE_DEVICE_PTR";
815 break;
816 case Symbol::Flag::OmpUseDeviceAddr:
817 clauseName = "USE_DEVICE_ADDR";
818 break;
819 case Symbol::Flag::OmpCopyIn:
820 clauseName = "COPYIN";
821 break;
822 case Symbol::Flag::OmpCopyPrivate:
823 clauseName = "COPYPRIVATE";
824 break;
825 case Symbol::Flag::OmpIsDevicePtr:
826 clauseName = "IS_DEVICE_PTR";
827 break;
828 case Symbol::Flag::OmpHasDeviceAddr:
829 clauseName = "HAS_DEVICE_ADDR";
830 break;
831 default:
832 clauseName = "";
833 break;
835 return clauseName;
838 bool SymbolOffsetCompare::operator()(
839 const SymbolRef &x, const SymbolRef &y) const {
840 const Symbol *xCommon{FindCommonBlockContaining(*x)};
841 const Symbol *yCommon{FindCommonBlockContaining(*y)};
842 if (xCommon) {
843 if (yCommon) {
844 const SymbolSourcePositionCompare sourceCmp;
845 if (sourceCmp(*xCommon, *yCommon)) {
846 return true;
847 } else if (sourceCmp(*yCommon, *xCommon)) {
848 return false;
849 } else if (x->offset() == y->offset()) {
850 return x->size() > y->size();
851 } else {
852 return x->offset() < y->offset();
854 } else {
855 return false;
857 } else if (yCommon) {
858 return true;
859 } else if (x->offset() == y->offset()) {
860 return x->size() > y->size();
861 } else {
862 return x->offset() < y->offset();
864 return x->GetSemanticsContext().allCookedSources().Precedes(
865 x->name(), y->name());
868 bool SymbolOffsetCompare::operator()(
869 const MutableSymbolRef &x, const MutableSymbolRef &y) const {
870 return (*this)(SymbolRef{*x}, SymbolRef{*y});
873 } // namespace Fortran::semantics