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