1 //===-- lib/Semantics/resolve-names-utils.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 "resolve-names-utils.h" 10 #include "flang/Common/Fortran-features.h" 11 #include "flang/Common/Fortran.h" 12 #include "flang/Common/idioms.h" 13 #include "flang/Common/indirection.h" 14 #include "flang/Evaluate/fold.h" 15 #include "flang/Evaluate/tools.h" 16 #include "flang/Evaluate/type.h" 17 #include "flang/Parser/char-block.h" 18 #include "flang/Parser/parse-tree.h" 19 #include "flang/Semantics/expression.h" 20 #include "flang/Semantics/semantics.h" 21 #include "flang/Semantics/tools.h" 22 #include <initializer_list> 23 #include <variant> 24 25 namespace Fortran::semantics { 26 27 using common::LanguageFeature; 28 using common::LogicalOperator; 29 using common::NumericOperator; 30 using common::RelationalOperator; 31 using IntrinsicOperator = parser::DefinedOperator::IntrinsicOperator; 32 33 static constexpr const char *operatorPrefix{"operator("}; 34 35 static GenericKind MapIntrinsicOperator(IntrinsicOperator); 36 37 Symbol *Resolve(const parser::Name &name, Symbol *symbol) { 38 if (symbol && !name.symbol) { 39 name.symbol = symbol; 40 } 41 return symbol; 42 } 43 Symbol &Resolve(const parser::Name &name, Symbol &symbol) { 44 return *Resolve(name, &symbol); 45 } 46 47 parser::MessageFixedText WithSeverity( 48 const parser::MessageFixedText &msg, parser::Severity severity) { 49 return parser::MessageFixedText{ 50 msg.text().begin(), msg.text().size(), severity}; 51 } 52 53 bool IsIntrinsicOperator( 54 const SemanticsContext &context, const SourceName &name) { 55 std::string str{name.ToString()}; 56 for (int i{0}; i != common::LogicalOperator_enumSize; ++i) { 57 auto names{context.languageFeatures().GetNames(LogicalOperator{i})}; 58 if (std::find(names.begin(), names.end(), str) != names.end()) { 59 return true; 60 } 61 } 62 for (int i{0}; i != common::RelationalOperator_enumSize; ++i) { 63 auto names{context.languageFeatures().GetNames(RelationalOperator{i})}; 64 if (std::find(names.begin(), names.end(), str) != names.end()) { 65 return true; 66 } 67 } 68 return false; 69 } 70 71 template <typename E> 72 std::forward_list<std::string> GetOperatorNames( 73 const SemanticsContext &context, E opr) { 74 std::forward_list<std::string> result; 75 for (const char *name : context.languageFeatures().GetNames(opr)) { 76 result.emplace_front(std::string{operatorPrefix} + name + ')'); 77 } 78 return result; 79 } 80 81 std::forward_list<std::string> GetAllNames( 82 const SemanticsContext &context, const SourceName &name) { 83 std::string str{name.ToString()}; 84 if (!name.empty() && name.end()[-1] == ')' && 85 name.ToString().rfind(std::string{operatorPrefix}, 0) == 0) { 86 for (int i{0}; i != common::LogicalOperator_enumSize; ++i) { 87 auto names{GetOperatorNames(context, LogicalOperator{i})}; 88 if (std::find(names.begin(), names.end(), str) != names.end()) { 89 return names; 90 } 91 } 92 for (int i{0}; i != common::RelationalOperator_enumSize; ++i) { 93 auto names{GetOperatorNames(context, RelationalOperator{i})}; 94 if (std::find(names.begin(), names.end(), str) != names.end()) { 95 return names; 96 } 97 } 98 } 99 return {str}; 100 } 101 102 bool IsLogicalConstant( 103 const SemanticsContext &context, const SourceName &name) { 104 std::string str{name.ToString()}; 105 return str == ".true." || str == ".false." || 106 (context.IsEnabled(LanguageFeature::LogicalAbbreviations) && 107 (str == ".t" || str == ".f.")); 108 } 109 110 void GenericSpecInfo::Resolve(Symbol *symbol) const { 111 if (symbol) { 112 if (auto *details{symbol->detailsIf<GenericDetails>()}) { 113 details->set_kind(kind_); 114 } 115 if (parseName_) { 116 semantics::Resolve(*parseName_, symbol); 117 } 118 } 119 } 120 121 void GenericSpecInfo::Analyze(const parser::DefinedOpName &name) { 122 kind_ = GenericKind::OtherKind::DefinedOp; 123 parseName_ = &name.v; 124 symbolName_ = name.v.source; 125 } 126 127 void GenericSpecInfo::Analyze(const parser::GenericSpec &x) { 128 symbolName_ = x.source; 129 kind_ = common::visit( 130 common::visitors{ 131 [&](const parser::Name &y) -> GenericKind { 132 parseName_ = &y; 133 symbolName_ = y.source; 134 return GenericKind::OtherKind::Name; 135 }, 136 [&](const parser::DefinedOperator &y) { 137 return common::visit( 138 common::visitors{ 139 [&](const parser::DefinedOpName &z) -> GenericKind { 140 Analyze(z); 141 return GenericKind::OtherKind::DefinedOp; 142 }, 143 [&](const IntrinsicOperator &z) { 144 return MapIntrinsicOperator(z); 145 }, 146 }, 147 y.u); 148 }, 149 [&](const parser::GenericSpec::Assignment &) -> GenericKind { 150 return GenericKind::OtherKind::Assignment; 151 }, 152 [&](const parser::GenericSpec::ReadFormatted &) -> GenericKind { 153 return GenericKind::DefinedIo::ReadFormatted; 154 }, 155 [&](const parser::GenericSpec::ReadUnformatted &) -> GenericKind { 156 return GenericKind::DefinedIo::ReadUnformatted; 157 }, 158 [&](const parser::GenericSpec::WriteFormatted &) -> GenericKind { 159 return GenericKind::DefinedIo::WriteFormatted; 160 }, 161 [&](const parser::GenericSpec::WriteUnformatted &) -> GenericKind { 162 return GenericKind::DefinedIo::WriteUnformatted; 163 }, 164 }, 165 x.u); 166 } 167 168 llvm::raw_ostream &operator<<( 169 llvm::raw_ostream &os, const GenericSpecInfo &info) { 170 os << "GenericSpecInfo: kind=" << info.kind_.ToString(); 171 os << " parseName=" 172 << (info.parseName_ ? info.parseName_->ToString() : "null"); 173 os << " symbolName=" 174 << (info.symbolName_ ? info.symbolName_->ToString() : "null"); 175 return os; 176 } 177 178 // parser::DefinedOperator::IntrinsicOperator -> GenericKind 179 static GenericKind MapIntrinsicOperator(IntrinsicOperator op) { 180 switch (op) { 181 SWITCH_COVERS_ALL_CASES 182 case IntrinsicOperator::Concat: 183 return GenericKind::OtherKind::Concat; 184 case IntrinsicOperator::Power: 185 return NumericOperator::Power; 186 case IntrinsicOperator::Multiply: 187 return NumericOperator::Multiply; 188 case IntrinsicOperator::Divide: 189 return NumericOperator::Divide; 190 case IntrinsicOperator::Add: 191 return NumericOperator::Add; 192 case IntrinsicOperator::Subtract: 193 return NumericOperator::Subtract; 194 case IntrinsicOperator::AND: 195 return LogicalOperator::And; 196 case IntrinsicOperator::OR: 197 return LogicalOperator::Or; 198 case IntrinsicOperator::EQV: 199 return LogicalOperator::Eqv; 200 case IntrinsicOperator::NEQV: 201 return LogicalOperator::Neqv; 202 case IntrinsicOperator::NOT: 203 return LogicalOperator::Not; 204 case IntrinsicOperator::LT: 205 return RelationalOperator::LT; 206 case IntrinsicOperator::LE: 207 return RelationalOperator::LE; 208 case IntrinsicOperator::EQ: 209 return RelationalOperator::EQ; 210 case IntrinsicOperator::NE: 211 return RelationalOperator::NE; 212 case IntrinsicOperator::GE: 213 return RelationalOperator::GE; 214 case IntrinsicOperator::GT: 215 return RelationalOperator::GT; 216 } 217 } 218 219 class ArraySpecAnalyzer { 220 public: 221 ArraySpecAnalyzer(SemanticsContext &context) : context_{context} {} 222 ArraySpec Analyze(const parser::ArraySpec &); 223 ArraySpec AnalyzeDeferredShapeSpecList(const parser::DeferredShapeSpecList &); 224 ArraySpec Analyze(const parser::ComponentArraySpec &); 225 ArraySpec Analyze(const parser::CoarraySpec &); 226 227 private: 228 SemanticsContext &context_; 229 ArraySpec arraySpec_; 230 231 template <typename T> void Analyze(const std::list<T> &list) { 232 for (const auto &elem : list) { 233 Analyze(elem); 234 } 235 } 236 void Analyze(const parser::AssumedShapeSpec &); 237 void Analyze(const parser::ExplicitShapeSpec &); 238 void Analyze(const parser::AssumedImpliedSpec &); 239 void Analyze(const parser::DeferredShapeSpecList &); 240 void Analyze(const parser::AssumedRankSpec &); 241 void MakeExplicit(const std::optional<parser::SpecificationExpr> &, 242 const parser::SpecificationExpr &); 243 void MakeImplied(const std::optional<parser::SpecificationExpr> &); 244 void MakeDeferred(int); 245 Bound GetBound(const std::optional<parser::SpecificationExpr> &); 246 Bound GetBound(const parser::SpecificationExpr &); 247 }; 248 249 ArraySpec AnalyzeArraySpec( 250 SemanticsContext &context, const parser::ArraySpec &arraySpec) { 251 return ArraySpecAnalyzer{context}.Analyze(arraySpec); 252 } 253 ArraySpec AnalyzeArraySpec( 254 SemanticsContext &context, const parser::ComponentArraySpec &arraySpec) { 255 return ArraySpecAnalyzer{context}.Analyze(arraySpec); 256 } 257 ArraySpec AnalyzeDeferredShapeSpecList(SemanticsContext &context, 258 const parser::DeferredShapeSpecList &deferredShapeSpecs) { 259 return ArraySpecAnalyzer{context}.AnalyzeDeferredShapeSpecList( 260 deferredShapeSpecs); 261 } 262 ArraySpec AnalyzeCoarraySpec( 263 SemanticsContext &context, const parser::CoarraySpec &coarraySpec) { 264 return ArraySpecAnalyzer{context}.Analyze(coarraySpec); 265 } 266 267 ArraySpec ArraySpecAnalyzer::Analyze(const parser::ComponentArraySpec &x) { 268 common::visit([this](const auto &y) { Analyze(y); }, x.u); 269 CHECK(!arraySpec_.empty()); 270 return arraySpec_; 271 } 272 ArraySpec ArraySpecAnalyzer::Analyze(const parser::ArraySpec &x) { 273 common::visit(common::visitors{ 274 [&](const parser::AssumedSizeSpec &y) { 275 Analyze( 276 std::get<std::list<parser::ExplicitShapeSpec>>(y.t)); 277 Analyze(std::get<parser::AssumedImpliedSpec>(y.t)); 278 }, 279 [&](const parser::ImpliedShapeSpec &y) { Analyze(y.v); }, 280 [&](const auto &y) { Analyze(y); }, 281 }, 282 x.u); 283 CHECK(!arraySpec_.empty()); 284 return arraySpec_; 285 } 286 ArraySpec ArraySpecAnalyzer::AnalyzeDeferredShapeSpecList( 287 const parser::DeferredShapeSpecList &x) { 288 Analyze(x); 289 CHECK(!arraySpec_.empty()); 290 return arraySpec_; 291 } 292 ArraySpec ArraySpecAnalyzer::Analyze(const parser::CoarraySpec &x) { 293 common::visit( 294 common::visitors{ 295 [&](const parser::DeferredCoshapeSpecList &y) { MakeDeferred(y.v); }, 296 [&](const parser::ExplicitCoshapeSpec &y) { 297 Analyze(std::get<std::list<parser::ExplicitShapeSpec>>(y.t)); 298 MakeImplied( 299 std::get<std::optional<parser::SpecificationExpr>>(y.t)); 300 }, 301 }, 302 x.u); 303 CHECK(!arraySpec_.empty()); 304 return arraySpec_; 305 } 306 307 void ArraySpecAnalyzer::Analyze(const parser::AssumedShapeSpec &x) { 308 arraySpec_.push_back(ShapeSpec::MakeAssumedShape(GetBound(x.v))); 309 } 310 void ArraySpecAnalyzer::Analyze(const parser::ExplicitShapeSpec &x) { 311 MakeExplicit(std::get<std::optional<parser::SpecificationExpr>>(x.t), 312 std::get<parser::SpecificationExpr>(x.t)); 313 } 314 void ArraySpecAnalyzer::Analyze(const parser::AssumedImpliedSpec &x) { 315 MakeImplied(x.v); 316 } 317 void ArraySpecAnalyzer::Analyze(const parser::DeferredShapeSpecList &x) { 318 MakeDeferred(x.v); 319 } 320 void ArraySpecAnalyzer::Analyze(const parser::AssumedRankSpec &) { 321 arraySpec_.push_back(ShapeSpec::MakeAssumedRank()); 322 } 323 324 void ArraySpecAnalyzer::MakeExplicit( 325 const std::optional<parser::SpecificationExpr> &lb, 326 const parser::SpecificationExpr &ub) { 327 arraySpec_.push_back(ShapeSpec::MakeExplicit(GetBound(lb), GetBound(ub))); 328 } 329 void ArraySpecAnalyzer::MakeImplied( 330 const std::optional<parser::SpecificationExpr> &lb) { 331 arraySpec_.push_back(ShapeSpec::MakeImplied(GetBound(lb))); 332 } 333 void ArraySpecAnalyzer::MakeDeferred(int n) { 334 for (int i = 0; i < n; ++i) { 335 arraySpec_.push_back(ShapeSpec::MakeDeferred()); 336 } 337 } 338 339 Bound ArraySpecAnalyzer::GetBound( 340 const std::optional<parser::SpecificationExpr> &x) { 341 return x ? GetBound(*x) : Bound{1}; 342 } 343 Bound ArraySpecAnalyzer::GetBound(const parser::SpecificationExpr &x) { 344 MaybeSubscriptIntExpr expr; 345 if (MaybeExpr maybeExpr{AnalyzeExpr(context_, x.v)}) { 346 if (auto *intExpr{evaluate::UnwrapExpr<SomeIntExpr>(*maybeExpr)}) { 347 expr = evaluate::Fold(context_.foldingContext(), 348 evaluate::ConvertToType<evaluate::SubscriptInteger>( 349 std::move(*intExpr))); 350 } 351 } 352 return Bound{std::move(expr)}; 353 } 354 355 // If SAVE is set on src, set it on all members of dst 356 static void PropagateSaveAttr( 357 const EquivalenceObject &src, EquivalenceSet &dst) { 358 if (src.symbol.attrs().test(Attr::SAVE)) { 359 for (auto &obj : dst) { 360 obj.symbol.attrs().set(Attr::SAVE); 361 } 362 } 363 } 364 static void PropagateSaveAttr(const EquivalenceSet &src, EquivalenceSet &dst) { 365 if (!src.empty()) { 366 PropagateSaveAttr(src.front(), dst); 367 } 368 } 369 370 void EquivalenceSets::AddToSet(const parser::Designator &designator) { 371 if (CheckDesignator(designator)) { 372 Symbol &symbol{*currObject_.symbol}; 373 if (!currSet_.empty()) { 374 // check this symbol against first of set for compatibility 375 Symbol &first{currSet_.front().symbol}; 376 CheckCanEquivalence(designator.source, first, symbol) && 377 CheckCanEquivalence(designator.source, symbol, first); 378 } 379 auto subscripts{currObject_.subscripts}; 380 if (subscripts.empty() && symbol.IsObjectArray()) { 381 // record a whole array as its first element 382 for (const ShapeSpec &spec : symbol.get<ObjectEntityDetails>().shape()) { 383 auto &lbound{spec.lbound().GetExplicit().value()}; 384 subscripts.push_back(evaluate::ToInt64(lbound).value()); 385 } 386 } 387 auto substringStart{currObject_.substringStart}; 388 currSet_.emplace_back( 389 symbol, subscripts, substringStart, designator.source); 390 PropagateSaveAttr(currSet_.back(), currSet_); 391 } 392 currObject_ = {}; 393 } 394 395 void EquivalenceSets::FinishSet(const parser::CharBlock &source) { 396 std::set<std::size_t> existing; // indices of sets intersecting this one 397 for (auto &obj : currSet_) { 398 auto it{objectToSet_.find(obj)}; 399 if (it != objectToSet_.end()) { 400 existing.insert(it->second); // symbol already in this set 401 } 402 } 403 if (existing.empty()) { 404 sets_.push_back({}); // create a new equivalence set 405 MergeInto(source, currSet_, sets_.size() - 1); 406 } else { 407 auto it{existing.begin()}; 408 std::size_t dstIndex{*it}; 409 MergeInto(source, currSet_, dstIndex); 410 while (++it != existing.end()) { 411 MergeInto(source, sets_[*it], dstIndex); 412 } 413 } 414 currSet_.clear(); 415 } 416 417 // Report an error or warning if sym1 and sym2 cannot be in the same equivalence 418 // set. 419 bool EquivalenceSets::CheckCanEquivalence( 420 const parser::CharBlock &source, const Symbol &sym1, const Symbol &sym2) { 421 std::optional<parser::MessageFixedText> msg; 422 const DeclTypeSpec *type1{sym1.GetType()}; 423 const DeclTypeSpec *type2{sym2.GetType()}; 424 bool isDefaultNum1{IsDefaultNumericSequenceType(type1)}; 425 bool isAnyNum1{IsAnyNumericSequenceType(type1)}; 426 bool isDefaultNum2{IsDefaultNumericSequenceType(type2)}; 427 bool isAnyNum2{IsAnyNumericSequenceType(type2)}; 428 bool isChar1{IsCharacterSequenceType(type1)}; 429 bool isChar2{IsCharacterSequenceType(type2)}; 430 if (sym1.attrs().test(Attr::PROTECTED) && 431 !sym2.attrs().test(Attr::PROTECTED)) { // C8114 432 msg = "Equivalence set cannot contain '%s'" 433 " with PROTECTED attribute and '%s' without"_err_en_US; 434 } else if ((isDefaultNum1 && isDefaultNum2) || (isChar1 && isChar2)) { 435 // ok & standard conforming 436 } else if (!(isAnyNum1 || isChar1) && 437 !(isAnyNum2 || isChar2)) { // C8110 - C8113 438 if (AreTkCompatibleTypes(type1, type2)) { 439 if (context_.ShouldWarn(LanguageFeature::EquivalenceSameNonSequence)) { 440 msg = 441 "nonstandard: Equivalence set contains '%s' and '%s' with same " 442 "type that is neither numeric nor character sequence type"_port_en_US; 443 } 444 } else { 445 msg = "Equivalence set cannot contain '%s' and '%s' with distinct types " 446 "that are not both numeric or character sequence types"_err_en_US; 447 } 448 } else if (isAnyNum1) { 449 if (isChar2) { 450 if (context_.ShouldWarn( 451 LanguageFeature::EquivalenceNumericWithCharacter)) { 452 msg = "nonstandard: Equivalence set contains '%s' that is numeric " 453 "sequence type and '%s' that is character"_port_en_US; 454 } 455 } else if (isAnyNum2 && 456 context_.ShouldWarn(LanguageFeature::EquivalenceNonDefaultNumeric)) { 457 if (isDefaultNum1) { 458 msg = 459 "nonstandard: Equivalence set contains '%s' that is a default " 460 "numeric sequence type and '%s' that is numeric with non-default kind"_port_en_US; 461 } else if (!isDefaultNum2) { 462 msg = "nonstandard: Equivalence set contains '%s' and '%s' that are " 463 "numeric sequence types with non-default kinds"_port_en_US; 464 } 465 } 466 } 467 if (msg) { 468 context_.Say(source, std::move(*msg), sym1.name(), sym2.name()); 469 return false; 470 } 471 return true; 472 } 473 474 // Move objects from src to sets_[dstIndex] 475 void EquivalenceSets::MergeInto(const parser::CharBlock &source, 476 EquivalenceSet &src, std::size_t dstIndex) { 477 EquivalenceSet &dst{sets_[dstIndex]}; 478 PropagateSaveAttr(dst, src); 479 for (const auto &obj : src) { 480 dst.push_back(obj); 481 objectToSet_[obj] = dstIndex; 482 } 483 PropagateSaveAttr(src, dst); 484 src.clear(); 485 } 486 487 // If set has an object with this symbol, return it. 488 const EquivalenceObject *EquivalenceSets::Find( 489 const EquivalenceSet &set, const Symbol &symbol) { 490 for (const auto &obj : set) { 491 if (obj.symbol == symbol) { 492 return &obj; 493 } 494 } 495 return nullptr; 496 } 497 498 bool EquivalenceSets::CheckDesignator(const parser::Designator &designator) { 499 return common::visit( 500 common::visitors{ 501 [&](const parser::DataRef &x) { 502 return CheckDataRef(designator.source, x); 503 }, 504 [&](const parser::Substring &x) { 505 const auto &dataRef{std::get<parser::DataRef>(x.t)}; 506 const auto &range{std::get<parser::SubstringRange>(x.t)}; 507 bool ok{CheckDataRef(designator.source, dataRef)}; 508 if (const auto &lb{std::get<0>(range.t)}) { 509 ok &= CheckSubstringBound(lb->thing.thing.value(), true); 510 } else { 511 currObject_.substringStart = 1; 512 } 513 if (const auto &ub{std::get<1>(range.t)}) { 514 ok &= CheckSubstringBound(ub->thing.thing.value(), false); 515 } 516 return ok; 517 }, 518 }, 519 designator.u); 520 } 521 522 bool EquivalenceSets::CheckDataRef( 523 const parser::CharBlock &source, const parser::DataRef &x) { 524 return common::visit( 525 common::visitors{ 526 [&](const parser::Name &name) { return CheckObject(name); }, 527 [&](const common::Indirection<parser::StructureComponent> &) { 528 context_.Say(source, // C8107 529 "Derived type component '%s' is not allowed in an equivalence set"_err_en_US, 530 source); 531 return false; 532 }, 533 [&](const common::Indirection<parser::ArrayElement> &elem) { 534 bool ok{CheckDataRef(source, elem.value().base)}; 535 for (const auto &subscript : elem.value().subscripts) { 536 ok &= common::visit( 537 common::visitors{ 538 [&](const parser::SubscriptTriplet &) { 539 context_.Say(source, // C924, R872 540 "Array section '%s' is not allowed in an equivalence set"_err_en_US, 541 source); 542 return false; 543 }, 544 [&](const parser::IntExpr &y) { 545 return CheckArrayBound(y.thing.value()); 546 }, 547 }, 548 subscript.u); 549 } 550 return ok; 551 }, 552 [&](const common::Indirection<parser::CoindexedNamedObject> &) { 553 context_.Say(source, // C924 (R872) 554 "Coindexed object '%s' is not allowed in an equivalence set"_err_en_US, 555 source); 556 return false; 557 }, 558 }, 559 x.u); 560 } 561 562 static bool InCommonWithBind(const Symbol &symbol) { 563 if (const auto *details{symbol.detailsIf<ObjectEntityDetails>()}) { 564 const Symbol *commonBlock{details->commonBlock()}; 565 return commonBlock && commonBlock->attrs().test(Attr::BIND_C); 566 } else { 567 return false; 568 } 569 } 570 571 // If symbol can't be in equivalence set report error and return false; 572 bool EquivalenceSets::CheckObject(const parser::Name &name) { 573 if (!name.symbol) { 574 return false; // an error has already occurred 575 } 576 currObject_.symbol = name.symbol; 577 parser::MessageFixedText msg; 578 const Symbol &symbol{*name.symbol}; 579 if (symbol.owner().IsDerivedType()) { // C8107 580 msg = "Derived type component '%s'" 581 " is not allowed in an equivalence set"_err_en_US; 582 } else if (IsDummy(symbol)) { // C8106 583 msg = "Dummy argument '%s' is not allowed in an equivalence set"_err_en_US; 584 } else if (symbol.IsFuncResult()) { // C8106 585 msg = "Function result '%s' is not allow in an equivalence set"_err_en_US; 586 } else if (IsPointer(symbol)) { // C8106 587 msg = "Pointer '%s' is not allowed in an equivalence set"_err_en_US; 588 } else if (IsAllocatable(symbol)) { // C8106 589 msg = "Allocatable variable '%s'" 590 " is not allowed in an equivalence set"_err_en_US; 591 } else if (symbol.Corank() > 0) { // C8106 592 msg = "Coarray '%s' is not allowed in an equivalence set"_err_en_US; 593 } else if (symbol.has<UseDetails>()) { // C8115 594 msg = "Use-associated variable '%s'" 595 " is not allowed in an equivalence set"_err_en_US; 596 } else if (symbol.attrs().test(Attr::BIND_C)) { // C8106 597 msg = "Variable '%s' with BIND attribute" 598 " is not allowed in an equivalence set"_err_en_US; 599 } else if (symbol.attrs().test(Attr::TARGET)) { // C8108 600 msg = "Variable '%s' with TARGET attribute" 601 " is not allowed in an equivalence set"_err_en_US; 602 } else if (IsNamedConstant(symbol)) { // C8106 603 msg = "Named constant '%s' is not allowed in an equivalence set"_err_en_US; 604 } else if (InCommonWithBind(symbol)) { // C8106 605 msg = "Variable '%s' in common block with BIND attribute" 606 " is not allowed in an equivalence set"_err_en_US; 607 } else if (const auto *type{symbol.GetType()}) { 608 if (const auto *derived{type->AsDerived()}) { 609 if (const auto *comp{FindUltimateComponent( 610 *derived, IsAllocatableOrPointer)}) { // C8106 611 msg = IsPointer(*comp) 612 ? "Derived type object '%s' with pointer ultimate component" 613 " is not allowed in an equivalence set"_err_en_US 614 : "Derived type object '%s' with allocatable ultimate component" 615 " is not allowed in an equivalence set"_err_en_US; 616 } else if (!derived->typeSymbol().get<DerivedTypeDetails>().sequence()) { 617 msg = "Nonsequence derived type object '%s'" 618 " is not allowed in an equivalence set"_err_en_US; 619 } 620 } else if (IsAutomatic(symbol)) { 621 msg = "Automatic object '%s'" 622 " is not allowed in an equivalence set"_err_en_US; 623 } 624 } 625 if (!msg.text().empty()) { 626 context_.Say(name.source, std::move(msg), name.source); 627 return false; 628 } 629 return true; 630 } 631 632 bool EquivalenceSets::CheckArrayBound(const parser::Expr &bound) { 633 MaybeExpr expr{ 634 evaluate::Fold(context_.foldingContext(), AnalyzeExpr(context_, bound))}; 635 if (!expr) { 636 return false; 637 } 638 if (expr->Rank() > 0) { 639 context_.Say(bound.source, // C924, R872 640 "Array with vector subscript '%s' is not allowed in an equivalence set"_err_en_US, 641 bound.source); 642 return false; 643 } 644 auto subscript{evaluate::ToInt64(*expr)}; 645 if (!subscript) { 646 context_.Say(bound.source, // C8109 647 "Array with nonconstant subscript '%s' is not allowed in an equivalence set"_err_en_US, 648 bound.source); 649 return false; 650 } 651 currObject_.subscripts.push_back(*subscript); 652 return true; 653 } 654 655 bool EquivalenceSets::CheckSubstringBound( 656 const parser::Expr &bound, bool isStart) { 657 MaybeExpr expr{ 658 evaluate::Fold(context_.foldingContext(), AnalyzeExpr(context_, bound))}; 659 if (!expr) { 660 return false; 661 } 662 auto subscript{evaluate::ToInt64(*expr)}; 663 if (!subscript) { 664 context_.Say(bound.source, // C8109 665 "Substring with nonconstant bound '%s' is not allowed in an equivalence set"_err_en_US, 666 bound.source); 667 return false; 668 } 669 if (!isStart) { 670 auto start{currObject_.substringStart}; 671 if (*subscript < (start ? *start : 1)) { 672 context_.Say(bound.source, // C8116 673 "Substring with zero length is not allowed in an equivalence set"_err_en_US); 674 return false; 675 } 676 } else if (*subscript != 1) { 677 currObject_.substringStart = *subscript; 678 } 679 return true; 680 } 681 682 bool EquivalenceSets::IsCharacterSequenceType(const DeclTypeSpec *type) { 683 return IsSequenceType(type, [&](const IntrinsicTypeSpec &type) { 684 auto kind{evaluate::ToInt64(type.kind())}; 685 return type.category() == TypeCategory::Character && kind && 686 kind.value() == context_.GetDefaultKind(TypeCategory::Character); 687 }); 688 } 689 690 // Numeric or logical type of default kind or DOUBLE PRECISION or DOUBLE COMPLEX 691 bool EquivalenceSets::IsDefaultKindNumericType(const IntrinsicTypeSpec &type) { 692 if (auto kind{evaluate::ToInt64(type.kind())}) { 693 switch (type.category()) { 694 case TypeCategory::Integer: 695 case TypeCategory::Logical: 696 return *kind == context_.GetDefaultKind(TypeCategory::Integer); 697 case TypeCategory::Real: 698 case TypeCategory::Complex: 699 return *kind == context_.GetDefaultKind(TypeCategory::Real) || 700 *kind == context_.doublePrecisionKind(); 701 default: 702 return false; 703 } 704 } 705 return false; 706 } 707 708 bool EquivalenceSets::IsDefaultNumericSequenceType(const DeclTypeSpec *type) { 709 return IsSequenceType(type, [&](const IntrinsicTypeSpec &type) { 710 return IsDefaultKindNumericType(type); 711 }); 712 } 713 714 bool EquivalenceSets::IsAnyNumericSequenceType(const DeclTypeSpec *type) { 715 return IsSequenceType(type, [&](const IntrinsicTypeSpec &type) { 716 return type.category() == TypeCategory::Logical || 717 common::IsNumericTypeCategory(type.category()); 718 }); 719 } 720 721 // Is type an intrinsic type that satisfies predicate or a sequence type 722 // whose components do. 723 bool EquivalenceSets::IsSequenceType(const DeclTypeSpec *type, 724 std::function<bool(const IntrinsicTypeSpec &)> predicate) { 725 if (!type) { 726 return false; 727 } else if (const IntrinsicTypeSpec * intrinsic{type->AsIntrinsic()}) { 728 return predicate(*intrinsic); 729 } else if (const DerivedTypeSpec * derived{type->AsDerived()}) { 730 for (const auto &pair : *derived->typeSymbol().scope()) { 731 const Symbol &component{*pair.second}; 732 if (IsAllocatableOrPointer(component) || 733 !IsSequenceType(component.GetType(), predicate)) { 734 return false; 735 } 736 } 737 return true; 738 } else { 739 return false; 740 } 741 } 742 743 } // namespace Fortran::semantics 744