1 //===-- lib/Semantics/symbol.cpp ------------------------------------------===//
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
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"
18 #include <type_traits>
20 namespace Fortran::semantics
{
23 static void DumpOptional(llvm::raw_ostream
&os
, const char *label
, const T
&x
) {
25 os
<< ' ' << label
<< ':' << *x
;
29 static void DumpExpr(llvm::raw_ostream
&os
, const char *label
,
30 const std::optional
<evaluate::Expr
<T
>> &x
) {
32 x
->AsFortran(os
<< ' ' << label
<< ':');
36 static void DumpBool(llvm::raw_ostream
&os
, const char *label
, bool x
) {
42 static void DumpSymbolVector(llvm::raw_ostream
&os
, const SymbolVector
&list
) {
44 for (const Symbol
&elem
: list
) {
45 os
<< sep
<< elem
.name();
50 static void DumpType(llvm::raw_ostream
&os
, const Symbol
&symbol
) {
51 if (const auto *type
{symbol
.GetType()}) {
55 static void DumpType(llvm::raw_ostream
&os
, const DeclTypeSpec
*type
) {
62 static void DumpList(llvm::raw_ostream
&os
, const char *label
, const T
&list
) {
64 os
<< ' ' << label
<< ':';
66 for (const auto &elem
: list
) {
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
) {
86 bool scopeIsSubmodule
{scope
->parent().kind() == Scope::Kind::Module
};
87 CHECK(isSubmodule_
== scopeIsSubmodule
);
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());
97 DumpType(os
<< " result:", x
.result());
98 os
<< x
.result_
->name();
99 if (!x
.result_
->attrs().empty()) {
100 os
<< ", " << x
.result_
->attrs();
105 if (x
.entryScope_
->symbol()) {
106 os
<< " in " << x
.entryScope_
->symbol()->name();
111 for (const Symbol
*arg
: x
.dummyArgs_
) {
121 os
<< (sep
== '(' ? "()" : ")");
122 if (x
.stmtFunction_
) {
123 os
<< " -> " << x
.stmtFunction_
->AsFortran();
125 if (x
.moduleInterface_
) {
126 os
<< " moduleInterface: " << *x
.moduleInterface_
;
131 void EntityDetails::set_type(const DeclTypeSpec
&type
) {
136 void AssocEntityDetails::set_rank(int rank
) { rank_
= rank
; }
137 void EntityDetails::ReplaceType(const DeclTypeSpec
&type
) { type_
= &type
; }
139 ObjectEntityDetails::ObjectEntityDetails(EntityDetails
&&d
)
140 : EntityDetails(std::move(d
)) {}
142 void ObjectEntityDetails::set_shape(const ArraySpec
&shape
) {
143 CHECK(shape_
.empty());
144 for (const auto &shapeSpec
: shape
) {
145 shape_
.push_back(shapeSpec
);
148 void ObjectEntityDetails::set_coshape(const ArraySpec
&coshape
) {
149 CHECK(coshape_
.empty());
150 for (const auto &shapeSpec
: coshape
) {
151 coshape_
.push_back(shapeSpec
);
155 ProcEntityDetails::ProcEntityDetails(EntityDetails
&&d
)
156 : EntityDetails(std::move(d
)) {}
158 UseErrorDetails::UseErrorDetails(const UseDetails
&useDetails
) {
159 add_occurrence(useDetails
.location(), *GetUsedModule(useDetails
).scope());
161 UseErrorDetails
&UseErrorDetails::add_occurrence(
162 const SourceName
&location
, const Scope
&module
) {
163 occurrences_
.push_back(std::make_pair(location
, &module
));
167 void GenericDetails::AddSpecificProc(
168 const Symbol
&proc
, SourceName bindingName
) {
169 specificProcs_
.push_back(proc
);
170 bindingNames_
.push_back(bindingName
);
172 void GenericDetails::set_specific(Symbol
&specific
) {
174 CHECK(!derivedType_
);
175 specific_
= &specific
;
177 void GenericDetails::clear_specific() { specific_
= nullptr; }
178 void GenericDetails::set_derivedType(Symbol
&derivedType
) {
180 CHECK(!derivedType_
);
181 derivedType_
= &derivedType
;
183 void GenericDetails::clear_derivedType() { derivedType_
= nullptr; }
184 void GenericDetails::AddUse(const Symbol
&use
) {
185 CHECK(use
.has
<UseDetails
>());
186 uses_
.push_back(use
);
189 const Symbol
*GenericDetails::CheckSpecific() const {
190 return const_cast<GenericDetails
*>(this)->CheckSpecific();
192 Symbol
*GenericDetails::CheckSpecific() {
194 for (const Symbol
&proc
: specificProcs_
) {
195 if (&proc
== specific_
) {
205 void GenericDetails::CopyFrom(const GenericDetails
&from
) {
206 CHECK(specificProcs_
.size() == bindingNames_
.size());
207 CHECK(from
.specificProcs_
.size() == from
.bindingNames_
.size());
209 if (from
.derivedType_
) {
210 CHECK(!derivedType_
|| derivedType_
== from
.derivedType_
);
211 derivedType_
= from
.derivedType_
;
213 for (std::size_t i
{0}; i
< from
.specificProcs_
.size(); ++i
) {
214 if (std::find_if(specificProcs_
.begin(), specificProcs_
.end(),
215 [&](const Symbol
&mySymbol
) {
216 return &mySymbol
.GetUltimate() ==
217 &from
.specificProcs_
[i
]->GetUltimate();
218 }) == specificProcs_
.end()) {
219 specificProcs_
.push_back(from
.specificProcs_
[i
]);
220 bindingNames_
.push_back(from
.bindingNames_
[i
]);
225 // The name of the kind of details for this symbol.
226 // This is primarily for debugging.
227 std::string
DetailsToString(const Details
&details
) {
228 return common::visit(
230 [](const UnknownDetails
&) { return "Unknown"; },
231 [](const MainProgramDetails
&) { return "MainProgram"; },
232 [](const ModuleDetails
&) { return "Module"; },
233 [](const SubprogramDetails
&) { return "Subprogram"; },
234 [](const SubprogramNameDetails
&) { return "SubprogramName"; },
235 [](const EntityDetails
&) { return "Entity"; },
236 [](const ObjectEntityDetails
&) { return "ObjectEntity"; },
237 [](const ProcEntityDetails
&) { return "ProcEntity"; },
238 [](const DerivedTypeDetails
&) { return "DerivedType"; },
239 [](const UseDetails
&) { return "Use"; },
240 [](const UseErrorDetails
&) { return "UseError"; },
241 [](const HostAssocDetails
&) { return "HostAssoc"; },
242 [](const GenericDetails
&) { return "Generic"; },
243 [](const ProcBindingDetails
&) { return "ProcBinding"; },
244 [](const NamelistDetails
&) { return "Namelist"; },
245 [](const CommonBlockDetails
&) { return "CommonBlockDetails"; },
246 [](const TypeParamDetails
&) { return "TypeParam"; },
247 [](const MiscDetails
&) { return "Misc"; },
248 [](const AssocEntityDetails
&) { return "AssocEntity"; },
253 std::string
Symbol::GetDetailsName() const { return DetailsToString(details_
); }
255 void Symbol::set_details(Details
&&details
) {
256 CHECK(CanReplaceDetails(details
));
257 details_
= std::move(details
);
260 bool Symbol::CanReplaceDetails(const Details
&details
) const {
261 if (has
<UnknownDetails
>()) {
262 return true; // can always replace UnknownDetails
264 return common::visit(
266 [](const UseErrorDetails
&) { return true; },
267 [&](const ObjectEntityDetails
&) { return has
<EntityDetails
>(); },
268 [&](const ProcEntityDetails
&) { return has
<EntityDetails
>(); },
269 [&](const SubprogramDetails
&) {
270 return has
<SubprogramNameDetails
>() || has
<EntityDetails
>();
272 [&](const DerivedTypeDetails
&) {
273 const auto *derived
{this->detailsIf
<DerivedTypeDetails
>()};
274 return derived
&& derived
->isForwardReferenced();
276 [&](const UseDetails
&x
) {
277 const auto *use
{this->detailsIf
<UseDetails
>()};
278 return use
&& use
->symbol() == x
.symbol();
280 [&](const HostAssocDetails
&) {
281 return this->has
<HostAssocDetails
>();
283 [](const auto &) { return false; },
289 // Usually a symbol's name is the first occurrence in the source, but sometimes
290 // we want to replace it with one at a different location (but same characters).
291 void Symbol::ReplaceName(const SourceName
&name
) {
292 CHECK(name
== name_
);
296 void Symbol::SetType(const DeclTypeSpec
&type
) {
297 common::visit(common::visitors
{
298 [&](EntityDetails
&x
) { x
.set_type(type
); },
299 [&](ObjectEntityDetails
&x
) { x
.set_type(type
); },
300 [&](AssocEntityDetails
&x
) { x
.set_type(type
); },
301 [&](ProcEntityDetails
&x
) { x
.set_type(type
); },
302 [&](TypeParamDetails
&x
) { x
.set_type(type
); },
308 template <typename T
>
309 constexpr bool HasBindName
{std::is_convertible_v
<T
, const WithBindName
*>};
311 const std::string
*Symbol::GetBindName() const {
312 return common::visit(
313 [&](auto &x
) -> const std::string
* {
314 if constexpr (HasBindName
<decltype(&x
)>) {
323 void Symbol::SetBindName(std::string
&&name
) {
326 if constexpr (HasBindName
<decltype(&x
)>) {
327 x
.set_bindName(std::move(name
));
329 DIE("bind name not allowed on this kind of symbol");
335 bool Symbol::GetIsExplicitBindName() const {
336 return common::visit(
337 [&](auto &x
) -> bool {
338 if constexpr (HasBindName
<decltype(&x
)>) {
339 return x
.isExplicitBindName();
347 void Symbol::SetIsExplicitBindName(bool yes
) {
350 if constexpr (HasBindName
<decltype(&x
)>) {
351 x
.set_isExplicitBindName(yes
);
353 DIE("bind name not allowed on this kind of symbol");
359 bool Symbol::IsFuncResult() const {
360 return common::visit(
361 common::visitors
{[](const EntityDetails
&x
) { return x
.isFuncResult(); },
362 [](const ObjectEntityDetails
&x
) { return x
.isFuncResult(); },
363 [](const ProcEntityDetails
&x
) { return x
.isFuncResult(); },
364 [](const HostAssocDetails
&x
) { return x
.symbol().IsFuncResult(); },
365 [](const auto &) { return false; }},
369 bool Symbol::IsObjectArray() const {
370 const auto *details
{std::get_if
<ObjectEntityDetails
>(&details_
)};
371 return details
&& details
->IsArray();
374 bool Symbol::IsSubprogram() const {
375 return common::visit(
377 [](const SubprogramDetails
&) { return true; },
378 [](const SubprogramNameDetails
&) { return true; },
379 [](const GenericDetails
&) { return true; },
380 [](const UseDetails
&x
) { return x
.symbol().IsSubprogram(); },
381 [](const auto &) { return false; },
386 bool Symbol::IsFromModFile() const {
387 return test(Flag::ModFile
) ||
388 (!owner_
->IsTopLevel() && owner_
->symbol()->IsFromModFile());
391 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&os
, const EntityDetails
&x
) {
392 DumpBool(os
, "dummy", x
.isDummy());
393 DumpBool(os
, "funcResult", x
.isFuncResult());
395 os
<< " type: " << *x
.type();
397 DumpOptional(os
, "bindName", x
.bindName());
401 llvm::raw_ostream
&operator<<(
402 llvm::raw_ostream
&os
, const ObjectEntityDetails
&x
) {
403 os
<< *static_cast<const EntityDetails
*>(&x
);
404 DumpList(os
, "shape", x
.shape());
405 DumpList(os
, "coshape", x
.coshape());
406 DumpExpr(os
, "init", x
.init_
);
407 if (x
.unanalyzedPDTComponentInit()) {
408 os
<< " (has unanalyzedPDTComponentInit)";
413 llvm::raw_ostream
&operator<<(
414 llvm::raw_ostream
&os
, const AssocEntityDetails
&x
) {
415 os
<< *static_cast<const EntityDetails
*>(&x
);
416 if (auto assocRank
{x
.rank()}) {
417 os
<< " rank: " << *assocRank
;
419 DumpExpr(os
, "expr", x
.expr());
423 llvm::raw_ostream
&operator<<(
424 llvm::raw_ostream
&os
, const ProcEntityDetails
&x
) {
425 if (x
.procInterface_
) {
426 os
<< ' ' << x
.procInterface_
->name();
428 DumpType(os
, x
.type());
430 DumpOptional(os
, "bindName", x
.bindName());
431 DumpOptional(os
, "passName", x
.passName());
433 if (const Symbol
* target
{*x
.init()}) {
434 os
<< " => " << target
->name();
442 llvm::raw_ostream
&operator<<(
443 llvm::raw_ostream
&os
, const DerivedTypeDetails
&x
) {
444 DumpBool(os
, "sequence", x
.sequence_
);
445 DumpList(os
, "components", x
.componentNames_
);
449 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&os
, const GenericDetails
&x
) {
450 os
<< ' ' << x
.kind().ToString();
451 DumpBool(os
, "(specific)", x
.specific() != nullptr);
452 DumpBool(os
, "(derivedType)", x
.derivedType() != nullptr);
453 if (const auto &uses
{x
.uses()}; !uses
.empty()) {
456 for (const Symbol
&use
: uses
) {
457 const Symbol
&ultimate
{use
.GetUltimate()};
458 os
<< sep
<< ultimate
.name() << "->"
459 << ultimate
.owner().GetName().value();
465 DumpSymbolVector(os
, x
.specificProcs());
469 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&os
, const Details
&details
) {
470 os
<< DetailsToString(details
);
473 [&](const UnknownDetails
&) {},
474 [&](const MainProgramDetails
&) {},
475 [&](const ModuleDetails
&x
) {
476 if (x
.isSubmodule()) {
479 auto ancestor
{x
.ancestor()->GetName().value()};
482 auto parent
{x
.parent()->GetName().value()};
483 if (ancestor
!= parent
) {
491 [&](const SubprogramNameDetails
&x
) {
492 os
<< ' ' << EnumToString(x
.kind());
494 [&](const UseDetails
&x
) {
495 os
<< " from " << x
.symbol().name() << " in "
496 << GetUsedModule(x
).name();
498 [&](const UseErrorDetails
&x
) {
501 for (const auto &[location
, module
] : x
.occurrences()) {
502 os
<< sep
<< " from " << module
->GetName().value() << " at "
507 [](const HostAssocDetails
&) {},
508 [&](const ProcBindingDetails
&x
) {
509 os
<< " => " << x
.symbol().name();
510 DumpOptional(os
, "passName", x
.passName());
512 [&](const NamelistDetails
&x
) {
514 DumpSymbolVector(os
, x
.objects());
516 [&](const CommonBlockDetails
&x
) {
517 DumpOptional(os
, "bindName", x
.bindName());
519 os
<< " alignment=" << x
.alignment();
522 for (const auto &object
: x
.objects()) {
523 os
<< ' ' << object
->name();
526 [&](const TypeParamDetails
&x
) {
527 DumpOptional(os
, "type", x
.type());
528 os
<< ' ' << common::EnumToString(x
.attr());
529 DumpExpr(os
, "init", x
.init());
531 [&](const MiscDetails
&x
) {
532 os
<< ' ' << MiscDetails::EnumToString(x
.kind());
534 [&](const auto &x
) { os
<< x
; },
540 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&o
, Symbol::Flag flag
) {
541 return o
<< Symbol::EnumToString(flag
);
544 llvm::raw_ostream
&operator<<(
545 llvm::raw_ostream
&o
, const Symbol::Flags
&flags
) {
546 std::size_t n
{flags
.count()};
548 for (std::size_t j
{0}; seen
< n
; ++j
) {
549 Symbol::Flag flag
{static_cast<Symbol::Flag
>(j
)};
550 if (flags
.test(flag
)) {
560 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&os
, const Symbol
&symbol
) {
562 if (!symbol
.attrs().empty()) {
563 os
<< ", " << symbol
.attrs();
565 if (!symbol
.flags().empty()) {
566 os
<< " (" << symbol
.flags() << ')';
569 os
<< " size=" << symbol
.size_
<< " offset=" << symbol
.offset_
;
571 os
<< ": " << symbol
.details_
;
575 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
576 void Symbol::dump() const { llvm::errs() << *this << '\n'; }
579 // Output a unique name for a scope by qualifying it with the names of
580 // parent scopes. For scopes without corresponding symbols, use the kind
581 // with an index (e.g. Block1, Block2, etc.).
582 static void DumpUniqueName(llvm::raw_ostream
&os
, const Scope
&scope
) {
583 if (!scope
.IsTopLevel()) {
584 DumpUniqueName(os
, scope
.parent());
586 if (auto *scopeSymbol
{scope
.symbol()};
587 scopeSymbol
&& !scopeSymbol
->name().empty()) {
588 os
<< scopeSymbol
->name();
591 for (auto &child
: scope
.parent().children()) {
592 if (child
== scope
) {
595 if (child
.kind() == scope
.kind()) {
599 os
<< Scope::EnumToString(scope
.kind()) << index
;
604 // Dump a symbol for UnparseWithSymbols. This will be used for tests so the
605 // format should be reasonably stable.
606 llvm::raw_ostream
&DumpForUnparse(
607 llvm::raw_ostream
&os
, const Symbol
&symbol
, bool isDef
) {
608 DumpUniqueName(os
, symbol
.owner());
609 os
<< '/' << symbol
.name();
611 if (!symbol
.attrs().empty()) {
612 os
<< ' ' << symbol
.attrs();
614 if (!symbol
.flags().empty()) {
615 os
<< " (" << symbol
.flags() << ')';
617 os
<< ' ' << symbol
.GetDetailsName();
618 DumpType(os
, symbol
.GetType());
623 const DerivedTypeSpec
*Symbol::GetParentTypeSpec(const Scope
*scope
) const {
624 if (const Symbol
* parentComponent
{GetParentComponent(scope
)}) {
625 const auto &object
{parentComponent
->get
<ObjectEntityDetails
>()};
626 return &object
.type()->derivedTypeSpec();
632 const Symbol
*Symbol::GetParentComponent(const Scope
*scope
) const {
633 if (const auto *dtDetails
{detailsIf
<DerivedTypeDetails
>()}) {
634 if (const Scope
* localScope
{scope
? scope
: scope_
}) {
635 return dtDetails
->GetParentComponent(DEREF(localScope
));
641 void DerivedTypeDetails::add_component(const Symbol
&symbol
) {
642 if (symbol
.test(Symbol::Flag::ParentComp
)) {
643 CHECK(componentNames_
.empty());
645 componentNames_
.push_back(symbol
.name());
648 const Symbol
*DerivedTypeDetails::GetParentComponent(const Scope
&scope
) const {
649 if (auto extends
{GetParentComponentName()}) {
650 if (auto iter
{scope
.find(*extends
)}; iter
!= scope
.cend()) {
651 if (const Symbol
& symbol
{*iter
->second
};
652 symbol
.test(Symbol::Flag::ParentComp
)) {
660 const Symbol
*DerivedTypeDetails::GetFinalForRank(int rank
) const {
661 for (const auto &pair
: finals_
) {
662 const Symbol
&symbol
{*pair
.second
};
663 if (const auto *details
{symbol
.detailsIf
<SubprogramDetails
>()}) {
664 if (details
->dummyArgs().size() == 1) {
665 if (const Symbol
* arg
{details
->dummyArgs().at(0)}) {
666 if (const auto *object
{arg
->detailsIf
<ObjectEntityDetails
>()}) {
667 if (rank
== object
->shape().Rank() || object
->IsAssumedRank() ||
668 IsElementalProcedure(symbol
)) {
679 void TypeParamDetails::set_type(const DeclTypeSpec
&type
) {
684 bool GenericKind::IsIntrinsicOperator() const {
685 return Is(OtherKind::Concat
) || Has
<common::LogicalOperator
>() ||
686 Has
<common::NumericOperator
>() || Has
<common::RelationalOperator
>();
689 bool GenericKind::IsOperator() const {
690 return IsDefinedOperator() || IsIntrinsicOperator();
693 std::string
GenericKind::ToString() const {
694 return common::visit(
696 [](const OtherKind
&x
) { return std::string
{EnumToString(x
)}; },
697 [](const DefinedIo
&x
) { return AsFortran(x
).ToString(); },
698 #if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2
699 [](const common::NumericOperator
&x
) {
700 return std::string
{common::EnumToString(x
)};
702 [](const common::LogicalOperator
&x
) {
703 return std::string
{common::EnumToString(x
)};
705 [](const common::RelationalOperator
&x
) {
706 return std::string
{common::EnumToString(x
)};
709 [](const auto &x
) { return std::string
{common::EnumToString(x
)}; },
715 SourceName
GenericKind::AsFortran(DefinedIo x
) {
716 const char *name
{nullptr};
718 SWITCH_COVERS_ALL_CASES
719 case DefinedIo::ReadFormatted
:
720 name
= "read(formatted)";
722 case DefinedIo::ReadUnformatted
:
723 name
= "read(unformatted)";
725 case DefinedIo::WriteFormatted
:
726 name
= "write(formatted)";
728 case DefinedIo::WriteUnformatted
:
729 name
= "write(unformatted)";
732 return {name
, std::strlen(name
)};
735 bool GenericKind::Is(GenericKind::OtherKind x
) const {
736 const OtherKind
*y
{std::get_if
<OtherKind
>(&u
)};
740 bool SymbolOffsetCompare::operator()(
741 const SymbolRef
&x
, const SymbolRef
&y
) const {
742 const Symbol
*xCommon
{FindCommonBlockContaining(*x
)};
743 const Symbol
*yCommon
{FindCommonBlockContaining(*y
)};
746 const SymbolSourcePositionCompare sourceCmp
;
747 if (sourceCmp(*xCommon
, *yCommon
)) {
749 } else if (sourceCmp(*yCommon
, *xCommon
)) {
751 } else if (x
->offset() == y
->offset()) {
752 return x
->size() > y
->size();
754 return x
->offset() < y
->offset();
759 } else if (yCommon
) {
761 } else if (x
->offset() == y
->offset()) {
762 return x
->size() > y
->size();
764 return x
->offset() < y
->offset();
766 return x
->GetSemanticsContext().allCookedSources().Precedes(
767 x
->name(), y
->name());
770 bool SymbolOffsetCompare::operator()(
771 const MutableSymbolRef
&x
, const MutableSymbolRef
&y
) const {
772 return (*this)(SymbolRef
{*x
}, SymbolRef
{*y
});
775 } // namespace Fortran::semantics