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 if (!x.openACCRoutineInfos_.empty()) {
148 os << " openACCRoutineInfos:";
149 for (const auto &x : x.openACCRoutineInfos_) {
150 os << x;
151 }
152 }
153 return os;
154}
155
156llvm::raw_ostream &operator<<(
157 llvm::raw_ostream &os, const OpenACCRoutineDeviceTypeInfo &x) {
158 if (x.dType() != common::OpenACCDeviceType::None) {
159 os << " deviceType(" << common::EnumToString(x.dType()) << ')';
160 }
161 if (x.isSeq()) {
162 os << " seq";
163 }
164 if (x.isVector()) {
165 os << " vector";
166 }
167 if (x.isWorker()) {
168 os << " worker";
169 }
170 if (x.isGang()) {
171 os << " gang(" << x.gangDim() << ')';
172 }
173 if (const auto *bindName{x.bindName()}) {
174 if (const auto &symbol{std::get_if<std::string>(bindName)}) {
175 os << " bindName(\"" << *symbol << "\")";
176 } else {
177 const SymbolRef s{std::get<SymbolRef>(*bindName)};
178 os << " bindName(" << s->name() << ")";
179 }
180 }
181 return os;
182}
183
184llvm::raw_ostream &operator<<(
185 llvm::raw_ostream &os, const OpenACCRoutineInfo &x) {
186 if (x.isNohost()) {
187 os << " nohost";
188 }
189 os << static_cast<const OpenACCRoutineDeviceTypeInfo &>(x);
190 for (const auto &d : x.deviceTypeInfos_) {
191 os << d;
192 }
193 return os;
194}
195
196void EntityDetails::set_type(const DeclTypeSpec &type) {
197 CHECK(!type_);
198 type_ = &type;
199}
200
201void AssocEntityDetails::set_rank(int rank) { rank_ = rank; }
202void AssocEntityDetails::set_IsAssumedSize() { rank_ = isAssumedSize; }
203void AssocEntityDetails::set_IsAssumedRank() { rank_ = isAssumedRank; }
204void AssocEntityDetails::set_isTypeGuard(bool yes) { isTypeGuard_ = yes; }
205void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; }
206
207ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d)
208 : EntityDetails(std::move(d)) {}
209
210void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
211 CHECK(shape_.empty());
212 for (const auto &shapeSpec : shape) {
213 shape_.push_back(shapeSpec);
214 }
215}
216void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) {
217 CHECK(coshape_.empty());
218 for (const auto &shapeSpec : coshape) {
219 coshape_.push_back(shapeSpec);
220 }
221}
222
223ProcEntityDetails::ProcEntityDetails(EntityDetails &&d)
224 : EntityDetails(std::move(d)) {}
225
226UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) {
227 add_occurrence(useDetails.location(), useDetails.symbol());
228}
229UseErrorDetails &UseErrorDetails::add_occurrence(
230 const SourceName &location, const Symbol &used) {
231 occurrences_.push_back(std::make_pair(location, &used));
232 return *this;
233}
234
235void GenericDetails::AddSpecificProc(
236 const Symbol &proc, SourceName bindingName) {
237 specificProcs_.push_back(proc);
238 bindingNames_.push_back(bindingName);
239}
240void GenericDetails::set_specific(Symbol &specific) {
241 CHECK(!specific_);
242 specific_ = &specific;
243}
244void GenericDetails::clear_specific() { specific_ = nullptr; }
245void GenericDetails::set_derivedType(Symbol &derivedType) {
246 CHECK(!derivedType_);
247 derivedType_ = &derivedType;
248}
249void GenericDetails::clear_derivedType() { derivedType_ = nullptr; }
250void GenericDetails::AddUse(const Symbol &use) {
251 CHECK(use.has<UseDetails>());
252 uses_.push_back(use);
253}
254
255const Symbol *GenericDetails::CheckSpecific() const {
256 return const_cast<GenericDetails *>(this)->CheckSpecific();
257}
258Symbol *GenericDetails::CheckSpecific() {
259 if (specific_ && !specific_->has<UseErrorDetails>()) {
260 const Symbol &ultimate{specific_->GetUltimate()};
261 for (const Symbol &proc : specificProcs_) {
262 if (&proc.GetUltimate() == &ultimate) {
263 return nullptr;
264 }
265 }
266 return specific_;
267 } else {
268 return nullptr;
269 }
270}
271
272void GenericDetails::CopyFrom(const GenericDetails &from) {
273 CHECK(specificProcs_.size() == bindingNames_.size());
274 CHECK(from.specificProcs_.size() == from.bindingNames_.size());
275 kind_ = from.kind_;
276 if (from.derivedType_) {
277 CHECK(!derivedType_ || derivedType_ == from.derivedType_);
278 derivedType_ = from.derivedType_;
279 }
280 for (std::size_t i{0}; i < from.specificProcs_.size(); ++i) {
281 if (llvm::none_of(specificProcs_, [&](const Symbol &mySymbol) {
282 return &mySymbol.GetUltimate() ==
283 &from.specificProcs_[i]->GetUltimate();
284 })) {
285 specificProcs_.push_back(from.specificProcs_[i]);
286 bindingNames_.push_back(from.bindingNames_[i]);
287 }
288 }
289}
290
291// The name of the kind of details for this symbol.
292// This is primarily for debugging.
293std::string DetailsToString(const Details &details) {
294 return common::visit(
295 common::visitors{[](const UnknownDetails &) { return "Unknown"; },
296 [](const MainProgramDetails &) { return "MainProgram"; },
297 [](const ModuleDetails &) { return "Module"; },
298 [](const SubprogramDetails &) { return "Subprogram"; },
299 [](const SubprogramNameDetails &) { return "SubprogramName"; },
300 [](const EntityDetails &) { return "Entity"; },
301 [](const ObjectEntityDetails &) { return "ObjectEntity"; },
302 [](const ProcEntityDetails &) { return "ProcEntity"; },
303 [](const DerivedTypeDetails &) { return "DerivedType"; },
304 [](const UseDetails &) { return "Use"; },
305 [](const UseErrorDetails &) { return "UseError"; },
306 [](const HostAssocDetails &) { return "HostAssoc"; },
307 [](const GenericDetails &) { return "Generic"; },
308 [](const ProcBindingDetails &) { return "ProcBinding"; },
309 [](const NamelistDetails &) { return "Namelist"; },
310 [](const CommonBlockDetails &) { return "CommonBlockDetails"; },
311 [](const TypeParamDetails &) { return "TypeParam"; },
312 [](const MiscDetails &) { return "Misc"; },
313 [](const AssocEntityDetails &) { return "AssocEntity"; },
314 [](const UserReductionDetails &) { return "UserReductionDetails"; }},
315 details);
316}
317
318std::string Symbol::GetDetailsName() const { return DetailsToString(details_); }
319
320void Symbol::set_details(Details &&details) {
321 CHECK(CanReplaceDetails(details));
322 details_ = std::move(details);
323}
324
325bool Symbol::CanReplaceDetails(const Details &details) const {
326 if (has<UnknownDetails>()) {
327 return true; // can always replace UnknownDetails
328 } else {
329 return common::visit(
330 common::visitors{
331 [](const UseErrorDetails &) { return true; },
332 [&](const ObjectEntityDetails &) { return has<EntityDetails>(); },
333 [&](const ProcEntityDetails &) { return has<EntityDetails>(); },
334 [&](const SubprogramDetails &) {
335 return has<SubprogramNameDetails>() || has<EntityDetails>();
336 },
337 [&](const DerivedTypeDetails &) {
338 const auto *derived{this->detailsIf<DerivedTypeDetails>()};
339 return derived && derived->isForwardReferenced();
340 },
341 [&](const UseDetails &x) {
342 const auto *use{this->detailsIf<UseDetails>()};
343 return use && use->symbol() == x.symbol();
344 },
345 [&](const HostAssocDetails &) {
346 return this->has<HostAssocDetails>();
347 },
348 [&](const UserReductionDetails &) {
349 return this->has<UserReductionDetails>();
350 },
351 [](const auto &) { return false; },
352 },
353 details);
354 }
355}
356
357// Usually a symbol's name is the first occurrence in the source, but sometimes
358// we want to replace it with one at a different location (but same characters).
359void Symbol::ReplaceName(const SourceName &name) {
360 CHECK(name == name_);
361 name_ = name;
362}
363
364void Symbol::SetType(const DeclTypeSpec &type) {
365 common::visit(common::visitors{
366 [&](EntityDetails &x) { x.set_type(type); },
367 [&](ObjectEntityDetails &x) { x.set_type(type); },
368 [&](AssocEntityDetails &x) { x.set_type(type); },
369 [&](ProcEntityDetails &x) { x.set_type(type); },
370 [&](TypeParamDetails &x) { x.set_type(type); },
371 [](auto &) {},
372 },
373 details_);
374}
375
376template <typename T>
377constexpr bool HasBindName{std::is_convertible_v<T, const WithBindName *>};
378
379const std::string *Symbol::GetBindName() const {
380 return common::visit(
381 [&](auto &x) -> const std::string * {
382 if constexpr (HasBindName<decltype(&x)>) {
383 return x.bindName();
384 } else {
385 return nullptr;
386 }
387 },
388 details_);
389}
390
391void Symbol::SetBindName(std::string &&name) {
392 common::visit(
393 [&](auto &x) {
394 if constexpr (HasBindName<decltype(&x)>) {
395 x.set_bindName(std::move(name));
396 } else {
397 DIE("bind name not allowed on this kind of symbol");
398 }
399 },
400 details_);
401}
402
403bool Symbol::GetIsExplicitBindName() const {
404 return common::visit(
405 [&](auto &x) -> bool {
406 if constexpr (HasBindName<decltype(&x)>) {
407 return x.isExplicitBindName();
408 } else {
409 return false;
410 }
411 },
412 details_);
413}
414
415void Symbol::SetIsExplicitBindName(bool yes) {
416 common::visit(
417 [&](auto &x) {
418 if constexpr (HasBindName<decltype(&x)>) {
419 x.set_isExplicitBindName(yes);
420 } else {
421 DIE("bind name not allowed on this kind of symbol");
422 }
423 },
424 details_);
425}
426
427void Symbol::SetIsCDefined(bool yes) {
428 common::visit(
429 [&](auto &x) {
430 if constexpr (HasBindName<decltype(&x)>) {
431 x.set_isCDefined(yes);
432 } else {
433 DIE("CDEFINED not allowed on this kind of symbol");
434 }
435 },
436 details_);
437}
438
439bool Symbol::IsFuncResult() const {
440 return common::visit(
441 common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); },
442 [](const ObjectEntityDetails &x) { return x.isFuncResult(); },
443 [](const ProcEntityDetails &x) { return x.isFuncResult(); },
444 [](const HostAssocDetails &x) { return x.symbol().IsFuncResult(); },
445 [](const auto &) { return false; }},
446 details_);
447}
448
449const ArraySpec *Symbol::GetShape() const {
450 if (const auto *details{std::get_if<ObjectEntityDetails>(&details_)}) {
451 return &details->shape();
452 } else {
453 return nullptr;
454 }
455}
456
457bool Symbol::IsObjectArray() const {
458 const ArraySpec *shape{GetShape()};
459 return shape && !shape->empty();
460}
461
462bool Symbol::IsSubprogram() const {
463 return common::visit(
464 common::visitors{
465 [](const SubprogramDetails &) { return true; },
466 [](const SubprogramNameDetails &) { return true; },
467 [](const GenericDetails &) { return true; },
468 [](const UseDetails &x) { return x.symbol().IsSubprogram(); },
469 [](const auto &) { return false; },
470 },
471 details_);
472}
473
474bool Symbol::IsFromModFile() const {
475 return test(Flag::ModFile) ||
476 (!owner_->IsTopLevel() && owner_->symbol()->IsFromModFile());
477}
478
479llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) {
480 DumpBool(os, "dummy", x.isDummy());
481 DumpBool(os, "funcResult", x.isFuncResult());
482 if (x.type()) {
483 os << " type: " << *x.type();
484 }
485 DumpOptional(os, "bindName", x.bindName());
486 DumpBool(os, "CDEFINED", x.isCDefined());
487 return os;
488}
489
490llvm::raw_ostream &operator<<(
491 llvm::raw_ostream &os, const ObjectEntityDetails &x) {
492 os << *static_cast<const EntityDetails *>(&x);
493 DumpList(os, "shape", x.shape());
494 DumpList(os, "coshape", x.coshape());
495 DumpExpr(os, "init", x.init_);
496 if (x.unanalyzedPDTComponentInit()) {
497 os << " (has unanalyzedPDTComponentInit)";
498 }
499 if (!x.ignoreTKR_.empty()) {
500 x.ignoreTKR_.Dump(os << ' ', common::EnumToString);
501 }
502 if (x.cudaDataAttr()) {
503 os << " cudaDataAttr: " << common::EnumToString(*x.cudaDataAttr());
504 }
505 return os;
506}
507
508llvm::raw_ostream &operator<<(
509 llvm::raw_ostream &os, const AssocEntityDetails &x) {
510 os << *static_cast<const EntityDetails *>(&x);
511 if (x.IsAssumedSize()) {
512 os << " RANK(*)";
513 } else if (x.IsAssumedRank()) {
514 os << " RANK DEFAULT";
515 } else if (auto assocRank{x.rank()}) {
516 os << " RANK(" << *assocRank << ')';
517 }
518 DumpExpr(os, "expr", x.expr());
519 return os;
520}
521
522llvm::raw_ostream &operator<<(
523 llvm::raw_ostream &os, const ProcEntityDetails &x) {
524 if (x.procInterface_) {
525 if (x.rawProcInterface_ != x.procInterface_) {
526 os << ' ' << x.rawProcInterface_->name() << " ->";
527 }
528 os << ' ' << x.procInterface_->name();
529 } else {
530 DumpType(os, x.type());
531 }
532 DumpOptional(os, "bindName", x.bindName());
533 DumpOptional(os, "passName", x.passName());
534 if (x.init()) {
535 if (const Symbol * target{*x.init()}) {
536 os << " => " << target->name();
537 } else {
538 os << " => NULL()";
539 }
540 }
541 if (x.isCUDAKernel()) {
542 os << " isCUDAKernel";
543 }
544 return os;
545}
546
547llvm::raw_ostream &operator<<(
548 llvm::raw_ostream &os, const DerivedTypeDetails &x) {
549 DumpBool(os, "sequence", x.sequence_);
550 DumpList(os, "components", x.componentNames_);
551 return os;
552}
553
554llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const GenericDetails &x) {
555 os << ' ' << x.kind().ToString();
556 DumpBool(os, "(specific)", x.specific() != nullptr);
557 DumpBool(os, "(derivedType)", x.derivedType() != nullptr);
558 if (const auto &uses{x.uses()}; !uses.empty()) {
559 os << " (uses:";
560 char sep{' '};
561 for (const Symbol &use : uses) {
562 const Symbol &ultimate{use.GetUltimate()};
563 os << sep << ultimate.name() << "->"
564 << ultimate.owner().GetName().value();
565 sep = ',';
566 }
567 os << ')';
568 }
569 os << " procs:";
570 DumpSymbolVector(os, x.specificProcs());
571 return os;
572}
573
574llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
575 os << DetailsToString(details);
576 common::visit( //
577 common::visitors{
578 [&](const UnknownDetails &) {},
579 [&](const MainProgramDetails &) {},
580 [&](const ModuleDetails &x) {
581 if (x.isSubmodule()) {
582 os << " (";
583 if (x.ancestor()) {
584 auto ancestor{x.ancestor()->GetName().value()};
585 os << ancestor;
586 if (x.parent()) {
587 auto parent{x.parent()->GetName().value()};
588 if (ancestor != parent) {
589 os << ':' << parent;
590 }
591 }
592 }
593 os << ")";
594 }
595 if (x.isDefaultPrivate()) {
596 os << " isDefaultPrivate";
597 }
598 },
599 [&](const SubprogramNameDetails &x) {
600 os << ' ' << EnumToString(x.kind());
601 },
602 [&](const UseDetails &x) {
603 os << " from " << x.symbol().name() << " in "
604 << GetUsedModule(x).name();
605 },
606 [&](const UseErrorDetails &x) {
607 os << " uses:";
608 char sep{':'};
609 for (const auto &[location, sym] : x.occurrences()) {
610 os << sep << " from " << sym->name() << " at " << location;
611 sep = ',';
612 }
613 },
614 [](const HostAssocDetails &) {},
615 [&](const ProcBindingDetails &x) {
616 os << " => " << x.symbol().name();
617 DumpOptional(os, "passName", x.passName());
618 if (x.numPrivatesNotOverridden() > 0) {
619 os << " numPrivatesNotOverridden: "
620 << x.numPrivatesNotOverridden();
621 }
622 },
623 [&](const NamelistDetails &x) {
624 os << ':';
625 DumpSymbolVector(os, x.objects());
626 },
627 [&](const CommonBlockDetails &x) {
628 DumpOptional(os, "bindName", x.bindName());
629 if (x.alignment()) {
630 os << " alignment=" << x.alignment();
631 }
632 os << ':';
633 for (const auto &object : x.objects()) {
634 os << ' ' << object->name();
635 }
636 },
637 [&](const TypeParamDetails &x) {
638 DumpOptional(os, "type", x.type());
639 if (auto attr{x.attr()}) {
640 os << ' ' << common::EnumToString(*attr);
641 } else {
642 os << " (no attr)";
643 }
644 DumpExpr(os, "init", x.init());
645 },
646 [&](const MiscDetails &x) {
647 os << ' ' << MiscDetails::EnumToString(x.kind());
648 },
649 [&](const UserReductionDetails &x) {
650 for (auto &type : x.GetTypeList()) {
651 DumpType(os, type);
652 }
653 },
654 [&](const auto &x) { os << x; },
655 },
656 details);
657 return os;
658}
659
660llvm::raw_ostream &operator<<(llvm::raw_ostream &o, Symbol::Flag flag) {
661 return o << Symbol::EnumToString(flag);
662}
663
664llvm::raw_ostream &operator<<(
665 llvm::raw_ostream &o, const Symbol::Flags &flags) {
666 std::size_t n{flags.count()};
667 std::size_t seen{0};
668 for (std::size_t j{0}; seen < n; ++j) {
669 Symbol::Flag flag{static_cast<Symbol::Flag>(j)};
670 if (flags.test(flag)) {
671 if (seen++ > 0) {
672 o << ", ";
673 }
674 o << flag;
675 }
676 }
677 return o;
678}
679
680llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Symbol &symbol) {
681 os << symbol.name();
682 if (!symbol.attrs().empty()) {
683 os << ", " << symbol.attrs();
684 }
685 if (!symbol.flags().empty()) {
686 os << " (" << symbol.flags() << ')';
687 }
688 if (symbol.size_) {
689 os << " size=" << symbol.size_ << " offset=" << symbol.offset_;
690 }
691 os << ": " << symbol.details_;
692 return os;
693}
694
695#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
696void Symbol::dump() const { llvm::errs() << *this << '\n'; }
697#endif
698
699// Output a unique name for a scope by qualifying it with the names of
700// parent scopes. For scopes without corresponding symbols, use the kind
701// with an index (e.g. Block1, Block2, etc.).
702static void DumpUniqueName(llvm::raw_ostream &os, const Scope &scope) {
703 if (!scope.IsTopLevel()) {
704 DumpUniqueName(os, scope.parent());
705 os << '/';
706 if (auto *scopeSymbol{scope.symbol()};
707 scopeSymbol && !scopeSymbol->name().empty()) {
708 os << scopeSymbol->name();
709 } else {
710 int index{1};
711 for (auto &child : scope.parent().children()) {
712 if (child == scope) {
713 break;
714 }
715 if (child.kind() == scope.kind()) {
716 ++index;
717 }
718 }
719 os << Scope::EnumToString(scope.kind()) << index;
720 }
721 }
722}
723
724// Dump a symbol for UnparseWithSymbols. This will be used for tests so the
725// format should be reasonably stable.
726llvm::raw_ostream &DumpForUnparse(
727 llvm::raw_ostream &os, const Symbol &symbol, bool isDef) {
728 DumpUniqueName(os, symbol.owner());
729 os << '/' << symbol.name();
730 if (isDef) {
731 if (!symbol.attrs().empty()) {
732 os << ' ' << symbol.attrs();
733 }
734 if (!symbol.flags().empty()) {
735 os << " (" << symbol.flags() << ')';
736 }
737 os << ' ' << symbol.GetDetailsName();
738 DumpType(os, symbol.GetType());
739 }
740 return os;
741}
742
743const DerivedTypeSpec *Symbol::GetParentTypeSpec(const Scope *scope) const {
744 if (const Symbol * parentComponent{GetParentComponent(scope)}) {
745 const auto &object{parentComponent->get<ObjectEntityDetails>()};
746 return &object.type()->derivedTypeSpec();
747 } else {
748 return nullptr;
749 }
750}
751
752const Symbol *Symbol::GetParentComponent(const Scope *scope) const {
753 if (const auto *dtDetails{detailsIf<DerivedTypeDetails>()}) {
754 if (const Scope * localScope{scope ? scope : scope_}) {
755 return dtDetails->GetParentComponent(DEREF(localScope));
756 }
757 }
758 return nullptr;
759}
760
761void DerivedTypeDetails::add_component(const Symbol &symbol) {
762 if (symbol.test(Symbol::Flag::ParentComp)) {
763 CHECK(componentNames_.empty());
764 }
765 componentNames_.push_back(symbol.name());
766}
767
768const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const {
769 if (auto extends{GetParentComponentName()}) {
770 if (auto iter{scope.find(*extends)}; iter != scope.cend()) {
771 if (const Symbol & symbol{*iter->second};
772 symbol.test(Symbol::Flag::ParentComp)) {
773 return &symbol;
774 }
775 }
776 }
777 return nullptr;
778}
779
780const Symbol *DerivedTypeDetails::GetFinalForRank(int rank) const {
781 for (const auto &pair : finals_) {
782 const Symbol &symbol{*pair.second};
783 if (const auto *details{symbol.detailsIf<SubprogramDetails>()}) {
784 if (details->dummyArgs().size() == 1) {
785 if (const Symbol * arg{details->dummyArgs().at(0)}) {
786 if (const auto *object{arg->detailsIf<ObjectEntityDetails>()}) {
787 if (rank == object->shape().Rank() || object->IsAssumedRank() ||
788 IsElementalProcedure(symbol)) {
789 return &symbol;
790 }
791 }
792 }
793 }
794 }
795 }
796 return nullptr;
797}
798
799TypeParamDetails &TypeParamDetails::set_attr(common::TypeParamAttr attr) {
800 CHECK(!attr_);
801 attr_ = attr;
802 return *this;
803}
804
805TypeParamDetails &TypeParamDetails::set_type(const DeclTypeSpec &type) {
806 CHECK(!type_);
807 type_ = &type;
808 return *this;
809}
810
811bool GenericKind::IsIntrinsicOperator() const {
812 return Is(OtherKind::Concat) || Has<common::LogicalOperator>() ||
813 Has<common::NumericOperator>() || Has<common::RelationalOperator>();
814}
815
816bool GenericKind::IsOperator() const {
817 return IsDefinedOperator() || IsIntrinsicOperator();
818}
819
820std::string GenericKind::ToString() const {
821 return common::visit(
822 common::visitors{
823 [](const OtherKind &x) { return std::string{EnumToString(x)}; },
824 [](const common::DefinedIo &x) { return AsFortran(x).ToString(); },
825 [](const auto &x) { return std::string{common::EnumToString(x)}; },
826 },
827 u);
828}
829
830SourceName GenericKind::AsFortran(common::DefinedIo x) {
831 const char *name{common::AsFortran(x)};
832 return {name, std::strlen(name)};
833}
834
835bool GenericKind::Is(GenericKind::OtherKind x) const {
836 const OtherKind *y{std::get_if<OtherKind>(&u)};
837 return y && *y == x;
838}
839
840std::string Symbol::OmpFlagToClauseName(Symbol::Flag ompFlag) {
841 std::string clauseName;
842 switch (ompFlag) {
843 case Symbol::Flag::OmpShared:
844 clauseName = "SHARED";
845 break;
846 case Symbol::Flag::OmpPrivate:
847 clauseName = "PRIVATE";
848 break;
849 case Symbol::Flag::OmpLinear:
850 clauseName = "LINEAR";
851 break;
852 case Symbol::Flag::OmpUniform:
853 clauseName = "UNIFORM";
854 break;
855 case Symbol::Flag::OmpFirstPrivate:
856 clauseName = "FIRSTPRIVATE";
857 break;
858 case Symbol::Flag::OmpLastPrivate:
859 clauseName = "LASTPRIVATE";
860 break;
861 case Symbol::Flag::OmpMapTo:
862 case Symbol::Flag::OmpMapFrom:
863 case Symbol::Flag::OmpMapToFrom:
864 case Symbol::Flag::OmpMapAlloc:
865 case Symbol::Flag::OmpMapRelease:
866 case Symbol::Flag::OmpMapDelete:
867 clauseName = "MAP";
868 break;
869 case Symbol::Flag::OmpUseDevicePtr:
870 clauseName = "USE_DEVICE_PTR";
871 break;
872 case Symbol::Flag::OmpUseDeviceAddr:
873 clauseName = "USE_DEVICE_ADDR";
874 break;
875 case Symbol::Flag::OmpCopyIn:
876 clauseName = "COPYIN";
877 break;
878 case Symbol::Flag::OmpCopyPrivate:
879 clauseName = "COPYPRIVATE";
880 break;
881 case Symbol::Flag::OmpIsDevicePtr:
882 clauseName = "IS_DEVICE_PTR";
883 break;
884 case Symbol::Flag::OmpHasDeviceAddr:
885 clauseName = "HAS_DEVICE_ADDR";
886 break;
887 default:
888 clauseName = "";
889 break;
890 }
891 return clauseName;
892}
893
894bool SymbolOffsetCompare::operator()(
895 const SymbolRef &x, const SymbolRef &y) const {
896 const Symbol *xCommon{FindCommonBlockContaining(*x)};
897 const Symbol *yCommon{FindCommonBlockContaining(*y)};
898 if (xCommon) {
899 if (yCommon) {
900 const SymbolSourcePositionCompare sourceCmp;
901 if (sourceCmp(*xCommon, *yCommon)) {
902 return true;
903 } else if (sourceCmp(*yCommon, *xCommon)) {
904 return false;
905 } else if (x->offset() == y->offset()) {
906 return x->size() > y->size();
907 } else {
908 return x->offset() < y->offset();
909 }
910 } else {
911 return false;
912 }
913 } else if (yCommon) {
914 return true;
915 } else if (x->offset() == y->offset()) {
916 return x->size() > y->size();
917 } else {
918 return x->offset() < y->offset();
919 }
920 return x->GetSemanticsContext().allCookedSources().Precedes(
921 x->name(), y->name());
922}
923
924bool SymbolOffsetCompare::operator()(
925 const MutableSymbolRef &x, const MutableSymbolRef &y) const {
926 return (*this)(SymbolRef{*x}, SymbolRef{*y});
927}
928
929} // namespace Fortran::semantics
930

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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