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 | |
20 | namespace Fortran::semantics { |
21 | |
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; |
26 | } |
27 | } |
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 << ':'); |
33 | } |
34 | } |
35 | |
36 | static void DumpBool(llvm::raw_ostream &os, const char *label, bool x) { |
37 | if (x) { |
38 | os << ' ' << label; |
39 | } |
40 | } |
41 | |
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 = ','; |
47 | } |
48 | } |
49 | |
50 | static void DumpType(llvm::raw_ostream &os, const Symbol &symbol) { |
51 | if (const auto *type{symbol.GetType()}) { |
52 | os << *type << ' '; |
53 | } |
54 | } |
55 | static void DumpType(llvm::raw_ostream &os, const DeclTypeSpec *type) { |
56 | if (type) { |
57 | os << ' ' << *type; |
58 | } |
59 | } |
60 | |
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 = ','; |
69 | } |
70 | } |
71 | } |
72 | |
73 | void SubprogramDetails::set_moduleInterface(Symbol &symbol) { |
74 | CHECK(!moduleInterface_); |
75 | moduleInterface_ = &symbol; |
76 | } |
77 | |
78 | const Scope *ModuleDetails::parent() const { |
79 | return isSubmodule_ && scope_ ? &scope_->parent() : nullptr; |
80 | } |
81 | const Scope *ModuleDetails::ancestor() const { |
82 | return isSubmodule_ && scope_ ? FindModuleContaining(*scope_) : nullptr; |
83 | } |
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; |
89 | } |
90 | |
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(); |
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 | |
150 | void EntityDetails::set_type(const DeclTypeSpec &type) { |
151 | CHECK(!type_); |
152 | type_ = &type; |
153 | } |
154 | |
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; } |
159 | |
160 | ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d) |
161 | : EntityDetails(std::move(d)) {} |
162 | |
163 | void ObjectEntityDetails::set_shape(const ArraySpec &shape) { |
164 | CHECK(shape_.empty()); |
165 | for (const auto &shapeSpec : shape) { |
166 | shape_.push_back(shapeSpec); |
167 | } |
168 | } |
169 | void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) { |
170 | CHECK(coshape_.empty()); |
171 | for (const auto &shapeSpec : coshape) { |
172 | coshape_.push_back(shapeSpec); |
173 | } |
174 | } |
175 | |
176 | ProcEntityDetails::ProcEntityDetails(EntityDetails &&d) |
177 | : EntityDetails(std::move(d)) {} |
178 | |
179 | UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) { |
180 | add_occurrence(useDetails.location(), *GetUsedModule(useDetails).scope()); |
181 | } |
182 | UseErrorDetails &UseErrorDetails::add_occurrence( |
183 | const SourceName &location, const Scope &module) { |
184 | occurrences_.push_back(std::make_pair(location, &module)); |
185 | return *this; |
186 | } |
187 | |
188 | void GenericDetails::AddSpecificProc( |
189 | const Symbol &proc, SourceName bindingName) { |
190 | specificProcs_.push_back(proc); |
191 | bindingNames_.push_back(bindingName); |
192 | } |
193 | void GenericDetails::set_specific(Symbol &specific) { |
194 | CHECK(!specific_); |
195 | specific_ = &specific; |
196 | } |
197 | void GenericDetails::clear_specific() { specific_ = nullptr; } |
198 | void GenericDetails::set_derivedType(Symbol &derivedType) { |
199 | CHECK(!derivedType_); |
200 | derivedType_ = &derivedType; |
201 | } |
202 | void GenericDetails::clear_derivedType() { derivedType_ = nullptr; } |
203 | void GenericDetails::AddUse(const Symbol &use) { |
204 | CHECK(use.has<UseDetails>()); |
205 | uses_.push_back(use); |
206 | } |
207 | |
208 | const Symbol *GenericDetails::CheckSpecific() const { |
209 | return const_cast<GenericDetails *>(this)->CheckSpecific(); |
210 | } |
211 | Symbol *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 | |
224 | void 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. |
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" ; }, |
268 | }, |
269 | details); |
270 | } |
271 | |
272 | std::string Symbol::GetDetailsName() const { return DetailsToString(details_); } |
273 | |
274 | void Symbol::set_details(Details &&details) { |
275 | CHECK(CanReplaceDetails(details)); |
276 | details_ = std::move(details); |
277 | } |
278 | |
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>(); |
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). |
310 | void Symbol::ReplaceName(const SourceName &name) { |
311 | CHECK(name == name_); |
312 | name_ = name; |
313 | } |
314 | |
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 &) {}, |
323 | }, |
324 | details_); |
325 | } |
326 | |
327 | template <typename T> |
328 | constexpr bool HasBindName{std::is_convertible_v<T, const WithBindName *>}; |
329 | |
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; |
337 | } |
338 | }, |
339 | details_); |
340 | } |
341 | |
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" ); |
349 | } |
350 | }, |
351 | details_); |
352 | } |
353 | |
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; |
361 | } |
362 | }, |
363 | details_); |
364 | } |
365 | |
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" ); |
373 | } |
374 | }, |
375 | details_); |
376 | } |
377 | |
378 | bool 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 | |
388 | bool Symbol::IsObjectArray() const { |
389 | const auto *details{std::get_if<ObjectEntityDetails>(&details_)}; |
390 | return details && details->IsArray(); |
391 | } |
392 | |
393 | bool 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 | |
405 | bool Symbol::IsFromModFile() const { |
406 | return test(Flag::ModFile) || |
407 | (!owner_->IsTopLevel() && owner_->symbol()->IsFromModFile()); |
408 | } |
409 | |
410 | llvm::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 | |
420 | llvm::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 | |
438 | llvm::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 | |
452 | llvm::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 | |
477 | llvm::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 | |
484 | llvm::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 | |
504 | llvm::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 | |
582 | llvm::raw_ostream &operator<<(llvm::raw_ostream &o, Symbol::Flag flag) { |
583 | return o << Symbol::EnumToString(flag); |
584 | } |
585 | |
586 | llvm::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 | |
602 | llvm::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) |
618 | void 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.). |
624 | static 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. |
648 | llvm::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 | |
665 | const 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 | |
674 | const 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 | |
683 | void 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 | |
690 | const 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 | |
702 | const 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 | |
721 | void TypeParamDetails::set_type(const DeclTypeSpec &type) { |
722 | CHECK(!type_); |
723 | type_ = &type; |
724 | } |
725 | |
726 | bool GenericKind::IsIntrinsicOperator() const { |
727 | return Is(OtherKind::Concat) || Has<common::LogicalOperator>() || |
728 | Has<common::NumericOperator>() || Has<common::RelationalOperator>(); |
729 | } |
730 | |
731 | bool GenericKind::IsOperator() const { |
732 | return IsDefinedOperator() || IsIntrinsicOperator(); |
733 | } |
734 | |
735 | std::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 | |
745 | SourceName GenericKind::AsFortran(common::DefinedIo x) { |
746 | const char *name{common::AsFortran(x)}; |
747 | return {name, std::strlen(name)}; |
748 | } |
749 | |
750 | bool GenericKind::Is(GenericKind::OtherKind x) const { |
751 | const OtherKind *y{std::get_if<OtherKind>(&u)}; |
752 | return y && *y == x; |
753 | } |
754 | |
755 | std::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 | |
806 | bool 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 | |
836 | bool SymbolOffsetCompare::operator()( |
837 | const MutableSymbolRef &x, const MutableSymbolRef &y) const { |
838 | return (*this)(SymbolRef{*x}, SymbolRef{*y}); |
839 | } |
840 | |
841 | } // namespace Fortran::semantics |
842 | |