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 <string> 17 18 namespace Fortran::semantics { 19 20 template <typename T> 21 static void DumpOptional(llvm::raw_ostream &os, const char *label, const T &x) { 22 if (x) { 23 os << ' ' << label << ':' << *x; 24 } 25 } 26 template <typename T> 27 static void DumpExpr(llvm::raw_ostream &os, const char *label, 28 const std::optional<evaluate::Expr<T>> &x) { 29 if (x) { 30 x->AsFortran(os << ' ' << label << ':'); 31 } 32 } 33 34 static void DumpBool(llvm::raw_ostream &os, const char *label, bool x) { 35 if (x) { 36 os << ' ' << label; 37 } 38 } 39 40 static void DumpSymbolVector(llvm::raw_ostream &os, const SymbolVector &list) { 41 char sep{' '}; 42 for (const Symbol &elem : list) { 43 os << sep << elem.name(); 44 sep = ','; 45 } 46 } 47 48 static void DumpType(llvm::raw_ostream &os, const Symbol &symbol) { 49 if (const auto *type{symbol.GetType()}) { 50 os << *type << ' '; 51 } 52 } 53 static void DumpType(llvm::raw_ostream &os, const DeclTypeSpec *type) { 54 if (type) { 55 os << ' ' << *type; 56 } 57 } 58 59 template <typename T> 60 static void DumpList(llvm::raw_ostream &os, const char *label, const T &list) { 61 if (!list.empty()) { 62 os << ' ' << label << ':'; 63 char sep{' '}; 64 for (const auto &elem : list) { 65 os << sep << elem; 66 sep = ','; 67 } 68 } 69 } 70 71 const Scope *ModuleDetails::parent() const { 72 return isSubmodule_ && scope_ ? &scope_->parent() : nullptr; 73 } 74 const Scope *ModuleDetails::ancestor() const { 75 return isSubmodule_ && scope_ ? FindModuleContaining(*scope_) : nullptr; 76 } 77 void ModuleDetails::set_scope(const Scope *scope) { 78 CHECK(!scope_); 79 bool scopeIsSubmodule{scope->parent().kind() == Scope::Kind::Module}; 80 CHECK(isSubmodule_ == scopeIsSubmodule); 81 scope_ = scope; 82 } 83 84 llvm::raw_ostream &operator<<( 85 llvm::raw_ostream &os, const SubprogramDetails &x) { 86 DumpBool(os, "isInterface", x.isInterface_); 87 DumpExpr(os, "bindName", x.bindName_); 88 if (x.result_) { 89 DumpType(os << " result:", x.result()); 90 os << x.result_->name(); 91 if (!x.result_->attrs().empty()) { 92 os << ", " << x.result_->attrs(); 93 } 94 } 95 if (x.entryScope_) { 96 os << " entry"; 97 if (x.entryScope_->symbol()) { 98 os << " in " << x.entryScope_->symbol()->name(); 99 } 100 } 101 char sep{'('}; 102 os << ' '; 103 for (const Symbol *arg : x.dummyArgs_) { 104 os << sep; 105 sep = ','; 106 if (arg) { 107 DumpType(os, *arg); 108 os << arg->name(); 109 } else { 110 os << '*'; 111 } 112 } 113 os << (sep == '(' ? "()" : ")"); 114 return os; 115 } 116 117 void EntityDetails::set_type(const DeclTypeSpec &type) { 118 CHECK(!type_); 119 type_ = &type; 120 } 121 122 void AssocEntityDetails::set_rank(int rank) { rank_ = rank; } 123 void EntityDetails::ReplaceType(const DeclTypeSpec &type) { type_ = &type; } 124 125 void ObjectEntityDetails::set_shape(const ArraySpec &shape) { 126 CHECK(shape_.empty()); 127 for (const auto &shapeSpec : shape) { 128 shape_.push_back(shapeSpec); 129 } 130 } 131 void ObjectEntityDetails::set_coshape(const ArraySpec &coshape) { 132 CHECK(coshape_.empty()); 133 for (const auto &shapeSpec : coshape) { 134 coshape_.push_back(shapeSpec); 135 } 136 } 137 138 ProcEntityDetails::ProcEntityDetails(EntityDetails &&d) : EntityDetails(d) { 139 if (type()) { 140 interface_.set_type(*type()); 141 } 142 } 143 144 const Symbol &UseDetails::module() const { 145 // owner is a module so it must have a symbol: 146 return *symbol_->owner().symbol(); 147 } 148 149 UseErrorDetails::UseErrorDetails(const UseDetails &useDetails) { 150 add_occurrence(useDetails.location(), *useDetails.module().scope()); 151 } 152 UseErrorDetails &UseErrorDetails::add_occurrence( 153 const SourceName &location, const Scope &module) { 154 occurrences_.push_back(std::make_pair(location, &module)); 155 return *this; 156 } 157 158 GenericDetails::GenericDetails(const SymbolVector &specificProcs) 159 : specificProcs_{specificProcs} {} 160 161 void GenericDetails::AddSpecificProc( 162 const Symbol &proc, SourceName bindingName) { 163 specificProcs_.push_back(proc); 164 bindingNames_.push_back(bindingName); 165 } 166 void GenericDetails::set_specific(Symbol &specific) { 167 CHECK(!specific_); 168 CHECK(!derivedType_); 169 specific_ = &specific; 170 } 171 void GenericDetails::set_derivedType(Symbol &derivedType) { 172 CHECK(!specific_); 173 CHECK(!derivedType_); 174 derivedType_ = &derivedType; 175 } 176 177 const Symbol *GenericDetails::CheckSpecific() const { 178 return const_cast<GenericDetails *>(this)->CheckSpecific(); 179 } 180 Symbol *GenericDetails::CheckSpecific() { 181 if (specific_) { 182 for (const Symbol &proc : specificProcs_) { 183 if (&proc == specific_) { 184 return nullptr; 185 } 186 } 187 return specific_; 188 } else { 189 return nullptr; 190 } 191 } 192 193 void GenericDetails::CopyFrom(const GenericDetails &from) { 194 if (from.specific_) { 195 CHECK(!specific_ || specific_ == from.specific_); 196 specific_ = from.specific_; 197 } 198 if (from.derivedType_) { 199 CHECK(!derivedType_ || derivedType_ == from.derivedType_); 200 derivedType_ = from.derivedType_; 201 } 202 for (const Symbol &symbol : from.specificProcs_) { 203 if (std::find_if(specificProcs_.begin(), specificProcs_.end(), 204 [&](const Symbol &mySymbol) { return &mySymbol == &symbol; }) == 205 specificProcs_.end()) { 206 specificProcs_.push_back(symbol); 207 } 208 } 209 } 210 211 // The name of the kind of details for this symbol. 212 // This is primarily for debugging. 213 std::string DetailsToString(const Details &details) { 214 return std::visit( 215 common::visitors{ 216 [](const UnknownDetails &) { return "Unknown"; }, 217 [](const MainProgramDetails &) { return "MainProgram"; }, 218 [](const ModuleDetails &) { return "Module"; }, 219 [](const SubprogramDetails &) { return "Subprogram"; }, 220 [](const SubprogramNameDetails &) { return "SubprogramName"; }, 221 [](const EntityDetails &) { return "Entity"; }, 222 [](const ObjectEntityDetails &) { return "ObjectEntity"; }, 223 [](const ProcEntityDetails &) { return "ProcEntity"; }, 224 [](const DerivedTypeDetails &) { return "DerivedType"; }, 225 [](const UseDetails &) { return "Use"; }, 226 [](const UseErrorDetails &) { return "UseError"; }, 227 [](const HostAssocDetails &) { return "HostAssoc"; }, 228 [](const GenericDetails &) { return "Generic"; }, 229 [](const ProcBindingDetails &) { return "ProcBinding"; }, 230 [](const NamelistDetails &) { return "Namelist"; }, 231 [](const CommonBlockDetails &) { return "CommonBlockDetails"; }, 232 [](const FinalProcDetails &) { return "FinalProc"; }, 233 [](const TypeParamDetails &) { return "TypeParam"; }, 234 [](const MiscDetails &) { return "Misc"; }, 235 [](const AssocEntityDetails &) { return "AssocEntity"; }, 236 }, 237 details); 238 } 239 240 const std::string Symbol::GetDetailsName() const { 241 return DetailsToString(details_); 242 } 243 244 void Symbol::set_details(Details &&details) { 245 CHECK(CanReplaceDetails(details)); 246 details_ = std::move(details); 247 } 248 249 bool Symbol::CanReplaceDetails(const Details &details) const { 250 if (has<UnknownDetails>()) { 251 return true; // can always replace UnknownDetails 252 } else { 253 return std::visit( 254 common::visitors{ 255 [](const UseErrorDetails &) { return true; }, 256 [&](const ObjectEntityDetails &) { return has<EntityDetails>(); }, 257 [&](const ProcEntityDetails &) { return has<EntityDetails>(); }, 258 [&](const SubprogramDetails &) { 259 return has<SubprogramNameDetails>() || has<EntityDetails>(); 260 }, 261 [&](const DerivedTypeDetails &) { 262 auto *derived{detailsIf<DerivedTypeDetails>()}; 263 return derived && derived->isForwardReferenced(); 264 }, 265 [](const auto &) { return false; }, 266 }, 267 details); 268 } 269 } 270 271 // Usually a symbol's name is the first occurrence in the source, but sometimes 272 // we want to replace it with one at a different location (but same characters). 273 void Symbol::ReplaceName(const SourceName &name) { 274 CHECK(name == name_); 275 name_ = name; 276 } 277 278 void Symbol::SetType(const DeclTypeSpec &type) { 279 std::visit(common::visitors{ 280 [&](EntityDetails &x) { x.set_type(type); }, 281 [&](ObjectEntityDetails &x) { x.set_type(type); }, 282 [&](AssocEntityDetails &x) { x.set_type(type); }, 283 [&](ProcEntityDetails &x) { x.interface().set_type(type); }, 284 [&](TypeParamDetails &x) { x.set_type(type); }, 285 [](auto &) {}, 286 }, 287 details_); 288 } 289 290 bool Symbol::IsDummy() const { 291 return std::visit( 292 common::visitors{[](const EntityDetails &x) { return x.isDummy(); }, 293 [](const ObjectEntityDetails &x) { return x.isDummy(); }, 294 [](const ProcEntityDetails &x) { return x.isDummy(); }, 295 [](const HostAssocDetails &x) { return x.symbol().IsDummy(); }, 296 [](const auto &) { return false; }}, 297 details_); 298 } 299 300 bool Symbol::IsFuncResult() const { 301 return std::visit( 302 common::visitors{[](const EntityDetails &x) { return x.isFuncResult(); }, 303 [](const ObjectEntityDetails &x) { return x.isFuncResult(); }, 304 [](const ProcEntityDetails &x) { return x.isFuncResult(); }, 305 [](const HostAssocDetails &x) { return x.symbol().IsFuncResult(); }, 306 [](const auto &) { return false; }}, 307 details_); 308 } 309 310 bool Symbol::IsObjectArray() const { 311 const auto *details{std::get_if<ObjectEntityDetails>(&details_)}; 312 return details && details->IsArray(); 313 } 314 315 bool Symbol::IsSubprogram() const { 316 return std::visit( 317 common::visitors{ 318 [](const SubprogramDetails &) { return true; }, 319 [](const SubprogramNameDetails &) { return true; }, 320 [](const GenericDetails &) { return true; }, 321 [](const UseDetails &x) { return x.symbol().IsSubprogram(); }, 322 [](const auto &) { return false; }, 323 }, 324 details_); 325 } 326 327 bool Symbol::IsFromModFile() const { 328 return test(Flag::ModFile) || 329 (!owner_->IsGlobal() && owner_->symbol()->IsFromModFile()); 330 } 331 332 ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d) 333 : EntityDetails(d) {} 334 335 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const EntityDetails &x) { 336 DumpBool(os, "dummy", x.isDummy()); 337 DumpBool(os, "funcResult", x.isFuncResult()); 338 if (x.type()) { 339 os << " type: " << *x.type(); 340 } 341 DumpExpr(os, "bindName", x.bindName_); 342 return os; 343 } 344 345 llvm::raw_ostream &operator<<( 346 llvm::raw_ostream &os, const ObjectEntityDetails &x) { 347 os << *static_cast<const EntityDetails *>(&x); 348 DumpList(os, "shape", x.shape()); 349 DumpList(os, "coshape", x.coshape()); 350 DumpExpr(os, "init", x.init_); 351 return os; 352 } 353 354 llvm::raw_ostream &operator<<( 355 llvm::raw_ostream &os, const AssocEntityDetails &x) { 356 os << *static_cast<const EntityDetails *>(&x); 357 if (auto assocRank{x.rank()}) { 358 os << " rank: " << *assocRank; 359 } 360 DumpExpr(os, "expr", x.expr()); 361 return os; 362 } 363 364 llvm::raw_ostream &operator<<( 365 llvm::raw_ostream &os, const ProcEntityDetails &x) { 366 if (auto *symbol{x.interface_.symbol()}) { 367 os << ' ' << symbol->name(); 368 } else { 369 DumpType(os, x.interface_.type()); 370 } 371 DumpExpr(os, "bindName", x.bindName()); 372 DumpOptional(os, "passName", x.passName()); 373 if (x.init()) { 374 if (const Symbol * target{*x.init()}) { 375 os << " => " << target->name(); 376 } else { 377 os << " => NULL()"; 378 } 379 } 380 return os; 381 } 382 383 llvm::raw_ostream &operator<<( 384 llvm::raw_ostream &os, const DerivedTypeDetails &x) { 385 DumpBool(os, "sequence", x.sequence_); 386 DumpList(os, "components", x.componentNames_); 387 return os; 388 } 389 390 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) { 391 os << DetailsToString(details); 392 std::visit( 393 common::visitors{ 394 [&](const UnknownDetails &) {}, 395 [&](const MainProgramDetails &) {}, 396 [&](const ModuleDetails &x) { 397 if (x.isSubmodule()) { 398 os << " ("; 399 if (x.ancestor()) { 400 auto ancestor{x.ancestor()->GetName().value()}; 401 os << ancestor; 402 if (x.parent()) { 403 auto parent{x.parent()->GetName().value()}; 404 if (ancestor != parent) { 405 os << ':' << parent; 406 } 407 } 408 } 409 os << ")"; 410 } 411 }, 412 [&](const SubprogramNameDetails &x) { 413 os << ' ' << EnumToString(x.kind()); 414 }, 415 [&](const UseDetails &x) { 416 os << " from " << x.symbol().name() << " in " << x.module().name(); 417 }, 418 [&](const UseErrorDetails &x) { 419 os << " uses:"; 420 for (const auto &[location, module] : x.occurrences()) { 421 os << " from " << module->GetName().value() << " at " << location; 422 } 423 }, 424 [](const HostAssocDetails &) {}, 425 [&](const GenericDetails &x) { 426 os << ' ' << x.kind().ToString(); 427 DumpBool(os, "(specific)", x.specific() != nullptr); 428 DumpBool(os, "(derivedType)", x.derivedType() != nullptr); 429 os << " procs:"; 430 DumpSymbolVector(os, x.specificProcs()); 431 }, 432 [&](const ProcBindingDetails &x) { 433 os << " => " << x.symbol().name(); 434 DumpOptional(os, "passName", x.passName()); 435 }, 436 [&](const NamelistDetails &x) { 437 os << ':'; 438 DumpSymbolVector(os, x.objects()); 439 }, 440 [&](const CommonBlockDetails &x) { 441 if (x.alignment()) { 442 os << " alignment=" << x.alignment(); 443 } 444 os << ':'; 445 for (const auto &object : x.objects()) { 446 os << ' ' << object->name(); 447 } 448 }, 449 [&](const FinalProcDetails &) {}, 450 [&](const TypeParamDetails &x) { 451 DumpOptional(os, "type", x.type()); 452 os << ' ' << common::EnumToString(x.attr()); 453 DumpExpr(os, "init", x.init()); 454 }, 455 [&](const MiscDetails &x) { 456 os << ' ' << MiscDetails::EnumToString(x.kind()); 457 }, 458 [&](const auto &x) { os << x; }, 459 }, 460 details); 461 return os; 462 } 463 464 llvm::raw_ostream &operator<<(llvm::raw_ostream &o, Symbol::Flag flag) { 465 return o << Symbol::EnumToString(flag); 466 } 467 468 llvm::raw_ostream &operator<<( 469 llvm::raw_ostream &o, const Symbol::Flags &flags) { 470 std::size_t n{flags.count()}; 471 std::size_t seen{0}; 472 for (std::size_t j{0}; seen < n; ++j) { 473 Symbol::Flag flag{static_cast<Symbol::Flag>(j)}; 474 if (flags.test(flag)) { 475 if (seen++ > 0) { 476 o << ", "; 477 } 478 o << flag; 479 } 480 } 481 return o; 482 } 483 484 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Symbol &symbol) { 485 os << symbol.name(); 486 if (!symbol.attrs().empty()) { 487 os << ", " << symbol.attrs(); 488 } 489 if (!symbol.flags().empty()) { 490 os << " (" << symbol.flags() << ')'; 491 } 492 if (symbol.size_) { 493 os << " size=" << symbol.size_ << " offset=" << symbol.offset_; 494 } 495 os << ": " << symbol.details_; 496 return os; 497 } 498 499 // Output a unique name for a scope by qualifying it with the names of 500 // parent scopes. For scopes without corresponding symbols, use the kind 501 // with an index (e.g. Block1, Block2, etc.). 502 static void DumpUniqueName(llvm::raw_ostream &os, const Scope &scope) { 503 if (!scope.IsGlobal()) { 504 DumpUniqueName(os, scope.parent()); 505 os << '/'; 506 if (auto *scopeSymbol{scope.symbol()}; 507 scopeSymbol && !scopeSymbol->name().empty()) { 508 os << scopeSymbol->name(); 509 } else { 510 int index{1}; 511 for (auto &child : scope.parent().children()) { 512 if (child == scope) { 513 break; 514 } 515 if (child.kind() == scope.kind()) { 516 ++index; 517 } 518 } 519 os << Scope::EnumToString(scope.kind()) << index; 520 } 521 } 522 } 523 524 // Dump a symbol for UnparseWithSymbols. This will be used for tests so the 525 // format should be reasonably stable. 526 llvm::raw_ostream &DumpForUnparse( 527 llvm::raw_ostream &os, const Symbol &symbol, bool isDef) { 528 DumpUniqueName(os, symbol.owner()); 529 os << '/' << symbol.name(); 530 if (isDef) { 531 if (!symbol.attrs().empty()) { 532 os << ' ' << symbol.attrs(); 533 } 534 if (!symbol.flags().empty()) { 535 os << " (" << symbol.flags() << ')'; 536 } 537 os << ' ' << symbol.GetDetailsName(); 538 DumpType(os, symbol.GetType()); 539 } 540 return os; 541 } 542 543 const DerivedTypeSpec *Symbol::GetParentTypeSpec(const Scope *scope) const { 544 if (const Symbol * parentComponent{GetParentComponent(scope)}) { 545 const auto &object{parentComponent->get<ObjectEntityDetails>()}; 546 return &object.type()->derivedTypeSpec(); 547 } else { 548 return nullptr; 549 } 550 } 551 552 const Symbol *Symbol::GetParentComponent(const Scope *scope) const { 553 if (const auto *dtDetails{detailsIf<DerivedTypeDetails>()}) { 554 if (!scope) { 555 scope = scope_; 556 } 557 return dtDetails->GetParentComponent(DEREF(scope)); 558 } else { 559 return nullptr; 560 } 561 } 562 563 void DerivedTypeDetails::add_component(const Symbol &symbol) { 564 if (symbol.test(Symbol::Flag::ParentComp)) { 565 CHECK(componentNames_.empty()); 566 } 567 componentNames_.push_back(symbol.name()); 568 } 569 570 const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const { 571 if (auto extends{GetParentComponentName()}) { 572 if (auto iter{scope.find(*extends)}; iter != scope.cend()) { 573 if (const Symbol & symbol{*iter->second}; 574 symbol.test(Symbol::Flag::ParentComp)) { 575 return &symbol; 576 } 577 } 578 } 579 return nullptr; 580 } 581 582 void TypeParamDetails::set_type(const DeclTypeSpec &type) { 583 CHECK(!type_); 584 type_ = &type; 585 } 586 587 bool GenericKind::IsIntrinsicOperator() const { 588 return Is(OtherKind::Concat) || Has<common::LogicalOperator>() || 589 Has<common::NumericOperator>() || Has<common::RelationalOperator>(); 590 } 591 592 bool GenericKind::IsOperator() const { 593 return IsDefinedOperator() || IsIntrinsicOperator(); 594 } 595 596 std::string GenericKind::ToString() const { 597 return std::visit( 598 common::visitors { 599 [](const OtherKind &x) { return EnumToString(x); }, 600 [](const DefinedIo &x) { return EnumToString(x); }, 601 #if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2 602 [](const common::NumericOperator &x) { 603 return common::EnumToString(x); 604 }, 605 [](const common::LogicalOperator &x) { 606 return common::EnumToString(x); 607 }, 608 [](const common::RelationalOperator &x) { 609 return common::EnumToString(x); 610 }, 611 #else 612 [](const auto &x) { return common::EnumToString(x); }, 613 #endif 614 }, 615 u); 616 } 617 618 bool GenericKind::Is(GenericKind::OtherKind x) const { 619 const OtherKind *y{std::get_if<OtherKind>(&u)}; 620 return y && *y == x; 621 } 622 623 } // namespace Fortran::semantics 624