1 //===-- lib/Semantics/check-declarations.cpp ------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Static declaration checking
11 #include "check-declarations.h"
12 #include "pointer-assignment.h"
13 #include "flang/Evaluate/check-expression.h"
14 #include "flang/Evaluate/fold.h"
15 #include "flang/Evaluate/tools.h"
16 #include "flang/Parser/characters.h"
17 #include "flang/Semantics/scope.h"
18 #include "flang/Semantics/semantics.h"
19 #include "flang/Semantics/symbol.h"
20 #include "flang/Semantics/tools.h"
21 #include "flang/Semantics/type.h"
26 namespace Fortran::semantics
{
28 namespace characteristics
= evaluate::characteristics
;
29 using characteristics::DummyArgument
;
30 using characteristics::DummyDataObject
;
31 using characteristics::DummyProcedure
;
32 using characteristics::FunctionResult
;
33 using characteristics::Procedure
;
37 explicit CheckHelper(SemanticsContext
&c
) : context_
{c
} {}
39 SemanticsContext
&context() { return context_
; }
40 void Check() { Check(context_
.globalScope()); }
41 void Check(const ParamValue
&, bool canBeAssumed
);
42 void Check(const Bound
&bound
) { CheckSpecExpr(bound
.GetExplicit()); }
43 void Check(const ShapeSpec
&spec
) {
47 void Check(const ArraySpec
&);
48 void Check(const DeclTypeSpec
&, bool canHaveAssumedTypeParameters
);
49 void Check(const Symbol
&);
50 void CheckCommonBlock(const Symbol
&);
51 void Check(const Scope
&);
52 const Procedure
*Characterize(const Symbol
&);
55 template <typename A
> void CheckSpecExpr(const A
&x
) {
56 evaluate::CheckSpecificationExpr(x
, DEREF(scope_
), foldingContext_
);
58 void CheckValue(const Symbol
&, const DerivedTypeSpec
*);
59 void CheckVolatile(const Symbol
&, const DerivedTypeSpec
*);
60 void CheckPointer(const Symbol
&);
62 const Symbol
&proc
, const Symbol
*interface
, const WithPassArg
&);
63 void CheckProcBinding(const Symbol
&, const ProcBindingDetails
&);
64 void CheckObjectEntity(const Symbol
&, const ObjectEntityDetails
&);
65 void CheckPointerInitialization(const Symbol
&);
66 void CheckArraySpec(const Symbol
&, const ArraySpec
&);
67 void CheckProcEntity(const Symbol
&, const ProcEntityDetails
&);
68 void CheckSubprogram(const Symbol
&, const SubprogramDetails
&);
69 void CheckLocalVsGlobal(const Symbol
&);
70 void CheckAssumedTypeEntity(const Symbol
&, const ObjectEntityDetails
&);
71 void CheckDerivedType(const Symbol
&, const DerivedTypeDetails
&);
73 const Symbol
&subroutine
, SourceName
, const Symbol
&derivedType
);
74 bool CheckDistinguishableFinals(const Symbol
&f1
, SourceName f1name
,
75 const Symbol
&f2
, SourceName f2name
, const Symbol
&derivedType
);
76 void CheckGeneric(const Symbol
&, const GenericDetails
&);
77 void CheckHostAssoc(const Symbol
&, const HostAssocDetails
&);
78 bool CheckDefinedOperator(
79 SourceName
, GenericKind
, const Symbol
&, const Procedure
&);
80 std::optional
<parser::MessageFixedText
> CheckNumberOfArgs(
81 const GenericKind
&, std::size_t);
82 bool CheckDefinedOperatorArg(
83 const SourceName
&, const Symbol
&, const Procedure
&, std::size_t);
84 bool CheckDefinedAssignment(const Symbol
&, const Procedure
&);
85 bool CheckDefinedAssignmentArg(const Symbol
&, const DummyArgument
&, int);
86 void CheckSpecifics(const Symbol
&, const GenericDetails
&);
87 void CheckEquivalenceSet(const EquivalenceSet
&);
88 void CheckBlockData(const Scope
&);
89 void CheckGenericOps(const Scope
&);
90 bool CheckConflicting(const Symbol
&, Attr
, Attr
);
91 void WarnMissingFinal(const Symbol
&);
92 void CheckSymbolType(const Symbol
&); // C702
94 return innermostSymbol_
&& IsPureProcedure(*innermostSymbol_
);
96 bool InElemental() const {
97 return innermostSymbol_
&& IsElementalProcedure(*innermostSymbol_
);
99 bool InFunction() const {
100 return innermostSymbol_
&& IsFunction(*innermostSymbol_
);
102 bool InInterface() const {
103 const SubprogramDetails
*subp
{innermostSymbol_
104 ? innermostSymbol_
->detailsIf
<SubprogramDetails
>()
106 return subp
&& subp
->isInterface();
108 template <typename
... A
>
109 parser::Message
*SayWithDeclaration(const Symbol
&symbol
, A
&&...x
) {
110 parser::Message
*msg
{messages_
.Say(std::forward
<A
>(x
)...)};
111 if (msg
&& messages_
.at().begin() != symbol
.name().begin()) {
112 evaluate::AttachDeclaration(*msg
, symbol
);
116 bool IsResultOkToDiffer(const FunctionResult
&);
117 void CheckGlobalName(const Symbol
&);
118 void CheckBindC(const Symbol
&);
119 void CheckBindCFunctionResult(const Symbol
&);
120 // Check functions for defined I/O procedures
121 void CheckDefinedIoProc(
122 const Symbol
&, const GenericDetails
&, GenericKind::DefinedIo
);
123 bool CheckDioDummyIsData(const Symbol
&, const Symbol
*, std::size_t);
124 void CheckDioDummyIsDerived(const Symbol
&, const Symbol
&,
125 GenericKind::DefinedIo ioKind
, const Symbol
&);
126 void CheckDioDummyIsDefaultInteger(const Symbol
&, const Symbol
&);
127 void CheckDioDummyIsScalar(const Symbol
&, const Symbol
&);
128 void CheckDioDummyAttrs(const Symbol
&, const Symbol
&, Attr
);
130 const Symbol
&, const Symbol
*, GenericKind::DefinedIo
, const Symbol
&);
131 void CheckGenericVsIntrinsic(const Symbol
&, const GenericDetails
&);
132 void CheckDefaultIntegerArg(const Symbol
&, const Symbol
*, Attr
);
133 void CheckDioAssumedLenCharacterArg(
134 const Symbol
&, const Symbol
*, std::size_t, Attr
);
135 void CheckDioVlistArg(const Symbol
&, const Symbol
*, std::size_t);
136 void CheckDioArgCount(
137 const Symbol
&, GenericKind::DefinedIo ioKind
, std::size_t);
138 struct TypeWithDefinedIo
{
139 const DerivedTypeSpec
&type
;
140 GenericKind::DefinedIo ioKind
;
142 const Symbol
&generic
;
144 void CheckAlreadySeenDefinedIo(const DerivedTypeSpec
&,
145 GenericKind::DefinedIo
, const Symbol
&, const Symbol
&generic
);
146 void CheckModuleProcedureDef(const Symbol
&);
148 SemanticsContext
&context_
;
149 evaluate::FoldingContext
&foldingContext_
{context_
.foldingContext()};
150 parser::ContextualMessages
&messages_
{foldingContext_
.messages()};
151 const Scope
*scope_
{nullptr};
152 bool scopeIsUninstantiatedPDT_
{false};
153 // This symbol is the one attached to the innermost enclosing scope
154 // that has a symbol.
155 const Symbol
*innermostSymbol_
{nullptr};
156 // Cache of calls to Procedure::Characterize(Symbol)
157 std::map
<SymbolRef
, std::optional
<Procedure
>, SymbolAddressCompare
>
159 // Collection of module procedure symbols with non-BIND(C)
160 // global names, qualified by their module.
161 std::map
<std::pair
<SourceName
, const Symbol
*>, SymbolRef
> moduleProcs_
;
162 // Collection of symbols with global names, BIND(C) or otherwise
163 std::map
<std::string
, SymbolRef
> globalNames_
;
164 // Derived types that have defined input/output procedures
165 std::vector
<TypeWithDefinedIo
> seenDefinedIoTypes_
;
168 class DistinguishabilityHelper
{
170 DistinguishabilityHelper(SemanticsContext
&context
) : context_
{context
} {}
171 void Add(const Symbol
&, GenericKind
, const Symbol
&, const Procedure
&);
172 void Check(const Scope
&);
175 void SayNotDistinguishable(const Scope
&, const SourceName
&, GenericKind
,
176 const Symbol
&, const Symbol
&);
177 void AttachDeclaration(parser::Message
&, const Scope
&, const Symbol
&);
179 SemanticsContext
&context_
;
180 struct ProcedureInfo
{
182 const Symbol
&symbol
;
183 const Procedure
&procedure
;
185 std::map
<SourceName
, std::vector
<ProcedureInfo
>> nameToInfo_
;
188 void CheckHelper::Check(const ParamValue
&value
, bool canBeAssumed
) {
189 if (value
.isAssumed()) {
190 if (!canBeAssumed
) { // C795, C721, C726
192 "An assumed (*) type parameter may be used only for a (non-statement"
193 " function) dummy argument, associate name, named constant, or"
194 " external function result"_err_en_US
);
197 CheckSpecExpr(value
.GetExplicit());
201 void CheckHelper::Check(const ArraySpec
&shape
) {
202 for (const auto &spec
: shape
) {
207 void CheckHelper::Check(
208 const DeclTypeSpec
&type
, bool canHaveAssumedTypeParameters
) {
209 if (type
.category() == DeclTypeSpec::Character
) {
210 Check(type
.characterTypeSpec().length(), canHaveAssumedTypeParameters
);
211 } else if (const DerivedTypeSpec
*derived
{type
.AsDerived()}) {
212 for (auto &parm
: derived
->parameters()) {
213 Check(parm
.second
, canHaveAssumedTypeParameters
);
218 void CheckHelper::Check(const Symbol
&symbol
) {
219 if (symbol
.name().size() > common::maxNameLen
&&
220 &symbol
== &symbol
.GetUltimate() &&
221 !FindModuleFileContaining(symbol
.owner())) {
222 messages_
.Say(symbol
.name(),
223 "%s has length %d, which is greater than the maximum name length "
225 symbol
.name(), symbol
.name().size(), common::maxNameLen
);
227 if (context_
.HasError(symbol
)) {
230 auto restorer
{messages_
.SetLocation(symbol
.name())};
231 context_
.set_location(symbol
.name());
232 const DeclTypeSpec
*type
{symbol
.GetType()};
233 const DerivedTypeSpec
*derived
{type
? type
->AsDerived() : nullptr};
237 [&](const UseDetails
&x
) { isDone
= true; },
238 [&](const HostAssocDetails
&x
) {
239 CheckHostAssoc(symbol
, x
);
242 [&](const ProcBindingDetails
&x
) {
243 CheckProcBinding(symbol
, x
);
246 [&](const ObjectEntityDetails
&x
) { CheckObjectEntity(symbol
, x
); },
247 [&](const ProcEntityDetails
&x
) { CheckProcEntity(symbol
, x
); },
248 [&](const SubprogramDetails
&x
) { CheckSubprogram(symbol
, x
); },
249 [&](const DerivedTypeDetails
&x
) { CheckDerivedType(symbol
, x
); },
250 [&](const GenericDetails
&x
) { CheckGeneric(symbol
, x
); },
254 if (symbol
.attrs().test(Attr::VOLATILE
)) {
255 CheckVolatile(symbol
, derived
);
257 if (symbol
.attrs().test(Attr::BIND_C
)) {
260 CheckGlobalName(symbol
);
262 return; // following checks do not apply
264 if (symbol
.attrs().test(Attr::PROTECTED
)) {
265 if (symbol
.owner().kind() != Scope::Kind::Module
) { // C854
267 "A PROTECTED entity must be in the specification part of a module"_err_en_US
);
269 if (!evaluate::IsVariable(symbol
) && !IsProcedurePointer(symbol
)) { // C855
271 "A PROTECTED entity must be a variable or pointer"_err_en_US
);
273 if (FindCommonBlockContaining(symbol
)) { // C856
275 "A PROTECTED entity may not be in a common block"_err_en_US
);
278 if (IsPointer(symbol
)) {
279 CheckPointer(symbol
);
283 // Declarations in interface definitions "have no effect" if they
284 // are not pertinent to the characteristics of the procedure.
285 // Restrictions on entities in pure procedure interfaces don't need
288 if (IsSaved(symbol
)) {
289 if (IsInitialized(symbol
)) {
291 "A pure subprogram may not initialize a variable"_err_en_US
);
294 "A pure subprogram may not have a variable with the SAVE attribute"_err_en_US
);
297 if (!IsDummy(symbol
) && !IsFunctionResult(symbol
)) {
298 if (IsPolymorphicAllocatable(symbol
)) {
299 SayWithDeclaration(symbol
,
300 "Deallocation of polymorphic object '%s' is not permitted in a pure subprogram"_err_en_US
,
302 } else if (derived
) {
303 if (auto bad
{FindPolymorphicAllocatableUltimateComponent(*derived
)}) {
304 SayWithDeclaration(*bad
,
305 "Deallocation of polymorphic object '%s%s' is not permitted in a pure subprogram"_err_en_US
,
306 symbol
.name(), bad
.BuildResultDesignatorName());
311 if (symbol
.attrs().test(Attr::VOLATILE
) &&
312 (IsDummy(symbol
) || !InInterface())) {
314 "A pure subprogram may not have a variable with the VOLATILE attribute"_err_en_US
);
316 if (IsProcedure(symbol
) && !IsPureProcedure(symbol
) && IsDummy(symbol
)) {
318 "A dummy procedure of a pure subprogram must be pure"_err_en_US
);
321 if (type
) { // Section 7.2, paragraph 7
322 bool canHaveAssumedParameter
{IsNamedConstant(symbol
) ||
323 (IsAssumedLengthCharacter(symbol
) && // C722
324 (IsExternal(symbol
) ||
325 ClassifyProcedure(symbol
) ==
326 ProcedureDefinitionClass::Dummy
)) ||
327 symbol
.test(Symbol::Flag::ParentComp
)};
328 if (!IsStmtFunctionDummy(symbol
)) { // C726
329 if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
330 canHaveAssumedParameter
|= object
->isDummy() ||
331 (object
->isFuncResult() &&
332 type
->category() == DeclTypeSpec::Character
) ||
333 IsStmtFunctionResult(symbol
); // Avoids multiple messages
335 canHaveAssumedParameter
|= symbol
.has
<AssocEntityDetails
>();
338 if (IsProcedurePointer(symbol
) && symbol
.HasExplicitInterface()) {
339 // Don't check function result types here
341 Check(*type
, canHaveAssumedParameter
);
343 if (InPure() && InFunction() && IsFunctionResult(symbol
)) {
344 if (derived
&& HasImpureFinal(*derived
)) { // C1584
346 "Result of pure function may not have an impure FINAL subroutine"_err_en_US
);
348 if (type
->IsPolymorphic() && IsAllocatable(symbol
)) { // C1585
350 "Result of pure function may not be both polymorphic and ALLOCATABLE"_err_en_US
);
353 if (auto bad
{FindPolymorphicAllocatableUltimateComponent(*derived
)}) {
354 SayWithDeclaration(*bad
,
355 "Result of pure function may not have polymorphic ALLOCATABLE ultimate component '%s'"_err_en_US
,
356 bad
.BuildResultDesignatorName());
361 if (IsAssumedLengthCharacter(symbol
) && IsFunction(symbol
)) { // C723
362 if (symbol
.attrs().test(Attr::RECURSIVE
)) {
364 "An assumed-length CHARACTER(*) function cannot be RECURSIVE"_err_en_US
);
366 if (symbol
.Rank() > 0) {
368 "An assumed-length CHARACTER(*) function cannot return an array"_err_en_US
);
370 if (!IsStmtFunction(symbol
)) {
371 if (IsElementalProcedure(symbol
)) {
373 "An assumed-length CHARACTER(*) function cannot be ELEMENTAL"_err_en_US
);
374 } else if (IsPureProcedure(symbol
)) {
376 "An assumed-length CHARACTER(*) function cannot be PURE"_err_en_US
);
379 if (const Symbol
*result
{FindFunctionResult(symbol
)}) {
380 if (IsPointer(*result
)) {
382 "An assumed-length CHARACTER(*) function cannot return a POINTER"_err_en_US
);
384 } else if (IsProcedurePointer(symbol
) && IsDummy(symbol
)) {
386 "A dummy procedure pointer should not have assumed-length CHARACTER(*) result type"_port_en_US
);
387 // The non-dummy case is a hard error that's caught elsewhere.
390 if (symbol
.attrs().test(Attr::VALUE
)) {
391 CheckValue(symbol
, derived
);
393 if (symbol
.attrs().test(Attr::CONTIGUOUS
) && IsPointer(symbol
) &&
394 symbol
.Rank() == 0) { // C830
395 messages_
.Say("CONTIGUOUS POINTER must be an array"_err_en_US
);
397 if (IsDummy(symbol
)) {
398 if (IsNamedConstant(symbol
)) {
400 "A dummy argument may not also be a named constant"_err_en_US
);
402 if (!symbol
.test(Symbol::Flag::InDataStmt
) /*caught elsewhere*/ &&
405 "A dummy argument may not have the SAVE attribute"_err_en_US
);
407 } else if (IsFunctionResult(symbol
)) {
408 if (IsNamedConstant(symbol
)) {
410 "A function result may not also be a named constant"_err_en_US
);
412 if (!symbol
.test(Symbol::Flag::InDataStmt
) /*caught elsewhere*/ &&
415 "A function result may not have the SAVE attribute"_err_en_US
);
417 CheckBindCFunctionResult(symbol
);
419 if (symbol
.owner().IsDerivedType() &&
420 (symbol
.attrs().test(Attr::CONTIGUOUS
) &&
421 !(IsPointer(symbol
) && symbol
.Rank() > 0))) { // C752
423 "A CONTIGUOUS component must be an array with the POINTER attribute"_err_en_US
);
425 if (symbol
.owner().IsModule() && IsAutomatic(symbol
)) {
427 "Automatic data object '%s' may not appear in the specification part"
428 " of a module"_err_en_US
,
433 void CheckHelper::CheckCommonBlock(const Symbol
&symbol
) {
434 CheckGlobalName(symbol
);
435 if (symbol
.attrs().test(Attr::BIND_C
)) {
440 void CheckHelper::CheckBindCFunctionResult(const Symbol
&symbol
) { // C1553
441 if (!innermostSymbol_
|| !IsBindCProcedure(*innermostSymbol_
)) {
444 if (IsPointer(symbol
) || IsAllocatable(symbol
)) {
446 "BIND(C) function result cannot have ALLOCATABLE or POINTER attribute"_err_en_US
);
448 if (const DeclTypeSpec
* type
{symbol
.GetType()};
449 type
&& type
->category() == DeclTypeSpec::Character
) {
450 bool isConstOne
{false}; // 18.3.1(1)
451 if (const auto &len
{type
->characterTypeSpec().length().GetExplicit()}) {
452 if (auto constLen
{evaluate::ToInt64(*len
)}) {
453 isConstOne
= constLen
== 1;
458 "BIND(C) character function result must have length one"_err_en_US
);
461 if (symbol
.Rank() > 0) {
462 messages_
.Say("BIND(C) function result must be scalar"_err_en_US
);
464 if (symbol
.Corank()) {
465 messages_
.Say("BIND(C) function result cannot be a coarray"_err_en_US
);
469 void CheckHelper::CheckValue(
470 const Symbol
&symbol
, const DerivedTypeSpec
*derived
) { // C863 - C865
471 if (!IsDummy(symbol
)) {
473 "VALUE attribute may apply only to a dummy argument"_err_en_US
);
475 if (IsProcedure(symbol
)) {
477 "VALUE attribute may apply only to a dummy data object"_err_en_US
);
479 if (IsAssumedSizeArray(symbol
)) {
481 "VALUE attribute may not apply to an assumed-size array"_err_en_US
);
483 if (evaluate::IsCoarray(symbol
)) {
484 messages_
.Say("VALUE attribute may not apply to a coarray"_err_en_US
);
486 if (IsAllocatable(symbol
)) {
487 messages_
.Say("VALUE attribute may not apply to an ALLOCATABLE"_err_en_US
);
488 } else if (IsPointer(symbol
)) {
489 messages_
.Say("VALUE attribute may not apply to a POINTER"_err_en_US
);
491 if (IsIntentInOut(symbol
)) {
493 "VALUE attribute may not apply to an INTENT(IN OUT) argument"_err_en_US
);
494 } else if (IsIntentOut(symbol
)) {
496 "VALUE attribute may not apply to an INTENT(OUT) argument"_err_en_US
);
498 if (symbol
.attrs().test(Attr::VOLATILE
)) {
499 messages_
.Say("VALUE attribute may not apply to a VOLATILE"_err_en_US
);
501 if (innermostSymbol_
&& IsBindCProcedure(*innermostSymbol_
)) {
502 if (IsOptional(symbol
)) {
504 "VALUE attribute may not apply to an OPTIONAL in a BIND(C) procedure"_err_en_US
);
506 if (symbol
.Rank() > 0) {
508 "VALUE attribute may not apply to an array in a BIND(C) procedure"_err_en_US
);
512 if (FindCoarrayUltimateComponent(*derived
)) {
514 "VALUE attribute may not apply to a type with a coarray ultimate component"_err_en_US
);
519 void CheckHelper::CheckAssumedTypeEntity( // C709
520 const Symbol
&symbol
, const ObjectEntityDetails
&details
) {
521 if (const DeclTypeSpec
*type
{symbol
.GetType()};
522 type
&& type
->category() == DeclTypeSpec::TypeStar
) {
523 if (!IsDummy(symbol
)) {
525 "Assumed-type entity '%s' must be a dummy argument"_err_en_US
,
528 if (symbol
.attrs().test(Attr::ALLOCATABLE
)) {
529 messages_
.Say("Assumed-type argument '%s' cannot have the ALLOCATABLE"
530 " attribute"_err_en_US
,
533 if (symbol
.attrs().test(Attr::POINTER
)) {
534 messages_
.Say("Assumed-type argument '%s' cannot have the POINTER"
535 " attribute"_err_en_US
,
538 if (symbol
.attrs().test(Attr::VALUE
)) {
539 messages_
.Say("Assumed-type argument '%s' cannot have the VALUE"
540 " attribute"_err_en_US
,
543 if (symbol
.attrs().test(Attr::INTENT_OUT
)) {
545 "Assumed-type argument '%s' cannot be INTENT(OUT)"_err_en_US
,
548 if (evaluate::IsCoarray(symbol
)) {
550 "Assumed-type argument '%s' cannot be a coarray"_err_en_US
,
553 if (details
.IsArray() && details
.shape().IsExplicitShape()) {
555 "Assumed-type array argument 'arg8' must be assumed shape,"
556 " assumed size, or assumed rank"_err_en_US
,
563 void CheckHelper::CheckObjectEntity(
564 const Symbol
&symbol
, const ObjectEntityDetails
&details
) {
565 CheckSymbolType(symbol
);
566 CheckArraySpec(symbol
, details
.shape());
567 Check(details
.shape());
568 Check(details
.coshape());
569 if (details
.shape().Rank() > common::maxRank
) {
571 "'%s' has rank %d, which is greater than the maximum supported rank %d"_err_en_US
,
572 symbol
.name(), details
.shape().Rank(), common::maxRank
);
573 } else if (details
.shape().Rank() + details
.coshape().Rank() >
576 "'%s' has rank %d and corank %d, whose sum is greater than the maximum supported rank %d"_err_en_US
,
577 symbol
.name(), details
.shape().Rank(), details
.coshape().Rank(),
580 CheckAssumedTypeEntity(symbol
, details
);
581 WarnMissingFinal(symbol
);
582 const DeclTypeSpec
*type
{details
.type()};
583 const DerivedTypeSpec
*derived
{type
? type
->AsDerived() : nullptr};
584 if (!details
.coshape().empty()) {
585 bool isDeferredCoshape
{details
.coshape().CanBeDeferredShape()};
586 if (IsAllocatable(symbol
)) {
587 if (!isDeferredCoshape
) { // C827
588 messages_
.Say("'%s' is an ALLOCATABLE coarray and must have a deferred"
589 " coshape"_err_en_US
,
592 } else if (symbol
.owner().IsDerivedType()) { // C746
593 std::string deferredMsg
{
594 isDeferredCoshape
? "" : " and have a deferred coshape"};
595 messages_
.Say("Component '%s' is a coarray and must have the ALLOCATABLE"
596 " attribute%s"_err_en_US
,
597 symbol
.name(), deferredMsg
);
599 if (!details
.coshape().CanBeAssumedSize()) { // C828
601 "'%s' is a non-ALLOCATABLE coarray and must have an explicit coshape"_err_en_US
,
605 if (IsBadCoarrayType(derived
)) { // C747 & C824
607 "Coarray '%s' may not have type TEAM_TYPE, C_PTR, or C_FUNPTR"_err_en_US
,
611 if (details
.isDummy()) {
612 if (IsIntentOut(symbol
)) {
613 if (FindUltimateComponent(symbol
, [](const Symbol
&x
) {
614 return evaluate::IsCoarray(x
) && IsAllocatable(x
);
617 "An INTENT(OUT) dummy argument may not be, or contain, an ALLOCATABLE coarray"_err_en_US
);
619 if (IsOrContainsEventOrLockComponent(symbol
)) { // C847
621 "An INTENT(OUT) dummy argument may not be, or contain, EVENT_TYPE or LOCK_TYPE"_err_en_US
);
623 if (details
.IsAssumedSize()) { // C834
624 if (type
&& type
->IsPolymorphic()) {
626 "An INTENT(OUT) assumed-size dummy argument array may not be polymorphic"_err_en_US
);
629 if (derived
->HasDefaultInitialization()) {
631 "An INTENT(OUT) assumed-size dummy argument array may not have a derived type with any default component initialization"_err_en_US
);
633 if (IsFinalizable(*derived
)) {
635 "An INTENT(OUT) assumed-size dummy argument array may not be finalizable"_err_en_US
);
640 if (InPure() && !IsStmtFunction(DEREF(innermostSymbol_
)) &&
641 !IsPointer(symbol
) && !IsIntentIn(symbol
) &&
642 !symbol
.attrs().test(Attr::VALUE
)) {
643 if (InFunction()) { // C1583
645 "non-POINTER dummy argument of pure function must be INTENT(IN) or VALUE"_err_en_US
);
646 } else if (IsIntentOut(symbol
)) {
647 if (type
&& type
->IsPolymorphic()) { // C1588
649 "An INTENT(OUT) dummy argument of a pure subroutine may not be polymorphic"_err_en_US
);
650 } else if (derived
) {
651 if (FindUltimateComponent(*derived
, [](const Symbol
&x
) {
652 const DeclTypeSpec
*type
{x
.GetType()};
653 return type
&& type
->IsPolymorphic();
656 "An INTENT(OUT) dummy argument of a pure subroutine may not have a polymorphic ultimate component"_err_en_US
);
658 if (HasImpureFinal(*derived
)) { // C1587
660 "An INTENT(OUT) dummy argument of a pure subroutine may not have an impure FINAL subroutine"_err_en_US
);
663 } else if (!IsIntentInOut(symbol
)) { // C1586
665 "non-POINTER dummy argument of pure subroutine must have INTENT() or VALUE attribute"_err_en_US
);
668 } else if (symbol
.attrs().test(Attr::INTENT_IN
) ||
669 symbol
.attrs().test(Attr::INTENT_OUT
) ||
670 symbol
.attrs().test(Attr::INTENT_INOUT
)) {
671 messages_
.Say("INTENT attributes may apply only to a dummy "
672 "argument"_err_en_US
); // C843
673 } else if (IsOptional(symbol
)) {
674 messages_
.Say("OPTIONAL attribute may apply only to a dummy "
675 "argument"_err_en_US
); // C849
678 if (details
.isDummy()) { // C15100
679 if (details
.shape().Rank() > 0) {
681 "A dummy argument of an ELEMENTAL procedure must be scalar"_err_en_US
);
683 if (IsAllocatable(symbol
)) {
685 "A dummy argument of an ELEMENTAL procedure may not be ALLOCATABLE"_err_en_US
);
687 if (evaluate::IsCoarray(symbol
)) {
689 "A dummy argument of an ELEMENTAL procedure may not be a coarray"_err_en_US
);
691 if (IsPointer(symbol
)) {
693 "A dummy argument of an ELEMENTAL procedure may not be a POINTER"_err_en_US
);
695 if (!symbol
.attrs().HasAny(Attrs
{Attr::VALUE
, Attr::INTENT_IN
,
696 Attr::INTENT_INOUT
, Attr::INTENT_OUT
})) { // C15102
698 "A dummy argument of an ELEMENTAL procedure must have an INTENT() or VALUE attribute"_err_en_US
);
700 } else if (IsFunctionResult(symbol
)) { // C15101
701 if (details
.shape().Rank() > 0) {
703 "The result of an ELEMENTAL function must be scalar"_err_en_US
);
705 if (IsAllocatable(symbol
)) {
707 "The result of an ELEMENTAL function may not be ALLOCATABLE"_err_en_US
);
709 if (IsPointer(symbol
)) {
711 "The result of an ELEMENTAL function may not be a POINTER"_err_en_US
);
715 if (HasDeclarationInitializer(symbol
)) { // C808; ignore DATA initialization
716 CheckPointerInitialization(symbol
);
717 if (IsAutomatic(symbol
)) {
719 "An automatic variable or component must not be initialized"_err_en_US
);
720 } else if (IsDummy(symbol
)) {
721 messages_
.Say("A dummy argument must not be initialized"_err_en_US
);
722 } else if (IsFunctionResult(symbol
)) {
723 messages_
.Say("A function result must not be initialized"_err_en_US
);
724 } else if (IsInBlankCommon(symbol
) &&
725 !FindModuleFileContaining(symbol
.owner())) {
727 "A variable in blank COMMON should not be initialized"_port_en_US
);
730 if (symbol
.owner().kind() == Scope::Kind::BlockData
) {
731 if (IsAllocatable(symbol
)) {
733 "An ALLOCATABLE variable may not appear in a BLOCK DATA subprogram"_err_en_US
);
734 } else if (IsInitialized(symbol
) && !FindCommonBlockContaining(symbol
)) {
736 "An initialized variable in BLOCK DATA must be in a COMMON block"_err_en_US
);
739 if (type
&& type
->IsPolymorphic() &&
740 !(type
->IsAssumedType() || IsAllocatableOrPointer(symbol
) ||
741 IsDummy(symbol
))) { // C708
742 messages_
.Say("CLASS entity '%s' must be a dummy argument or have "
743 "ALLOCATABLE or POINTER attribute"_err_en_US
,
748 void CheckHelper::CheckPointerInitialization(const Symbol
&symbol
) {
749 if (IsPointer(symbol
) && !context_
.HasError(symbol
) &&
750 !scopeIsUninstantiatedPDT_
) {
751 if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
752 if (object
->init()) { // C764, C765; C808
753 if (auto designator
{evaluate::AsGenericExpr(symbol
)}) {
754 auto restorer
{messages_
.SetLocation(symbol
.name())};
755 context_
.set_location(symbol
.name());
757 foldingContext_
, *designator
, *object
->init(), DEREF(scope_
));
760 } else if (const auto *proc
{symbol
.detailsIf
<ProcEntityDetails
>()}) {
761 if (proc
->init() && *proc
->init()) {
762 // C1519 - must be nonelemental external or module procedure,
763 // or an unrestricted specific intrinsic function.
764 const Symbol
&ultimate
{(*proc
->init())->GetUltimate()};
765 if (ultimate
.attrs().test(Attr::INTRINSIC
)) {
766 if (const auto intrinsic
{
767 context_
.intrinsics().IsSpecificIntrinsicFunction(
768 ultimate
.name().ToString())};
769 !intrinsic
|| intrinsic
->isRestrictedSpecific
) { // C1030
771 "Intrinsic procedure '%s' is not an unrestricted specific "
772 "intrinsic permitted for use as the initializer for procedure "
773 "pointer '%s'"_err_en_US
,
774 ultimate
.name(), symbol
.name());
776 } else if (!ultimate
.attrs().test(Attr::EXTERNAL
) &&
777 ultimate
.owner().kind() != Scope::Kind::Module
) {
778 context_
.Say("Procedure pointer '%s' initializer '%s' is neither "
779 "an external nor a module procedure"_err_en_US
,
780 symbol
.name(), ultimate
.name());
781 } else if (IsElementalProcedure(ultimate
)) {
782 context_
.Say("Procedure pointer '%s' cannot be initialized with the "
783 "elemental procedure '%s"_err_en_US
,
784 symbol
.name(), ultimate
.name());
786 // TODO: Check the "shalls" in the 15.4.3.6 paragraphs 7-10.
793 // The six different kinds of array-specs:
794 // array-spec -> explicit-shape-list | deferred-shape-list
795 // | assumed-shape-list | implied-shape-list
796 // | assumed-size | assumed-rank
797 // explicit-shape -> [ lb : ] ub
798 // deferred-shape -> :
799 // assumed-shape -> [ lb ] :
800 // implied-shape -> [ lb : ] *
801 // assumed-size -> [ explicit-shape-list , ] [ lb : ] *
802 // assumed-rank -> ..
804 // - deferred-shape is also an assumed-shape
805 // - A single "*" or "lb:*" might be assumed-size or implied-shape-list
806 void CheckHelper::CheckArraySpec(
807 const Symbol
&symbol
, const ArraySpec
&arraySpec
) {
808 if (arraySpec
.Rank() == 0) {
811 bool isExplicit
{arraySpec
.IsExplicitShape()};
812 bool canBeDeferred
{arraySpec
.CanBeDeferredShape()};
813 bool canBeImplied
{arraySpec
.CanBeImpliedShape()};
814 bool canBeAssumedShape
{arraySpec
.CanBeAssumedShape()};
815 bool canBeAssumedSize
{arraySpec
.CanBeAssumedSize()};
816 bool isAssumedRank
{arraySpec
.IsAssumedRank()};
817 std::optional
<parser::MessageFixedText
> msg
;
818 if (symbol
.test(Symbol::Flag::CrayPointee
) && !isExplicit
&&
820 msg
= "Cray pointee '%s' must have explicit shape or"
821 " assumed size"_err_en_US
;
822 } else if (IsAllocatableOrPointer(symbol
) && !canBeDeferred
&&
824 if (symbol
.owner().IsDerivedType()) { // C745
825 if (IsAllocatable(symbol
)) {
826 msg
= "Allocatable array component '%s' must have"
827 " deferred shape"_err_en_US
;
829 msg
= "Array pointer component '%s' must have deferred shape"_err_en_US
;
832 if (IsAllocatable(symbol
)) { // C832
833 msg
= "Allocatable array '%s' must have deferred shape or"
834 " assumed rank"_err_en_US
;
836 msg
= "Array pointer '%s' must have deferred shape or"
837 " assumed rank"_err_en_US
;
840 } else if (IsDummy(symbol
)) {
841 if (canBeImplied
&& !canBeAssumedSize
) { // C836
842 msg
= "Dummy array argument '%s' may not have implied shape"_err_en_US
;
844 } else if (canBeAssumedShape
&& !canBeDeferred
) {
845 msg
= "Assumed-shape array '%s' must be a dummy argument"_err_en_US
;
846 } else if (canBeAssumedSize
&& !canBeImplied
) { // C833
847 msg
= "Assumed-size array '%s' must be a dummy argument"_err_en_US
;
848 } else if (isAssumedRank
) { // C837
849 msg
= "Assumed-rank array '%s' must be a dummy argument"_err_en_US
;
850 } else if (canBeImplied
) {
851 if (!IsNamedConstant(symbol
)) { // C835, C836
852 msg
= "Implied-shape array '%s' must be a named constant or a "
853 "dummy argument"_err_en_US
;
855 } else if (IsNamedConstant(symbol
)) {
856 if (!isExplicit
&& !canBeImplied
) {
857 msg
= "Named constant '%s' array must have constant or"
858 " implied shape"_err_en_US
;
860 } else if (!IsAllocatableOrPointer(symbol
) && !isExplicit
) {
861 if (symbol
.owner().IsDerivedType()) { // C749
862 msg
= "Component array '%s' without ALLOCATABLE or POINTER attribute must"
863 " have explicit shape"_err_en_US
;
865 msg
= "Array '%s' without ALLOCATABLE or POINTER attribute must have"
866 " explicit shape"_err_en_US
;
870 context_
.Say(std::move(*msg
), symbol
.name());
874 void CheckHelper::CheckProcEntity(
875 const Symbol
&symbol
, const ProcEntityDetails
&details
) {
876 CheckSymbolType(symbol
);
877 if (details
.isDummy()) {
878 if (!symbol
.attrs().test(Attr::POINTER
) && // C843
879 (symbol
.attrs().test(Attr::INTENT_IN
) ||
880 symbol
.attrs().test(Attr::INTENT_OUT
) ||
881 symbol
.attrs().test(Attr::INTENT_INOUT
))) {
882 messages_
.Say("A dummy procedure without the POINTER attribute"
883 " may not have an INTENT attribute"_err_en_US
);
885 if (InElemental()) { // C15100
887 "An ELEMENTAL subprogram may not have a dummy procedure"_err_en_US
);
889 const Symbol
*interface
{
890 details
.procInterface()
892 if (!symbol
.attrs().test(Attr::INTRINSIC
) &&
893 (IsElementalProcedure(symbol
) ||
894 (interface
&& !interface
->attrs().test(Attr::INTRINSIC
) &&
895 IsElementalProcedure(*interface
)))) {
896 // There's no explicit constraint or "shall" that we can find in the
897 // standard for this check, but it seems to be implied in multiple
898 // sites, and ELEMENTAL non-intrinsic actual arguments *are*
899 // explicitly forbidden. But we allow "PROCEDURE(SIN)::dummy"
900 // because it is explicitly legal to *pass* the specific intrinsic
901 // function SIN as an actual argument.
902 messages_
.Say("A dummy procedure may not be ELEMENTAL"_err_en_US
);
904 } else if (symbol
.attrs().test(Attr::INTENT_IN
) ||
905 symbol
.attrs().test(Attr::INTENT_OUT
) ||
906 symbol
.attrs().test(Attr::INTENT_INOUT
)) {
907 messages_
.Say("INTENT attributes may apply only to a dummy "
908 "argument"_err_en_US
); // C843
909 } else if (IsOptional(symbol
)) {
910 messages_
.Say("OPTIONAL attribute may apply only to a dummy "
911 "argument"_err_en_US
); // C849
912 } else if (symbol
.owner().IsDerivedType()) {
913 if (!symbol
.attrs().test(Attr::POINTER
)) { // C756
914 const auto &name
{symbol
.name()};
916 "Procedure component '%s' must have POINTER attribute"_err_en_US
,
919 CheckPassArg(symbol
, details
.procInterface(), details
);
921 if (symbol
.attrs().test(Attr::POINTER
)) {
922 CheckPointerInitialization(symbol
);
923 if (const Symbol
* interface
{details
.procInterface()}) {
924 const Symbol
&ultimate
{interface
->GetUltimate()};
925 if (ultimate
.attrs().test(Attr::INTRINSIC
)) {
926 if (const auto intrinsic
{
927 context_
.intrinsics().IsSpecificIntrinsicFunction(
928 ultimate
.name().ToString())};
929 !intrinsic
|| intrinsic
->isRestrictedSpecific
) { // C1515
931 "Intrinsic procedure '%s' is not an unrestricted specific "
932 "intrinsic permitted for use as the definition of the interface "
933 "to procedure pointer '%s'"_err_en_US
,
934 ultimate
.name(), symbol
.name());
936 } else if (IsElementalProcedure(*interface
)) {
937 messages_
.Say("Procedure pointer '%s' may not be ELEMENTAL"_err_en_US
,
938 symbol
.name()); // C1517
941 } else if (symbol
.attrs().test(Attr::SAVE
)) {
943 "Procedure '%s' with SAVE attribute must also have POINTER attribute"_err_en_US
,
946 CheckLocalVsGlobal(symbol
);
949 // When a module subprogram has the MODULE prefix the following must match
950 // with the corresponding separate module procedure interface body:
951 // - C1549: characteristics and dummy argument names
952 // - C1550: binding label
953 // - C1551: NON_RECURSIVE prefix
954 class SubprogramMatchHelper
{
956 explicit SubprogramMatchHelper(CheckHelper
&checkHelper
)
957 : checkHelper
{checkHelper
} {}
959 void Check(const Symbol
&, const Symbol
&);
962 SemanticsContext
&context() { return checkHelper
.context(); }
963 void CheckDummyArg(const Symbol
&, const Symbol
&, const DummyArgument
&,
964 const DummyArgument
&);
965 void CheckDummyDataObject(const Symbol
&, const Symbol
&,
966 const DummyDataObject
&, const DummyDataObject
&);
967 void CheckDummyProcedure(const Symbol
&, const Symbol
&,
968 const DummyProcedure
&, const DummyProcedure
&);
969 bool CheckSameIntent(
970 const Symbol
&, const Symbol
&, common::Intent
, common::Intent
);
971 template <typename
... A
>
973 const Symbol
&, const Symbol
&, parser::MessageFixedText
&&, A
&&...);
974 template <typename ATTRS
>
975 bool CheckSameAttrs(const Symbol
&, const Symbol
&, ATTRS
, ATTRS
);
976 bool ShapesAreCompatible(const DummyDataObject
&, const DummyDataObject
&);
977 evaluate::Shape
FoldShape(const evaluate::Shape
&);
978 std::string
AsFortran(DummyDataObject::Attr attr
) {
979 return parser::ToUpperCaseLetters(DummyDataObject::EnumToString(attr
));
981 std::string
AsFortran(DummyProcedure::Attr attr
) {
982 return parser::ToUpperCaseLetters(DummyProcedure::EnumToString(attr
));
985 CheckHelper
&checkHelper
;
988 // 15.6.2.6 para 3 - can the result of an ENTRY differ from its function?
989 bool CheckHelper::IsResultOkToDiffer(const FunctionResult
&result
) {
990 if (result
.attrs
.test(FunctionResult::Attr::Allocatable
) ||
991 result
.attrs
.test(FunctionResult::Attr::Pointer
)) {
994 const auto *typeAndShape
{result
.GetTypeAndShape()};
995 if (!typeAndShape
|| typeAndShape
->Rank() != 0) {
998 auto category
{typeAndShape
->type().category()};
999 if (category
== TypeCategory::Character
||
1000 category
== TypeCategory::Derived
) {
1003 int kind
{typeAndShape
->type().kind()};
1004 return kind
== context_
.GetDefaultKind(category
) ||
1005 (category
== TypeCategory::Real
&&
1006 kind
== context_
.doublePrecisionKind());
1009 void CheckHelper::CheckSubprogram(
1010 const Symbol
&symbol
, const SubprogramDetails
&details
) {
1011 if (const Symbol
*iface
{FindSeparateModuleSubprogramInterface(&symbol
)}) {
1012 SubprogramMatchHelper
{*this}.Check(symbol
, *iface
);
1014 if (const Scope
*entryScope
{details
.entryScope()}) {
1015 // ENTRY 15.6.2.6, esp. C1571
1016 std::optional
<parser::MessageFixedText
> error
;
1017 const Symbol
*subprogram
{entryScope
->symbol()};
1018 const SubprogramDetails
*subprogramDetails
{nullptr};
1020 subprogramDetails
= subprogram
->detailsIf
<SubprogramDetails
>();
1022 if (!(entryScope
->parent().IsGlobal() || entryScope
->parent().IsModule() ||
1023 entryScope
->parent().IsSubmodule())) {
1024 error
= "ENTRY may not appear in an internal subprogram"_err_en_US
;
1025 } else if (subprogramDetails
&& details
.isFunction() &&
1026 subprogramDetails
->isFunction() &&
1027 !context_
.HasError(details
.result()) &&
1028 !context_
.HasError(subprogramDetails
->result())) {
1029 auto result
{FunctionResult::Characterize(
1030 details
.result(), context_
.foldingContext())};
1031 auto subpResult
{FunctionResult::Characterize(
1032 subprogramDetails
->result(), context_
.foldingContext())};
1033 if (result
&& subpResult
&& *result
!= *subpResult
&&
1034 (!IsResultOkToDiffer(*result
) || !IsResultOkToDiffer(*subpResult
))) {
1036 "Result of ENTRY is not compatible with result of containing function"_err_en_US
;
1040 if (auto *msg
{messages_
.Say(symbol
.name(), *error
)}) {
1042 msg
->Attach(subprogram
->name(), "Containing subprogram"_en_US
);
1047 if (const MaybeExpr
& stmtFunction
{details
.stmtFunction()}) {
1048 if (auto msg
{evaluate::CheckStatementFunction(
1049 symbol
, *stmtFunction
, context_
.foldingContext())}) {
1050 SayWithDeclaration(symbol
, std::move(*msg
));
1051 } else if (details
.result().flags().test(Symbol::Flag::Implicit
)) {
1052 // 15.6.4 p2 weird requirement
1054 host
{symbol
.owner().parent().FindSymbol(symbol
.name())}) {
1055 evaluate::AttachDeclaration(
1056 messages_
.Say(symbol
.name(),
1057 "An implicitly typed statement function should not appear when the same symbol is available in its host scope"_port_en_US
),
1061 if (GetProgramUnitOrBlockConstructContaining(symbol
).kind() ==
1062 Scope::Kind::BlockConstruct
) { // C1107
1063 messages_
.Say(symbol
.name(),
1064 "A statement function definition may not appear in a BLOCK construct"_err_en_US
);
1067 if (IsElementalProcedure(symbol
)) {
1068 // See comment on the similar check in CheckProcEntity()
1069 if (details
.isDummy()) {
1070 messages_
.Say("A dummy procedure may not be ELEMENTAL"_err_en_US
);
1072 for (const Symbol
*dummy
: details
.dummyArgs()) {
1073 if (!dummy
) { // C15100
1075 "An ELEMENTAL subroutine may not have an alternate return dummy argument"_err_en_US
);
1080 if (details
.isInterface()) {
1081 if (!details
.isDummy() && details
.isFunction() &&
1082 IsAssumedLengthCharacter(details
.result())) { // C721
1083 messages_
.Say(details
.result().name(),
1084 "A function interface may not declare an assumed-length CHARACTER(*) result"_err_en_US
);
1087 CheckLocalVsGlobal(symbol
);
1088 CheckModuleProcedureDef(symbol
);
1091 void CheckHelper::CheckLocalVsGlobal(const Symbol
&symbol
) {
1092 if (IsExternal(symbol
)) {
1093 if (const Symbol
*global
{FindGlobal(symbol
)}; global
&& global
!= &symbol
) {
1094 std::string interfaceName
{symbol
.name().ToString()};
1095 if (const auto *bind
{symbol
.GetBindName()}) {
1096 interfaceName
= *bind
;
1098 std::string definitionName
{global
->name().ToString()};
1099 if (const auto *bind
{global
->GetBindName()}) {
1100 definitionName
= *bind
;
1102 if (interfaceName
== definitionName
) {
1103 parser::Message
*msg
{nullptr};
1104 if (!IsProcedure(*global
)) {
1105 if (symbol
.flags().test(Symbol::Flag::Function
) ||
1106 symbol
.flags().test(Symbol::Flag::Subroutine
)) {
1107 msg
= messages_
.Say(
1108 "The global entity '%s' corresponding to the local procedure '%s' is not a callable subprogram"_err_en_US
,
1109 global
->name(), symbol
.name());
1111 } else if (auto chars
{Characterize(symbol
)}) {
1112 if (auto globalChars
{Characterize(*global
)}) {
1113 if (chars
->HasExplicitInterface()) {
1115 if (!chars
->IsCompatibleWith(*globalChars
, &whyNot
)) {
1116 msg
= messages_
.Say(
1117 "The global subprogram '%s' is not compatible with its local procedure declaration (%s)"_warn_en_US
,
1118 global
->name(), whyNot
);
1120 } else if (!globalChars
->CanBeCalledViaImplicitInterface()) {
1121 msg
= messages_
.Say(
1122 "The global subprogram '%s' may not be referenced via the implicit interface '%s'"_err_en_US
,
1123 global
->name(), symbol
.name());
1128 if (msg
->IsFatal()) {
1129 context_
.SetError(symbol
);
1131 evaluate::AttachDeclaration(msg
, *global
);
1132 evaluate::AttachDeclaration(msg
, symbol
);
1139 void CheckHelper::CheckDerivedType(
1140 const Symbol
&derivedType
, const DerivedTypeDetails
&details
) {
1141 if (details
.isForwardReferenced() && !context_
.HasError(derivedType
)) {
1142 messages_
.Say("The derived type '%s' has not been defined"_err_en_US
,
1143 derivedType
.name());
1145 const Scope
*scope
{derivedType
.scope()};
1147 CHECK(details
.isForwardReferenced());
1150 CHECK(scope
->symbol() == &derivedType
);
1151 CHECK(scope
->IsDerivedType());
1152 if (derivedType
.attrs().test(Attr::ABSTRACT
) && // C734
1153 (derivedType
.attrs().test(Attr::BIND_C
) || details
.sequence())) {
1154 messages_
.Say("An ABSTRACT derived type must be extensible"_err_en_US
);
1156 if (const DeclTypeSpec
*parent
{FindParentTypeSpec(derivedType
)}) {
1157 const DerivedTypeSpec
*parentDerived
{parent
->AsDerived()};
1158 if (!IsExtensibleType(parentDerived
)) { // C705
1159 messages_
.Say("The parent type is not extensible"_err_en_US
);
1161 if (!derivedType
.attrs().test(Attr::ABSTRACT
) && parentDerived
&&
1162 parentDerived
->typeSymbol().attrs().test(Attr::ABSTRACT
)) {
1163 ScopeComponentIterator components
{*parentDerived
};
1164 for (const Symbol
&component
: components
) {
1165 if (component
.attrs().test(Attr::DEFERRED
)) {
1166 if (scope
->FindComponent(component
.name()) == &component
) {
1167 SayWithDeclaration(component
,
1168 "Non-ABSTRACT extension of ABSTRACT derived type '%s' lacks a binding for DEFERRED procedure '%s'"_err_en_US
,
1169 parentDerived
->typeSymbol().name(), component
.name());
1174 DerivedTypeSpec derived
{derivedType
.name(), derivedType
};
1175 derived
.set_scope(*scope
);
1176 if (FindCoarrayUltimateComponent(derived
) && // C736
1177 !(parentDerived
&& FindCoarrayUltimateComponent(*parentDerived
))) {
1179 "Type '%s' has a coarray ultimate component so the type at the base "
1180 "of its type extension chain ('%s') must be a type that has a "
1181 "coarray ultimate component"_err_en_US
,
1182 derivedType
.name(), scope
->GetDerivedTypeBase().GetSymbol()->name());
1184 if (FindEventOrLockPotentialComponent(derived
) && // C737
1185 !(FindEventOrLockPotentialComponent(*parentDerived
) ||
1186 IsEventTypeOrLockType(parentDerived
))) {
1188 "Type '%s' has an EVENT_TYPE or LOCK_TYPE component, so the type "
1189 "at the base of its type extension chain ('%s') must either have an "
1190 "EVENT_TYPE or LOCK_TYPE component, or be EVENT_TYPE or "
1191 "LOCK_TYPE"_err_en_US
,
1192 derivedType
.name(), scope
->GetDerivedTypeBase().GetSymbol()->name());
1195 if (HasIntrinsicTypeName(derivedType
)) { // C729
1196 messages_
.Say("A derived type name cannot be the name of an intrinsic"
1199 std::map
<SourceName
, SymbolRef
> previous
;
1200 for (const auto &pair
: details
.finals()) {
1201 SourceName source
{pair
.first
};
1202 const Symbol
&ref
{*pair
.second
};
1203 if (CheckFinal(ref
, source
, derivedType
) &&
1204 std::all_of(previous
.begin(), previous
.end(),
1205 [&](std::pair
<SourceName
, SymbolRef
> prev
) {
1206 return CheckDistinguishableFinals(
1207 ref
, source
, *prev
.second
, prev
.first
, derivedType
);
1209 previous
.emplace(source
, ref
);
1215 bool CheckHelper::CheckFinal(
1216 const Symbol
&subroutine
, SourceName finalName
, const Symbol
&derivedType
) {
1217 if (!IsModuleProcedure(subroutine
)) {
1218 SayWithDeclaration(subroutine
, finalName
,
1219 "FINAL subroutine '%s' of derived type '%s' must be a module procedure"_err_en_US
,
1220 subroutine
.name(), derivedType
.name());
1223 const Procedure
*proc
{Characterize(subroutine
)};
1225 return false; // error recovery
1227 if (!proc
->IsSubroutine()) {
1228 SayWithDeclaration(subroutine
, finalName
,
1229 "FINAL subroutine '%s' of derived type '%s' must be a subroutine"_err_en_US
,
1230 subroutine
.name(), derivedType
.name());
1233 if (proc
->dummyArguments
.size() != 1) {
1234 SayWithDeclaration(subroutine
, finalName
,
1235 "FINAL subroutine '%s' of derived type '%s' must have a single dummy argument"_err_en_US
,
1236 subroutine
.name(), derivedType
.name());
1239 const auto &arg
{proc
->dummyArguments
[0]};
1240 const Symbol
*errSym
{&subroutine
};
1241 if (const auto *details
{subroutine
.detailsIf
<SubprogramDetails
>()}) {
1242 if (!details
->dummyArgs().empty()) {
1243 if (const Symbol
*argSym
{details
->dummyArgs()[0]}) {
1248 const auto *ddo
{std::get_if
<DummyDataObject
>(&arg
.u
)};
1250 SayWithDeclaration(subroutine
, finalName
,
1251 "FINAL subroutine '%s' of derived type '%s' must have a single dummy argument that is a data object"_err_en_US
,
1252 subroutine
.name(), derivedType
.name());
1256 if (arg
.IsOptional()) {
1257 SayWithDeclaration(*errSym
, finalName
,
1258 "FINAL subroutine '%s' of derived type '%s' must not have an OPTIONAL dummy argument"_err_en_US
,
1259 subroutine
.name(), derivedType
.name());
1262 if (ddo
->attrs
.test(DummyDataObject::Attr::Allocatable
)) {
1263 SayWithDeclaration(*errSym
, finalName
,
1264 "FINAL subroutine '%s' of derived type '%s' must not have an ALLOCATABLE dummy argument"_err_en_US
,
1265 subroutine
.name(), derivedType
.name());
1268 if (ddo
->attrs
.test(DummyDataObject::Attr::Pointer
)) {
1269 SayWithDeclaration(*errSym
, finalName
,
1270 "FINAL subroutine '%s' of derived type '%s' must not have a POINTER dummy argument"_err_en_US
,
1271 subroutine
.name(), derivedType
.name());
1274 if (ddo
->intent
== common::Intent::Out
) {
1275 SayWithDeclaration(*errSym
, finalName
,
1276 "FINAL subroutine '%s' of derived type '%s' must not have a dummy argument with INTENT(OUT)"_err_en_US
,
1277 subroutine
.name(), derivedType
.name());
1280 if (ddo
->attrs
.test(DummyDataObject::Attr::Value
)) {
1281 SayWithDeclaration(*errSym
, finalName
,
1282 "FINAL subroutine '%s' of derived type '%s' must not have a dummy argument with the VALUE attribute"_err_en_US
,
1283 subroutine
.name(), derivedType
.name());
1286 if (ddo
->type
.corank() > 0) {
1287 SayWithDeclaration(*errSym
, finalName
,
1288 "FINAL subroutine '%s' of derived type '%s' must not have a coarray dummy argument"_err_en_US
,
1289 subroutine
.name(), derivedType
.name());
1292 if (ddo
->type
.type().IsPolymorphic()) {
1293 SayWithDeclaration(*errSym
, finalName
,
1294 "FINAL subroutine '%s' of derived type '%s' must not have a polymorphic dummy argument"_err_en_US
,
1295 subroutine
.name(), derivedType
.name());
1297 } else if (ddo
->type
.type().category() != TypeCategory::Derived
||
1298 &ddo
->type
.type().GetDerivedTypeSpec().typeSymbol() != &derivedType
) {
1299 SayWithDeclaration(*errSym
, finalName
,
1300 "FINAL subroutine '%s' of derived type '%s' must have a TYPE(%s) dummy argument"_err_en_US
,
1301 subroutine
.name(), derivedType
.name(), derivedType
.name());
1303 } else { // check that all LEN type parameters are assumed
1304 for (auto ref
: OrderParameterDeclarations(derivedType
)) {
1305 if (IsLenTypeParameter(*ref
)) {
1307 ddo
->type
.type().GetDerivedTypeSpec().FindParameter(ref
->name())};
1308 if (!value
|| !value
->isAssumed()) {
1309 SayWithDeclaration(*errSym
, finalName
,
1310 "FINAL subroutine '%s' of derived type '%s' must have a dummy argument with an assumed LEN type parameter '%s=*'"_err_en_US
,
1311 subroutine
.name(), derivedType
.name(), ref
->name());
1320 bool CheckHelper::CheckDistinguishableFinals(const Symbol
&f1
,
1321 SourceName f1Name
, const Symbol
&f2
, SourceName f2Name
,
1322 const Symbol
&derivedType
) {
1323 const Procedure
*p1
{Characterize(f1
)};
1324 const Procedure
*p2
{Characterize(f2
)};
1326 if (characteristics::Distinguishable(
1327 context_
.languageFeatures(), *p1
, *p2
)) {
1330 if (auto *msg
{messages_
.Say(f1Name
,
1331 "FINAL subroutines '%s' and '%s' of derived type '%s' cannot be distinguished by rank or KIND type parameter value"_err_en_US
,
1332 f1Name
, f2Name
, derivedType
.name())}) {
1333 msg
->Attach(f2Name
, "FINAL declaration of '%s'"_en_US
, f2
.name())
1334 .Attach(f1
.name(), "Definition of '%s'"_en_US
, f1Name
)
1335 .Attach(f2
.name(), "Definition of '%s'"_en_US
, f2Name
);
1341 void CheckHelper::CheckHostAssoc(
1342 const Symbol
&symbol
, const HostAssocDetails
&details
) {
1343 const Symbol
&hostSymbol
{details
.symbol()};
1344 if (hostSymbol
.test(Symbol::Flag::ImplicitOrError
)) {
1345 if (details
.implicitOrSpecExprError
) {
1346 messages_
.Say("Implicitly typed local entity '%s' not allowed in"
1347 " specification expression"_err_en_US
,
1349 } else if (details
.implicitOrExplicitTypeError
) {
1351 "No explicit type declared for '%s'"_err_en_US
, symbol
.name());
1356 void CheckHelper::CheckGeneric(
1357 const Symbol
&symbol
, const GenericDetails
&details
) {
1358 CheckSpecifics(symbol
, details
);
1359 common::visit(common::visitors
{
1360 [&](const GenericKind::DefinedIo
&io
) {
1361 CheckDefinedIoProc(symbol
, details
, io
);
1363 [&](const GenericKind::OtherKind
&other
) {
1364 if (other
== GenericKind::OtherKind::Name
) {
1365 CheckGenericVsIntrinsic(symbol
, details
);
1368 [](const auto &) {},
1371 // Ensure that shadowed symbols are checked
1372 if (details
.specific()) {
1373 Check(*details
.specific());
1375 if (details
.derivedType()) {
1376 Check(*details
.derivedType());
1380 // Check that the specifics of this generic are distinguishable from each other
1381 void CheckHelper::CheckSpecifics(
1382 const Symbol
&generic
, const GenericDetails
&details
) {
1383 GenericKind kind
{details
.kind()};
1384 DistinguishabilityHelper helper
{context_
};
1385 for (const Symbol
&specific
: details
.specificProcs()) {
1386 if (specific
.attrs().test(Attr::ABSTRACT
)) {
1387 if (auto *msg
{messages_
.Say(generic
.name(),
1388 "Generic interface '%s' must not use abstract interface '%s' as a specific procedure"_err_en_US
,
1389 generic
.name(), specific
.name())}) {
1391 specific
.name(), "Definition of '%s'"_en_US
, specific
.name());
1395 if (specific
.attrs().test(Attr::INTRINSIC
)) {
1396 if (auto *msg
{messages_
.Say(specific
.name(),
1397 "Specific procedure '%s' of generic interface '%s' may not be INTRINSIC"_err_en_US
,
1398 specific
.name(), generic
.name())}) {
1399 msg
->Attach(generic
.name(), "Definition of '%s'"_en_US
, generic
.name());
1403 if (IsStmtFunction(specific
)) {
1404 if (auto *msg
{messages_
.Say(specific
.name(),
1405 "Specific procedure '%s' of generic interface '%s' may not be a statement function"_err_en_US
,
1406 specific
.name(), generic
.name())}) {
1407 msg
->Attach(generic
.name(), "Definition of '%s'"_en_US
, generic
.name());
1411 if (const Procedure
*procedure
{Characterize(specific
)}) {
1412 if (procedure
->HasExplicitInterface()) {
1413 helper
.Add(generic
, kind
, specific
, *procedure
);
1415 if (auto *msg
{messages_
.Say(specific
.name(),
1416 "Specific procedure '%s' of generic interface '%s' must have an explicit interface"_err_en_US
,
1417 specific
.name(), generic
.name())}) {
1419 generic
.name(), "Definition of '%s'"_en_US
, generic
.name());
1424 helper
.Check(generic
.owner());
1427 static bool ConflictsWithIntrinsicAssignment(const Procedure
&proc
) {
1428 auto lhs
{std::get
<DummyDataObject
>(proc
.dummyArguments
[0].u
).type
};
1429 auto rhs
{std::get
<DummyDataObject
>(proc
.dummyArguments
[1].u
).type
};
1430 return Tristate::No
==
1431 IsDefinedAssignment(lhs
.type(), lhs
.Rank(), rhs
.type(), rhs
.Rank());
1434 static bool ConflictsWithIntrinsicOperator(
1435 const GenericKind
&kind
, const Procedure
&proc
) {
1436 if (!kind
.IsIntrinsicOperator()) {
1439 auto arg0
{std::get
<DummyDataObject
>(proc
.dummyArguments
[0].u
).type
};
1440 auto type0
{arg0
.type()};
1441 if (proc
.dummyArguments
.size() == 1) { // unary
1442 return common::visit(
1444 [&](common::NumericOperator
) { return IsIntrinsicNumeric(type0
); },
1445 [&](common::LogicalOperator
) { return IsIntrinsicLogical(type0
); },
1446 [](const auto &) -> bool { DIE("bad generic kind"); },
1450 int rank0
{arg0
.Rank()};
1451 auto arg1
{std::get
<DummyDataObject
>(proc
.dummyArguments
[1].u
).type
};
1452 auto type1
{arg1
.type()};
1453 int rank1
{arg1
.Rank()};
1454 return common::visit(
1456 [&](common::NumericOperator
) {
1457 return IsIntrinsicNumeric(type0
, rank0
, type1
, rank1
);
1459 [&](common::LogicalOperator
) {
1460 return IsIntrinsicLogical(type0
, rank0
, type1
, rank1
);
1462 [&](common::RelationalOperator opr
) {
1463 return IsIntrinsicRelational(opr
, type0
, rank0
, type1
, rank1
);
1465 [&](GenericKind::OtherKind x
) {
1466 CHECK(x
== GenericKind::OtherKind::Concat
);
1467 return IsIntrinsicConcat(type0
, rank0
, type1
, rank1
);
1469 [](const auto &) -> bool { DIE("bad generic kind"); },
1475 // Check if this procedure can be used for defined operators (see 15.4.3.4.2).
1476 bool CheckHelper::CheckDefinedOperator(SourceName opName
, GenericKind kind
,
1477 const Symbol
&specific
, const Procedure
&proc
) {
1478 if (context_
.HasError(specific
)) {
1481 std::optional
<parser::MessageFixedText
> msg
;
1482 auto checkDefinedOperatorArgs
{
1483 [&](SourceName opName
, const Symbol
&specific
, const Procedure
&proc
) {
1484 bool arg0Defined
{CheckDefinedOperatorArg(opName
, specific
, proc
, 0)};
1485 bool arg1Defined
{CheckDefinedOperatorArg(opName
, specific
, proc
, 1)};
1486 return arg0Defined
&& arg1Defined
;
1488 if (specific
.attrs().test(Attr::NOPASS
)) { // C774
1489 msg
= "%s procedure '%s' may not have NOPASS attribute"_err_en_US
;
1490 } else if (!proc
.functionResult
.has_value()) {
1491 msg
= "%s procedure '%s' must be a function"_err_en_US
;
1492 } else if (proc
.functionResult
->IsAssumedLengthCharacter()) {
1493 const auto *subpDetails
{specific
.detailsIf
<SubprogramDetails
>()};
1494 if (subpDetails
&& !subpDetails
->isDummy() && subpDetails
->isInterface()) {
1495 // Error is caught by more general test for interfaces with
1496 // assumed-length character function results
1499 msg
= "%s function '%s' may not have assumed-length CHARACTER(*)"
1500 " result"_err_en_US
;
1501 } else if (auto m
{CheckNumberOfArgs(kind
, proc
.dummyArguments
.size())}) {
1503 } else if (!checkDefinedOperatorArgs(opName
, specific
, proc
)) {
1504 return false; // error was reported
1505 } else if (ConflictsWithIntrinsicOperator(kind
, proc
)) {
1506 msg
= "%s function '%s' conflicts with intrinsic operator"_err_en_US
;
1510 bool isFatal
{msg
->IsFatal()};
1512 specific
, std::move(*msg
), MakeOpName(opName
), specific
.name());
1514 context_
.SetError(specific
);
1519 // If the number of arguments is wrong for this intrinsic operator, return
1520 // false and return the error message in msg.
1521 std::optional
<parser::MessageFixedText
> CheckHelper::CheckNumberOfArgs(
1522 const GenericKind
&kind
, std::size_t nargs
) {
1523 if (!kind
.IsIntrinsicOperator()) {
1524 if (nargs
< 1 || nargs
> 2) {
1525 return "%s function '%s' should have 1 or 2 dummy arguments"_warn_en_US
;
1527 return std::nullopt
;
1529 std::size_t min
{2}, max
{2}; // allowed number of args; default is binary
1530 common::visit(common::visitors
{
1531 [&](const common::NumericOperator
&x
) {
1532 if (x
== common::NumericOperator::Add
||
1533 x
== common::NumericOperator::Subtract
) {
1534 min
= 1; // + and - are unary or binary
1537 [&](const common::LogicalOperator
&x
) {
1538 if (x
== common::LogicalOperator::Not
) {
1539 min
= 1; // .NOT. is unary
1543 [](const common::RelationalOperator
&) {
1546 [](const GenericKind::OtherKind
&x
) {
1547 CHECK(x
== GenericKind::OtherKind::Concat
);
1549 [](const auto &) { DIE("expected intrinsic operator"); },
1552 if (nargs
>= min
&& nargs
<= max
) {
1553 return std::nullopt
;
1554 } else if (max
== 1) {
1555 return "%s function '%s' must have one dummy argument"_err_en_US
;
1556 } else if (min
== 2) {
1557 return "%s function '%s' must have two dummy arguments"_err_en_US
;
1559 return "%s function '%s' must have one or two dummy arguments"_err_en_US
;
1563 bool CheckHelper::CheckDefinedOperatorArg(const SourceName
&opName
,
1564 const Symbol
&symbol
, const Procedure
&proc
, std::size_t pos
) {
1565 if (pos
>= proc
.dummyArguments
.size()) {
1568 auto &arg
{proc
.dummyArguments
.at(pos
)};
1569 std::optional
<parser::MessageFixedText
> msg
;
1570 if (arg
.IsOptional()) {
1571 msg
= "In %s function '%s', dummy argument '%s' may not be"
1572 " OPTIONAL"_err_en_US
;
1573 } else if (const auto *dataObject
{std::get_if
<DummyDataObject
>(&arg
.u
)};
1574 dataObject
== nullptr) {
1575 msg
= "In %s function '%s', dummy argument '%s' must be a"
1576 " data object"_err_en_US
;
1577 } else if (dataObject
->intent
!= common::Intent::In
&&
1578 !dataObject
->attrs
.test(DummyDataObject::Attr::Value
)) {
1579 msg
= "In %s function '%s', dummy argument '%s' must have INTENT(IN)"
1580 " or VALUE attribute"_err_en_US
;
1583 SayWithDeclaration(symbol
, std::move(*msg
),
1584 parser::ToUpperCaseLetters(opName
.ToString()), symbol
.name(), arg
.name
);
1590 // Check if this procedure can be used for defined assignment (see 15.4.3.4.3).
1591 bool CheckHelper::CheckDefinedAssignment(
1592 const Symbol
&specific
, const Procedure
&proc
) {
1593 if (context_
.HasError(specific
)) {
1596 std::optional
<parser::MessageFixedText
> msg
;
1597 if (specific
.attrs().test(Attr::NOPASS
)) { // C774
1598 msg
= "Defined assignment procedure '%s' may not have"
1599 " NOPASS attribute"_err_en_US
;
1600 } else if (!proc
.IsSubroutine()) {
1601 msg
= "Defined assignment procedure '%s' must be a subroutine"_err_en_US
;
1602 } else if (proc
.dummyArguments
.size() != 2) {
1603 msg
= "Defined assignment subroutine '%s' must have"
1604 " two dummy arguments"_err_en_US
;
1606 // Check both arguments even if the first has an error.
1607 bool ok0
{CheckDefinedAssignmentArg(specific
, proc
.dummyArguments
[0], 0)};
1608 bool ok1
{CheckDefinedAssignmentArg(specific
, proc
.dummyArguments
[1], 1)};
1609 if (!(ok0
&& ok1
)) {
1610 return false; // error was reported
1611 } else if (ConflictsWithIntrinsicAssignment(proc
)) {
1612 msg
= "Defined assignment subroutine '%s' conflicts with"
1613 " intrinsic assignment"_err_en_US
;
1618 SayWithDeclaration(specific
, std::move(msg
.value()), specific
.name());
1619 context_
.SetError(specific
);
1623 bool CheckHelper::CheckDefinedAssignmentArg(
1624 const Symbol
&symbol
, const DummyArgument
&arg
, int pos
) {
1625 std::optional
<parser::MessageFixedText
> msg
;
1626 if (arg
.IsOptional()) {
1627 msg
= "In defined assignment subroutine '%s', dummy argument '%s'"
1628 " may not be OPTIONAL"_err_en_US
;
1629 } else if (const auto *dataObject
{std::get_if
<DummyDataObject
>(&arg
.u
)}) {
1631 if (dataObject
->intent
!= common::Intent::Out
&&
1632 dataObject
->intent
!= common::Intent::InOut
) {
1633 msg
= "In defined assignment subroutine '%s', first dummy argument '%s'"
1634 " must have INTENT(OUT) or INTENT(INOUT)"_err_en_US
;
1636 } else if (pos
== 1) {
1637 if (dataObject
->intent
!= common::Intent::In
&&
1638 !dataObject
->attrs
.test(DummyDataObject::Attr::Value
)) {
1640 "In defined assignment subroutine '%s', second dummy"
1641 " argument '%s' must have INTENT(IN) or VALUE attribute"_err_en_US
;
1642 } else if (dataObject
->attrs
.test(DummyDataObject::Attr::Pointer
)) {
1644 "In defined assignment subroutine '%s', second dummy argument '%s' must not be a pointer"_err_en_US
;
1645 } else if (dataObject
->attrs
.test(DummyDataObject::Attr::Allocatable
)) {
1647 "In defined assignment subroutine '%s', second dummy argument '%s' must not be an allocatable"_err_en_US
;
1650 DIE("pos must be 0 or 1");
1653 msg
= "In defined assignment subroutine '%s', dummy argument '%s'"
1654 " must be a data object"_err_en_US
;
1657 SayWithDeclaration(symbol
, std::move(*msg
), symbol
.name(), arg
.name
);
1658 context_
.SetError(symbol
);
1664 // Report a conflicting attribute error if symbol has both of these attributes
1665 bool CheckHelper::CheckConflicting(const Symbol
&symbol
, Attr a1
, Attr a2
) {
1666 if (symbol
.attrs().test(a1
) && symbol
.attrs().test(a2
)) {
1667 messages_
.Say("'%s' may not have both the %s and %s attributes"_err_en_US
,
1668 symbol
.name(), AttrToString(a1
), AttrToString(a2
));
1675 void CheckHelper::WarnMissingFinal(const Symbol
&symbol
) {
1676 const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()};
1677 if (!object
|| IsPointer(symbol
)) {
1680 const DeclTypeSpec
*type
{object
->type()};
1681 const DerivedTypeSpec
*derived
{type
? type
->AsDerived() : nullptr};
1682 const Symbol
*derivedSym
{derived
? &derived
->typeSymbol() : nullptr};
1683 int rank
{object
->shape().Rank()};
1684 const Symbol
*initialDerivedSym
{derivedSym
};
1685 while (const auto *derivedDetails
{
1686 derivedSym
? derivedSym
->detailsIf
<DerivedTypeDetails
>() : nullptr}) {
1687 if (!derivedDetails
->finals().empty() &&
1688 !derivedDetails
->GetFinalForRank(rank
)) {
1689 if (auto *msg
{derivedSym
== initialDerivedSym
1690 ? messages_
.Say(symbol
.name(),
1691 "'%s' of derived type '%s' does not have a FINAL subroutine for its rank (%d)"_warn_en_US
,
1692 symbol
.name(), derivedSym
->name(), rank
)
1693 : messages_
.Say(symbol
.name(),
1694 "'%s' of derived type '%s' extended from '%s' does not have a FINAL subroutine for its rank (%d)"_warn_en_US
,
1695 symbol
.name(), initialDerivedSym
->name(),
1696 derivedSym
->name(), rank
)}) {
1697 msg
->Attach(derivedSym
->name(),
1698 "Declaration of derived type '%s'"_en_US
, derivedSym
->name());
1702 derived
= derivedSym
->GetParentTypeSpec();
1703 derivedSym
= derived
? &derived
->typeSymbol() : nullptr;
1707 const Procedure
*CheckHelper::Characterize(const Symbol
&symbol
) {
1708 auto it
{characterizeCache_
.find(symbol
)};
1709 if (it
== characterizeCache_
.end()) {
1710 auto pair
{characterizeCache_
.emplace(SymbolRef
{symbol
},
1711 Procedure::Characterize(symbol
, context_
.foldingContext()))};
1714 return common::GetPtrFromOptional(it
->second
);
1717 void CheckHelper::CheckVolatile(const Symbol
&symbol
,
1718 const DerivedTypeSpec
*derived
) { // C866 - C868
1719 if (IsIntentIn(symbol
)) {
1721 "VOLATILE attribute may not apply to an INTENT(IN) argument"_err_en_US
);
1723 if (IsProcedure(symbol
)) {
1724 messages_
.Say("VOLATILE attribute may apply only to a variable"_err_en_US
);
1726 if (symbol
.has
<UseDetails
>() || symbol
.has
<HostAssocDetails
>()) {
1727 const Symbol
&ultimate
{symbol
.GetUltimate()};
1728 if (evaluate::IsCoarray(ultimate
)) {
1730 "VOLATILE attribute may not apply to a coarray accessed by USE or host association"_err_en_US
);
1733 if (FindCoarrayUltimateComponent(*derived
)) {
1735 "VOLATILE attribute may not apply to a type with a coarray ultimate component accessed by USE or host association"_err_en_US
);
1741 void CheckHelper::CheckPointer(const Symbol
&symbol
) { // C852
1742 CheckConflicting(symbol
, Attr::POINTER
, Attr::TARGET
);
1743 CheckConflicting(symbol
, Attr::POINTER
, Attr::ALLOCATABLE
); // C751
1744 CheckConflicting(symbol
, Attr::POINTER
, Attr::INTRINSIC
);
1745 // Prohibit constant pointers. The standard does not explicitly prohibit
1746 // them, but the PARAMETER attribute requires a entity-decl to have an
1747 // initialization that is a constant-expr, and the only form of
1748 // initialization that allows a constant-expr is the one that's not a "=>"
1749 // pointer initialization. See C811, C807, and section 8.5.13.
1750 CheckConflicting(symbol
, Attr::POINTER
, Attr::PARAMETER
);
1751 if (symbol
.Corank() > 0) {
1753 "'%s' may not have the POINTER attribute because it is a coarray"_err_en_US
,
1758 // C760 constraints on the passed-object dummy argument
1759 // C757 constraints on procedure pointer components
1760 void CheckHelper::CheckPassArg(
1761 const Symbol
&proc
, const Symbol
*interface0
, const WithPassArg
&details
) {
1762 if (proc
.attrs().test(Attr::NOPASS
)) {
1765 const auto &name
{proc
.name()};
1766 const Symbol
*interface
{
1767 interface0
? FindInterface(*interface0
) : nullptr
1771 "Procedure component '%s' must have NOPASS attribute or explicit interface"_err_en_US
,
1775 const auto *subprogram
{interface
->detailsIf
<SubprogramDetails
>()};
1778 "Procedure component '%s' has invalid interface '%s'"_err_en_US
, name
,
1782 std::optional
<SourceName
> passName
{details
.passName()};
1783 const auto &dummyArgs
{subprogram
->dummyArgs()};
1785 if (dummyArgs
.empty()) {
1787 proc
.has
<ProcEntityDetails
>()
1788 ? "Procedure component '%s' with no dummy arguments"
1789 " must have NOPASS attribute"_err_en_US
1790 : "Procedure binding '%s' with no dummy arguments"
1791 " must have NOPASS attribute"_err_en_US
,
1793 context_
.SetError(*interface
);
1796 Symbol
*argSym
{dummyArgs
[0]};
1798 messages_
.Say(interface
->name(),
1799 "Cannot use an alternate return as the passed-object dummy "
1800 "argument"_err_en_US
);
1803 passName
= dummyArgs
[0]->name();
1805 std::optional
<int> passArgIndex
{};
1806 for (std::size_t i
{0}; i
< dummyArgs
.size(); ++i
) {
1807 if (dummyArgs
[i
] && dummyArgs
[i
]->name() == *passName
) {
1812 if (!passArgIndex
) { // C758
1813 messages_
.Say(*passName
,
1814 "'%s' is not a dummy argument of procedure interface '%s'"_err_en_US
,
1815 *passName
, interface
->name());
1818 const Symbol
&passArg
{*dummyArgs
[*passArgIndex
]};
1819 std::optional
<parser::MessageFixedText
> msg
;
1820 if (!passArg
.has
<ObjectEntityDetails
>()) {
1821 msg
= "Passed-object dummy argument '%s' of procedure '%s'"
1822 " must be a data object"_err_en_US
;
1823 } else if (passArg
.attrs().test(Attr::POINTER
)) {
1824 msg
= "Passed-object dummy argument '%s' of procedure '%s'"
1825 " may not have the POINTER attribute"_err_en_US
;
1826 } else if (passArg
.attrs().test(Attr::ALLOCATABLE
)) {
1827 msg
= "Passed-object dummy argument '%s' of procedure '%s'"
1828 " may not have the ALLOCATABLE attribute"_err_en_US
;
1829 } else if (passArg
.attrs().test(Attr::VALUE
)) {
1830 msg
= "Passed-object dummy argument '%s' of procedure '%s'"
1831 " may not have the VALUE attribute"_err_en_US
;
1832 } else if (passArg
.Rank() > 0) {
1833 msg
= "Passed-object dummy argument '%s' of procedure '%s'"
1834 " must be scalar"_err_en_US
;
1837 messages_
.Say(name
, std::move(*msg
), passName
.value(), name
);
1840 const DeclTypeSpec
*type
{passArg
.GetType()};
1842 return; // an error already occurred
1844 const Symbol
&typeSymbol
{*proc
.owner().GetSymbol()};
1845 const DerivedTypeSpec
*derived
{type
->AsDerived()};
1846 if (!derived
|| derived
->typeSymbol() != typeSymbol
) {
1848 "Passed-object dummy argument '%s' of procedure '%s'"
1849 " must be of type '%s' but is '%s'"_err_en_US
,
1850 passName
.value(), name
, typeSymbol
.name(), type
->AsFortran());
1853 if (IsExtensibleType(derived
) != type
->IsPolymorphic()) {
1855 type
->IsPolymorphic()
1856 ? "Passed-object dummy argument '%s' of procedure '%s'"
1857 " may not be polymorphic because '%s' is not extensible"_err_en_US
1858 : "Passed-object dummy argument '%s' of procedure '%s'"
1859 " must be polymorphic because '%s' is extensible"_err_en_US
,
1860 passName
.value(), name
, typeSymbol
.name());
1863 for (const auto &[paramName
, paramValue
] : derived
->parameters()) {
1864 if (paramValue
.isLen() && !paramValue
.isAssumed()) {
1866 "Passed-object dummy argument '%s' of procedure '%s'"
1867 " has non-assumed length parameter '%s'"_err_en_US
,
1868 passName
.value(), name
, paramName
);
1873 void CheckHelper::CheckProcBinding(
1874 const Symbol
&symbol
, const ProcBindingDetails
&binding
) {
1875 const Scope
&dtScope
{symbol
.owner()};
1876 CHECK(dtScope
.kind() == Scope::Kind::DerivedType
);
1877 if (symbol
.attrs().test(Attr::DEFERRED
)) {
1878 if (const Symbol
*dtSymbol
{dtScope
.symbol()}) {
1879 if (!dtSymbol
->attrs().test(Attr::ABSTRACT
)) { // C733
1880 SayWithDeclaration(*dtSymbol
,
1881 "Procedure bound to non-ABSTRACT derived type '%s' may not be DEFERRED"_err_en_US
,
1885 if (symbol
.attrs().test(Attr::NON_OVERRIDABLE
)) {
1887 "Type-bound procedure '%s' may not be both DEFERRED and NON_OVERRIDABLE"_err_en_US
,
1891 if (binding
.symbol().attrs().test(Attr::INTRINSIC
) &&
1892 !context_
.intrinsics().IsSpecificIntrinsicFunction(
1893 binding
.symbol().name().ToString())) {
1895 "Intrinsic procedure '%s' is not a specific intrinsic permitted for use in the definition of binding '%s'"_err_en_US
,
1896 binding
.symbol().name(), symbol
.name());
1898 if (const Symbol
*overridden
{FindOverriddenBinding(symbol
)}) {
1899 if (overridden
->attrs().test(Attr::NON_OVERRIDABLE
)) {
1900 SayWithDeclaration(*overridden
,
1901 "Override of NON_OVERRIDABLE '%s' is not permitted"_err_en_US
,
1904 if (const auto *overriddenBinding
{
1905 overridden
->detailsIf
<ProcBindingDetails
>()}) {
1906 if (!IsPureProcedure(symbol
) && IsPureProcedure(*overridden
)) {
1907 SayWithDeclaration(*overridden
,
1908 "An overridden pure type-bound procedure binding must also be pure"_err_en_US
);
1911 if (!IsElementalProcedure(binding
.symbol()) &&
1912 IsElementalProcedure(*overridden
)) {
1913 SayWithDeclaration(*overridden
,
1914 "A type-bound procedure and its override must both, or neither, be ELEMENTAL"_err_en_US
);
1917 bool isNopass
{symbol
.attrs().test(Attr::NOPASS
)};
1918 if (isNopass
!= overridden
->attrs().test(Attr::NOPASS
)) {
1919 SayWithDeclaration(*overridden
,
1921 ? "A NOPASS type-bound procedure may not override a passed-argument procedure"_err_en_US
1922 : "A passed-argument type-bound procedure may not override a NOPASS procedure"_err_en_US
);
1924 const auto *bindingChars
{Characterize(binding
.symbol())};
1925 const auto *overriddenChars
{Characterize(*overridden
)};
1926 if (bindingChars
&& overriddenChars
) {
1928 if (!bindingChars
->CanOverride(*overriddenChars
, std::nullopt
)) {
1929 SayWithDeclaration(*overridden
,
1930 "A NOPASS type-bound procedure and its override must have identical interfaces"_err_en_US
);
1932 } else if (!context_
.HasError(binding
.symbol())) {
1933 int passIndex
{bindingChars
->FindPassIndex(binding
.passName())};
1934 int overriddenPassIndex
{
1935 overriddenChars
->FindPassIndex(overriddenBinding
->passName())};
1936 if (passIndex
!= overriddenPassIndex
) {
1937 SayWithDeclaration(*overridden
,
1938 "A type-bound procedure and its override must use the same PASS argument"_err_en_US
);
1939 } else if (!bindingChars
->CanOverride(
1940 *overriddenChars
, passIndex
)) {
1941 SayWithDeclaration(*overridden
,
1942 "A type-bound procedure and its override must have compatible interfaces"_err_en_US
);
1947 if (symbol
.attrs().test(Attr::PRIVATE
)) {
1948 if (FindModuleContaining(dtScope
) ==
1949 FindModuleContaining(overridden
->owner())) {
1950 // types declared in same madule
1951 if (overridden
->attrs().test(Attr::PUBLIC
)) {
1952 SayWithDeclaration(*overridden
,
1953 "A PRIVATE procedure may not override a PUBLIC procedure"_err_en_US
);
1955 } else { // types declared in distinct madules
1956 if (!CheckAccessibleSymbol(dtScope
.parent(), *overridden
)) {
1957 SayWithDeclaration(*overridden
,
1958 "A PRIVATE procedure may not override an accessible procedure"_err_en_US
);
1963 SayWithDeclaration(*overridden
,
1964 "A type-bound procedure binding may not have the same name as a parent component"_err_en_US
);
1967 CheckPassArg(symbol
, &binding
.symbol(), binding
);
1970 void CheckHelper::Check(const Scope
&scope
) {
1972 common::Restorer
<const Symbol
*> restorer
{innermostSymbol_
, innermostSymbol_
};
1973 if (const Symbol
*symbol
{scope
.symbol()}) {
1974 innermostSymbol_
= symbol
;
1976 if (scope
.IsParameterizedDerivedTypeInstantiation()) {
1977 auto restorer
{common::ScopedSet(scopeIsUninstantiatedPDT_
, false)};
1978 auto restorer2
{context_
.foldingContext().messages().SetContext(
1979 scope
.instantiationContext().get())};
1980 for (const auto &pair
: scope
) {
1981 CheckPointerInitialization(*pair
.second
);
1984 auto restorer
{common::ScopedSet(
1985 scopeIsUninstantiatedPDT_
, scope
.IsParameterizedDerivedType())};
1986 for (const auto &set
: scope
.equivalenceSets()) {
1987 CheckEquivalenceSet(set
);
1989 for (const auto &pair
: scope
) {
1990 Check(*pair
.second
);
1992 for (const auto &pair
: scope
.commonBlocks()) {
1993 CheckCommonBlock(*pair
.second
);
1996 for (const Scope
&child
: scope
.children()) {
1998 // A program shall consist of exactly one main program (5.2.2).
1999 if (child
.kind() == Scope::Kind::MainProgram
) {
2001 if (mainProgCnt
> 1) {
2002 messages_
.Say(child
.sourceRange(),
2003 "A source file cannot contain more than one main program"_err_en_US
);
2007 if (scope
.kind() == Scope::Kind::BlockData
) {
2008 CheckBlockData(scope
);
2010 if (auto name
{scope
.GetName()}) {
2011 auto iter
{scope
.find(*name
)};
2012 if (iter
!= scope
.end()) {
2013 const char *kind
{nullptr};
2014 switch (scope
.kind()) {
2015 case Scope::Kind::Module
:
2016 kind
= scope
.symbol()->get
<ModuleDetails
>().isSubmodule()
2020 case Scope::Kind::MainProgram
:
2021 kind
= "main program";
2023 case Scope::Kind::BlockData
:
2024 kind
= "BLOCK DATA subprogram";
2029 messages_
.Say(iter
->second
->name(),
2030 "Name '%s' declared in a %s should not have the same name as the %s"_port_en_US
,
2035 CheckGenericOps(scope
);
2039 void CheckHelper::CheckEquivalenceSet(const EquivalenceSet
&set
) {
2041 std::find_if(set
.begin(), set
.end(), [](const EquivalenceObject
&object
) {
2042 return FindCommonBlockContaining(object
.symbol
) != nullptr;
2044 if (iter
!= set
.end()) {
2045 const Symbol
&commonBlock
{DEREF(FindCommonBlockContaining(iter
->symbol
))};
2046 for (auto &object
: set
) {
2047 if (&object
!= &*iter
) {
2048 if (auto *details
{object
.symbol
.detailsIf
<ObjectEntityDetails
>()}) {
2049 if (details
->commonBlock()) {
2050 if (details
->commonBlock() != &commonBlock
) { // 8.10.3 paragraph 1
2051 if (auto *msg
{messages_
.Say(object
.symbol
.name(),
2052 "Two objects in the same EQUIVALENCE set may not be members of distinct COMMON blocks"_err_en_US
)}) {
2053 msg
->Attach(iter
->symbol
.name(),
2054 "Other object in EQUIVALENCE set"_en_US
)
2055 .Attach(details
->commonBlock()->name(),
2056 "COMMON block containing '%s'"_en_US
,
2057 object
.symbol
.name())
2058 .Attach(commonBlock
.name(),
2059 "COMMON block containing '%s'"_en_US
,
2060 iter
->symbol
.name());
2064 // Mark all symbols in the equivalence set with the same COMMON
2065 // block to prevent spurious error messages about initialization
2066 // in BLOCK DATA outside COMMON
2067 details
->set_commonBlock(commonBlock
);
2073 // TODO: Move C8106 (&al.) checks here from resolve-names-utils.cpp
2076 void CheckHelper::CheckBlockData(const Scope
&scope
) {
2077 // BLOCK DATA subprograms should contain only named common blocks.
2078 // C1415 presents a list of statements that shouldn't appear in
2079 // BLOCK DATA, but so long as the subprogram contains no executable
2080 // code and allocates no storage outside named COMMON, we're happy
2081 // (e.g., an ENUM is strictly not allowed).
2082 for (const auto &pair
: scope
) {
2083 const Symbol
&symbol
{*pair
.second
};
2084 if (!(symbol
.has
<CommonBlockDetails
>() || symbol
.has
<UseDetails
>() ||
2085 symbol
.has
<UseErrorDetails
>() || symbol
.has
<DerivedTypeDetails
>() ||
2086 symbol
.has
<SubprogramDetails
>() ||
2087 symbol
.has
<ObjectEntityDetails
>() ||
2088 (symbol
.has
<ProcEntityDetails
>() &&
2089 !symbol
.attrs().test(Attr::POINTER
)))) {
2090 messages_
.Say(symbol
.name(),
2091 "'%s' may not appear in a BLOCK DATA subprogram"_err_en_US
,
2097 // Check distinguishability of generic assignment and operators.
2098 // For these, generics and generic bindings must be considered together.
2099 void CheckHelper::CheckGenericOps(const Scope
&scope
) {
2100 DistinguishabilityHelper helper
{context_
};
2101 auto addSpecifics
{[&](const Symbol
&generic
) {
2102 const auto *details
{generic
.GetUltimate().detailsIf
<GenericDetails
>()};
2104 // Not a generic; ensure characteristics are defined if a function.
2105 auto restorer
{messages_
.SetLocation(generic
.name())};
2106 if (IsFunction(generic
) && !context_
.HasError(generic
)) {
2107 if (const Symbol
*result
{FindFunctionResult(generic
)};
2108 result
&& !context_
.HasError(*result
)) {
2109 Characterize(generic
);
2114 GenericKind kind
{details
->kind()};
2115 if (!kind
.IsAssignment() && !kind
.IsOperator()) {
2118 const SymbolVector
&specifics
{details
->specificProcs()};
2119 const std::vector
<SourceName
> &bindingNames
{details
->bindingNames()};
2120 for (std::size_t i
{0}; i
< specifics
.size(); ++i
) {
2121 const Symbol
&specific
{*specifics
[i
]};
2122 auto restorer
{messages_
.SetLocation(bindingNames
[i
])};
2123 if (const Procedure
*proc
{Characterize(specific
)}) {
2124 if (kind
.IsAssignment()) {
2125 if (!CheckDefinedAssignment(specific
, *proc
)) {
2129 if (!CheckDefinedOperator(generic
.name(), kind
, specific
, *proc
)) {
2133 helper
.Add(generic
, kind
, specific
, *proc
);
2137 for (const auto &pair
: scope
) {
2138 const Symbol
&symbol
{*pair
.second
};
2139 addSpecifics(symbol
);
2140 const Symbol
&ultimate
{symbol
.GetUltimate()};
2141 if (ultimate
.has
<DerivedTypeDetails
>()) {
2142 if (const Scope
*typeScope
{ultimate
.scope()}) {
2143 for (const auto &pair2
: *typeScope
) {
2144 addSpecifics(*pair2
.second
);
2149 helper
.Check(scope
);
2152 static bool IsSubprogramDefinition(const Symbol
&symbol
) {
2153 const auto *subp
{symbol
.detailsIf
<SubprogramDetails
>()};
2154 return subp
&& !subp
->isInterface() && symbol
.scope() &&
2155 symbol
.scope()->kind() == Scope::Kind::Subprogram
;
2158 static bool IsBlockData(const Symbol
&symbol
) {
2159 return symbol
.scope() && symbol
.scope()->kind() == Scope::Kind::BlockData
;
2162 static bool IsExternalProcedureDefinition(const Symbol
&symbol
) {
2163 return IsBlockData(symbol
) ||
2164 (IsSubprogramDefinition(symbol
) &&
2165 (IsExternal(symbol
) || symbol
.GetBindName()));
2168 static std::optional
<std::string
> DefinesGlobalName(const Symbol
&symbol
) {
2169 if (const auto *module
{symbol
.detailsIf
<ModuleDetails
>()}) {
2170 if (!module
->isSubmodule() && !symbol
.owner().IsIntrinsicModules()) {
2171 return symbol
.name().ToString();
2173 } else if (IsBlockData(symbol
)) {
2174 return symbol
.name().ToString();
2176 const std::string
*bindC
{symbol
.GetBindName()};
2177 if (symbol
.has
<CommonBlockDetails
>() ||
2178 IsExternalProcedureDefinition(symbol
)) {
2179 return bindC
? *bindC
: symbol
.name().ToString();
2181 (symbol
.has
<ObjectEntityDetails
>() || IsModuleProcedure(symbol
))) {
2185 return std::nullopt
;
2189 void CheckHelper::CheckGlobalName(const Symbol
&symbol
) {
2190 if (auto global
{DefinesGlobalName(symbol
)}) {
2191 auto pair
{globalNames_
.emplace(std::move(*global
), symbol
)};
2193 const Symbol
&other
{*pair
.first
->second
};
2194 if (context_
.HasError(symbol
) || context_
.HasError(other
)) {
2196 } else if (symbol
.has
<CommonBlockDetails
>() &&
2197 other
.has
<CommonBlockDetails
>() && symbol
.name() == other
.name()) {
2198 // Two common blocks can have the same global name so long as
2199 // they're not in the same scope.
2200 } else if ((IsProcedure(symbol
) || IsBlockData(symbol
)) &&
2201 (IsProcedure(other
) || IsBlockData(other
)) &&
2202 (!IsExternalProcedureDefinition(symbol
) ||
2203 !IsExternalProcedureDefinition(other
))) {
2204 // both are procedures/BLOCK DATA, not both definitions
2205 } else if (symbol
.has
<ModuleDetails
>()) {
2206 messages_
.Say(symbol
.name(),
2207 "Module '%s' conflicts with a global name"_port_en_US
,
2209 } else if (other
.has
<ModuleDetails
>()) {
2210 messages_
.Say(symbol
.name(),
2211 "Global name '%s' conflicts with a module"_port_en_US
,
2213 } else if (auto *msg
{messages_
.Say(symbol
.name(),
2214 "Two entities have the same global name '%s'"_err_en_US
,
2215 pair
.first
->first
)}) {
2216 msg
->Attach(other
.name(), "Conflicting declaration"_en_US
);
2217 context_
.SetError(symbol
);
2218 context_
.SetError(other
);
2224 void CheckHelper::CheckBindC(const Symbol
&symbol
) {
2225 bool isExplicitBindC
{symbol
.attrs().test(Attr::BIND_C
)};
2226 if (isExplicitBindC
) {
2227 CheckConflicting(symbol
, Attr::BIND_C
, Attr::PARAMETER
);
2228 CheckConflicting(symbol
, Attr::BIND_C
, Attr::ELEMENTAL
);
2230 // symbol must be interoperable (e.g., dummy argument of interoperable
2231 // procedure interface) but is not itself BIND(C).
2233 if (const std::string
* bindName
{symbol
.GetBindName()};
2234 bindName
) { // has a binding name
2235 if (!bindName
->empty()) {
2236 bool ok
{bindName
->front() == '_' || parser::IsLetter(bindName
->front())};
2237 for (char ch
: *bindName
) {
2238 ok
&= ch
== '_' || parser::IsLetter(ch
) || parser::IsDecimalDigit(ch
);
2241 messages_
.Say(symbol
.name(),
2242 "Symbol has a BIND(C) name that is not a valid C language identifier"_err_en_US
);
2243 context_
.SetError(symbol
);
2247 if (symbol
.GetIsExplicitBindName()) { // BIND(C,NAME=...); C1552, C1529
2248 auto defClass
{ClassifyProcedure(symbol
)};
2249 if (IsProcedurePointer(symbol
)) {
2250 messages_
.Say(symbol
.name(),
2251 "A procedure pointer may not have a BIND attribute with a name"_err_en_US
);
2252 context_
.SetError(symbol
);
2253 } else if (defClass
== ProcedureDefinitionClass::None
||
2254 IsExternal(symbol
)) {
2255 } else if (symbol
.attrs().test(Attr::ABSTRACT
)) {
2256 messages_
.Say(symbol
.name(),
2257 "An ABSTRACT interface may not have a BIND attribute with a name"_err_en_US
);
2258 context_
.SetError(symbol
);
2259 } else if (defClass
== ProcedureDefinitionClass::Internal
||
2260 defClass
== ProcedureDefinitionClass::Dummy
) {
2261 messages_
.Say(symbol
.name(),
2262 "An internal or dummy procedure may not have a BIND(C,NAME=) binding label"_err_en_US
);
2263 context_
.SetError(symbol
);
2266 if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
2267 if (isExplicitBindC
&& !symbol
.owner().IsModule()) {
2268 messages_
.Say(symbol
.name(),
2269 "A variable with BIND(C) attribute may only appear in the specification part of a module"_err_en_US
);
2270 context_
.SetError(symbol
);
2272 auto shape
{evaluate::GetShape(foldingContext_
, symbol
)};
2274 if (evaluate::GetRank(*shape
) == 0) { // 18.3.4
2275 if (isExplicitBindC
&& IsAllocatableOrPointer(symbol
)) {
2276 messages_
.Say(symbol
.name(),
2277 "A scalar interoperable variable may not be ALLOCATABLE or POINTER"_err_en_US
);
2278 context_
.SetError(symbol
);
2282 evaluate::AsConstantExtents(foldingContext_
, *shape
)}) {
2283 if (evaluate::GetSize(*extents
) == 0) {
2284 SayWithDeclaration(symbol
, symbol
.name(),
2285 "Interoperable array must have at least one element"_err_en_US
);
2286 context_
.SetError(symbol
);
2288 } else if ((isExplicitBindC
|| symbol
.attrs().test(Attr::VALUE
)) &&
2289 !evaluate::IsExplicitShape(symbol
) && !object
->IsAssumedSize()) {
2290 SayWithDeclaration(symbol
, symbol
.name(),
2291 "BIND(C) array must have explicit shape or be assumed-size unless a dummy argument without the VALUE attribute"_err_en_US
);
2292 context_
.SetError(symbol
);
2296 if (const auto *type
{symbol
.GetType()}) {
2297 const auto *derived
{type
->AsDerived()};
2298 if (derived
&& !derived
->typeSymbol().attrs().test(Attr::BIND_C
)) {
2299 if (auto *msg
{messages_
.Say(symbol
.name(),
2300 "The derived type of a BIND(C) object must also be BIND(C)"_err_en_US
)}) {
2302 derived
->typeSymbol().name(), "Non-interoperable type"_en_US
);
2304 context_
.SetError(symbol
);
2306 if (type
->IsAssumedType() || IsAssumedLengthCharacter(symbol
)) {
2308 } else if (IsAllocatableOrPointer(symbol
) &&
2309 type
->category() == DeclTypeSpec::Character
&&
2310 type
->characterTypeSpec().length().isDeferred()) {
2311 // ok; F'2018 18.3.6 p2(6)
2312 } else if (derived
|| IsInteroperableIntrinsicType(*type
)) {
2313 // F'2018 18.3.6 p2(4,5)
2314 } else if (type
->category() == DeclTypeSpec::Logical
&& IsDummy(symbol
) &&
2315 evaluate::GetRank(*shape
) == 0) {
2316 // Special exception: LOGICAL scalar dummy arguments can be converted
2317 // before a call -- & after if not INTENT(IN) -- without loss of
2318 // information, and are accepted by some older compilers.
2319 messages_
.Say(symbol
.name(),
2320 "A BIND(C) LOGICAL dummy argument should have the interoperable KIND=C_BOOL"_port_en_US
);
2321 } else if (symbol
.attrs().test(Attr::VALUE
)) {
2322 messages_
.Say(symbol
.name(),
2323 "A BIND(C) VALUE dummy argument must have an interoperable type"_err_en_US
);
2324 context_
.SetError(symbol
);
2326 messages_
.Say(symbol
.name(),
2327 "A BIND(C) object must have an interoperable type"_err_en_US
);
2328 context_
.SetError(symbol
);
2331 if (IsOptional(symbol
) && !symbol
.attrs().test(Attr::VALUE
)) {
2332 messages_
.Say(symbol
.name(),
2333 "An interoperable procedure with an OPTIONAL dummy argument might not be portable"_port_en_US
);
2335 } else if (const auto *proc
{symbol
.detailsIf
<ProcEntityDetails
>()}) {
2336 if (!proc
->procInterface() ||
2337 !proc
->procInterface()->attrs().test(Attr::BIND_C
)) {
2338 messages_
.Say(symbol
.name(),
2339 "An interface name with BIND attribute must be specified if the BIND attribute is specified in a procedure declaration statement"_err_en_US
);
2340 context_
.SetError(symbol
);
2342 } else if (const auto *subp
{symbol
.detailsIf
<SubprogramDetails
>()}) {
2343 for (const Symbol
*dummy
: subp
->dummyArgs()) {
2347 messages_
.Say(symbol
.name(),
2348 "A subprogram interface with the BIND attribute may not have an alternate return argument"_err_en_US
);
2349 context_
.SetError(symbol
);
2352 } else if (const auto *derived
{symbol
.detailsIf
<DerivedTypeDetails
>()}) {
2353 if (derived
->sequence()) { // C1801
2354 messages_
.Say(symbol
.name(),
2355 "A derived type with the BIND attribute cannot have the SEQUENCE attribute"_err_en_US
);
2356 context_
.SetError(symbol
);
2357 } else if (!derived
->paramDecls().empty()) { // C1802
2358 messages_
.Say(symbol
.name(),
2359 "A derived type with the BIND attribute has type parameter(s)"_err_en_US
);
2360 context_
.SetError(symbol
);
2361 } else if (symbol
.scope()->GetDerivedTypeParent()) { // C1803
2362 messages_
.Say(symbol
.name(),
2363 "A derived type with the BIND attribute cannot extend from another derived type"_err_en_US
);
2364 context_
.SetError(symbol
);
2366 for (const auto &pair
: *symbol
.scope()) {
2367 const Symbol
*component
{&*pair
.second
};
2368 if (IsProcedure(*component
)) { // C1804
2369 messages_
.Say(component
->name(),
2370 "A derived type with the BIND attribute cannot have a type bound procedure"_err_en_US
);
2371 context_
.SetError(symbol
);
2373 if (IsAllocatableOrPointer(*component
)) { // C1806
2374 messages_
.Say(component
->name(),
2375 "A derived type with the BIND attribute cannot have a pointer or allocatable component"_err_en_US
);
2376 context_
.SetError(symbol
);
2378 if (const auto *type
{component
->GetType()}) {
2379 if (const auto *derived
{type
->AsDerived()}) {
2380 if (!derived
->typeSymbol().attrs().test(Attr::BIND_C
)) {
2381 if (auto *msg
{messages_
.Say(component
->name(),
2382 "Component '%s' of an interoperable derived type must have the BIND attribute"_err_en_US
,
2383 component
->name())}) {
2384 msg
->Attach(derived
->typeSymbol().name(),
2385 "Non-interoperable component type"_en_US
);
2387 context_
.SetError(symbol
);
2389 } else if (!IsInteroperableIntrinsicType(*type
)) {
2390 messages_
.Say(component
->name(),
2391 "Each component of an interoperable derived type must have an interoperable type"_err_en_US
);
2392 context_
.SetError(symbol
);
2396 evaluate::GetConstantExtents(foldingContext_
, component
)};
2397 extents
&& evaluate::GetSize(*extents
) == 0) {
2398 messages_
.Say(component
->name(),
2399 "An array component of an interoperable type must have at least one element"_err_en_US
);
2400 context_
.SetError(symbol
);
2404 if (derived
->componentNames().empty() &&
2405 !FindModuleFileContaining(symbol
.owner())) { // C1805
2406 messages_
.Say(symbol
.name(),
2407 "A derived type with the BIND attribute is empty"_port_en_US
);
2412 bool CheckHelper::CheckDioDummyIsData(
2413 const Symbol
&subp
, const Symbol
*arg
, std::size_t position
) {
2414 if (arg
&& arg
->detailsIf
<ObjectEntityDetails
>()) {
2418 messages_
.Say(arg
->name(),
2419 "Dummy argument '%s' must be a data object"_err_en_US
, arg
->name());
2421 messages_
.Say(subp
.name(),
2422 "Dummy argument %d of '%s' must be a data object"_err_en_US
, position
,
2429 void CheckHelper::CheckAlreadySeenDefinedIo(const DerivedTypeSpec
&derivedType
,
2430 GenericKind::DefinedIo ioKind
, const Symbol
&proc
, const Symbol
&generic
) {
2431 for (TypeWithDefinedIo definedIoType
: seenDefinedIoTypes_
) {
2432 // It's okay to have two or more distinct derived type I/O procedures
2433 // for the same type if they're coming from distinct non-type-bound
2434 // interfaces. (The non-type-bound interfaces would have been merged into
2435 // a single generic if both were visible in the same scope.)
2436 if (derivedType
== definedIoType
.type
&& ioKind
== definedIoType
.ioKind
&&
2437 proc
!= definedIoType
.proc
&&
2438 (generic
.owner().IsDerivedType() ||
2439 definedIoType
.generic
.owner().IsDerivedType())) {
2440 SayWithDeclaration(proc
, definedIoType
.proc
.name(),
2441 "Derived type '%s' already has defined input/output procedure"
2443 derivedType
.name(), GenericKind::AsFortran(ioKind
));
2447 seenDefinedIoTypes_
.emplace_back(
2448 TypeWithDefinedIo
{derivedType
, ioKind
, proc
, generic
});
2451 void CheckHelper::CheckDioDummyIsDerived(const Symbol
&subp
, const Symbol
&arg
,
2452 GenericKind::DefinedIo ioKind
, const Symbol
&generic
) {
2453 if (const DeclTypeSpec
*type
{arg
.GetType()}) {
2454 if (const DerivedTypeSpec
*derivedType
{type
->AsDerived()}) {
2455 CheckAlreadySeenDefinedIo(*derivedType
, ioKind
, subp
, generic
);
2456 bool isPolymorphic
{type
->IsPolymorphic()};
2457 if (isPolymorphic
!= IsExtensibleType(derivedType
)) {
2458 messages_
.Say(arg
.name(),
2459 "Dummy argument '%s' of a defined input/output procedure must be %s when the derived type is %s"_err_en_US
,
2460 arg
.name(), isPolymorphic
? "TYPE()" : "CLASS()",
2461 isPolymorphic
? "not extensible" : "extensible");
2464 messages_
.Say(arg
.name(),
2465 "Dummy argument '%s' of a defined input/output procedure must have a"
2466 " derived type"_err_en_US
,
2472 void CheckHelper::CheckDioDummyIsDefaultInteger(
2473 const Symbol
&subp
, const Symbol
&arg
) {
2474 if (const DeclTypeSpec
*type
{arg
.GetType()};
2475 type
&& type
->IsNumeric(TypeCategory::Integer
)) {
2476 if (const auto kind
{evaluate::ToInt64(type
->numericTypeSpec().kind())};
2477 kind
&& *kind
== context_
.GetDefaultKind(TypeCategory::Integer
)) {
2481 messages_
.Say(arg
.name(),
2482 "Dummy argument '%s' of a defined input/output procedure"
2483 " must be an INTEGER of default KIND"_err_en_US
,
2487 void CheckHelper::CheckDioDummyIsScalar(const Symbol
&subp
, const Symbol
&arg
) {
2488 if (arg
.Rank() > 0 || arg
.Corank() > 0) {
2489 messages_
.Say(arg
.name(),
2490 "Dummy argument '%s' of a defined input/output procedure"
2491 " must be a scalar"_err_en_US
,
2496 void CheckHelper::CheckDioDtvArg(const Symbol
&subp
, const Symbol
*arg
,
2497 GenericKind::DefinedIo ioKind
, const Symbol
&generic
) {
2498 // Dtv argument looks like: dtv-type-spec, INTENT(INOUT) :: dtv
2499 if (CheckDioDummyIsData(subp
, arg
, 0)) {
2500 CheckDioDummyIsDerived(subp
, *arg
, ioKind
, generic
);
2501 CheckDioDummyAttrs(subp
, *arg
,
2502 ioKind
== GenericKind::DefinedIo::ReadFormatted
||
2503 ioKind
== GenericKind::DefinedIo::ReadUnformatted
2504 ? Attr::INTENT_INOUT
2509 // If an explicit INTRINSIC name is a function, so must all the specifics be,
2510 // and similarly for subroutines
2511 void CheckHelper::CheckGenericVsIntrinsic(
2512 const Symbol
&symbol
, const GenericDetails
&generic
) {
2513 if (symbol
.attrs().test(Attr::INTRINSIC
)) {
2514 const evaluate::IntrinsicProcTable
&table
{
2515 context_
.foldingContext().intrinsics()};
2516 bool isSubroutine
{table
.IsIntrinsicSubroutine(symbol
.name().ToString())};
2517 if (isSubroutine
|| table
.IsIntrinsicFunction(symbol
.name().ToString())) {
2518 for (const SymbolRef
&ref
: generic
.specificProcs()) {
2519 const Symbol
&ultimate
{ref
->GetUltimate()};
2520 bool specificFunc
{ultimate
.test(Symbol::Flag::Function
)};
2521 bool specificSubr
{ultimate
.test(Symbol::Flag::Subroutine
)};
2522 if (!specificFunc
&& !specificSubr
) {
2523 if (const auto *proc
{ultimate
.detailsIf
<SubprogramDetails
>()}) {
2524 if (proc
->isFunction()) {
2525 specificFunc
= true;
2527 specificSubr
= true;
2531 if ((specificFunc
|| specificSubr
) &&
2532 isSubroutine
!= specificSubr
) { // C848
2533 messages_
.Say(symbol
.name(),
2534 "Generic interface '%s' with explicit intrinsic %s of the same name may not have specific procedure '%s' that is a %s"_err_en_US
,
2535 symbol
.name(), isSubroutine
? "subroutine" : "function",
2536 ref
->name(), isSubroutine
? "function" : "subroutine");
2543 void CheckHelper::CheckDefaultIntegerArg(
2544 const Symbol
&subp
, const Symbol
*arg
, Attr intent
) {
2545 // Argument looks like: INTEGER, INTENT(intent) :: arg
2546 if (CheckDioDummyIsData(subp
, arg
, 1)) {
2547 CheckDioDummyIsDefaultInteger(subp
, *arg
);
2548 CheckDioDummyIsScalar(subp
, *arg
);
2549 CheckDioDummyAttrs(subp
, *arg
, intent
);
2553 void CheckHelper::CheckDioAssumedLenCharacterArg(const Symbol
&subp
,
2554 const Symbol
*arg
, std::size_t argPosition
, Attr intent
) {
2555 // Argument looks like: CHARACTER (LEN=*), INTENT(intent) :: (iotype OR iomsg)
2556 if (CheckDioDummyIsData(subp
, arg
, argPosition
)) {
2557 CheckDioDummyAttrs(subp
, *arg
, intent
);
2558 if (!IsAssumedLengthCharacter(*arg
)) {
2559 messages_
.Say(arg
->name(),
2560 "Dummy argument '%s' of a defined input/output procedure"
2561 " must be assumed-length CHARACTER"_err_en_US
,
2567 void CheckHelper::CheckDioVlistArg(
2568 const Symbol
&subp
, const Symbol
*arg
, std::size_t argPosition
) {
2569 // Vlist argument looks like: INTEGER, INTENT(IN) :: v_list(:)
2570 if (CheckDioDummyIsData(subp
, arg
, argPosition
)) {
2571 CheckDioDummyIsDefaultInteger(subp
, *arg
);
2572 CheckDioDummyAttrs(subp
, *arg
, Attr::INTENT_IN
);
2573 const auto *objectDetails
{arg
->detailsIf
<ObjectEntityDetails
>()};
2574 if (!objectDetails
|| !objectDetails
->shape().CanBeDeferredShape()) {
2575 messages_
.Say(arg
->name(),
2576 "Dummy argument '%s' of a defined input/output procedure must be"
2577 " deferred shape"_err_en_US
,
2583 void CheckHelper::CheckDioArgCount(
2584 const Symbol
&subp
, GenericKind::DefinedIo ioKind
, std::size_t argCount
) {
2585 const std::size_t requiredArgCount
{
2586 (std::size_t)(ioKind
== GenericKind::DefinedIo::ReadFormatted
||
2587 ioKind
== GenericKind::DefinedIo::WriteFormatted
2590 if (argCount
!= requiredArgCount
) {
2591 SayWithDeclaration(subp
,
2592 "Defined input/output procedure '%s' must have"
2593 " %d dummy arguments rather than %d"_err_en_US
,
2594 subp
.name(), requiredArgCount
, argCount
);
2595 context_
.SetError(subp
);
2599 void CheckHelper::CheckDioDummyAttrs(
2600 const Symbol
&subp
, const Symbol
&arg
, Attr goodIntent
) {
2601 // Defined I/O procedures can't have attributes other than INTENT
2602 Attrs attrs
{arg
.attrs()};
2603 if (!attrs
.test(goodIntent
)) {
2604 messages_
.Say(arg
.name(),
2605 "Dummy argument '%s' of a defined input/output procedure"
2606 " must have intent '%s'"_err_en_US
,
2607 arg
.name(), AttrToString(goodIntent
));
2609 attrs
= attrs
- Attr::INTENT_IN
- Attr::INTENT_OUT
- Attr::INTENT_INOUT
;
2610 if (!attrs
.empty()) {
2611 messages_
.Say(arg
.name(),
2612 "Dummy argument '%s' of a defined input/output procedure may not have"
2613 " any attributes"_err_en_US
,
2618 // Enforce semantics for defined input/output procedures (12.6.4.8.2) and C777
2619 void CheckHelper::CheckDefinedIoProc(const Symbol
&symbol
,
2620 const GenericDetails
&details
, GenericKind::DefinedIo ioKind
) {
2621 for (auto ref
: details
.specificProcs()) {
2622 const auto *binding
{ref
->detailsIf
<ProcBindingDetails
>()};
2623 const Symbol
&specific
{*(binding
? &binding
->symbol() : &*ref
)};
2624 if (ref
->attrs().test(Attr::NOPASS
)) { // C774
2625 messages_
.Say("Defined input/output procedure '%s' may not have NOPASS "
2626 "attribute"_err_en_US
,
2628 context_
.SetError(*ref
);
2630 if (const auto *subpDetails
{specific
.detailsIf
<SubprogramDetails
>()}) {
2631 const std::vector
<Symbol
*> &dummyArgs
{subpDetails
->dummyArgs()};
2632 CheckDioArgCount(specific
, ioKind
, dummyArgs
.size());
2634 for (auto *arg
: dummyArgs
) {
2635 switch (argCount
++) {
2637 // dtv-type-spec, INTENT(INOUT) :: dtv
2638 CheckDioDtvArg(specific
, arg
, ioKind
, symbol
);
2641 // INTEGER, INTENT(IN) :: unit
2642 CheckDefaultIntegerArg(specific
, arg
, Attr::INTENT_IN
);
2645 if (ioKind
== GenericKind::DefinedIo::ReadFormatted
||
2646 ioKind
== GenericKind::DefinedIo::WriteFormatted
) {
2647 // CHARACTER (LEN=*), INTENT(IN) :: iotype
2648 CheckDioAssumedLenCharacterArg(
2649 specific
, arg
, argCount
, Attr::INTENT_IN
);
2651 // INTEGER, INTENT(OUT) :: iostat
2652 CheckDefaultIntegerArg(specific
, arg
, Attr::INTENT_OUT
);
2656 if (ioKind
== GenericKind::DefinedIo::ReadFormatted
||
2657 ioKind
== GenericKind::DefinedIo::WriteFormatted
) {
2658 // INTEGER, INTENT(IN) :: v_list(:)
2659 CheckDioVlistArg(specific
, arg
, argCount
);
2661 // CHARACTER (LEN=*), INTENT(INOUT) :: iomsg
2662 CheckDioAssumedLenCharacterArg(
2663 specific
, arg
, argCount
, Attr::INTENT_INOUT
);
2667 // INTEGER, INTENT(OUT) :: iostat
2668 CheckDefaultIntegerArg(specific
, arg
, Attr::INTENT_OUT
);
2671 // CHARACTER (LEN=*), INTENT(INOUT) :: iomsg
2672 CheckDioAssumedLenCharacterArg(
2673 specific
, arg
, argCount
, Attr::INTENT_INOUT
);
2682 void CheckHelper::CheckSymbolType(const Symbol
&symbol
) {
2683 if (!IsAllocatable(symbol
) &&
2684 (!IsPointer(symbol
) ||
2685 (IsProcedure(symbol
) && !symbol
.HasExplicitInterface()))) { // C702
2686 if (auto dyType
{evaluate::DynamicType::From(symbol
)}) {
2687 if (dyType
->HasDeferredTypeParameter()) {
2689 "'%s' has a type %s with a deferred type parameter but is neither an allocatable nor an object pointer"_err_en_US
,
2690 symbol
.name(), dyType
->AsFortran());
2696 void CheckHelper::CheckModuleProcedureDef(const Symbol
&symbol
) {
2697 auto procClass
{ClassifyProcedure(symbol
)};
2698 if (const auto *subprogram
{symbol
.detailsIf
<SubprogramDetails
>()};
2700 (procClass
== ProcedureDefinitionClass::Module
&&
2701 symbol
.attrs().test(Attr::MODULE
)) &&
2702 !subprogram
->bindName() && !subprogram
->isInterface()) {
2703 const Symbol
*module
{nullptr};
2704 if (const Scope
* moduleScope
{FindModuleContaining(symbol
.owner())};
2705 moduleScope
&& moduleScope
->symbol()) {
2706 if (const auto *details
{
2707 moduleScope
->symbol()->detailsIf
<ModuleDetails
>()}) {
2708 if (details
->parent()) {
2709 moduleScope
= details
->parent();
2711 module
= moduleScope
->symbol();
2715 std::pair
<SourceName
, const Symbol
*> key
{symbol
.name(), module
};
2716 auto iter
{moduleProcs_
.find(key
)};
2717 if (iter
== moduleProcs_
.end()) {
2718 moduleProcs_
.emplace(std::move(key
), symbol
);
2720 auto *msg
{messages_
.Say(symbol
.name(),
2721 "Module procedure '%s' in module '%s' has multiple definitions"_err_en_US
,
2722 symbol
.name(), module
->name())}) {
2723 msg
->Attach(iter
->second
->name(), "Previous definition of '%s'"_en_US
,
2730 void SubprogramMatchHelper::Check(
2731 const Symbol
&symbol1
, const Symbol
&symbol2
) {
2732 const auto details1
{symbol1
.get
<SubprogramDetails
>()};
2733 const auto details2
{symbol2
.get
<SubprogramDetails
>()};
2734 if (details1
.isFunction() != details2
.isFunction()) {
2735 Say(symbol1
, symbol2
,
2736 details1
.isFunction()
2737 ? "Module function '%s' was declared as a subroutine in the"
2738 " corresponding interface body"_err_en_US
2739 : "Module subroutine '%s' was declared as a function in the"
2740 " corresponding interface body"_err_en_US
);
2743 const auto &args1
{details1
.dummyArgs()};
2744 const auto &args2
{details2
.dummyArgs()};
2745 int nargs1
{static_cast<int>(args1
.size())};
2746 int nargs2
{static_cast<int>(args2
.size())};
2747 if (nargs1
!= nargs2
) {
2748 Say(symbol1
, symbol2
,
2749 "Module subprogram '%s' has %d args but the corresponding interface"
2750 " body has %d"_err_en_US
,
2754 bool nonRecursive1
{symbol1
.attrs().test(Attr::NON_RECURSIVE
)};
2755 if (nonRecursive1
!= symbol2
.attrs().test(Attr::NON_RECURSIVE
)) { // C1551
2756 Say(symbol1
, symbol2
,
2758 ? "Module subprogram '%s' has NON_RECURSIVE prefix but"
2759 " the corresponding interface body does not"_err_en_US
2760 : "Module subprogram '%s' does not have NON_RECURSIVE prefix but "
2761 "the corresponding interface body does"_err_en_US
);
2763 const std::string
*bindName1
{details1
.bindName()};
2764 const std::string
*bindName2
{details2
.bindName()};
2765 if (!bindName1
&& !bindName2
) {
2766 // OK - neither has a binding label
2767 } else if (!bindName1
) {
2768 Say(symbol1
, symbol2
,
2769 "Module subprogram '%s' does not have a binding label but the"
2770 " corresponding interface body does"_err_en_US
);
2771 } else if (!bindName2
) {
2772 Say(symbol1
, symbol2
,
2773 "Module subprogram '%s' has a binding label but the"
2774 " corresponding interface body does not"_err_en_US
);
2775 } else if (*bindName1
!= *bindName2
) {
2776 Say(symbol1
, symbol2
,
2777 "Module subprogram '%s' has binding label '%s' but the corresponding"
2778 " interface body has '%s'"_err_en_US
,
2779 *details1
.bindName(), *details2
.bindName());
2781 const Procedure
*proc1
{checkHelper
.Characterize(symbol1
)};
2782 const Procedure
*proc2
{checkHelper
.Characterize(symbol2
)};
2783 if (!proc1
|| !proc2
) {
2786 if (proc1
->attrs
.test(Procedure::Attr::Pure
) !=
2787 proc2
->attrs
.test(Procedure::Attr::Pure
)) {
2788 Say(symbol1
, symbol2
,
2789 "Module subprogram '%s' and its corresponding interface body are not both PURE"_err_en_US
);
2791 if (proc1
->attrs
.test(Procedure::Attr::Elemental
) !=
2792 proc2
->attrs
.test(Procedure::Attr::Elemental
)) {
2793 Say(symbol1
, symbol2
,
2794 "Module subprogram '%s' and its corresponding interface body are not both ELEMENTAL"_err_en_US
);
2796 if (proc1
->attrs
.test(Procedure::Attr::BindC
) !=
2797 proc2
->attrs
.test(Procedure::Attr::BindC
)) {
2798 Say(symbol1
, symbol2
,
2799 "Module subprogram '%s' and its corresponding interface body are not both BIND(C)"_err_en_US
);
2801 if (proc1
->functionResult
&& proc2
->functionResult
&&
2802 *proc1
->functionResult
!= *proc2
->functionResult
) {
2803 Say(symbol1
, symbol2
,
2804 "Return type of function '%s' does not match return type of"
2805 " the corresponding interface body"_err_en_US
);
2807 for (int i
{0}; i
< nargs1
; ++i
) {
2808 const Symbol
*arg1
{args1
[i
]};
2809 const Symbol
*arg2
{args2
[i
]};
2810 if (arg1
&& !arg2
) {
2811 Say(symbol1
, symbol2
,
2812 "Dummy argument %2$d of '%1$s' is not an alternate return indicator"
2813 " but the corresponding argument in the interface body is"_err_en_US
,
2815 } else if (!arg1
&& arg2
) {
2816 Say(symbol1
, symbol2
,
2817 "Dummy argument %2$d of '%1$s' is an alternate return indicator but"
2818 " the corresponding argument in the interface body is not"_err_en_US
,
2820 } else if (arg1
&& arg2
) {
2821 SourceName name1
{arg1
->name()};
2822 SourceName name2
{arg2
->name()};
2823 if (name1
!= name2
) {
2825 "Dummy argument name '%s' does not match corresponding name '%s'"
2826 " in interface body"_err_en_US
,
2830 *arg1
, *arg2
, proc1
->dummyArguments
[i
], proc2
->dummyArguments
[i
]);
2836 void SubprogramMatchHelper::CheckDummyArg(const Symbol
&symbol1
,
2837 const Symbol
&symbol2
, const DummyArgument
&arg1
,
2838 const DummyArgument
&arg2
) {
2841 [&](const DummyDataObject
&obj1
, const DummyDataObject
&obj2
) {
2842 CheckDummyDataObject(symbol1
, symbol2
, obj1
, obj2
);
2844 [&](const DummyProcedure
&proc1
, const DummyProcedure
&proc2
) {
2845 CheckDummyProcedure(symbol1
, symbol2
, proc1
, proc2
);
2847 [&](const DummyDataObject
&, const auto &) {
2848 Say(symbol1
, symbol2
,
2849 "Dummy argument '%s' is a data object; the corresponding"
2850 " argument in the interface body is not"_err_en_US
);
2852 [&](const DummyProcedure
&, const auto &) {
2853 Say(symbol1
, symbol2
,
2854 "Dummy argument '%s' is a procedure; the corresponding"
2855 " argument in the interface body is not"_err_en_US
);
2857 [&](const auto &, const auto &) {
2858 llvm_unreachable("Dummy arguments are not data objects or"
2865 void SubprogramMatchHelper::CheckDummyDataObject(const Symbol
&symbol1
,
2866 const Symbol
&symbol2
, const DummyDataObject
&obj1
,
2867 const DummyDataObject
&obj2
) {
2868 if (!CheckSameIntent(symbol1
, symbol2
, obj1
.intent
, obj2
.intent
)) {
2869 } else if (!CheckSameAttrs(symbol1
, symbol2
, obj1
.attrs
, obj2
.attrs
)) {
2870 } else if (obj1
.type
.type() != obj2
.type
.type()) {
2871 Say(symbol1
, symbol2
,
2872 "Dummy argument '%s' has type %s; the corresponding argument in the"
2873 " interface body has type %s"_err_en_US
,
2874 obj1
.type
.type().AsFortran(), obj2
.type
.type().AsFortran());
2875 } else if (!ShapesAreCompatible(obj1
, obj2
)) {
2876 Say(symbol1
, symbol2
,
2877 "The shape of dummy argument '%s' does not match the shape of the"
2878 " corresponding argument in the interface body"_err_en_US
);
2883 void SubprogramMatchHelper::CheckDummyProcedure(const Symbol
&symbol1
,
2884 const Symbol
&symbol2
, const DummyProcedure
&proc1
,
2885 const DummyProcedure
&proc2
) {
2886 if (!CheckSameIntent(symbol1
, symbol2
, proc1
.intent
, proc2
.intent
)) {
2887 } else if (!CheckSameAttrs(symbol1
, symbol2
, proc1
.attrs
, proc2
.attrs
)) {
2888 } else if (proc1
!= proc2
) {
2889 Say(symbol1
, symbol2
,
2890 "Dummy procedure '%s' does not match the corresponding argument in"
2891 " the interface body"_err_en_US
);
2895 bool SubprogramMatchHelper::CheckSameIntent(const Symbol
&symbol1
,
2896 const Symbol
&symbol2
, common::Intent intent1
, common::Intent intent2
) {
2897 if (intent1
== intent2
) {
2900 Say(symbol1
, symbol2
,
2901 "The intent of dummy argument '%s' does not match the intent"
2902 " of the corresponding argument in the interface body"_err_en_US
);
2907 // Report an error referring to first symbol with declaration of second symbol
2908 template <typename
... A
>
2909 void SubprogramMatchHelper::Say(const Symbol
&symbol1
, const Symbol
&symbol2
,
2910 parser::MessageFixedText
&&text
, A
&&...args
) {
2911 auto &message
{context().Say(symbol1
.name(), std::move(text
), symbol1
.name(),
2912 std::forward
<A
>(args
)...)};
2913 evaluate::AttachDeclaration(message
, symbol2
);
2916 template <typename ATTRS
>
2917 bool SubprogramMatchHelper::CheckSameAttrs(
2918 const Symbol
&symbol1
, const Symbol
&symbol2
, ATTRS attrs1
, ATTRS attrs2
) {
2919 if (attrs1
== attrs2
) {
2922 attrs1
.IterateOverMembers([&](auto attr
) {
2923 if (!attrs2
.test(attr
)) {
2924 Say(symbol1
, symbol2
,
2925 "Dummy argument '%s' has the %s attribute; the corresponding"
2926 " argument in the interface body does not"_err_en_US
,
2930 attrs2
.IterateOverMembers([&](auto attr
) {
2931 if (!attrs1
.test(attr
)) {
2932 Say(symbol1
, symbol2
,
2933 "Dummy argument '%s' does not have the %s attribute; the"
2934 " corresponding argument in the interface body does"_err_en_US
,
2941 bool SubprogramMatchHelper::ShapesAreCompatible(
2942 const DummyDataObject
&obj1
, const DummyDataObject
&obj2
) {
2943 return characteristics::ShapesAreCompatible(
2944 FoldShape(obj1
.type
.shape()), FoldShape(obj2
.type
.shape()));
2947 evaluate::Shape
SubprogramMatchHelper::FoldShape(const evaluate::Shape
&shape
) {
2948 evaluate::Shape result
;
2949 for (const auto &extent
: shape
) {
2950 result
.emplace_back(
2951 evaluate::Fold(context().foldingContext(), common::Clone(extent
)));
2956 void DistinguishabilityHelper::Add(const Symbol
&generic
, GenericKind kind
,
2957 const Symbol
&specific
, const Procedure
&procedure
) {
2958 if (!context_
.HasError(specific
)) {
2959 nameToInfo_
[generic
.name()].emplace_back(
2960 ProcedureInfo
{kind
, specific
, procedure
});
2964 void DistinguishabilityHelper::Check(const Scope
&scope
) {
2965 for (const auto &[name
, info
] : nameToInfo_
) {
2966 auto count
{info
.size()};
2967 for (std::size_t i1
{0}; i1
< count
- 1; ++i1
) {
2968 const auto &[kind
, symbol
, proc
]{info
[i1
]};
2969 for (std::size_t i2
{i1
+ 1}; i2
< count
; ++i2
) {
2970 auto distinguishable
{kind
.IsName()
2971 ? evaluate::characteristics::Distinguishable
2972 : evaluate::characteristics::DistinguishableOpOrAssign
};
2973 if (!distinguishable(
2974 context_
.languageFeatures(), proc
, info
[i2
].procedure
)) {
2975 SayNotDistinguishable(GetTopLevelUnitContaining(scope
), name
, kind
,
2976 symbol
, info
[i2
].symbol
);
2983 void DistinguishabilityHelper::SayNotDistinguishable(const Scope
&scope
,
2984 const SourceName
&name
, GenericKind kind
, const Symbol
&proc1
,
2985 const Symbol
&proc2
) {
2986 std::string name1
{proc1
.name().ToString()};
2987 std::string name2
{proc2
.name().ToString()};
2988 if (kind
.IsOperator() || kind
.IsAssignment()) {
2989 // proc1 and proc2 may come from different scopes so qualify their names
2990 if (proc1
.owner().IsDerivedType()) {
2991 name1
= proc1
.owner().GetName()->ToString() + '%' + name1
;
2993 if (proc2
.owner().IsDerivedType()) {
2994 name2
= proc2
.owner().GetName()->ToString() + '%' + name2
;
2997 parser::Message
*msg
;
2998 if (scope
.sourceRange().Contains(name
)) {
2999 msg
= &context_
.Say(name
,
3000 "Generic '%s' may not have specific procedures '%s' and '%s' as their interfaces are not distinguishable"_err_en_US
,
3001 MakeOpName(name
), name1
, name2
);
3003 msg
= &context_
.Say(*GetTopLevelUnitContaining(proc1
).GetName(),
3004 "USE-associated generic '%s' may not have specific procedures '%s' and '%s' as their interfaces are not distinguishable"_err_en_US
,
3005 MakeOpName(name
), name1
, name2
);
3007 AttachDeclaration(*msg
, scope
, proc1
);
3008 AttachDeclaration(*msg
, scope
, proc2
);
3011 // `evaluate::AttachDeclaration` doesn't handle the generic case where `proc`
3012 // comes from a different module but is not necessarily use-associated.
3013 void DistinguishabilityHelper::AttachDeclaration(
3014 parser::Message
&msg
, const Scope
&scope
, const Symbol
&proc
) {
3015 const Scope
&unit
{GetTopLevelUnitContaining(proc
)};
3016 if (unit
== scope
) {
3017 evaluate::AttachDeclaration(msg
, proc
);
3019 msg
.Attach(unit
.GetName().value(),
3020 "'%s' is USE-associated from module '%s'"_en_US
, proc
.name(),
3021 unit
.GetName().value());
3025 void CheckDeclarations(SemanticsContext
&context
) {
3026 CheckHelper
{context
}.Check();
3028 } // namespace Fortran::semantics