1 //===-- lib/Semantics/check-declarations.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 // Static declaration checking 10 11 #include "check-declarations.h" 12 #include "flang/Evaluate/check-expression.h" 13 #include "flang/Evaluate/fold.h" 14 #include "flang/Evaluate/tools.h" 15 #include "flang/Semantics/scope.h" 16 #include "flang/Semantics/semantics.h" 17 #include "flang/Semantics/symbol.h" 18 #include "flang/Semantics/tools.h" 19 #include "flang/Semantics/type.h" 20 #include <algorithm> 21 22 namespace Fortran::semantics { 23 24 using evaluate::characteristics::DummyArgument; 25 using evaluate::characteristics::DummyDataObject; 26 using evaluate::characteristics::DummyProcedure; 27 using evaluate::characteristics::FunctionResult; 28 using evaluate::characteristics::Procedure; 29 30 class CheckHelper { 31 public: 32 explicit CheckHelper(SemanticsContext &c) : context_{c} {} 33 34 void Check() { Check(context_.globalScope()); } 35 void Check(const ParamValue &, bool canBeAssumed); 36 void Check(const Bound &bound) { CheckSpecExpr(bound.GetExplicit()); } 37 void Check(const ShapeSpec &spec) { 38 Check(spec.lbound()); 39 Check(spec.ubound()); 40 } 41 void Check(const ArraySpec &); 42 void Check(const DeclTypeSpec &, bool canHaveAssumedTypeParameters); 43 void Check(const Symbol &); 44 void Check(const Scope &); 45 46 private: 47 template <typename A> void CheckSpecExpr(const A &x) { 48 if (symbolBeingChecked_ && IsSaved(*symbolBeingChecked_)) { 49 if (!evaluate::IsConstantExpr(x)) { 50 messages_.Say( 51 "Specification expression must be constant in declaration of '%s' with the SAVE attribute"_err_en_US, 52 symbolBeingChecked_->name()); 53 } 54 } else { 55 evaluate::CheckSpecificationExpr( 56 x, messages_, DEREF(scope_), context_.intrinsics()); 57 } 58 } 59 template <typename A> void CheckSpecExpr(const std::optional<A> &x) { 60 if (x) { 61 CheckSpecExpr(*x); 62 } 63 } 64 template <typename A> void CheckSpecExpr(A &x) { 65 x = Fold(foldingContext_, std::move(x)); 66 const A &constx{x}; 67 CheckSpecExpr(constx); 68 } 69 void CheckValue(const Symbol &, const DerivedTypeSpec *); 70 void CheckVolatile( 71 const Symbol &, bool isAssociated, const DerivedTypeSpec *); 72 void CheckPointer(const Symbol &); 73 void CheckPassArg( 74 const Symbol &proc, const Symbol *interface, const WithPassArg &); 75 void CheckProcBinding(const Symbol &, const ProcBindingDetails &); 76 void CheckObjectEntity(const Symbol &, const ObjectEntityDetails &); 77 void CheckArraySpec(const Symbol &, const ArraySpec &); 78 void CheckProcEntity(const Symbol &, const ProcEntityDetails &); 79 void CheckSubprogram(const Symbol &, const SubprogramDetails &); 80 void CheckAssumedTypeEntity(const Symbol &, const ObjectEntityDetails &); 81 void CheckDerivedType(const Symbol &, const DerivedTypeDetails &); 82 void CheckGeneric(const Symbol &, const GenericDetails &); 83 std::optional<std::vector<Procedure>> Characterize(const SymbolVector &); 84 bool CheckDefinedOperator(const SourceName &, const GenericKind &, 85 const Symbol &, const Procedure &); 86 std::optional<parser::MessageFixedText> CheckNumberOfArgs( 87 const GenericKind &, std::size_t); 88 bool CheckDefinedOperatorArg( 89 const SourceName &, const Symbol &, const Procedure &, std::size_t); 90 bool CheckDefinedAssignment(const Symbol &, const Procedure &); 91 bool CheckDefinedAssignmentArg(const Symbol &, const DummyArgument &, int); 92 void CheckSpecificsAreDistinguishable( 93 const Symbol &, const GenericDetails &, const std::vector<Procedure> &); 94 void CheckEquivalenceSet(const EquivalenceSet &); 95 void CheckBlockData(const Scope &); 96 97 void SayNotDistinguishable( 98 const SourceName &, GenericKind, const Symbol &, const Symbol &); 99 bool CheckConflicting(const Symbol &, Attr, Attr); 100 bool InPure() const { 101 return innermostSymbol_ && IsPureProcedure(*innermostSymbol_); 102 } 103 bool InFunction() const { 104 return innermostSymbol_ && IsFunction(*innermostSymbol_); 105 } 106 template <typename... A> 107 void SayWithDeclaration(const Symbol &symbol, A &&... x) { 108 if (parser::Message * msg{messages_.Say(std::forward<A>(x)...)}) { 109 if (messages_.at().begin() != symbol.name().begin()) { 110 evaluate::AttachDeclaration(*msg, symbol); 111 } 112 } 113 } 114 bool IsResultOkToDiffer(const FunctionResult &); 115 116 SemanticsContext &context_; 117 evaluate::FoldingContext &foldingContext_{context_.foldingContext()}; 118 parser::ContextualMessages &messages_{foldingContext_.messages()}; 119 const Scope *scope_{nullptr}; 120 // This symbol is the one attached to the innermost enclosing scope 121 // that has a symbol. 122 const Symbol *innermostSymbol_{nullptr}; 123 const Symbol *symbolBeingChecked_{nullptr}; 124 }; 125 126 void CheckHelper::Check(const ParamValue &value, bool canBeAssumed) { 127 if (value.isAssumed()) { 128 if (!canBeAssumed) { // C795, C721, C726 129 messages_.Say( 130 "An assumed (*) type parameter may be used only for a (non-statement" 131 " function) dummy argument, associate name, named constant, or" 132 " external function result"_err_en_US); 133 } 134 } else { 135 CheckSpecExpr(value.GetExplicit()); 136 } 137 } 138 139 void CheckHelper::Check(const ArraySpec &shape) { 140 for (const auto &spec : shape) { 141 Check(spec); 142 } 143 } 144 145 void CheckHelper::Check( 146 const DeclTypeSpec &type, bool canHaveAssumedTypeParameters) { 147 if (type.category() == DeclTypeSpec::Character) { 148 Check(type.characterTypeSpec().length(), canHaveAssumedTypeParameters); 149 } else if (const DerivedTypeSpec * derived{type.AsDerived()}) { 150 for (auto &parm : derived->parameters()) { 151 Check(parm.second, canHaveAssumedTypeParameters); 152 } 153 } 154 } 155 156 void CheckHelper::Check(const Symbol &symbol) { 157 if (context_.HasError(symbol)) { 158 return; 159 } 160 const DeclTypeSpec *type{symbol.GetType()}; 161 const DerivedTypeSpec *derived{type ? type->AsDerived() : nullptr}; 162 auto restorer{messages_.SetLocation(symbol.name())}; 163 context_.set_location(symbol.name()); 164 bool isAssociated{symbol.has<UseDetails>() || symbol.has<HostAssocDetails>()}; 165 if (symbol.attrs().test(Attr::VOLATILE)) { 166 CheckVolatile(symbol, isAssociated, derived); 167 } 168 if (isAssociated) { 169 return; // only care about checking VOLATILE on associated symbols 170 } 171 if (IsPointer(symbol)) { 172 CheckPointer(symbol); 173 } 174 std::visit( 175 common::visitors{ 176 [&](const ProcBindingDetails &x) { CheckProcBinding(symbol, x); }, 177 [&](const ObjectEntityDetails &x) { CheckObjectEntity(symbol, x); }, 178 [&](const ProcEntityDetails &x) { CheckProcEntity(symbol, x); }, 179 [&](const SubprogramDetails &x) { CheckSubprogram(symbol, x); }, 180 [&](const DerivedTypeDetails &x) { CheckDerivedType(symbol, x); }, 181 [&](const GenericDetails &x) { CheckGeneric(symbol, x); }, 182 [](const auto &) {}, 183 }, 184 symbol.details()); 185 if (InPure()) { 186 if (IsSaved(symbol)) { 187 messages_.Say( 188 "A pure subprogram may not have a variable with the SAVE attribute"_err_en_US); 189 } 190 if (symbol.attrs().test(Attr::VOLATILE)) { 191 messages_.Say( 192 "A pure subprogram may not have a variable with the VOLATILE attribute"_err_en_US); 193 } 194 if (IsProcedure(symbol) && !IsPureProcedure(symbol) && IsDummy(symbol)) { 195 messages_.Say( 196 "A dummy procedure of a pure subprogram must be pure"_err_en_US); 197 } 198 if (!IsDummy(symbol) && !IsFunctionResult(symbol)) { 199 if (IsPolymorphicAllocatable(symbol)) { 200 SayWithDeclaration(symbol, 201 "Deallocation of polymorphic object '%s' is not permitted in a pure subprogram"_err_en_US, 202 symbol.name()); 203 } else if (derived) { 204 if (auto bad{FindPolymorphicAllocatableUltimateComponent(*derived)}) { 205 SayWithDeclaration(*bad, 206 "Deallocation of polymorphic object '%s%s' is not permitted in a pure subprogram"_err_en_US, 207 symbol.name(), bad.BuildResultDesignatorName()); 208 } 209 } 210 } 211 } 212 if (type) { // Section 7.2, paragraph 7 213 bool canHaveAssumedParameter{IsNamedConstant(symbol) || 214 (IsAssumedLengthCharacter(symbol) && // C722 215 IsExternal(symbol)) || 216 symbol.test(Symbol::Flag::ParentComp)}; 217 if (!IsStmtFunctionDummy(symbol)) { // C726 218 if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 219 canHaveAssumedParameter |= object->isDummy() || 220 (object->isFuncResult() && 221 type->category() == DeclTypeSpec::Character) || 222 IsStmtFunctionResult(symbol); // Avoids multiple messages 223 } else { 224 canHaveAssumedParameter |= symbol.has<AssocEntityDetails>(); 225 } 226 } 227 Check(*type, canHaveAssumedParameter); 228 if (InPure() && InFunction() && IsFunctionResult(symbol)) { 229 if (derived && HasImpureFinal(*derived)) { // C1584 230 messages_.Say( 231 "Result of pure function may not have an impure FINAL subroutine"_err_en_US); 232 } 233 if (type->IsPolymorphic() && IsAllocatable(symbol)) { // C1585 234 messages_.Say( 235 "Result of pure function may not be both polymorphic and ALLOCATABLE"_err_en_US); 236 } 237 if (derived) { 238 if (auto bad{FindPolymorphicAllocatableUltimateComponent(*derived)}) { 239 SayWithDeclaration(*bad, 240 "Result of pure function may not have polymorphic ALLOCATABLE ultimate component '%s'"_err_en_US, 241 bad.BuildResultDesignatorName()); 242 } 243 } 244 } 245 } 246 if (IsAssumedLengthCharacter(symbol) && IsExternal(symbol)) { // C723 247 if (symbol.attrs().test(Attr::RECURSIVE)) { 248 messages_.Say( 249 "An assumed-length CHARACTER(*) function cannot be RECURSIVE"_err_en_US); 250 } 251 if (symbol.Rank() > 0) { 252 messages_.Say( 253 "An assumed-length CHARACTER(*) function cannot return an array"_err_en_US); 254 } 255 if (symbol.attrs().test(Attr::PURE)) { 256 messages_.Say( 257 "An assumed-length CHARACTER(*) function cannot be PURE"_err_en_US); 258 } 259 if (symbol.attrs().test(Attr::ELEMENTAL)) { 260 messages_.Say( 261 "An assumed-length CHARACTER(*) function cannot be ELEMENTAL"_err_en_US); 262 } 263 if (const Symbol * result{FindFunctionResult(symbol)}) { 264 if (IsPointer(*result)) { 265 messages_.Say( 266 "An assumed-length CHARACTER(*) function cannot return a POINTER"_err_en_US); 267 } 268 } 269 } 270 if (symbol.attrs().test(Attr::VALUE)) { 271 CheckValue(symbol, derived); 272 } 273 if (symbol.attrs().test(Attr::CONTIGUOUS) && IsPointer(symbol) && 274 symbol.Rank() == 0) { // C830 275 messages_.Say("CONTIGUOUS POINTER must be an array"_err_en_US); 276 } 277 if (IsDummy(symbol)) { 278 if (IsNamedConstant(symbol)) { 279 messages_.Say( 280 "A dummy argument may not also be a named constant"_err_en_US); 281 } 282 if (IsSaved(symbol)) { 283 messages_.Say( 284 "A dummy argument may not have the SAVE attribute"_err_en_US); 285 } 286 } 287 if (symbol.owner().IsDerivedType() && 288 (symbol.attrs().test(Attr::CONTIGUOUS) && 289 !(IsPointer(symbol) && symbol.Rank() > 0))) { // C752 290 messages_.Say( 291 "A CONTIGUOUS component must be an array with the POINTER attribute"_err_en_US); 292 } 293 } 294 295 void CheckHelper::CheckValue( 296 const Symbol &symbol, const DerivedTypeSpec *derived) { // C863 - C865 297 if (!IsDummy(symbol)) { 298 messages_.Say( 299 "VALUE attribute may apply only to a dummy argument"_err_en_US); 300 } 301 if (IsProcedure(symbol)) { 302 messages_.Say( 303 "VALUE attribute may apply only to a dummy data object"_err_en_US); 304 } 305 if (IsAssumedSizeArray(symbol)) { 306 messages_.Say( 307 "VALUE attribute may not apply to an assumed-size array"_err_en_US); 308 } 309 if (IsCoarray(symbol)) { 310 messages_.Say("VALUE attribute may not apply to a coarray"_err_en_US); 311 } 312 if (IsAllocatable(symbol)) { 313 messages_.Say("VALUE attribute may not apply to an ALLOCATABLE"_err_en_US); 314 } else if (IsPointer(symbol)) { 315 messages_.Say("VALUE attribute may not apply to a POINTER"_err_en_US); 316 } 317 if (IsIntentInOut(symbol)) { 318 messages_.Say( 319 "VALUE attribute may not apply to an INTENT(IN OUT) argument"_err_en_US); 320 } else if (IsIntentOut(symbol)) { 321 messages_.Say( 322 "VALUE attribute may not apply to an INTENT(OUT) argument"_err_en_US); 323 } 324 if (symbol.attrs().test(Attr::VOLATILE)) { 325 messages_.Say("VALUE attribute may not apply to a VOLATILE"_err_en_US); 326 } 327 if (innermostSymbol_ && IsBindCProcedure(*innermostSymbol_) && 328 IsOptional(symbol)) { 329 messages_.Say( 330 "VALUE attribute may not apply to an OPTIONAL in a BIND(C) procedure"_err_en_US); 331 } 332 if (derived) { 333 if (FindCoarrayUltimateComponent(*derived)) { 334 messages_.Say( 335 "VALUE attribute may not apply to a type with a coarray ultimate component"_err_en_US); 336 } 337 } 338 } 339 340 void CheckHelper::CheckAssumedTypeEntity( // C709 341 const Symbol &symbol, const ObjectEntityDetails &details) { 342 if (const DeclTypeSpec * type{symbol.GetType()}; 343 type && type->category() == DeclTypeSpec::TypeStar) { 344 if (!IsDummy(symbol)) { 345 messages_.Say( 346 "Assumed-type entity '%s' must be a dummy argument"_err_en_US, 347 symbol.name()); 348 } else { 349 if (symbol.attrs().test(Attr::ALLOCATABLE)) { 350 messages_.Say("Assumed-type argument '%s' cannot have the ALLOCATABLE" 351 " attribute"_err_en_US, 352 symbol.name()); 353 } 354 if (symbol.attrs().test(Attr::POINTER)) { 355 messages_.Say("Assumed-type argument '%s' cannot have the POINTER" 356 " attribute"_err_en_US, 357 symbol.name()); 358 } 359 if (symbol.attrs().test(Attr::VALUE)) { 360 messages_.Say("Assumed-type argument '%s' cannot have the VALUE" 361 " attribute"_err_en_US, 362 symbol.name()); 363 } 364 if (symbol.attrs().test(Attr::INTENT_OUT)) { 365 messages_.Say( 366 "Assumed-type argument '%s' cannot be INTENT(OUT)"_err_en_US, 367 symbol.name()); 368 } 369 if (IsCoarray(symbol)) { 370 messages_.Say( 371 "Assumed-type argument '%s' cannot be a coarray"_err_en_US, 372 symbol.name()); 373 } 374 if (details.IsArray() && details.shape().IsExplicitShape()) { 375 messages_.Say( 376 "Assumed-type array argument 'arg8' must be assumed shape," 377 " assumed size, or assumed rank"_err_en_US, 378 symbol.name()); 379 } 380 } 381 } 382 } 383 384 void CheckHelper::CheckObjectEntity( 385 const Symbol &symbol, const ObjectEntityDetails &details) { 386 CHECK(!symbolBeingChecked_); 387 symbolBeingChecked_ = &symbol; // for specification expr checks 388 CheckArraySpec(symbol, details.shape()); 389 Check(details.shape()); 390 Check(details.coshape()); 391 CheckAssumedTypeEntity(symbol, details); 392 symbolBeingChecked_ = nullptr; 393 if (!details.coshape().empty()) { 394 bool isDeferredShape{details.coshape().IsDeferredShape()}; 395 if (IsAllocatable(symbol)) { 396 if (!isDeferredShape) { // C827 397 messages_.Say("'%s' is an ALLOCATABLE coarray and must have a deferred" 398 " coshape"_err_en_US, 399 symbol.name()); 400 } 401 } else if (symbol.owner().IsDerivedType()) { // C746 402 std::string deferredMsg{ 403 isDeferredShape ? "" : " and have a deferred coshape"}; 404 messages_.Say("Component '%s' is a coarray and must have the ALLOCATABLE" 405 " attribute%s"_err_en_US, 406 symbol.name(), deferredMsg); 407 } else { 408 if (!details.coshape().IsAssumedSize()) { // C828 409 messages_.Say( 410 "Component '%s' is a non-ALLOCATABLE coarray and must have" 411 " an explicit coshape"_err_en_US, 412 symbol.name()); 413 } 414 } 415 } 416 if (details.isDummy()) { 417 if (symbol.attrs().test(Attr::INTENT_OUT)) { 418 if (FindUltimateComponent(symbol, [](const Symbol &x) { 419 return IsCoarray(x) && IsAllocatable(x); 420 })) { // C846 421 messages_.Say( 422 "An INTENT(OUT) dummy argument may not be, or contain, an ALLOCATABLE coarray"_err_en_US); 423 } 424 if (IsOrContainsEventOrLockComponent(symbol)) { // C847 425 messages_.Say( 426 "An INTENT(OUT) dummy argument may not be, or contain, EVENT_TYPE or LOCK_TYPE"_err_en_US); 427 } 428 } 429 if (InPure() && !IsStmtFunction(DEREF(innermostSymbol_)) && 430 !IsPointer(symbol) && !IsIntentIn(symbol) && 431 !symbol.attrs().test(Attr::VALUE)) { 432 if (InFunction()) { // C1583 433 messages_.Say( 434 "non-POINTER dummy argument of pure function must be INTENT(IN) or VALUE"_err_en_US); 435 } else if (IsIntentOut(symbol)) { 436 if (const DeclTypeSpec * type{details.type()}) { 437 if (type && type->IsPolymorphic()) { // C1588 438 messages_.Say( 439 "An INTENT(OUT) dummy argument of a pure subroutine may not be polymorphic"_err_en_US); 440 } else if (const DerivedTypeSpec * derived{type->AsDerived()}) { 441 if (FindUltimateComponent(*derived, [](const Symbol &x) { 442 const DeclTypeSpec *type{x.GetType()}; 443 return type && type->IsPolymorphic(); 444 })) { // C1588 445 messages_.Say( 446 "An INTENT(OUT) dummy argument of a pure subroutine may not have a polymorphic ultimate component"_err_en_US); 447 } 448 if (HasImpureFinal(*derived)) { // C1587 449 messages_.Say( 450 "An INTENT(OUT) dummy argument of a pure subroutine may not have an impure FINAL subroutine"_err_en_US); 451 } 452 } 453 } 454 } else if (!IsIntentInOut(symbol)) { // C1586 455 messages_.Say( 456 "non-POINTER dummy argument of pure subroutine must have INTENT() or VALUE attribute"_err_en_US); 457 } 458 } 459 } 460 if (symbol.owner().kind() != Scope::Kind::DerivedType && 461 IsInitialized(symbol)) { 462 if (details.commonBlock()) { 463 if (details.commonBlock()->name().empty()) { 464 messages_.Say( 465 "A variable in blank COMMON should not be initialized"_en_US); 466 } 467 } else if (symbol.owner().kind() == Scope::Kind::BlockData) { 468 if (IsAllocatable(symbol)) { 469 messages_.Say( 470 "An ALLOCATABLE variable may not appear in a BLOCK DATA subprogram"_err_en_US); 471 } else { 472 messages_.Say( 473 "An initialized variable in BLOCK DATA must be in a COMMON block"_err_en_US); 474 } 475 } 476 } 477 if (const DeclTypeSpec * type{details.type()}) { // C708 478 if (type->IsPolymorphic() && 479 !(type->IsAssumedType() || IsAllocatableOrPointer(symbol) || 480 IsDummy(symbol))) { 481 messages_.Say("CLASS entity '%s' must be a dummy argument or have " 482 "ALLOCATABLE or POINTER attribute"_err_en_US, 483 symbol.name()); 484 } 485 } 486 } 487 488 // The six different kinds of array-specs: 489 // array-spec -> explicit-shape-list | deferred-shape-list 490 // | assumed-shape-list | implied-shape-list 491 // | assumed-size | assumed-rank 492 // explicit-shape -> [ lb : ] ub 493 // deferred-shape -> : 494 // assumed-shape -> [ lb ] : 495 // implied-shape -> [ lb : ] * 496 // assumed-size -> [ explicit-shape-list , ] [ lb : ] * 497 // assumed-rank -> .. 498 // Note: 499 // - deferred-shape is also an assumed-shape 500 // - A single "*" or "lb:*" might be assumed-size or implied-shape-list 501 void CheckHelper::CheckArraySpec( 502 const Symbol &symbol, const ArraySpec &arraySpec) { 503 if (arraySpec.Rank() == 0) { 504 return; 505 } 506 bool isExplicit{arraySpec.IsExplicitShape()}; 507 bool isDeferred{arraySpec.IsDeferredShape()}; 508 bool isImplied{arraySpec.IsImpliedShape()}; 509 bool isAssumedShape{arraySpec.IsAssumedShape()}; 510 bool isAssumedSize{arraySpec.IsAssumedSize()}; 511 bool isAssumedRank{arraySpec.IsAssumedRank()}; 512 std::optional<parser::MessageFixedText> msg; 513 if (symbol.test(Symbol::Flag::CrayPointee) && !isExplicit && !isAssumedSize) { 514 msg = "Cray pointee '%s' must have must have explicit shape or" 515 " assumed size"_err_en_US; 516 } else if (IsAllocatableOrPointer(symbol) && !isDeferred && !isAssumedRank) { 517 if (symbol.owner().IsDerivedType()) { // C745 518 if (IsAllocatable(symbol)) { 519 msg = "Allocatable array component '%s' must have" 520 " deferred shape"_err_en_US; 521 } else { 522 msg = "Array pointer component '%s' must have deferred shape"_err_en_US; 523 } 524 } else { 525 if (IsAllocatable(symbol)) { // C832 526 msg = "Allocatable array '%s' must have deferred shape or" 527 " assumed rank"_err_en_US; 528 } else { 529 msg = "Array pointer '%s' must have deferred shape or" 530 " assumed rank"_err_en_US; 531 } 532 } 533 } else if (IsDummy(symbol)) { 534 if (isImplied && !isAssumedSize) { // C836 535 msg = "Dummy array argument '%s' may not have implied shape"_err_en_US; 536 } 537 } else if (isAssumedShape && !isDeferred) { 538 msg = "Assumed-shape array '%s' must be a dummy argument"_err_en_US; 539 } else if (isAssumedSize && !isImplied) { // C833 540 msg = "Assumed-size array '%s' must be a dummy argument"_err_en_US; 541 } else if (isAssumedRank) { // C837 542 msg = "Assumed-rank array '%s' must be a dummy argument"_err_en_US; 543 } else if (isImplied) { 544 if (!IsNamedConstant(symbol)) { // C836 545 msg = "Implied-shape array '%s' must be a named constant"_err_en_US; 546 } 547 } else if (IsNamedConstant(symbol)) { 548 if (!isExplicit && !isImplied) { 549 msg = "Named constant '%s' array must have explicit or" 550 " implied shape"_err_en_US; 551 } 552 } else if (!IsAllocatableOrPointer(symbol) && !isExplicit) { 553 if (symbol.owner().IsDerivedType()) { // C749 554 msg = "Component array '%s' without ALLOCATABLE or POINTER attribute must" 555 " have explicit shape"_err_en_US; 556 } else { // C816 557 msg = "Array '%s' without ALLOCATABLE or POINTER attribute must have" 558 " explicit shape"_err_en_US; 559 } 560 } 561 if (msg) { 562 context_.Say(std::move(*msg), symbol.name()); 563 } 564 } 565 566 void CheckHelper::CheckProcEntity( 567 const Symbol &symbol, const ProcEntityDetails &details) { 568 if (details.isDummy()) { 569 const Symbol *interface{details.interface().symbol()}; 570 if (!symbol.attrs().test(Attr::INTRINSIC) && 571 (symbol.attrs().test(Attr::ELEMENTAL) || 572 (interface && !interface->attrs().test(Attr::INTRINSIC) && 573 interface->attrs().test(Attr::ELEMENTAL)))) { 574 // There's no explicit constraint or "shall" that we can find in the 575 // standard for this check, but it seems to be implied in multiple 576 // sites, and ELEMENTAL non-intrinsic actual arguments *are* 577 // explicitly forbidden. But we allow "PROCEDURE(SIN)::dummy" 578 // because it is explicitly legal to *pass* the specific intrinsic 579 // function SIN as an actual argument. 580 messages_.Say("A dummy procedure may not be ELEMENTAL"_err_en_US); 581 } 582 } else if (symbol.owner().IsDerivedType()) { 583 if (!symbol.attrs().test(Attr::POINTER)) { // C756 584 const auto &name{symbol.name()}; 585 messages_.Say(name, 586 "Procedure component '%s' must have POINTER attribute"_err_en_US, 587 name); 588 } 589 CheckPassArg(symbol, details.interface().symbol(), details); 590 } 591 if (symbol.attrs().test(Attr::POINTER)) { 592 if (const Symbol * interface{details.interface().symbol()}) { 593 if (interface->attrs().test(Attr::ELEMENTAL) && 594 !interface->attrs().test(Attr::INTRINSIC)) { 595 messages_.Say("Procedure pointer '%s' may not be ELEMENTAL"_err_en_US, 596 symbol.name()); // C1517 597 } 598 } 599 } 600 } 601 602 // When a module subprogram has the MODULE prefix the following must match 603 // with the corresponding separate module procedure interface body: 604 // - C1549: characteristics and dummy argument names 605 // - C1550: binding label 606 // - C1551: NON_RECURSIVE prefix 607 class SubprogramMatchHelper { 608 public: 609 explicit SubprogramMatchHelper(SemanticsContext &context) 610 : context{context} {} 611 612 void Check(const Symbol &, const Symbol &); 613 614 private: 615 void CheckDummyArg(const Symbol &, const Symbol &, const DummyArgument &, 616 const DummyArgument &); 617 void CheckDummyDataObject(const Symbol &, const Symbol &, 618 const DummyDataObject &, const DummyDataObject &); 619 void CheckDummyProcedure(const Symbol &, const Symbol &, 620 const DummyProcedure &, const DummyProcedure &); 621 bool CheckSameIntent( 622 const Symbol &, const Symbol &, common::Intent, common::Intent); 623 template <typename... A> 624 void Say( 625 const Symbol &, const Symbol &, parser::MessageFixedText &&, A &&...); 626 template <typename ATTRS> 627 bool CheckSameAttrs(const Symbol &, const Symbol &, ATTRS, ATTRS); 628 bool ShapesAreCompatible(const DummyDataObject &, const DummyDataObject &); 629 evaluate::Shape FoldShape(const evaluate::Shape &); 630 std::string AsFortran(DummyDataObject::Attr attr) { 631 return parser::ToUpperCaseLetters(DummyDataObject::EnumToString(attr)); 632 } 633 std::string AsFortran(DummyProcedure::Attr attr) { 634 return parser::ToUpperCaseLetters(DummyProcedure::EnumToString(attr)); 635 } 636 637 SemanticsContext &context; 638 }; 639 640 // 15.6.2.6 para 3 - can the result of an ENTRY differ from its function? 641 bool CheckHelper::IsResultOkToDiffer(const FunctionResult &result) { 642 if (result.attrs.test(FunctionResult::Attr::Allocatable) || 643 result.attrs.test(FunctionResult::Attr::Pointer)) { 644 return false; 645 } 646 const auto *typeAndShape{result.GetTypeAndShape()}; 647 if (!typeAndShape || typeAndShape->Rank() != 0) { 648 return false; 649 } 650 auto category{typeAndShape->type().category()}; 651 if (category == TypeCategory::Character || 652 category == TypeCategory::Derived) { 653 return false; 654 } 655 int kind{typeAndShape->type().kind()}; 656 return kind == context_.GetDefaultKind(category) || 657 (category == TypeCategory::Real && 658 kind == context_.doublePrecisionKind()); 659 } 660 661 void CheckHelper::CheckSubprogram( 662 const Symbol &symbol, const SubprogramDetails &details) { 663 if (const Symbol * iface{FindSeparateModuleSubprogramInterface(&symbol)}) { 664 SubprogramMatchHelper{context_}.Check(symbol, *iface); 665 } 666 if (const Scope * entryScope{details.entryScope()}) { 667 // ENTRY 15.6.2.6, esp. C1571 668 std::optional<parser::MessageFixedText> error; 669 const Symbol *subprogram{entryScope->symbol()}; 670 const SubprogramDetails *subprogramDetails{nullptr}; 671 if (subprogram) { 672 subprogramDetails = subprogram->detailsIf<SubprogramDetails>(); 673 } 674 if (entryScope->kind() != Scope::Kind::Subprogram) { 675 error = "ENTRY may appear only in a subroutine or function"_err_en_US; 676 } else if (!(entryScope->parent().IsGlobal() || 677 entryScope->parent().IsModule() || 678 entryScope->parent().IsSubmodule())) { 679 error = "ENTRY may not appear in an internal subprogram"_err_en_US; 680 } else if (FindSeparateModuleSubprogramInterface(subprogram)) { 681 error = "ENTRY may not appear in a separate module procedure"_err_en_US; 682 } else if (subprogramDetails && details.isFunction() && 683 subprogramDetails->isFunction()) { 684 auto result{FunctionResult::Characterize( 685 details.result(), context_.intrinsics())}; 686 auto subpResult{FunctionResult::Characterize( 687 subprogramDetails->result(), context_.intrinsics())}; 688 if (result && subpResult && *result != *subpResult && 689 (!IsResultOkToDiffer(*result) || !IsResultOkToDiffer(*subpResult))) { 690 error = 691 "Result of ENTRY is not compatible with result of containing function"_err_en_US; 692 } 693 } 694 if (error) { 695 if (auto *msg{messages_.Say(symbol.name(), *error)}) { 696 if (subprogram) { 697 msg->Attach(subprogram->name(), "Containing subprogram"_en_US); 698 } 699 } 700 } 701 } 702 } 703 704 void CheckHelper::CheckDerivedType( 705 const Symbol &symbol, const DerivedTypeDetails &details) { 706 const Scope *scope{symbol.scope()}; 707 if (!scope) { 708 CHECK(details.isForwardReferenced()); 709 return; 710 } 711 CHECK(scope->symbol() == &symbol); 712 CHECK(scope->IsDerivedType()); 713 if (symbol.attrs().test(Attr::ABSTRACT) && // C734 714 (symbol.attrs().test(Attr::BIND_C) || details.sequence())) { 715 messages_.Say("An ABSTRACT derived type must be extensible"_err_en_US); 716 } 717 if (const DeclTypeSpec * parent{FindParentTypeSpec(symbol)}) { 718 const DerivedTypeSpec *parentDerived{parent->AsDerived()}; 719 if (!IsExtensibleType(parentDerived)) { // C705 720 messages_.Say("The parent type is not extensible"_err_en_US); 721 } 722 if (!symbol.attrs().test(Attr::ABSTRACT) && parentDerived && 723 parentDerived->typeSymbol().attrs().test(Attr::ABSTRACT)) { 724 ScopeComponentIterator components{*parentDerived}; 725 for (const Symbol &component : components) { 726 if (component.attrs().test(Attr::DEFERRED)) { 727 if (scope->FindComponent(component.name()) == &component) { 728 SayWithDeclaration(component, 729 "Non-ABSTRACT extension of ABSTRACT derived type '%s' lacks a binding for DEFERRED procedure '%s'"_err_en_US, 730 parentDerived->typeSymbol().name(), component.name()); 731 } 732 } 733 } 734 } 735 DerivedTypeSpec derived{symbol.name(), symbol}; 736 derived.set_scope(*scope); 737 if (FindCoarrayUltimateComponent(derived) && // C736 738 !(parentDerived && FindCoarrayUltimateComponent(*parentDerived))) { 739 messages_.Say( 740 "Type '%s' has a coarray ultimate component so the type at the base " 741 "of its type extension chain ('%s') must be a type that has a " 742 "coarray ultimate component"_err_en_US, 743 symbol.name(), scope->GetDerivedTypeBase().GetSymbol()->name()); 744 } 745 if (FindEventOrLockPotentialComponent(derived) && // C737 746 !(FindEventOrLockPotentialComponent(*parentDerived) || 747 IsEventTypeOrLockType(parentDerived))) { 748 messages_.Say( 749 "Type '%s' has an EVENT_TYPE or LOCK_TYPE component, so the type " 750 "at the base of its type extension chain ('%s') must either have an " 751 "EVENT_TYPE or LOCK_TYPE component, or be EVENT_TYPE or " 752 "LOCK_TYPE"_err_en_US, 753 symbol.name(), scope->GetDerivedTypeBase().GetSymbol()->name()); 754 } 755 } 756 if (HasIntrinsicTypeName(symbol)) { // C729 757 messages_.Say("A derived type name cannot be the name of an intrinsic" 758 " type"_err_en_US); 759 } 760 } 761 762 void CheckHelper::CheckGeneric( 763 const Symbol &symbol, const GenericDetails &details) { 764 const SymbolVector &specifics{details.specificProcs()}; 765 const auto &bindingNames{details.bindingNames()}; 766 std::optional<std::vector<Procedure>> procs{Characterize(specifics)}; 767 if (!procs) { 768 return; 769 } 770 bool ok{true}; 771 if (details.kind().IsIntrinsicOperator()) { 772 for (std::size_t i{0}; i < specifics.size(); ++i) { 773 auto restorer{messages_.SetLocation(bindingNames[i])}; 774 ok &= CheckDefinedOperator( 775 symbol.name(), details.kind(), specifics[i], (*procs)[i]); 776 } 777 } 778 if (details.kind().IsAssignment()) { 779 for (std::size_t i{0}; i < specifics.size(); ++i) { 780 auto restorer{messages_.SetLocation(bindingNames[i])}; 781 ok &= CheckDefinedAssignment(specifics[i], (*procs)[i]); 782 } 783 } 784 if (ok) { 785 CheckSpecificsAreDistinguishable(symbol, details, *procs); 786 } 787 } 788 789 // Check that the specifics of this generic are distinguishable from each other 790 void CheckHelper::CheckSpecificsAreDistinguishable(const Symbol &generic, 791 const GenericDetails &details, const std::vector<Procedure> &procs) { 792 const SymbolVector &specifics{details.specificProcs()}; 793 std::size_t count{specifics.size()}; 794 if (count < 2) { 795 return; 796 } 797 GenericKind kind{details.kind()}; 798 auto distinguishable{kind.IsAssignment() || kind.IsOperator() 799 ? evaluate::characteristics::DistinguishableOpOrAssign 800 : evaluate::characteristics::Distinguishable}; 801 for (std::size_t i1{0}; i1 < count - 1; ++i1) { 802 auto &proc1{procs[i1]}; 803 for (std::size_t i2{i1 + 1}; i2 < count; ++i2) { 804 auto &proc2{procs[i2]}; 805 if (!distinguishable(proc1, proc2)) { 806 SayNotDistinguishable( 807 generic.name(), kind, specifics[i1], specifics[i2]); 808 } 809 } 810 } 811 } 812 813 void CheckHelper::SayNotDistinguishable(const SourceName &name, 814 GenericKind kind, const Symbol &proc1, const Symbol &proc2) { 815 auto &&text{kind.IsDefinedOperator() 816 ? "Generic operator '%s' may not have specific procedures '%s'" 817 " and '%s' as their interfaces are not distinguishable"_err_en_US 818 : "Generic '%s' may not have specific procedures '%s'" 819 " and '%s' as their interfaces are not distinguishable"_err_en_US}; 820 auto &msg{ 821 context_.Say(name, std::move(text), name, proc1.name(), proc2.name())}; 822 evaluate::AttachDeclaration(msg, proc1); 823 evaluate::AttachDeclaration(msg, proc2); 824 } 825 826 static bool ConflictsWithIntrinsicAssignment(const Procedure &proc) { 827 auto lhs{std::get<DummyDataObject>(proc.dummyArguments[0].u).type}; 828 auto rhs{std::get<DummyDataObject>(proc.dummyArguments[1].u).type}; 829 return Tristate::No == 830 IsDefinedAssignment(lhs.type(), lhs.Rank(), rhs.type(), rhs.Rank()); 831 } 832 833 static bool ConflictsWithIntrinsicOperator( 834 const GenericKind &kind, const Procedure &proc) { 835 auto arg0{std::get<DummyDataObject>(proc.dummyArguments[0].u).type}; 836 auto type0{arg0.type()}; 837 if (proc.dummyArguments.size() == 1) { // unary 838 return std::visit( 839 common::visitors{ 840 [&](common::NumericOperator) { return IsIntrinsicNumeric(type0); }, 841 [&](common::LogicalOperator) { return IsIntrinsicLogical(type0); }, 842 [](const auto &) -> bool { DIE("bad generic kind"); }, 843 }, 844 kind.u); 845 } else { // binary 846 int rank0{arg0.Rank()}; 847 auto arg1{std::get<DummyDataObject>(proc.dummyArguments[1].u).type}; 848 auto type1{arg1.type()}; 849 int rank1{arg1.Rank()}; 850 return std::visit( 851 common::visitors{ 852 [&](common::NumericOperator) { 853 return IsIntrinsicNumeric(type0, rank0, type1, rank1); 854 }, 855 [&](common::LogicalOperator) { 856 return IsIntrinsicLogical(type0, rank0, type1, rank1); 857 }, 858 [&](common::RelationalOperator opr) { 859 return IsIntrinsicRelational(opr, type0, rank0, type1, rank1); 860 }, 861 [&](GenericKind::OtherKind x) { 862 CHECK(x == GenericKind::OtherKind::Concat); 863 return IsIntrinsicConcat(type0, rank0, type1, rank1); 864 }, 865 [](const auto &) -> bool { DIE("bad generic kind"); }, 866 }, 867 kind.u); 868 } 869 } 870 871 // Check if this procedure can be used for defined operators (see 15.4.3.4.2). 872 bool CheckHelper::CheckDefinedOperator(const SourceName &opName, 873 const GenericKind &kind, const Symbol &specific, const Procedure &proc) { 874 std::optional<parser::MessageFixedText> msg; 875 if (specific.attrs().test(Attr::NOPASS)) { // C774 876 msg = "%s procedure '%s' may not have NOPASS attribute"_err_en_US; 877 } else if (!proc.functionResult.has_value()) { 878 msg = "%s procedure '%s' must be a function"_err_en_US; 879 } else if (proc.functionResult->IsAssumedLengthCharacter()) { 880 msg = "%s function '%s' may not have assumed-length CHARACTER(*)" 881 " result"_err_en_US; 882 } else if (auto m{CheckNumberOfArgs(kind, proc.dummyArguments.size())}) { 883 msg = std::move(m); 884 } else if (!CheckDefinedOperatorArg(opName, specific, proc, 0) | 885 !CheckDefinedOperatorArg(opName, specific, proc, 1)) { 886 return false; // error was reported 887 } else if (ConflictsWithIntrinsicOperator(kind, proc)) { 888 msg = "%s function '%s' conflicts with intrinsic operator"_err_en_US; 889 } else { 890 return true; // OK 891 } 892 SayWithDeclaration(specific, std::move(msg.value()), 893 parser::ToUpperCaseLetters(opName.ToString()), specific.name()); 894 return false; 895 } 896 897 // If the number of arguments is wrong for this intrinsic operator, return 898 // false and return the error message in msg. 899 std::optional<parser::MessageFixedText> CheckHelper::CheckNumberOfArgs( 900 const GenericKind &kind, std::size_t nargs) { 901 std::size_t min{2}, max{2}; // allowed number of args; default is binary 902 std::visit(common::visitors{ 903 [&](const common::NumericOperator &x) { 904 if (x == common::NumericOperator::Add || 905 x == common::NumericOperator::Subtract) { 906 min = 1; // + and - are unary or binary 907 } 908 }, 909 [&](const common::LogicalOperator &x) { 910 if (x == common::LogicalOperator::Not) { 911 min = 1; // .NOT. is unary 912 max = 1; 913 } 914 }, 915 [](const common::RelationalOperator &) { 916 // all are binary 917 }, 918 [](const GenericKind::OtherKind &x) { 919 CHECK(x == GenericKind::OtherKind::Concat); 920 }, 921 [](const auto &) { DIE("expected intrinsic operator"); }, 922 }, 923 kind.u); 924 if (nargs >= min && nargs <= max) { 925 return std::nullopt; 926 } else if (max == 1) { 927 return "%s function '%s' must have one dummy argument"_err_en_US; 928 } else if (min == 2) { 929 return "%s function '%s' must have two dummy arguments"_err_en_US; 930 } else { 931 return "%s function '%s' must have one or two dummy arguments"_err_en_US; 932 } 933 } 934 935 bool CheckHelper::CheckDefinedOperatorArg(const SourceName &opName, 936 const Symbol &symbol, const Procedure &proc, std::size_t pos) { 937 if (pos >= proc.dummyArguments.size()) { 938 return true; 939 } 940 auto &arg{proc.dummyArguments.at(pos)}; 941 std::optional<parser::MessageFixedText> msg; 942 if (arg.IsOptional()) { 943 msg = "In %s function '%s', dummy argument '%s' may not be" 944 " OPTIONAL"_err_en_US; 945 } else if (const auto *dataObject{std::get_if<DummyDataObject>(&arg.u)}; 946 dataObject == nullptr) { 947 msg = "In %s function '%s', dummy argument '%s' must be a" 948 " data object"_err_en_US; 949 } else if (dataObject->intent != common::Intent::In && 950 !dataObject->attrs.test(DummyDataObject::Attr::Value)) { 951 msg = "In %s function '%s', dummy argument '%s' must have INTENT(IN)" 952 " or VALUE attribute"_err_en_US; 953 } 954 if (msg) { 955 SayWithDeclaration(symbol, std::move(*msg), 956 parser::ToUpperCaseLetters(opName.ToString()), symbol.name(), arg.name); 957 return false; 958 } 959 return true; 960 } 961 962 // Check if this procedure can be used for defined assignment (see 15.4.3.4.3). 963 bool CheckHelper::CheckDefinedAssignment( 964 const Symbol &specific, const Procedure &proc) { 965 std::optional<parser::MessageFixedText> msg; 966 if (specific.attrs().test(Attr::NOPASS)) { // C774 967 msg = "Defined assignment procedure '%s' may not have" 968 " NOPASS attribute"_err_en_US; 969 } else if (!proc.IsSubroutine()) { 970 msg = "Defined assignment procedure '%s' must be a subroutine"_err_en_US; 971 } else if (proc.dummyArguments.size() != 2) { 972 msg = "Defined assignment subroutine '%s' must have" 973 " two dummy arguments"_err_en_US; 974 } else if (!CheckDefinedAssignmentArg(specific, proc.dummyArguments[0], 0) | 975 !CheckDefinedAssignmentArg(specific, proc.dummyArguments[1], 1)) { 976 return false; // error was reported 977 } else if (ConflictsWithIntrinsicAssignment(proc)) { 978 msg = "Defined assignment subroutine '%s' conflicts with" 979 " intrinsic assignment"_err_en_US; 980 } else { 981 return true; // OK 982 } 983 SayWithDeclaration(specific, std::move(msg.value()), specific.name()); 984 return false; 985 } 986 987 bool CheckHelper::CheckDefinedAssignmentArg( 988 const Symbol &symbol, const DummyArgument &arg, int pos) { 989 std::optional<parser::MessageFixedText> msg; 990 if (arg.IsOptional()) { 991 msg = "In defined assignment subroutine '%s', dummy argument '%s'" 992 " may not be OPTIONAL"_err_en_US; 993 } else if (const auto *dataObject{std::get_if<DummyDataObject>(&arg.u)}) { 994 if (pos == 0) { 995 if (dataObject->intent != common::Intent::Out && 996 dataObject->intent != common::Intent::InOut) { 997 msg = "In defined assignment subroutine '%s', first dummy argument '%s'" 998 " must have INTENT(OUT) or INTENT(INOUT)"_err_en_US; 999 } 1000 } else if (pos == 1) { 1001 if (dataObject->intent != common::Intent::In && 1002 !dataObject->attrs.test(DummyDataObject::Attr::Value)) { 1003 msg = 1004 "In defined assignment subroutine '%s', second dummy" 1005 " argument '%s' must have INTENT(IN) or VALUE attribute"_err_en_US; 1006 } 1007 } else { 1008 DIE("pos must be 0 or 1"); 1009 } 1010 } else { 1011 msg = "In defined assignment subroutine '%s', dummy argument '%s'" 1012 " must be a data object"_err_en_US; 1013 } 1014 if (msg) { 1015 SayWithDeclaration(symbol, std::move(*msg), symbol.name(), arg.name); 1016 return false; 1017 } 1018 return true; 1019 } 1020 1021 // Report a conflicting attribute error if symbol has both of these attributes 1022 bool CheckHelper::CheckConflicting(const Symbol &symbol, Attr a1, Attr a2) { 1023 if (symbol.attrs().test(a1) && symbol.attrs().test(a2)) { 1024 messages_.Say("'%s' may not have both the %s and %s attributes"_err_en_US, 1025 symbol.name(), EnumToString(a1), EnumToString(a2)); 1026 return true; 1027 } else { 1028 return false; 1029 } 1030 } 1031 1032 std::optional<std::vector<Procedure>> CheckHelper::Characterize( 1033 const SymbolVector &specifics) { 1034 std::vector<Procedure> result; 1035 for (const Symbol &specific : specifics) { 1036 auto proc{Procedure::Characterize(specific, context_.intrinsics())}; 1037 if (!proc || context_.HasError(specific)) { 1038 return std::nullopt; 1039 } 1040 result.emplace_back(*proc); 1041 } 1042 return result; 1043 } 1044 1045 void CheckHelper::CheckVolatile(const Symbol &symbol, bool isAssociated, 1046 const DerivedTypeSpec *derived) { // C866 - C868 1047 if (IsIntentIn(symbol)) { 1048 messages_.Say( 1049 "VOLATILE attribute may not apply to an INTENT(IN) argument"_err_en_US); 1050 } 1051 if (IsProcedure(symbol)) { 1052 messages_.Say("VOLATILE attribute may apply only to a variable"_err_en_US); 1053 } 1054 if (isAssociated) { 1055 const Symbol &ultimate{symbol.GetUltimate()}; 1056 if (IsCoarray(ultimate)) { 1057 messages_.Say( 1058 "VOLATILE attribute may not apply to a coarray accessed by USE or host association"_err_en_US); 1059 } 1060 if (derived) { 1061 if (FindCoarrayUltimateComponent(*derived)) { 1062 messages_.Say( 1063 "VOLATILE attribute may not apply to a type with a coarray ultimate component accessed by USE or host association"_err_en_US); 1064 } 1065 } 1066 } 1067 } 1068 1069 void CheckHelper::CheckPointer(const Symbol &symbol) { // C852 1070 CheckConflicting(symbol, Attr::POINTER, Attr::TARGET); 1071 CheckConflicting(symbol, Attr::POINTER, Attr::ALLOCATABLE); // C751 1072 CheckConflicting(symbol, Attr::POINTER, Attr::INTRINSIC); 1073 if (symbol.Corank() > 0) { 1074 messages_.Say( 1075 "'%s' may not have the POINTER attribute because it is a coarray"_err_en_US, 1076 symbol.name()); 1077 } 1078 } 1079 1080 // C760 constraints on the passed-object dummy argument 1081 // C757 constraints on procedure pointer components 1082 void CheckHelper::CheckPassArg( 1083 const Symbol &proc, const Symbol *interface, const WithPassArg &details) { 1084 if (proc.attrs().test(Attr::NOPASS)) { 1085 return; 1086 } 1087 const auto &name{proc.name()}; 1088 if (!interface) { 1089 messages_.Say(name, 1090 "Procedure component '%s' must have NOPASS attribute or explicit interface"_err_en_US, 1091 name); 1092 return; 1093 } 1094 const auto *subprogram{interface->detailsIf<SubprogramDetails>()}; 1095 if (!subprogram) { 1096 messages_.Say(name, 1097 "Procedure component '%s' has invalid interface '%s'"_err_en_US, name, 1098 interface->name()); 1099 return; 1100 } 1101 std::optional<SourceName> passName{details.passName()}; 1102 const auto &dummyArgs{subprogram->dummyArgs()}; 1103 if (!passName) { 1104 if (dummyArgs.empty()) { 1105 messages_.Say(name, 1106 proc.has<ProcEntityDetails>() 1107 ? "Procedure component '%s' with no dummy arguments" 1108 " must have NOPASS attribute"_err_en_US 1109 : "Procedure binding '%s' with no dummy arguments" 1110 " must have NOPASS attribute"_err_en_US, 1111 name); 1112 return; 1113 } 1114 passName = dummyArgs[0]->name(); 1115 } 1116 std::optional<int> passArgIndex{}; 1117 for (std::size_t i{0}; i < dummyArgs.size(); ++i) { 1118 if (dummyArgs[i] && dummyArgs[i]->name() == *passName) { 1119 passArgIndex = i; 1120 break; 1121 } 1122 } 1123 if (!passArgIndex) { // C758 1124 messages_.Say(*passName, 1125 "'%s' is not a dummy argument of procedure interface '%s'"_err_en_US, 1126 *passName, interface->name()); 1127 return; 1128 } 1129 const Symbol &passArg{*dummyArgs[*passArgIndex]}; 1130 std::optional<parser::MessageFixedText> msg; 1131 if (!passArg.has<ObjectEntityDetails>()) { 1132 msg = "Passed-object dummy argument '%s' of procedure '%s'" 1133 " must be a data object"_err_en_US; 1134 } else if (passArg.attrs().test(Attr::POINTER)) { 1135 msg = "Passed-object dummy argument '%s' of procedure '%s'" 1136 " may not have the POINTER attribute"_err_en_US; 1137 } else if (passArg.attrs().test(Attr::ALLOCATABLE)) { 1138 msg = "Passed-object dummy argument '%s' of procedure '%s'" 1139 " may not have the ALLOCATABLE attribute"_err_en_US; 1140 } else if (passArg.attrs().test(Attr::VALUE)) { 1141 msg = "Passed-object dummy argument '%s' of procedure '%s'" 1142 " may not have the VALUE attribute"_err_en_US; 1143 } else if (passArg.Rank() > 0) { 1144 msg = "Passed-object dummy argument '%s' of procedure '%s'" 1145 " must be scalar"_err_en_US; 1146 } 1147 if (msg) { 1148 messages_.Say(name, std::move(*msg), passName.value(), name); 1149 return; 1150 } 1151 const DeclTypeSpec *type{passArg.GetType()}; 1152 if (!type) { 1153 return; // an error already occurred 1154 } 1155 const Symbol &typeSymbol{*proc.owner().GetSymbol()}; 1156 const DerivedTypeSpec *derived{type->AsDerived()}; 1157 if (!derived || derived->typeSymbol() != typeSymbol) { 1158 messages_.Say(name, 1159 "Passed-object dummy argument '%s' of procedure '%s'" 1160 " must be of type '%s' but is '%s'"_err_en_US, 1161 passName.value(), name, typeSymbol.name(), type->AsFortran()); 1162 return; 1163 } 1164 if (IsExtensibleType(derived) != type->IsPolymorphic()) { 1165 messages_.Say(name, 1166 type->IsPolymorphic() 1167 ? "Passed-object dummy argument '%s' of procedure '%s'" 1168 " may not be polymorphic because '%s' is not extensible"_err_en_US 1169 : "Passed-object dummy argument '%s' of procedure '%s'" 1170 " must be polymorphic because '%s' is extensible"_err_en_US, 1171 passName.value(), name, typeSymbol.name()); 1172 return; 1173 } 1174 for (const auto &[paramName, paramValue] : derived->parameters()) { 1175 if (paramValue.isLen() && !paramValue.isAssumed()) { 1176 messages_.Say(name, 1177 "Passed-object dummy argument '%s' of procedure '%s'" 1178 " has non-assumed length parameter '%s'"_err_en_US, 1179 passName.value(), name, paramName); 1180 } 1181 } 1182 } 1183 1184 void CheckHelper::CheckProcBinding( 1185 const Symbol &symbol, const ProcBindingDetails &binding) { 1186 const Scope &dtScope{symbol.owner()}; 1187 CHECK(dtScope.kind() == Scope::Kind::DerivedType); 1188 if (const Symbol * dtSymbol{dtScope.symbol()}) { 1189 if (symbol.attrs().test(Attr::DEFERRED)) { 1190 if (!dtSymbol->attrs().test(Attr::ABSTRACT)) { // C733 1191 SayWithDeclaration(*dtSymbol, 1192 "Procedure bound to non-ABSTRACT derived type '%s' may not be DEFERRED"_err_en_US, 1193 dtSymbol->name()); 1194 } 1195 if (symbol.attrs().test(Attr::NON_OVERRIDABLE)) { 1196 messages_.Say( 1197 "Type-bound procedure '%s' may not be both DEFERRED and NON_OVERRIDABLE"_err_en_US, 1198 symbol.name()); 1199 } 1200 } 1201 } 1202 if (const Symbol * overridden{FindOverriddenBinding(symbol)}) { 1203 if (overridden->attrs().test(Attr::NON_OVERRIDABLE)) { 1204 SayWithDeclaration(*overridden, 1205 "Override of NON_OVERRIDABLE '%s' is not permitted"_err_en_US, 1206 symbol.name()); 1207 } 1208 if (const auto *overriddenBinding{ 1209 overridden->detailsIf<ProcBindingDetails>()}) { 1210 if (!IsPureProcedure(symbol) && IsPureProcedure(*overridden)) { 1211 SayWithDeclaration(*overridden, 1212 "An overridden pure type-bound procedure binding must also be pure"_err_en_US); 1213 return; 1214 } 1215 if (!binding.symbol().attrs().test(Attr::ELEMENTAL) && 1216 overriddenBinding->symbol().attrs().test(Attr::ELEMENTAL)) { 1217 SayWithDeclaration(*overridden, 1218 "A type-bound procedure and its override must both, or neither, be ELEMENTAL"_err_en_US); 1219 return; 1220 } 1221 bool isNopass{symbol.attrs().test(Attr::NOPASS)}; 1222 if (isNopass != overridden->attrs().test(Attr::NOPASS)) { 1223 SayWithDeclaration(*overridden, 1224 isNopass 1225 ? "A NOPASS type-bound procedure may not override a passed-argument procedure"_err_en_US 1226 : "A passed-argument type-bound procedure may not override a NOPASS procedure"_err_en_US); 1227 } else { 1228 auto bindingChars{evaluate::characteristics::Procedure::Characterize( 1229 binding.symbol(), context_.intrinsics())}; 1230 auto overriddenChars{evaluate::characteristics::Procedure::Characterize( 1231 overriddenBinding->symbol(), context_.intrinsics())}; 1232 if (bindingChars && overriddenChars) { 1233 if (isNopass) { 1234 if (!bindingChars->CanOverride(*overriddenChars, std::nullopt)) { 1235 SayWithDeclaration(*overridden, 1236 "A type-bound procedure and its override must have compatible interfaces"_err_en_US); 1237 } 1238 } else { 1239 int passIndex{bindingChars->FindPassIndex(binding.passName())}; 1240 int overriddenPassIndex{ 1241 overriddenChars->FindPassIndex(overriddenBinding->passName())}; 1242 if (passIndex != overriddenPassIndex) { 1243 SayWithDeclaration(*overridden, 1244 "A type-bound procedure and its override must use the same PASS argument"_err_en_US); 1245 } else if (!bindingChars->CanOverride( 1246 *overriddenChars, passIndex)) { 1247 SayWithDeclaration(*overridden, 1248 "A type-bound procedure and its override must have compatible interfaces apart from their passed argument"_err_en_US); 1249 } 1250 } 1251 } 1252 } 1253 if (symbol.attrs().test(Attr::PRIVATE) && 1254 overridden->attrs().test(Attr::PUBLIC)) { 1255 SayWithDeclaration(*overridden, 1256 "A PRIVATE procedure may not override a PUBLIC procedure"_err_en_US); 1257 } 1258 } else { 1259 SayWithDeclaration(*overridden, 1260 "A type-bound procedure binding may not have the same name as a parent component"_err_en_US); 1261 } 1262 } 1263 CheckPassArg(symbol, &binding.symbol(), binding); 1264 } 1265 1266 void CheckHelper::Check(const Scope &scope) { 1267 scope_ = &scope; 1268 common::Restorer<const Symbol *> restorer{innermostSymbol_}; 1269 if (const Symbol * symbol{scope.symbol()}) { 1270 innermostSymbol_ = symbol; 1271 } else if (scope.IsDerivedType()) { 1272 return; // PDT instantiations have null symbol() 1273 } 1274 for (const auto &set : scope.equivalenceSets()) { 1275 CheckEquivalenceSet(set); 1276 } 1277 for (const auto &pair : scope) { 1278 Check(*pair.second); 1279 } 1280 for (const Scope &child : scope.children()) { 1281 Check(child); 1282 } 1283 if (scope.kind() == Scope::Kind::BlockData) { 1284 CheckBlockData(scope); 1285 } 1286 } 1287 1288 void CheckHelper::CheckEquivalenceSet(const EquivalenceSet &set) { 1289 auto iter{ 1290 std::find_if(set.begin(), set.end(), [](const EquivalenceObject &object) { 1291 return FindCommonBlockContaining(object.symbol) != nullptr; 1292 })}; 1293 if (iter != set.end()) { 1294 const Symbol &commonBlock{DEREF(FindCommonBlockContaining(iter->symbol))}; 1295 for (auto &object : set) { 1296 if (&object != &*iter) { 1297 if (auto *details{object.symbol.detailsIf<ObjectEntityDetails>()}) { 1298 if (details->commonBlock()) { 1299 if (details->commonBlock() != &commonBlock) { // 8.10.3 paragraph 1 1300 if (auto *msg{messages_.Say(object.symbol.name(), 1301 "Two objects in the same EQUIVALENCE set may not be members of distinct COMMON blocks"_err_en_US)}) { 1302 msg->Attach(iter->symbol.name(), 1303 "Other object in EQUIVALENCE set"_en_US) 1304 .Attach(details->commonBlock()->name(), 1305 "COMMON block containing '%s'"_en_US, 1306 object.symbol.name()) 1307 .Attach(commonBlock.name(), 1308 "COMMON block containing '%s'"_en_US, 1309 iter->symbol.name()); 1310 } 1311 } 1312 } else { 1313 // Mark all symbols in the equivalence set with the same COMMON 1314 // block to prevent spurious error messages about initialization 1315 // in BLOCK DATA outside COMMON 1316 details->set_commonBlock(commonBlock); 1317 } 1318 } 1319 } 1320 } 1321 } 1322 // TODO: Move C8106 (&al.) checks here from resolve-names-utils.cpp 1323 } 1324 1325 void CheckHelper::CheckBlockData(const Scope &scope) { 1326 // BLOCK DATA subprograms should contain only named common blocks. 1327 // C1415 presents a list of statements that shouldn't appear in 1328 // BLOCK DATA, but so long as the subprogram contains no executable 1329 // code and allocates no storage outside named COMMON, we're happy 1330 // (e.g., an ENUM is strictly not allowed). 1331 for (const auto &pair : scope) { 1332 const Symbol &symbol{*pair.second}; 1333 if (!(symbol.has<CommonBlockDetails>() || symbol.has<UseDetails>() || 1334 symbol.has<UseErrorDetails>() || symbol.has<DerivedTypeDetails>() || 1335 symbol.has<SubprogramDetails>() || 1336 symbol.has<ObjectEntityDetails>() || 1337 (symbol.has<ProcEntityDetails>() && 1338 !symbol.attrs().test(Attr::POINTER)))) { 1339 messages_.Say(symbol.name(), 1340 "'%s' may not appear in a BLOCK DATA subprogram"_err_en_US, 1341 symbol.name()); 1342 } 1343 } 1344 } 1345 1346 void SubprogramMatchHelper::Check( 1347 const Symbol &symbol1, const Symbol &symbol2) { 1348 const auto details1{symbol1.get<SubprogramDetails>()}; 1349 const auto details2{symbol2.get<SubprogramDetails>()}; 1350 if (details1.isFunction() != details2.isFunction()) { 1351 Say(symbol1, symbol2, 1352 details1.isFunction() 1353 ? "Module function '%s' was declared as a subroutine in the" 1354 " corresponding interface body"_err_en_US 1355 : "Module subroutine '%s' was declared as a function in the" 1356 " corresponding interface body"_err_en_US); 1357 return; 1358 } 1359 const auto &args1{details1.dummyArgs()}; 1360 const auto &args2{details2.dummyArgs()}; 1361 int nargs1{static_cast<int>(args1.size())}; 1362 int nargs2{static_cast<int>(args2.size())}; 1363 if (nargs1 != nargs2) { 1364 Say(symbol1, symbol2, 1365 "Module subprogram '%s' has %d args but the corresponding interface" 1366 " body has %d"_err_en_US, 1367 nargs1, nargs2); 1368 return; 1369 } 1370 bool nonRecursive1{symbol1.attrs().test(Attr::NON_RECURSIVE)}; 1371 if (nonRecursive1 != symbol2.attrs().test(Attr::NON_RECURSIVE)) { // C1551 1372 Say(symbol1, symbol2, 1373 nonRecursive1 1374 ? "Module subprogram '%s' has NON_RECURSIVE prefix but" 1375 " the corresponding interface body does not"_err_en_US 1376 : "Module subprogram '%s' does not have NON_RECURSIVE prefix but " 1377 "the corresponding interface body does"_err_en_US); 1378 } 1379 MaybeExpr bindName1{details1.bindName()}; 1380 MaybeExpr bindName2{details2.bindName()}; 1381 if (bindName1.has_value() != bindName2.has_value()) { 1382 Say(symbol1, symbol2, 1383 bindName1.has_value() 1384 ? "Module subprogram '%s' has a binding label but the corresponding" 1385 " interface body does not"_err_en_US 1386 : "Module subprogram '%s' does not have a binding label but the" 1387 " corresponding interface body does"_err_en_US); 1388 } else if (bindName1) { 1389 std::string string1{bindName1->AsFortran()}; 1390 std::string string2{bindName2->AsFortran()}; 1391 if (string1 != string2) { 1392 Say(symbol1, symbol2, 1393 "Module subprogram '%s' has binding label %s but the corresponding" 1394 " interface body has %s"_err_en_US, 1395 string1, string2); 1396 } 1397 } 1398 auto proc1{Procedure::Characterize(symbol1, context.intrinsics())}; 1399 auto proc2{Procedure::Characterize(symbol2, context.intrinsics())}; 1400 if (!proc1 || !proc2) { 1401 return; 1402 } 1403 if (proc1->functionResult && proc2->functionResult && 1404 *proc1->functionResult != *proc2->functionResult) { 1405 Say(symbol1, symbol2, 1406 "Return type of function '%s' does not match return type of" 1407 " the corresponding interface body"_err_en_US); 1408 } 1409 for (int i{0}; i < nargs1; ++i) { 1410 const Symbol *arg1{args1[i]}; 1411 const Symbol *arg2{args2[i]}; 1412 if (arg1 && !arg2) { 1413 Say(symbol1, symbol2, 1414 "Dummy argument %2$d of '%1$s' is not an alternate return indicator" 1415 " but the corresponding argument in the interface body is"_err_en_US, 1416 i + 1); 1417 } else if (!arg1 && arg2) { 1418 Say(symbol1, symbol2, 1419 "Dummy argument %2$d of '%1$s' is an alternate return indicator but" 1420 " the corresponding argument in the interface body is not"_err_en_US, 1421 i + 1); 1422 } else if (arg1 && arg2) { 1423 SourceName name1{arg1->name()}; 1424 SourceName name2{arg2->name()}; 1425 if (name1 != name2) { 1426 Say(*arg1, *arg2, 1427 "Dummy argument name '%s' does not match corresponding name '%s'" 1428 " in interface body"_err_en_US, 1429 name2); 1430 } else { 1431 CheckDummyArg( 1432 *arg1, *arg2, proc1->dummyArguments[i], proc2->dummyArguments[i]); 1433 } 1434 } 1435 } 1436 } 1437 1438 void SubprogramMatchHelper::CheckDummyArg(const Symbol &symbol1, 1439 const Symbol &symbol2, const DummyArgument &arg1, 1440 const DummyArgument &arg2) { 1441 std::visit(common::visitors{ 1442 [&](const DummyDataObject &obj1, const DummyDataObject &obj2) { 1443 CheckDummyDataObject(symbol1, symbol2, obj1, obj2); 1444 }, 1445 [&](const DummyProcedure &proc1, const DummyProcedure &proc2) { 1446 CheckDummyProcedure(symbol1, symbol2, proc1, proc2); 1447 }, 1448 [&](const DummyDataObject &, const auto &) { 1449 Say(symbol1, symbol2, 1450 "Dummy argument '%s' is a data object; the corresponding" 1451 " argument in the interface body is not"_err_en_US); 1452 }, 1453 [&](const DummyProcedure &, const auto &) { 1454 Say(symbol1, symbol2, 1455 "Dummy argument '%s' is a procedure; the corresponding" 1456 " argument in the interface body is not"_err_en_US); 1457 }, 1458 [&](const auto &, const auto &) { DIE("can't happen"); }, 1459 }, 1460 arg1.u, arg2.u); 1461 } 1462 1463 void SubprogramMatchHelper::CheckDummyDataObject(const Symbol &symbol1, 1464 const Symbol &symbol2, const DummyDataObject &obj1, 1465 const DummyDataObject &obj2) { 1466 if (!CheckSameIntent(symbol1, symbol2, obj1.intent, obj2.intent)) { 1467 } else if (!CheckSameAttrs(symbol1, symbol2, obj1.attrs, obj2.attrs)) { 1468 } else if (obj1.type.type() != obj2.type.type()) { 1469 Say(symbol1, symbol2, 1470 "Dummy argument '%s' has type %s; the corresponding argument in the" 1471 " interface body has type %s"_err_en_US, 1472 obj1.type.type().AsFortran(), obj2.type.type().AsFortran()); 1473 } else if (!ShapesAreCompatible(obj1, obj2)) { 1474 Say(symbol1, symbol2, 1475 "The shape of dummy argument '%s' does not match the shape of the" 1476 " corresponding argument in the interface body"_err_en_US); 1477 } 1478 // TODO: coshape 1479 } 1480 1481 void SubprogramMatchHelper::CheckDummyProcedure(const Symbol &symbol1, 1482 const Symbol &symbol2, const DummyProcedure &proc1, 1483 const DummyProcedure &proc2) { 1484 if (!CheckSameIntent(symbol1, symbol2, proc1.intent, proc2.intent)) { 1485 } else if (!CheckSameAttrs(symbol1, symbol2, proc1.attrs, proc2.attrs)) { 1486 } else if (proc1 != proc2) { 1487 Say(symbol1, symbol2, 1488 "Dummy procedure '%s' does not match the corresponding argument in" 1489 " the interface body"_err_en_US); 1490 } 1491 } 1492 1493 bool SubprogramMatchHelper::CheckSameIntent(const Symbol &symbol1, 1494 const Symbol &symbol2, common::Intent intent1, common::Intent intent2) { 1495 if (intent1 == intent2) { 1496 return true; 1497 } else { 1498 Say(symbol1, symbol2, 1499 "The intent of dummy argument '%s' does not match the intent" 1500 " of the corresponding argument in the interface body"_err_en_US); 1501 return false; 1502 } 1503 } 1504 1505 // Report an error referring to first symbol with declaration of second symbol 1506 template <typename... A> 1507 void SubprogramMatchHelper::Say(const Symbol &symbol1, const Symbol &symbol2, 1508 parser::MessageFixedText &&text, A &&... args) { 1509 auto &message{context.Say(symbol1.name(), std::move(text), symbol1.name(), 1510 std::forward<A>(args)...)}; 1511 evaluate::AttachDeclaration(message, symbol2); 1512 } 1513 1514 template <typename ATTRS> 1515 bool SubprogramMatchHelper::CheckSameAttrs( 1516 const Symbol &symbol1, const Symbol &symbol2, ATTRS attrs1, ATTRS attrs2) { 1517 if (attrs1 == attrs2) { 1518 return true; 1519 } 1520 attrs1.IterateOverMembers([&](auto attr) { 1521 if (!attrs2.test(attr)) { 1522 Say(symbol1, symbol2, 1523 "Dummy argument '%s' has the %s attribute; the corresponding" 1524 " argument in the interface body does not"_err_en_US, 1525 AsFortran(attr)); 1526 } 1527 }); 1528 attrs2.IterateOverMembers([&](auto attr) { 1529 if (!attrs1.test(attr)) { 1530 Say(symbol1, symbol2, 1531 "Dummy argument '%s' does not have the %s attribute; the" 1532 " corresponding argument in the interface body does"_err_en_US, 1533 AsFortran(attr)); 1534 } 1535 }); 1536 return false; 1537 } 1538 1539 bool SubprogramMatchHelper::ShapesAreCompatible( 1540 const DummyDataObject &obj1, const DummyDataObject &obj2) { 1541 return evaluate::characteristics::ShapesAreCompatible( 1542 FoldShape(obj1.type.shape()), FoldShape(obj2.type.shape())); 1543 } 1544 1545 evaluate::Shape SubprogramMatchHelper::FoldShape(const evaluate::Shape &shape) { 1546 evaluate::Shape result; 1547 for (const auto &extent : shape) { 1548 result.emplace_back( 1549 evaluate::Fold(context.foldingContext(), common::Clone(extent))); 1550 } 1551 return result; 1552 } 1553 1554 void CheckDeclarations(SemanticsContext &context) { 1555 CheckHelper{context}.Check(); 1556 } 1557 1558 } // namespace Fortran::semantics 1559