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