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 "definable.h"
13 #include "pointer-assignment.h"
14 #include "flang/Evaluate/check-expression.h"
15 #include "flang/Evaluate/fold.h"
16 #include "flang/Evaluate/tools.h"
17 #include "flang/Parser/characters.h"
18 #include "flang/Semantics/scope.h"
19 #include "flang/Semantics/semantics.h"
20 #include "flang/Semantics/symbol.h"
21 #include "flang/Semantics/tools.h"
22 #include "flang/Semantics/type.h"
27 namespace Fortran::semantics
{
29 namespace characteristics
= evaluate::characteristics
;
30 using characteristics::DummyArgument
;
31 using characteristics::DummyDataObject
;
32 using characteristics::DummyProcedure
;
33 using characteristics::FunctionResult
;
34 using characteristics::Procedure
;
38 explicit CheckHelper(SemanticsContext
&c
) : context_
{c
} {}
40 SemanticsContext
&context() { return context_
; }
41 void Check() { Check(context_
.globalScope()); }
42 void Check(const ParamValue
&, bool canBeAssumed
);
43 void Check(const Bound
&bound
) {
44 CheckSpecExpr(bound
.GetExplicit(), /*forElementalFunctionResult=*/false);
46 void Check(const ShapeSpec
&spec
) {
50 void Check(const ArraySpec
&);
51 void Check(const DeclTypeSpec
&, bool canHaveAssumedTypeParameters
);
52 void Check(const Symbol
&);
53 void CheckCommonBlock(const Symbol
&);
54 void Check(const Scope
&);
55 const Procedure
*Characterize(const Symbol
&);
59 void CheckSpecExpr(const A
&x
, bool forElementalFunctionResult
) {
60 evaluate::CheckSpecificationExpr(
61 x
, DEREF(scope_
), foldingContext_
, forElementalFunctionResult
);
63 void CheckValue(const Symbol
&, const DerivedTypeSpec
*);
64 void CheckVolatile(const Symbol
&, const DerivedTypeSpec
*);
65 void CheckContiguous(const Symbol
&);
66 void CheckPointer(const Symbol
&);
68 const Symbol
&proc
, const Symbol
*interface
, const WithPassArg
&);
69 void CheckProcBinding(const Symbol
&, const ProcBindingDetails
&);
70 void CheckObjectEntity(const Symbol
&, const ObjectEntityDetails
&);
71 void CheckPointerInitialization(const Symbol
&);
72 void CheckArraySpec(const Symbol
&, const ArraySpec
&);
73 void CheckProcEntity(const Symbol
&, const ProcEntityDetails
&);
74 void CheckSubprogram(const Symbol
&, const SubprogramDetails
&);
75 void CheckExternal(const Symbol
&);
76 void CheckAssumedTypeEntity(const Symbol
&, const ObjectEntityDetails
&);
77 void CheckDerivedType(const Symbol
&, const DerivedTypeDetails
&);
79 const Symbol
&subroutine
, SourceName
, const Symbol
&derivedType
);
80 bool CheckDistinguishableFinals(const Symbol
&f1
, SourceName f1name
,
81 const Symbol
&f2
, SourceName f2name
, const Symbol
&derivedType
);
82 void CheckGeneric(const Symbol
&, const GenericDetails
&);
83 void CheckHostAssoc(const Symbol
&, const HostAssocDetails
&);
84 bool CheckDefinedOperator(
85 SourceName
, GenericKind
, const Symbol
&, const Procedure
&);
86 std::optional
<parser::MessageFixedText
> CheckNumberOfArgs(
87 const GenericKind
&, std::size_t);
88 bool CheckDefinedOperatorArg(
89 const SourceName
&, const Symbol
&, const Procedure
&, std::size_t);
90 bool CheckDefinedAssignment(const Symbol
&, const Procedure
&);
91 bool CheckDefinedAssignmentArg(const Symbol
&, const DummyArgument
&, int);
92 void CheckSpecifics(const Symbol
&, const GenericDetails
&);
93 void CheckEquivalenceSet(const EquivalenceSet
&);
94 void CheckEquivalenceObject(const EquivalenceObject
&);
95 void CheckBlockData(const Scope
&);
96 void CheckGenericOps(const Scope
&);
97 bool CheckConflicting(const Symbol
&, Attr
, Attr
);
98 void WarnMissingFinal(const Symbol
&);
99 void CheckSymbolType(const Symbol
&); // C702
100 bool InPure() const {
101 return innermostSymbol_
&& IsPureProcedure(*innermostSymbol_
);
103 bool InElemental() const {
104 return innermostSymbol_
&& IsElementalProcedure(*innermostSymbol_
);
106 bool InFunction() const {
107 return innermostSymbol_
&& IsFunction(*innermostSymbol_
);
109 bool InInterface() const {
110 const SubprogramDetails
*subp
{innermostSymbol_
111 ? innermostSymbol_
->detailsIf
<SubprogramDetails
>()
113 return subp
&& subp
->isInterface();
115 template <typename
... A
>
116 parser::Message
*SayWithDeclaration(const Symbol
&symbol
, A
&&...x
) {
117 parser::Message
*msg
{messages_
.Say(std::forward
<A
>(x
)...)};
118 if (msg
&& messages_
.at().begin() != symbol
.name().begin()) {
119 evaluate::AttachDeclaration(*msg
, symbol
);
123 bool InModuleFile() const {
124 return FindModuleFileContaining(context_
.FindScope(messages_
.at())) !=
127 template <typename FeatureOrUsageWarning
, typename
... A
>
128 parser::Message
*Warn(FeatureOrUsageWarning warning
, A
&&...x
) {
129 if (!context_
.ShouldWarn(warning
) || InModuleFile()) {
132 return messages_
.Say(warning
, std::forward
<A
>(x
)...);
135 template <typename FeatureOrUsageWarning
, typename
... A
>
136 parser::Message
*Warn(
137 FeatureOrUsageWarning warning
, parser::CharBlock source
, A
&&...x
) {
138 if (!context_
.ShouldWarn(warning
) ||
139 FindModuleFileContaining(context_
.FindScope(source
))) {
142 return messages_
.Say(warning
, source
, std::forward
<A
>(x
)...);
145 bool IsResultOkToDiffer(const FunctionResult
&);
146 void CheckGlobalName(const Symbol
&);
147 void CheckProcedureAssemblyName(const Symbol
&symbol
);
148 void CheckExplicitSave(const Symbol
&);
149 parser::Messages
WhyNotInteroperableDerivedType(const Symbol
&);
150 parser::Messages
WhyNotInteroperableObject(
151 const Symbol
&, bool allowNonInteroperableType
= false);
152 parser::Messages
WhyNotInteroperableFunctionResult(const Symbol
&);
153 parser::Messages
WhyNotInteroperableProcedure(const Symbol
&, bool isError
);
154 void CheckBindC(const Symbol
&);
155 // Check functions for defined I/O procedures
156 void CheckDefinedIoProc(
157 const Symbol
&, const GenericDetails
&, common::DefinedIo
);
158 bool CheckDioDummyIsData(const Symbol
&, const Symbol
*, std::size_t);
159 void CheckDioDummyIsDerived(
160 const Symbol
&, const Symbol
&, common::DefinedIo ioKind
, const Symbol
&);
161 void CheckDioDummyIsDefaultInteger(const Symbol
&, const Symbol
&);
162 void CheckDioDummyIsScalar(const Symbol
&, const Symbol
&);
163 void CheckDioDummyAttrs(const Symbol
&, const Symbol
&, Attr
);
165 const Symbol
&, const Symbol
*, common::DefinedIo
, const Symbol
&);
166 void CheckGenericVsIntrinsic(const Symbol
&, const GenericDetails
&);
167 void CheckDefaultIntegerArg(const Symbol
&, const Symbol
*, Attr
);
168 void CheckDioAssumedLenCharacterArg(
169 const Symbol
&, const Symbol
*, std::size_t, Attr
);
170 void CheckDioVlistArg(const Symbol
&, const Symbol
*, std::size_t);
171 void CheckDioArgCount(const Symbol
&, common::DefinedIo ioKind
, std::size_t);
172 struct TypeWithDefinedIo
{
173 const DerivedTypeSpec
&type
;
174 common::DefinedIo ioKind
;
176 const Symbol
&generic
;
178 void CheckAlreadySeenDefinedIo(const DerivedTypeSpec
&, common::DefinedIo
,
179 const Symbol
&, const Symbol
&generic
);
180 void CheckModuleProcedureDef(const Symbol
&);
182 SemanticsContext
&context_
;
183 evaluate::FoldingContext
&foldingContext_
{context_
.foldingContext()};
184 parser::ContextualMessages
&messages_
{foldingContext_
.messages()};
185 const Scope
*scope_
{nullptr};
186 bool scopeIsUninstantiatedPDT_
{false};
187 // This symbol is the one attached to the innermost enclosing scope
188 // that has a symbol.
189 const Symbol
*innermostSymbol_
{nullptr};
190 // Cache of calls to Procedure::Characterize(Symbol)
191 std::map
<SymbolRef
, std::optional
<Procedure
>, SymbolAddressCompare
>
193 // Collection of module procedure symbols with non-BIND(C)
194 // global names, qualified by their module.
195 std::map
<std::pair
<SourceName
, const Symbol
*>, SymbolRef
> moduleProcs_
;
196 // Collection of symbols with global names, BIND(C) or otherwise
197 std::map
<std::string
, SymbolRef
> globalNames_
;
198 // Collection of external procedures without global definitions
199 std::map
<std::string
, SymbolRef
> externalNames_
;
200 // Collection of target dependent assembly names of external and BIND(C)
202 std::map
<std::string
, SymbolRef
> procedureAssemblyNames_
;
203 // Derived types that have been examined by WhyNotInteroperable_XXX
204 UnorderedSymbolSet examinedByWhyNotInteroperable_
;
207 class DistinguishabilityHelper
{
209 DistinguishabilityHelper(SemanticsContext
&context
) : context_
{context
} {}
210 void Add(const Symbol
&, GenericKind
, const Symbol
&, const Procedure
&);
211 void Check(const Scope
&);
214 void SayNotDistinguishable(const Scope
&, const SourceName
&, GenericKind
,
215 const Symbol
&, const Symbol
&, bool isHardConflict
);
216 void AttachDeclaration(parser::Message
&, const Scope
&, const Symbol
&);
218 SemanticsContext
&context_
;
219 struct ProcedureInfo
{
221 const Procedure
&procedure
;
223 std::map
<SourceName
, std::map
<const Symbol
*, ProcedureInfo
>>
227 void CheckHelper::Check(const ParamValue
&value
, bool canBeAssumed
) {
228 if (value
.isAssumed()) {
229 if (!canBeAssumed
) { // C795, C721, C726
231 "An assumed (*) type parameter may be used only for a (non-statement function) dummy argument, associate name, character named constant, or external function result"_err_en_US
);
234 CheckSpecExpr(value
.GetExplicit(), /*forElementalFunctionResult=*/false);
238 void CheckHelper::Check(const ArraySpec
&shape
) {
239 for (const auto &spec
: shape
) {
244 void CheckHelper::Check(
245 const DeclTypeSpec
&type
, bool canHaveAssumedTypeParameters
) {
246 if (type
.category() == DeclTypeSpec::Character
) {
247 Check(type
.characterTypeSpec().length(), canHaveAssumedTypeParameters
);
248 } else if (const DerivedTypeSpec
*derived
{type
.AsDerived()}) {
249 for (auto &parm
: derived
->parameters()) {
250 Check(parm
.second
, canHaveAssumedTypeParameters
);
255 static bool IsBlockData(const Scope
&scope
) {
256 return scope
.kind() == Scope::Kind::BlockData
;
259 static bool IsBlockData(const Symbol
&symbol
) {
260 return symbol
.scope() && IsBlockData(*symbol
.scope());
263 void CheckHelper::Check(const Symbol
&symbol
) {
264 if (symbol
.has
<UseErrorDetails
>()) {
267 if (symbol
.name().size() > common::maxNameLen
&&
268 &symbol
== &symbol
.GetUltimate()) {
269 Warn(common::LanguageFeature::LongNames
, symbol
.name(),
270 "%s has length %d, which is greater than the maximum name length %d"_port_en_US
,
271 symbol
.name(), symbol
.name().size(), common::maxNameLen
);
273 if (context_
.HasError(symbol
)) {
276 auto restorer
{messages_
.SetLocation(symbol
.name())};
277 context_
.set_location(symbol
.name());
278 const DeclTypeSpec
*type
{symbol
.GetType()};
279 const DerivedTypeSpec
*derived
{type
? type
->AsDerived() : nullptr};
283 [&](const UseDetails
&x
) { isDone
= true; },
284 [&](const HostAssocDetails
&x
) {
285 CheckHostAssoc(symbol
, x
);
288 [&](const ProcBindingDetails
&x
) {
289 CheckProcBinding(symbol
, x
);
292 [&](const ObjectEntityDetails
&x
) { CheckObjectEntity(symbol
, x
); },
293 [&](const ProcEntityDetails
&x
) { CheckProcEntity(symbol
, x
); },
294 [&](const SubprogramDetails
&x
) { CheckSubprogram(symbol
, x
); },
295 [&](const DerivedTypeDetails
&x
) { CheckDerivedType(symbol
, x
); },
296 [&](const GenericDetails
&x
) { CheckGeneric(symbol
, x
); },
300 if (symbol
.attrs().test(Attr::VOLATILE
)) {
301 CheckVolatile(symbol
, derived
);
303 if (symbol
.attrs().test(Attr::BIND_C
)) {
306 if (symbol
.attrs().test(Attr::SAVE
) &&
307 !symbol
.implicitAttrs().test(Attr::SAVE
)) {
308 CheckExplicitSave(symbol
);
310 if (symbol
.attrs().test(Attr::CONTIGUOUS
)) {
311 CheckContiguous(symbol
);
313 CheckGlobalName(symbol
);
314 CheckProcedureAssemblyName(symbol
);
315 if (symbol
.attrs().test(Attr::ASYNCHRONOUS
) &&
316 !evaluate::IsVariable(symbol
)) {
318 "An entity may not have the ASYNCHRONOUS attribute unless it is a variable"_err_en_US
);
320 if (symbol
.attrs().HasAny({Attr::INTENT_IN
, Attr::INTENT_INOUT
,
321 Attr::INTENT_OUT
, Attr::OPTIONAL
, Attr::VALUE
}) &&
324 "Only a dummy argument may have an INTENT, VALUE, or OPTIONAL attribute"_err_en_US
);
325 } else if (symbol
.attrs().test(Attr::VALUE
)) {
326 CheckValue(symbol
, derived
);
330 return; // following checks do not apply
333 if (symbol
.attrs().test(Attr::PROTECTED
)) {
334 if (symbol
.owner().kind() != Scope::Kind::Module
) { // C854
336 "A PROTECTED entity must be in the specification part of a module"_err_en_US
);
338 if (!evaluate::IsVariable(symbol
) && !IsProcedurePointer(symbol
)) { // C855
340 "A PROTECTED entity must be a variable or pointer"_err_en_US
);
342 if (FindCommonBlockContaining(symbol
)) { // C856
344 "A PROTECTED entity may not be in a common block"_err_en_US
);
347 if (IsPointer(symbol
)) {
348 CheckPointer(symbol
);
352 // Declarations in interface definitions "have no effect" if they
353 // are not pertinent to the characteristics of the procedure.
354 // Restrictions on entities in pure procedure interfaces don't need
356 } else if (!FindCommonBlockContaining(symbol
) && IsSaved(symbol
)) {
357 if (IsInitialized(symbol
)) {
359 "A pure subprogram may not initialize a variable"_err_en_US
);
362 "A pure subprogram may not have a variable with the SAVE attribute"_err_en_US
);
365 if (symbol
.attrs().test(Attr::VOLATILE
) &&
366 (IsDummy(symbol
) || !InInterface())) {
368 "A pure subprogram may not have a variable with the VOLATILE attribute"_err_en_US
);
370 if (innermostSymbol_
&& innermostSymbol_
->name() == "__builtin_c_funloc") {
371 // The intrinsic procedure C_FUNLOC() gets a pass on this check.
372 } else if (IsProcedure(symbol
) && !IsPureProcedure(symbol
) &&
375 "A dummy procedure of a pure subprogram must be pure"_err_en_US
);
378 const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()};
379 if (type
) { // Section 7.2, paragraph 7; C795
380 bool isChar
{type
->category() == DeclTypeSpec::Character
};
381 bool canHaveAssumedParameter
{(isChar
&& IsNamedConstant(symbol
)) ||
382 (IsAssumedLengthCharacter(symbol
) && // C722
383 (IsExternal(symbol
) ||
384 ClassifyProcedure(symbol
) ==
385 ProcedureDefinitionClass::Dummy
)) ||
386 symbol
.test(Symbol::Flag::ParentComp
)};
387 if (!IsStmtFunctionDummy(symbol
)) { // C726
389 canHaveAssumedParameter
|= object
->isDummy() ||
390 (isChar
&& object
->isFuncResult()) ||
391 IsStmtFunctionResult(symbol
); // Avoids multiple messages
393 canHaveAssumedParameter
|= symbol
.has
<AssocEntityDetails
>();
396 if (IsProcedurePointer(symbol
) && symbol
.HasExplicitInterface()) {
397 // Don't check function result types here
399 Check(*type
, canHaveAssumedParameter
);
401 if (InFunction() && IsFunctionResult(symbol
)) {
403 if (type
->IsPolymorphic() && IsAllocatable(symbol
)) { // C1585
405 "Result of pure function may not be both polymorphic and ALLOCATABLE"_err_en_US
);
408 // These cases would be caught be the general validation of local
409 // variables in a pure context, but these messages are more specific.
410 if (HasImpureFinal(symbol
)) { // C1584
412 "Result of pure function may not have an impure FINAL subroutine"_err_en_US
);
415 FindPolymorphicAllocatablePotentialComponent(*derived
)}) {
416 SayWithDeclaration(*bad
,
417 "Result of pure function may not have polymorphic ALLOCATABLE potential component '%s'"_err_en_US
,
418 bad
.BuildResultDesignatorName());
422 if (InElemental() && isChar
) { // F'2023 C15121
423 CheckSpecExpr(type
->characterTypeSpec().length().GetExplicit(),
424 /*forElementalFunctionResult=*/true);
425 // TODO: check PDT LEN parameters
429 if (IsAssumedLengthCharacter(symbol
) && IsFunction(symbol
)) { // C723
430 if (symbol
.attrs().test(Attr::RECURSIVE
)) {
432 "An assumed-length CHARACTER(*) function cannot be RECURSIVE"_err_en_US
);
434 if (symbol
.Rank() > 0) {
436 "An assumed-length CHARACTER(*) function cannot return an array"_err_en_US
);
438 if (!IsStmtFunction(symbol
)) {
439 if (IsElementalProcedure(symbol
)) {
441 "An assumed-length CHARACTER(*) function cannot be ELEMENTAL"_err_en_US
);
442 } else if (IsPureProcedure(symbol
)) {
444 "An assumed-length CHARACTER(*) function cannot be PURE"_err_en_US
);
447 if (const Symbol
*result
{FindFunctionResult(symbol
)}) {
448 if (IsPointer(*result
)) {
450 "An assumed-length CHARACTER(*) function cannot return a POINTER"_err_en_US
);
453 if (IsProcedurePointer(symbol
) && IsDummy(symbol
)) {
454 Warn(common::UsageWarning::Portability
,
455 "A dummy procedure pointer should not have assumed-length CHARACTER(*) result type"_port_en_US
);
456 // The non-dummy case is a hard error that's caught elsewhere.
459 if (IsDummy(symbol
)) {
460 if (IsNamedConstant(symbol
)) {
462 "A dummy argument may not also be a named constant"_err_en_US
);
464 } else if (IsFunctionResult(symbol
)) {
465 if (IsNamedConstant(symbol
)) {
467 "A function result may not also be a named constant"_err_en_US
);
470 if (IsAutomatic(symbol
)) {
471 if (const Symbol
* common
{FindCommonBlockContaining(symbol
)}) {
473 "Automatic data object '%s' may not appear in COMMON block /%s/"_err_en_US
,
474 symbol
.name(), common
->name());
475 } else if (symbol
.owner().IsModule()) {
477 "Automatic data object '%s' may not appear in a module"_err_en_US
,
479 } else if (IsBlockData(symbol
.owner())) {
481 "Automatic data object '%s' may not appear in a BLOCK DATA subprogram"_err_en_US
,
483 } else if (symbol
.owner().kind() == Scope::Kind::MainProgram
) {
484 if (context_
.IsEnabled(common::LanguageFeature::AutomaticInMainProgram
)) {
485 Warn(common::LanguageFeature::AutomaticInMainProgram
,
486 "Automatic data object '%s' should not appear in the specification part of a main program"_port_en_US
,
490 "Automatic data object '%s' may not appear in the specification part of a main program"_err_en_US
,
495 if (IsProcedure(symbol
)) {
496 if (IsAllocatable(symbol
)) {
498 "Procedure '%s' may not be ALLOCATABLE"_err_en_US
, symbol
.name());
500 if (!symbol
.HasExplicitInterface() && symbol
.Rank() > 0) {
502 "Procedure '%s' may not be an array without an explicit interface"_err_en_US
,
508 void CheckHelper::CheckCommonBlock(const Symbol
&symbol
) {
509 CheckGlobalName(symbol
);
510 if (symbol
.attrs().test(Attr::BIND_C
)) {
513 for (MutableSymbolRef ref
: symbol
.get
<CommonBlockDetails
>().objects()) {
514 if (ref
->test(Symbol::Flag::CrayPointee
)) {
515 messages_
.Say(ref
->name(),
516 "Cray pointee '%s' may not be a member of a COMMON block"_err_en_US
,
523 void CheckHelper::CheckExplicitSave(const Symbol
&symbol
) {
524 const Symbol
&ultimate
{symbol
.GetUltimate()};
525 if (ultimate
.test(Symbol::Flag::InDataStmt
)) {
527 } else if (symbol
.has
<UseDetails
>()) {
529 "The USE-associated name '%s' may not have an explicit SAVE attribute"_err_en_US
,
531 } else if (IsDummy(ultimate
)) {
533 "The dummy argument '%s' may not have an explicit SAVE attribute"_err_en_US
,
535 } else if (IsFunctionResult(ultimate
)) {
537 "The function result variable '%s' may not have an explicit SAVE attribute"_err_en_US
,
539 } else if (const Symbol
* common
{FindCommonBlockContaining(ultimate
)}) {
541 "The entity '%s' in COMMON block /%s/ may not have an explicit SAVE attribute"_err_en_US
,
542 symbol
.name(), common
->name());
543 } else if (IsAutomatic(ultimate
)) {
545 "The automatic object '%s' may not have an explicit SAVE attribute"_err_en_US
,
547 } else if (!evaluate::IsVariable(ultimate
) && !IsProcedurePointer(ultimate
)) {
549 "The entity '%s' with an explicit SAVE attribute must be a variable, procedure pointer, or COMMON block"_err_en_US
,
554 void CheckHelper::CheckValue(
555 const Symbol
&symbol
, const DerivedTypeSpec
*derived
) { // C863 - C865
556 if (IsProcedure(symbol
)) {
558 "VALUE attribute may apply only to a dummy data object"_err_en_US
);
559 return; // don't pile on
561 if (IsAssumedSizeArray(symbol
)) {
563 "VALUE attribute may not apply to an assumed-size array"_err_en_US
);
565 if (evaluate::IsCoarray(symbol
)) {
566 messages_
.Say("VALUE attribute may not apply to a coarray"_err_en_US
);
568 if (IsAllocatable(symbol
)) {
569 messages_
.Say("VALUE attribute may not apply to an ALLOCATABLE"_err_en_US
);
570 } else if (IsPointer(symbol
)) {
571 messages_
.Say("VALUE attribute may not apply to a POINTER"_err_en_US
);
573 if (IsIntentInOut(symbol
)) {
575 "VALUE attribute may not apply to an INTENT(IN OUT) argument"_err_en_US
);
576 } else if (IsIntentOut(symbol
)) {
578 "VALUE attribute may not apply to an INTENT(OUT) argument"_err_en_US
);
580 if (symbol
.attrs().test(Attr::VOLATILE
)) {
581 messages_
.Say("VALUE attribute may not apply to a VOLATILE"_err_en_US
);
583 if (innermostSymbol_
&& IsBindCProcedure(*innermostSymbol_
)) {
584 if (IsOptional(symbol
)) {
586 "VALUE attribute may not apply to an OPTIONAL in a BIND(C) procedure"_err_en_US
);
588 if (symbol
.Rank() > 0) {
590 "VALUE attribute may not apply to an array in a BIND(C) procedure"_err_en_US
);
594 if (FindCoarrayUltimateComponent(*derived
)) {
596 "VALUE attribute may not apply to a type with a coarray ultimate component"_err_en_US
);
599 if (evaluate::IsAssumedRank(symbol
)) {
601 "VALUE attribute may not apply to an assumed-rank array"_err_en_US
);
603 if (IsAssumedLengthCharacter(symbol
)) {
604 // F'2008 feature not widely implemented
605 Warn(common::UsageWarning::Portability
,
606 "VALUE attribute on assumed-length CHARACTER may not be portable"_port_en_US
);
610 void CheckHelper::CheckAssumedTypeEntity( // C709
611 const Symbol
&symbol
, const ObjectEntityDetails
&details
) {
612 if (const DeclTypeSpec
*type
{symbol
.GetType()};
613 type
&& type
->category() == DeclTypeSpec::TypeStar
) {
614 if (!IsDummy(symbol
)) {
616 "Assumed-type entity '%s' must be a dummy argument"_err_en_US
,
619 if (symbol
.attrs().test(Attr::ALLOCATABLE
)) {
620 messages_
.Say("Assumed-type argument '%s' cannot have the ALLOCATABLE"
621 " attribute"_err_en_US
,
624 if (symbol
.attrs().test(Attr::POINTER
)) {
625 messages_
.Say("Assumed-type argument '%s' cannot have the POINTER"
626 " attribute"_err_en_US
,
629 if (symbol
.attrs().test(Attr::VALUE
)) {
630 messages_
.Say("Assumed-type argument '%s' cannot have the VALUE"
631 " attribute"_err_en_US
,
634 if (symbol
.attrs().test(Attr::INTENT_OUT
)) {
636 "Assumed-type argument '%s' cannot be INTENT(OUT)"_err_en_US
,
639 if (evaluate::IsCoarray(symbol
)) {
641 "Assumed-type argument '%s' cannot be a coarray"_err_en_US
,
644 if (details
.IsArray() && details
.shape().IsExplicitShape()) {
645 messages_
.Say("Assumed-type array argument '%s' must be assumed shape,"
646 " assumed size, or assumed rank"_err_en_US
,
653 void CheckHelper::CheckObjectEntity(
654 const Symbol
&symbol
, const ObjectEntityDetails
&details
) {
655 CheckSymbolType(symbol
);
656 CheckArraySpec(symbol
, details
.shape());
657 CheckConflicting(symbol
, Attr::ALLOCATABLE
, Attr::PARAMETER
);
658 CheckConflicting(symbol
, Attr::ASYNCHRONOUS
, Attr::PARAMETER
);
659 CheckConflicting(symbol
, Attr::SAVE
, Attr::PARAMETER
);
660 CheckConflicting(symbol
, Attr::TARGET
, Attr::PARAMETER
);
661 CheckConflicting(symbol
, Attr::VOLATILE
, Attr::PARAMETER
);
662 Check(details
.shape());
663 Check(details
.coshape());
664 if (details
.shape().Rank() > common::maxRank
) {
666 "'%s' has rank %d, which is greater than the maximum supported rank %d"_err_en_US
,
667 symbol
.name(), details
.shape().Rank(), common::maxRank
);
668 } else if (details
.shape().Rank() + details
.coshape().Rank() >
671 "'%s' has rank %d and corank %d, whose sum is greater than the maximum supported rank %d"_err_en_US
,
672 symbol
.name(), details
.shape().Rank(), details
.coshape().Rank(),
675 CheckAssumedTypeEntity(symbol
, details
);
676 WarnMissingFinal(symbol
);
677 const DeclTypeSpec
*type
{details
.type()};
678 const DerivedTypeSpec
*derived
{type
? type
->AsDerived() : nullptr};
679 bool isComponent
{symbol
.owner().IsDerivedType()};
680 if (!details
.coshape().empty()) {
681 bool isDeferredCoshape
{details
.coshape().CanBeDeferredShape()};
682 if (IsAllocatable(symbol
)) {
683 if (!isDeferredCoshape
) { // C827
684 messages_
.Say("'%s' is an ALLOCATABLE coarray and must have a deferred"
685 " coshape"_err_en_US
,
688 } else if (isComponent
) { // C746
689 std::string deferredMsg
{
690 isDeferredCoshape
? "" : " and have a deferred coshape"};
691 messages_
.Say("Component '%s' is a coarray and must have the ALLOCATABLE"
692 " attribute%s"_err_en_US
,
693 symbol
.name(), deferredMsg
);
695 if (!details
.coshape().CanBeAssumedSize()) { // C828
697 "'%s' is a non-ALLOCATABLE coarray and must have an explicit coshape"_err_en_US
,
701 if (IsBadCoarrayType(derived
)) { // C747 & C824
703 "Coarray '%s' may not have type TEAM_TYPE, C_PTR, or C_FUNPTR"_err_en_US
,
706 if (evaluate::IsAssumedRank(symbol
)) {
707 messages_
.Say("Coarray '%s' may not be an assumed-rank array"_err_en_US
,
711 if (details
.isDummy()) {
712 if (IsIntentOut(symbol
)) {
713 // Some of these errors would also be caught by the general check
714 // for definability of automatically deallocated local variables,
715 // but these messages are more specific.
716 if (FindUltimateComponent(symbol
, [](const Symbol
&x
) {
717 return evaluate::IsCoarray(x
) && IsAllocatable(x
);
720 "An INTENT(OUT) dummy argument may not be, or contain, an ALLOCATABLE coarray"_err_en_US
);
722 if (IsOrContainsEventOrLockComponent(symbol
)) { // C847
724 "An INTENT(OUT) dummy argument may not be, or contain, EVENT_TYPE or LOCK_TYPE"_err_en_US
);
726 if (IsAssumedSizeArray(symbol
)) { // C834
727 if (type
&& type
->IsPolymorphic()) {
729 "An INTENT(OUT) assumed-size dummy argument array may not be polymorphic"_err_en_US
);
732 if (derived
->HasDefaultInitialization()) {
734 "An INTENT(OUT) assumed-size dummy argument array may not have a derived type with any default component initialization"_err_en_US
);
736 if (IsFinalizable(*derived
)) {
738 "An INTENT(OUT) assumed-size dummy argument array may not be finalizable"_err_en_US
);
743 if (InPure() && !IsStmtFunction(DEREF(innermostSymbol_
)) &&
744 !IsPointer(symbol
) && !IsIntentIn(symbol
) &&
745 !symbol
.attrs().test(Attr::VALUE
)) {
746 const char *what
{InFunction() ? "function" : "subroutine"};
748 if (IsIntentOut(symbol
)) {
749 if (type
&& type
->IsPolymorphic()) { // C1588
751 "An INTENT(OUT) dummy argument of a pure %s may not be polymorphic"_err_en_US
,
754 } else if (derived
) {
755 if (FindUltimateComponent(*derived
, [](const Symbol
&x
) {
756 const DeclTypeSpec
*type
{x
.GetType()};
757 return type
&& type
->IsPolymorphic();
760 "An INTENT(OUT) dummy argument of a pure %s may not have a polymorphic ultimate component"_err_en_US
,
764 if (HasImpureFinal(symbol
)) { // C1587
766 "An INTENT(OUT) dummy argument of a pure %s may not have an impure FINAL subroutine"_err_en_US
,
771 } else if (!IsIntentInOut(symbol
)) { // C1586
773 "non-POINTER dummy argument of pure %s must have INTENT() or VALUE attribute"_err_en_US
,
777 if (ok
&& InFunction() && !InModuleFile() && !InElemental()) {
778 if (context_
.IsEnabled(common::LanguageFeature::RelaxedPureDummy
)) {
779 Warn(common::LanguageFeature::RelaxedPureDummy
,
780 "non-POINTER dummy argument of pure function should be INTENT(IN) or VALUE"_warn_en_US
);
783 "non-POINTER dummy argument of pure function must be INTENT(IN) or VALUE"_err_en_US
);
787 if (auto ignoreTKR
{GetIgnoreTKR(symbol
)}; !ignoreTKR
.empty()) {
788 const Symbol
*ownerSymbol
{symbol
.owner().symbol()};
789 bool inModuleProc
{ownerSymbol
&& IsModuleProcedure(*ownerSymbol
)};
790 bool inExplicitExternalInterface
{
791 InInterface() && !IsSeparateModuleProcedureInterface(ownerSymbol
)};
792 if (!InInterface() && !inModuleProc
) {
794 "!DIR$ IGNORE_TKR may apply only in an interface or a module procedure"_err_en_US
);
796 if (ownerSymbol
&& ownerSymbol
->attrs().test(Attr::ELEMENTAL
) &&
797 details
.ignoreTKR().test(common::IgnoreTKR::Rank
)) {
799 "!DIR$ IGNORE_TKR(R) may not apply in an ELEMENTAL procedure"_err_en_US
);
801 if (IsPassedViaDescriptor(symbol
)) {
802 if (IsAllocatableOrObjectPointer(&symbol
)) {
803 if (inExplicitExternalInterface
) {
804 Warn(common::UsageWarning::IgnoreTKRUsage
,
805 "!DIR$ IGNORE_TKR should not apply to an allocatable or pointer"_warn_en_US
);
808 "!DIR$ IGNORE_TKR may not apply to an allocatable or pointer"_err_en_US
);
810 } else if (ignoreTKR
.test(common::IgnoreTKR::Rank
)) {
811 if (ignoreTKR
.count() == 1 && evaluate::IsAssumedRank(symbol
)) {
812 Warn(common::UsageWarning::IgnoreTKRUsage
,
813 "!DIR$ IGNORE_TKR(R) is not meaningful for an assumed-rank array"_warn_en_US
);
814 } else if (inExplicitExternalInterface
) {
815 Warn(common::UsageWarning::IgnoreTKRUsage
,
816 "!DIR$ IGNORE_TKR(R) should not apply to a dummy argument passed via descriptor"_warn_en_US
);
819 "!DIR$ IGNORE_TKR(R) may not apply to a dummy argument passed via descriptor"_err_en_US
);
824 } else if (!details
.ignoreTKR().empty()) {
826 "!DIR$ IGNORE_TKR directive may apply only to a dummy data argument"_err_en_US
);
829 if (details
.isDummy()) { // C15100
830 if (details
.shape().Rank() > 0) {
832 "A dummy argument of an ELEMENTAL procedure must be scalar"_err_en_US
);
834 if (IsAllocatable(symbol
)) {
836 "A dummy argument of an ELEMENTAL procedure may not be ALLOCATABLE"_err_en_US
);
838 if (evaluate::IsCoarray(symbol
)) {
840 "A dummy argument of an ELEMENTAL procedure may not be a coarray"_err_en_US
);
842 if (IsPointer(symbol
)) {
844 "A dummy argument of an ELEMENTAL procedure may not be a POINTER"_err_en_US
);
846 if (!symbol
.attrs().HasAny(Attrs
{Attr::VALUE
, Attr::INTENT_IN
,
847 Attr::INTENT_INOUT
, Attr::INTENT_OUT
})) { // F'2023 C15120
849 "A dummy argument of an ELEMENTAL procedure must have an INTENT() or VALUE attribute"_err_en_US
);
851 } else if (IsFunctionResult(symbol
)) { // C15101
852 if (details
.shape().Rank() > 0) {
854 "The result of an ELEMENTAL function must be scalar"_err_en_US
);
856 if (IsAllocatable(symbol
)) {
858 "The result of an ELEMENTAL function may not be ALLOCATABLE"_err_en_US
);
860 if (IsPointer(symbol
)) {
862 "The result of an ELEMENTAL function may not be a POINTER"_err_en_US
);
866 if (HasDeclarationInitializer(symbol
)) { // C808; ignore DATA initialization
867 CheckPointerInitialization(symbol
);
868 if (IsAutomatic(symbol
)) {
870 "An automatic variable or component must not be initialized"_err_en_US
);
871 } else if (IsDummy(symbol
)) {
872 messages_
.Say("A dummy argument must not be initialized"_err_en_US
);
873 } else if (IsFunctionResult(symbol
)) {
874 messages_
.Say("A function result must not be initialized"_err_en_US
);
875 } else if (IsInBlankCommon(symbol
)) {
876 Warn(common::LanguageFeature::InitBlankCommon
,
877 "A variable in blank COMMON should not be initialized"_port_en_US
);
880 if (symbol
.owner().kind() == Scope::Kind::BlockData
) {
881 if (IsAllocatable(symbol
)) {
883 "An ALLOCATABLE variable may not appear in a BLOCK DATA subprogram"_err_en_US
);
884 } else if (IsInitialized(symbol
) && !FindCommonBlockContaining(symbol
)) {
886 "An initialized variable in BLOCK DATA must be in a COMMON block"_err_en_US
);
889 if (derived
&& InPure() && !InInterface() &&
890 IsAutomaticallyDestroyed(symbol
) &&
891 !IsIntentOut(symbol
) /*has better messages*/ &&
892 !IsFunctionResult(symbol
) /*ditto*/) {
893 // Check automatically deallocated local variables for possible
894 // problems with finalization in PURE.
896 WhyNotDefinable(symbol
.name(), symbol
.owner(), {}, symbol
)}) {
897 if (auto *msg
{messages_
.Say(
898 "'%s' may not be a local variable in a pure subprogram"_err_en_US
,
900 msg
->Attach(std::move(whyNot
->set_severity(parser::Severity::Because
)));
904 if (symbol
.attrs().test(Attr::EXTERNAL
)) {
905 SayWithDeclaration(symbol
,
906 "'%s' is a data object and may not be EXTERNAL"_err_en_US
,
910 // Check CUDA attributes and special circumstances of being in device
912 const Scope
&progUnit
{GetProgramUnitContaining(symbol
)};
913 const auto *subpDetails
{!isComponent
&& progUnit
.symbol()
914 ? progUnit
.symbol()->detailsIf
<SubprogramDetails
>()
916 bool inDeviceSubprogram
{IsCUDADeviceContext(&symbol
.owner())};
917 if (inDeviceSubprogram
) {
918 if (IsSaved(symbol
)) {
919 Warn(common::UsageWarning::CUDAUsage
,
920 "'%s' should not have the SAVE attribute or initialization in a device subprogram"_warn_en_US
,
923 if (IsPointer(symbol
)) {
924 Warn(common::UsageWarning::CUDAUsage
,
925 "Pointer '%s' may not be associated in a device subprogram"_warn_en_US
,
928 if (details
.isDummy() &&
929 details
.cudaDataAttr().value_or(common::CUDADataAttr::Device
) !=
930 common::CUDADataAttr::Device
&&
931 details
.cudaDataAttr().value_or(common::CUDADataAttr::Device
) !=
932 common::CUDADataAttr::Managed
&&
933 details
.cudaDataAttr().value_or(common::CUDADataAttr::Device
) !=
934 common::CUDADataAttr::Shared
) {
935 Warn(common::UsageWarning::CUDAUsage
,
936 "Dummy argument '%s' may not have ATTRIBUTES(%s) in a device subprogram"_warn_en_US
,
938 parser::ToUpperCaseLetters(
939 common::EnumToString(*details
.cudaDataAttr())));
942 if (details
.cudaDataAttr()) {
943 if (auto dyType
{evaluate::DynamicType::From(symbol
)}) {
944 if (dyType
->category() != TypeCategory::Derived
) {
945 if (!IsCUDAIntrinsicType(*dyType
)) {
947 "'%s' has intrinsic type '%s' that is not available on the device"_err_en_US
,
948 symbol
.name(), dyType
->AsFortran());
952 auto attr
{*details
.cudaDataAttr()};
954 case common::CUDADataAttr::Constant
:
955 if (subpDetails
&& !inDeviceSubprogram
) {
957 "Object '%s' with ATTRIBUTES(CONSTANT) may not be declared in a host subprogram"_err_en_US
,
959 } else if (IsAllocatableOrPointer(symbol
) ||
960 symbol
.attrs().test(Attr::TARGET
)) {
962 "Object '%s' with ATTRIBUTES(CONSTANT) may not be allocatable, pointer, or target"_err_en_US
,
964 } else if (auto shape
{evaluate::GetShape(foldingContext_
, symbol
)};
966 !evaluate::AsConstantExtents(foldingContext_
, *shape
)) {
968 "Object '%s' with ATTRIBUTES(CONSTANT) must have constant array bounds"_err_en_US
,
972 case common::CUDADataAttr::Device
:
973 if (isComponent
&& !IsAllocatable(symbol
)) {
975 "Component '%s' with ATTRIBUTES(DEVICE) must also be allocatable"_err_en_US
,
979 case common::CUDADataAttr::Managed
:
980 if (!IsAutomatic(symbol
) && !IsAllocatable(symbol
) &&
981 !details
.isDummy() && !evaluate::IsExplicitShape(symbol
)) {
983 "Object '%s' with ATTRIBUTES(MANAGED) must also be allocatable, automatic, explicit shape, or a dummy argument"_err_en_US
,
987 case common::CUDADataAttr::Pinned
:
988 if (inDeviceSubprogram
) {
989 Warn(common::UsageWarning::CUDAUsage
,
990 "Object '%s' with ATTRIBUTES(PINNED) may not be declared in a device subprogram"_warn_en_US
,
992 } else if (IsPointer(symbol
)) {
993 Warn(common::UsageWarning::CUDAUsage
,
994 "Object '%s' with ATTRIBUTES(PINNED) may not be a pointer"_warn_en_US
,
996 } else if (!IsAllocatable(symbol
)) {
997 Warn(common::UsageWarning::CUDAUsage
,
998 "Object '%s' with ATTRIBUTES(PINNED) should also be allocatable"_warn_en_US
,
1002 case common::CUDADataAttr::Shared
:
1003 if (IsAllocatableOrPointer(symbol
) || symbol
.attrs().test(Attr::TARGET
)) {
1005 "Object '%s' with ATTRIBUTES(SHARED) may not be allocatable, pointer, or target"_err_en_US
,
1007 } else if (!inDeviceSubprogram
) {
1009 "Object '%s' with ATTRIBUTES(SHARED) must be declared in a device subprogram"_err_en_US
,
1013 case common::CUDADataAttr::Unified
:
1014 if (((!subpDetails
&&
1015 symbol
.owner().kind() != Scope::Kind::MainProgram
) ||
1016 inDeviceSubprogram
) &&
1019 "Object '%s' with ATTRIBUTES(UNIFIED) must be declared in a host subprogram"_err_en_US
,
1023 case common::CUDADataAttr::Texture
:
1025 "ATTRIBUTES(TEXTURE) is obsolete and no longer supported"_err_en_US
);
1028 if (attr
!= common::CUDADataAttr::Pinned
) {
1029 if (details
.commonBlock()) {
1031 "Object '%s' with ATTRIBUTES(%s) may not be in COMMON"_err_en_US
,
1033 parser::ToUpperCaseLetters(common::EnumToString(attr
)));
1034 } else if (FindEquivalenceSet(symbol
)) {
1036 "Object '%s' with ATTRIBUTES(%s) may not be in an equivalence group"_err_en_US
,
1038 parser::ToUpperCaseLetters(common::EnumToString(attr
)));
1041 if (subpDetails
/* not a module variable */ && IsSaved(symbol
) &&
1042 !inDeviceSubprogram
&& !IsAllocatable(symbol
) &&
1043 attr
== common::CUDADataAttr::Device
) {
1045 "Saved object '%s' in host code may not have ATTRIBUTES(DEVICE) unless allocatable"_err_en_US
,
1047 parser::ToUpperCaseLetters(common::EnumToString(attr
)));
1050 if (attr
== common::CUDADataAttr::Device
) {
1051 const DeclTypeSpec
*type
{symbol
.GetType()};
1052 if (const DerivedTypeSpec
*
1053 derived
{type
? type
->AsDerived() : nullptr}) {
1054 DirectComponentIterator directs
{*derived
};
1055 if (auto iter
{std::find_if(directs
.begin(), directs
.end(),
1056 [](const Symbol
&) { return false; })}) {
1058 "Derived type component '%s' may not have ATTRIBUTES(DEVICE) as it has a direct device component '%s'"_err_en_US
,
1059 symbol
.name(), iter
.BuildResultDesignatorName());
1062 } else if (attr
== common::CUDADataAttr::Constant
||
1063 attr
== common::CUDADataAttr::Shared
) {
1065 "Derived type component '%s' may not have ATTRIBUTES(%s)"_err_en_US
,
1067 parser::ToUpperCaseLetters(common::EnumToString(attr
)));
1069 } else if (!subpDetails
&& symbol
.owner().kind() != Scope::Kind::Module
&&
1070 symbol
.owner().kind() != Scope::Kind::MainProgram
&&
1071 symbol
.owner().kind() != Scope::Kind::BlockConstruct
) {
1073 "ATTRIBUTES(%s) may apply only to module, host subprogram, block, or device subprogram data"_err_en_US
,
1074 parser::ToUpperCaseLetters(common::EnumToString(attr
)));
1078 if (derived
&& derived
->IsVectorType()) {
1080 std::string typeName
{type
->AsFortran()};
1081 if (IsAssumedShape(symbol
)) {
1082 SayWithDeclaration(symbol
,
1083 "Assumed-shape entity of %s type is not supported"_err_en_US
,
1085 } else if (IsDeferredShape(symbol
)) {
1086 SayWithDeclaration(symbol
,
1087 "Deferred-shape entity of %s type is not supported"_err_en_US
,
1089 } else if (evaluate::IsAssumedRank(symbol
)) {
1090 SayWithDeclaration(symbol
,
1091 "Assumed Rank entity of %s type is not supported"_err_en_US
,
1097 void CheckHelper::CheckPointerInitialization(const Symbol
&symbol
) {
1098 if (IsPointer(symbol
) && !context_
.HasError(symbol
) &&
1099 !scopeIsUninstantiatedPDT_
) {
1100 if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
1101 if (object
->init()) { // C764, C765; C808
1102 if (auto designator
{evaluate::AsGenericExpr(symbol
)}) {
1103 auto restorer
{messages_
.SetLocation(symbol
.name())};
1104 context_
.set_location(symbol
.name());
1105 CheckInitialDataPointerTarget(
1106 context_
, *designator
, *object
->init(), DEREF(scope_
));
1109 } else if (const auto *proc
{symbol
.detailsIf
<ProcEntityDetails
>()}) {
1110 if (proc
->init() && *proc
->init()) {
1111 // C1519 - must be nonelemental external or module procedure,
1112 // or an unrestricted specific intrinsic function.
1113 const Symbol
&local
{DEREF(*proc
->init())};
1114 const Symbol
&ultimate
{local
.GetUltimate()};
1115 bool checkTarget
{true};
1116 if (ultimate
.attrs().test(Attr::INTRINSIC
)) {
1117 if (auto intrinsic
{context_
.intrinsics().IsSpecificIntrinsicFunction(
1118 ultimate
.name().ToString())};
1119 !intrinsic
|| intrinsic
->isRestrictedSpecific
) { // C1030
1121 "Intrinsic procedure '%s' is not an unrestricted specific "
1122 "intrinsic permitted for use as the initializer for procedure "
1123 "pointer '%s'"_err_en_US
,
1124 ultimate
.name(), symbol
.name());
1125 checkTarget
= false;
1127 } else if (!(ultimate
.attrs().test(Attr::EXTERNAL
) ||
1128 ultimate
.owner().kind() == Scope::Kind::Module
||
1129 ultimate
.owner().IsTopLevel()) ||
1130 IsDummy(ultimate
) || IsPointer(ultimate
)) {
1132 "Procedure pointer '%s' initializer '%s' is neither an external nor a module procedure"_err_en_US
,
1133 symbol
.name(), ultimate
.name());
1134 checkTarget
= false;
1135 } else if (IsElementalProcedure(ultimate
)) {
1136 context_
.Say("Procedure pointer '%s' cannot be initialized with the "
1137 "elemental procedure '%s'"_err_en_US
,
1138 symbol
.name(), ultimate
.name());
1139 checkTarget
= false;
1142 SomeExpr lhs
{evaluate::ProcedureDesignator
{symbol
}};
1143 SomeExpr rhs
{evaluate::ProcedureDesignator
{**proc
->init()}};
1144 CheckPointerAssignment(context_
, lhs
, rhs
,
1145 GetProgramUnitOrBlockConstructContaining(symbol
),
1146 /*isBoundsRemapping=*/false, /*isAssumedRank=*/false);
1153 // The six different kinds of array-specs:
1154 // array-spec -> explicit-shape-list | deferred-shape-list
1155 // | assumed-shape-list | implied-shape-list
1156 // | assumed-size | assumed-rank
1157 // explicit-shape -> [ lb : ] ub
1158 // deferred-shape -> :
1159 // assumed-shape -> [ lb ] :
1160 // implied-shape -> [ lb : ] *
1161 // assumed-size -> [ explicit-shape-list , ] [ lb : ] *
1162 // assumed-rank -> ..
1164 // - deferred-shape is also an assumed-shape
1165 // - A single "*" or "lb:*" might be assumed-size or implied-shape-list
1166 void CheckHelper::CheckArraySpec(
1167 const Symbol
&symbol
, const ArraySpec
&arraySpec
) {
1168 if (arraySpec
.Rank() == 0) {
1171 bool isExplicit
{arraySpec
.IsExplicitShape()};
1172 bool canBeDeferred
{arraySpec
.CanBeDeferredShape()};
1173 bool canBeImplied
{arraySpec
.CanBeImpliedShape()};
1174 bool canBeAssumedShape
{arraySpec
.CanBeAssumedShape()};
1175 bool canBeAssumedSize
{arraySpec
.CanBeAssumedSize()};
1176 bool isAssumedRank
{arraySpec
.IsAssumedRank()};
1178 GetCUDADataAttr(&symbol
).value_or(common::CUDADataAttr::Device
) ==
1179 common::CUDADataAttr::Shared
};
1180 bool isCrayPointee
{symbol
.test(Symbol::Flag::CrayPointee
)};
1181 std::optional
<parser::MessageFixedText
> msg
;
1182 if (isCrayPointee
&& !isExplicit
&& !canBeAssumedSize
) {
1184 "Cray pointee '%s' must have explicit shape or assumed size"_err_en_US
;
1185 } else if (IsAllocatableOrPointer(symbol
) && !canBeDeferred
&&
1187 if (symbol
.owner().IsDerivedType()) { // C745
1188 if (IsAllocatable(symbol
)) {
1189 msg
= "Allocatable array component '%s' must have"
1190 " deferred shape"_err_en_US
;
1192 msg
= "Array pointer component '%s' must have deferred shape"_err_en_US
;
1195 if (IsAllocatable(symbol
)) { // C832
1196 msg
= "Allocatable array '%s' must have deferred shape or"
1197 " assumed rank"_err_en_US
;
1199 msg
= "Array pointer '%s' must have deferred shape or"
1200 " assumed rank"_err_en_US
;
1203 } else if (IsDummy(symbol
)) {
1204 if (canBeImplied
&& !canBeAssumedSize
) { // C836
1205 msg
= "Dummy array argument '%s' may not have implied shape"_err_en_US
;
1207 } else if (canBeAssumedShape
&& !canBeDeferred
) {
1208 msg
= "Assumed-shape array '%s' must be a dummy argument"_err_en_US
;
1209 } else if (isAssumedRank
) { // C837
1210 msg
= "Assumed-rank array '%s' must be a dummy argument"_err_en_US
;
1211 } else if (canBeAssumedSize
&& !canBeImplied
&& !isCUDAShared
&&
1212 !isCrayPointee
) { // C833
1213 msg
= "Assumed-size array '%s' must be a dummy argument"_err_en_US
;
1214 } else if (canBeImplied
) {
1215 if (!IsNamedConstant(symbol
) && !isCUDAShared
&&
1216 !isCrayPointee
) { // C835, C836
1217 msg
= "Implied-shape array '%s' must be a named constant or a "
1218 "dummy argument"_err_en_US
;
1220 } else if (IsNamedConstant(symbol
)) {
1221 if (!isExplicit
&& !canBeImplied
) {
1222 msg
= "Named constant '%s' array must have constant or"
1223 " implied shape"_err_en_US
;
1225 } else if (!isExplicit
&&
1226 !(IsAllocatableOrPointer(symbol
) || isCrayPointee
)) {
1227 if (symbol
.owner().IsDerivedType()) { // C749
1228 msg
= "Component array '%s' without ALLOCATABLE or POINTER attribute must"
1229 " have explicit shape"_err_en_US
;
1231 msg
= "Array '%s' without ALLOCATABLE or POINTER attribute must have"
1232 " explicit shape"_err_en_US
;
1236 context_
.Say(std::move(*msg
), symbol
.name());
1240 void CheckHelper::CheckProcEntity(
1241 const Symbol
&symbol
, const ProcEntityDetails
&details
) {
1242 CheckSymbolType(symbol
);
1243 const Symbol
*interface
{details
.procInterface()};
1244 if (details
.isDummy()) {
1245 if (!symbol
.attrs().test(Attr::POINTER
) && // C843
1246 symbol
.attrs().HasAny(
1247 {Attr::INTENT_IN
, Attr::INTENT_OUT
, Attr::INTENT_INOUT
})) {
1248 messages_
.Say("A dummy procedure without the POINTER attribute"
1249 " may not have an INTENT attribute"_err_en_US
);
1251 if (InElemental()) { // C15100
1253 "An ELEMENTAL subprogram may not have a dummy procedure"_err_en_US
);
1255 if (interface
&& IsElementalProcedure(*interface
)) {
1256 // There's no explicit constraint or "shall" that we can find in the
1257 // standard for this check, but it seems to be implied in multiple
1258 // sites, and ELEMENTAL non-intrinsic actual arguments *are*
1259 // explicitly forbidden. But we allow "PROCEDURE(SIN)::dummy"
1260 // because it is explicitly legal to *pass* the specific intrinsic
1261 // function SIN as an actual argument.
1262 if (interface
->attrs().test(Attr::INTRINSIC
)) {
1263 Warn(common::UsageWarning::Portability
,
1264 "A dummy procedure should not have an ELEMENTAL intrinsic as its interface"_port_en_US
);
1266 messages_
.Say("A dummy procedure may not be ELEMENTAL"_err_en_US
);
1269 } else if (IsPointer(symbol
)) {
1270 CheckPointerInitialization(symbol
);
1272 if (interface
->attrs().test(Attr::INTRINSIC
)) {
1273 auto intrinsic
{context_
.intrinsics().IsSpecificIntrinsicFunction(
1274 interface
->name().ToString())};
1275 if (!intrinsic
|| intrinsic
->isRestrictedSpecific
) { // C1515
1277 "Intrinsic procedure '%s' is not an unrestricted specific "
1278 "intrinsic permitted for use as the definition of the interface "
1279 "to procedure pointer '%s'"_err_en_US
,
1280 interface
->name(), symbol
.name());
1281 } else if (IsElementalProcedure(*interface
)) {
1282 Warn(common::UsageWarning::Portability
,
1283 "Procedure pointer '%s' should not have an ELEMENTAL intrinsic as its interface"_port_en_US
,
1284 symbol
.name()); // C1517
1286 } else if (IsElementalProcedure(*interface
)) {
1287 messages_
.Say("Procedure pointer '%s' may not be ELEMENTAL"_err_en_US
,
1288 symbol
.name()); // C1517
1291 if (symbol
.owner().IsDerivedType()) {
1292 CheckPassArg(symbol
, interface
, details
);
1294 } else if (symbol
.owner().IsDerivedType()) {
1295 const auto &name
{symbol
.name()};
1297 "Procedure component '%s' must have POINTER attribute"_err_en_US
, name
);
1299 CheckExternal(symbol
);
1302 // When a module subprogram has the MODULE prefix the following must match
1303 // with the corresponding separate module procedure interface body:
1304 // - C1549: characteristics and dummy argument names
1305 // - C1550: binding label
1306 // - C1551: NON_RECURSIVE prefix
1307 class SubprogramMatchHelper
{
1309 explicit SubprogramMatchHelper(CheckHelper
&checkHelper
)
1310 : checkHelper
{checkHelper
} {}
1312 void Check(const Symbol
&, const Symbol
&);
1315 SemanticsContext
&context() { return checkHelper
.context(); }
1316 void CheckDummyArg(const Symbol
&, const Symbol
&, const DummyArgument
&,
1317 const DummyArgument
&);
1318 void CheckDummyDataObject(const Symbol
&, const Symbol
&,
1319 const DummyDataObject
&, const DummyDataObject
&);
1320 void CheckDummyProcedure(const Symbol
&, const Symbol
&,
1321 const DummyProcedure
&, const DummyProcedure
&);
1322 bool CheckSameIntent(
1323 const Symbol
&, const Symbol
&, common::Intent
, common::Intent
);
1324 template <typename
... A
>
1326 const Symbol
&, const Symbol
&, parser::MessageFixedText
&&, A
&&...);
1327 template <typename ATTRS
>
1328 bool CheckSameAttrs(const Symbol
&, const Symbol
&, ATTRS
, ATTRS
);
1329 bool ShapesAreCompatible(const DummyDataObject
&, const DummyDataObject
&);
1330 evaluate::Shape
FoldShape(const evaluate::Shape
&);
1331 std::optional
<evaluate::Shape
> FoldShape(
1332 const std::optional
<evaluate::Shape
> &shape
) {
1334 return FoldShape(*shape
);
1336 return std::nullopt
;
1338 std::string
AsFortran(DummyDataObject::Attr attr
) {
1339 return parser::ToUpperCaseLetters(DummyDataObject::EnumToString(attr
));
1341 std::string
AsFortran(DummyProcedure::Attr attr
) {
1342 return parser::ToUpperCaseLetters(DummyProcedure::EnumToString(attr
));
1345 CheckHelper
&checkHelper
;
1348 // 15.6.2.6 para 3 - can the result of an ENTRY differ from its function?
1349 bool CheckHelper::IsResultOkToDiffer(const FunctionResult
&result
) {
1350 if (result
.attrs
.test(FunctionResult::Attr::Allocatable
) ||
1351 result
.attrs
.test(FunctionResult::Attr::Pointer
)) {
1354 const auto *typeAndShape
{result
.GetTypeAndShape()};
1355 if (!typeAndShape
|| typeAndShape
->Rank() != 0) {
1358 auto category
{typeAndShape
->type().category()};
1359 if (category
== TypeCategory::Character
||
1360 category
== TypeCategory::Derived
) {
1363 int kind
{typeAndShape
->type().kind()};
1364 return kind
== context_
.GetDefaultKind(category
) ||
1365 (category
== TypeCategory::Real
&&
1366 kind
== context_
.doublePrecisionKind());
1369 void CheckHelper::CheckSubprogram(
1370 const Symbol
&symbol
, const SubprogramDetails
&details
) {
1371 // Evaluate a procedure definition's characteristics to flush out
1372 // any errors that analysis might expose, in case this subprogram hasn't
1373 // had any calls in this compilation unit that would have validated them.
1374 if (!context_
.HasError(symbol
) && !details
.isDummy() &&
1375 !details
.isInterface() && !details
.stmtFunction()) {
1376 if (!Procedure::Characterize(symbol
, foldingContext_
)) {
1377 context_
.SetError(symbol
);
1380 if (const Symbol
*iface
{FindSeparateModuleSubprogramInterface(&symbol
)}) {
1381 SubprogramMatchHelper
{*this}.Check(symbol
, *iface
);
1383 if (const Scope
*entryScope
{details
.entryScope()}) {
1384 // ENTRY F'2023 15.6.2.6
1385 std::optional
<parser::MessageFixedText
> error
;
1386 const Symbol
*subprogram
{entryScope
->symbol()};
1387 const SubprogramDetails
*subprogramDetails
{nullptr};
1389 subprogramDetails
= subprogram
->detailsIf
<SubprogramDetails
>();
1391 if (!(entryScope
->parent().IsGlobal() || entryScope
->parent().IsModule() ||
1392 entryScope
->parent().IsSubmodule())) {
1393 error
= "ENTRY may not appear in an internal subprogram"_err_en_US
;
1394 } else if (subprogramDetails
&& details
.isFunction() &&
1395 subprogramDetails
->isFunction() &&
1396 !context_
.HasError(details
.result()) &&
1397 !context_
.HasError(subprogramDetails
->result())) {
1398 auto result
{FunctionResult::Characterize(
1399 details
.result(), context_
.foldingContext())};
1400 auto subpResult
{FunctionResult::Characterize(
1401 subprogramDetails
->result(), context_
.foldingContext())};
1402 if (result
&& subpResult
&& *result
!= *subpResult
&&
1403 (!IsResultOkToDiffer(*result
) || !IsResultOkToDiffer(*subpResult
))) {
1405 "Result of ENTRY is not compatible with result of containing function"_err_en_US
;
1409 if (auto *msg
{messages_
.Say(symbol
.name(), *error
)}) {
1411 msg
->Attach(subprogram
->name(), "Containing subprogram"_en_US
);
1416 if (details
.isFunction() &&
1417 details
.result().name() != symbol
.name()) { // F'2023 C1569 & C1583
1418 if (auto iter
{symbol
.owner().find(details
.result().name())};
1419 iter
!= symbol
.owner().end()) {
1420 const Symbol
&resNameSym
{*iter
->second
};
1421 if (const auto *resNameSubp
{resNameSym
.detailsIf
<SubprogramDetails
>()}) {
1422 if (const Scope
* resNameEntryScope
{resNameSubp
->entryScope()}) {
1423 const Scope
*myScope
{
1424 details
.entryScope() ? details
.entryScope() : symbol
.scope()};
1425 if (resNameEntryScope
== myScope
) {
1426 if (auto *msg
{messages_
.Say(symbol
.name(),
1427 "Explicit RESULT('%s') of function '%s' cannot have the same name as a distinct ENTRY into the same scope"_err_en_US
,
1428 details
.result().name(), symbol
.name())}) {
1430 resNameSym
.name(), "ENTRY with conflicting name"_en_US
);
1437 if (const MaybeExpr
& stmtFunction
{details
.stmtFunction()}) {
1438 if (auto msg
{evaluate::CheckStatementFunction(
1439 symbol
, *stmtFunction
, context_
.foldingContext())}) {
1440 SayWithDeclaration(symbol
, std::move(*msg
));
1441 } else if (IsPointer(symbol
)) {
1442 SayWithDeclaration(symbol
,
1443 "A statement function must not have the POINTER attribute"_err_en_US
);
1444 } else if (details
.result().flags().test(Symbol::Flag::Implicit
)) {
1445 // 15.6.4 p2 weird requirement
1447 host
{symbol
.owner().parent().FindSymbol(symbol
.name())}) {
1448 evaluate::AttachDeclaration(
1449 Warn(common::LanguageFeature::StatementFunctionExtensions
,
1451 "An implicitly typed statement function should not appear when the same symbol is available in its host scope"_port_en_US
),
1455 if (GetProgramUnitOrBlockConstructContaining(symbol
).kind() ==
1456 Scope::Kind::BlockConstruct
) { // C1107
1457 messages_
.Say(symbol
.name(),
1458 "A statement function definition may not appear in a BLOCK construct"_err_en_US
);
1461 if (IsElementalProcedure(symbol
)) {
1462 // See comment on the similar check in CheckProcEntity()
1463 if (details
.isDummy()) {
1464 messages_
.Say("A dummy procedure may not be ELEMENTAL"_err_en_US
);
1466 for (const Symbol
*dummy
: details
.dummyArgs()) {
1467 if (!dummy
) { // C15100
1469 "An ELEMENTAL subroutine may not have an alternate return dummy argument"_err_en_US
);
1474 if (details
.isInterface()) {
1475 if (!details
.isDummy() && details
.isFunction() &&
1476 IsAssumedLengthCharacter(details
.result())) { // C721
1477 messages_
.Say(details
.result().name(),
1478 "A function interface may not declare an assumed-length CHARACTER(*) result"_err_en_US
);
1481 CheckExternal(symbol
);
1482 CheckModuleProcedureDef(symbol
);
1483 auto cudaAttrs
{details
.cudaSubprogramAttrs()};
1485 (*cudaAttrs
== common::CUDASubprogramAttrs::Global
||
1486 *cudaAttrs
== common::CUDASubprogramAttrs::Grid_Global
) &&
1487 details
.isFunction()) {
1488 messages_
.Say(symbol
.name(),
1489 "A function may not have ATTRIBUTES(GLOBAL) or ATTRIBUTES(GRID_GLOBAL)"_err_en_US
);
1492 (*cudaAttrs
== common::CUDASubprogramAttrs::Global
||
1493 *cudaAttrs
== common::CUDASubprogramAttrs::Grid_Global
) &&
1494 symbol
.attrs().HasAny({Attr::RECURSIVE
, Attr::PURE
, Attr::ELEMENTAL
})) {
1495 messages_
.Say(symbol
.name(),
1496 "A kernel subprogram may not be RECURSIVE, PURE, or ELEMENTAL"_err_en_US
);
1498 if (cudaAttrs
&& *cudaAttrs
!= common::CUDASubprogramAttrs::Host
) {
1499 // CUDA device subprogram checks
1500 if (ClassifyProcedure(symbol
) == ProcedureDefinitionClass::Internal
) {
1501 messages_
.Say(symbol
.name(),
1502 "A device subprogram may not be an internal subprogram"_err_en_US
);
1505 if ((!details
.cudaLaunchBounds().empty() ||
1506 !details
.cudaClusterDims().empty()) &&
1508 (*cudaAttrs
== common::CUDASubprogramAttrs::Global
||
1509 *cudaAttrs
== common::CUDASubprogramAttrs::Grid_Global
))) {
1510 messages_
.Say(symbol
.name(),
1511 "A subroutine may not have LAUNCH_BOUNDS() or CLUSTER_DIMS() unless it has ATTRIBUTES(GLOBAL) or ATTRIBUTES(GRID_GLOBAL)"_err_en_US
);
1513 if (!IsStmtFunction(symbol
)) {
1514 if (const Scope
* outerDevice
{FindCUDADeviceContext(&symbol
.owner())};
1515 outerDevice
&& outerDevice
->symbol()) {
1516 if (auto *msg
{messages_
.Say(symbol
.name(),
1517 "'%s' may not be an internal procedure of CUDA device subprogram '%s'"_err_en_US
,
1518 symbol
.name(), outerDevice
->symbol()->name())}) {
1519 msg
->Attach(outerDevice
->symbol()->name(),
1520 "Containing CUDA device subprogram"_en_US
);
1526 void CheckHelper::CheckExternal(const Symbol
&symbol
) {
1527 if (IsExternal(symbol
)) {
1528 std::string interfaceName
{symbol
.name().ToString()};
1529 if (const auto *bind
{symbol
.GetBindName()}) {
1530 interfaceName
= *bind
;
1532 if (const Symbol
* global
{FindGlobal(symbol
)};
1533 global
&& global
!= &symbol
) {
1534 std::string definitionName
{global
->name().ToString()};
1535 if (const auto *bind
{global
->GetBindName()}) {
1536 definitionName
= *bind
;
1538 if (interfaceName
== definitionName
) {
1539 parser::Message
*msg
{nullptr};
1540 if (!IsProcedure(*global
)) {
1541 if ((symbol
.flags().test(Symbol::Flag::Function
) ||
1542 symbol
.flags().test(Symbol::Flag::Subroutine
))) {
1543 msg
= Warn(common::UsageWarning::ExternalNameConflict
,
1544 "The global entity '%s' corresponding to the local procedure '%s' is not a callable subprogram"_warn_en_US
,
1545 global
->name(), symbol
.name());
1547 } else if (auto chars
{Characterize(symbol
)}) {
1548 if (auto globalChars
{Characterize(*global
)}) {
1549 if (chars
->HasExplicitInterface()) {
1551 if (!chars
->IsCompatibleWith(*globalChars
,
1552 /*ignoreImplicitVsExplicit=*/false, &whyNot
)) {
1553 msg
= Warn(common::UsageWarning::ExternalInterfaceMismatch
,
1554 "The global subprogram '%s' is not compatible with its local procedure declaration (%s)"_warn_en_US
,
1555 global
->name(), whyNot
);
1557 } else if (!globalChars
->CanBeCalledViaImplicitInterface()) {
1558 // TODO: This should be a hard error if the procedure has
1559 // actually been called (as opposed to just being used as a
1560 // procedure pointer target or passed as an actual argument).
1561 msg
= Warn(common::UsageWarning::ExternalInterfaceMismatch
,
1562 "The global subprogram '%s' should not be referenced via the implicit interface '%s'"_warn_en_US
,
1563 global
->name(), symbol
.name());
1568 if (msg
->IsFatal()) {
1569 context_
.SetError(symbol
);
1571 evaluate::AttachDeclaration(msg
, *global
);
1572 evaluate::AttachDeclaration(msg
, symbol
);
1575 } else if (auto iter
{externalNames_
.find(interfaceName
)};
1576 iter
!= externalNames_
.end()) {
1577 const Symbol
&previous
{*iter
->second
};
1578 if (auto chars
{Characterize(symbol
)}) {
1579 if (auto previousChars
{Characterize(previous
)}) {
1581 if (!chars
->IsCompatibleWith(*previousChars
,
1582 /*ignoreImplicitVsExplicit=*/false, &whyNot
)) {
1583 if (auto *msg
{Warn(common::UsageWarning::ExternalInterfaceMismatch
,
1584 "The external interface '%s' is not compatible with an earlier definition (%s)"_warn_en_US
,
1585 symbol
.name(), whyNot
)}) {
1586 evaluate::AttachDeclaration(msg
, previous
);
1587 evaluate::AttachDeclaration(msg
, symbol
);
1593 externalNames_
.emplace(interfaceName
, symbol
);
1598 void CheckHelper::CheckDerivedType(
1599 const Symbol
&derivedType
, const DerivedTypeDetails
&details
) {
1600 if (details
.isForwardReferenced() && !context_
.HasError(derivedType
)) {
1601 messages_
.Say("The derived type '%s' has not been defined"_err_en_US
,
1602 derivedType
.name());
1604 const Scope
*scope
{derivedType
.scope()};
1606 CHECK(details
.isForwardReferenced());
1609 CHECK(scope
->symbol() == &derivedType
);
1610 CHECK(scope
->IsDerivedType());
1611 if (derivedType
.attrs().test(Attr::ABSTRACT
) && // C734
1612 (derivedType
.attrs().test(Attr::BIND_C
) || details
.sequence())) {
1613 messages_
.Say("An ABSTRACT derived type must be extensible"_err_en_US
);
1615 if (const DeclTypeSpec
*parent
{FindParentTypeSpec(derivedType
)}) {
1616 const DerivedTypeSpec
*parentDerived
{parent
->AsDerived()};
1617 if (!IsExtensibleType(parentDerived
)) { // C705
1618 messages_
.Say("The parent type is not extensible"_err_en_US
);
1620 if (!derivedType
.attrs().test(Attr::ABSTRACT
) && parentDerived
&&
1621 parentDerived
->typeSymbol().attrs().test(Attr::ABSTRACT
)) {
1622 ScopeComponentIterator components
{*parentDerived
};
1623 for (const Symbol
&component
: components
) {
1624 if (component
.attrs().test(Attr::DEFERRED
)) {
1625 if (scope
->FindComponent(component
.name()) == &component
) {
1626 SayWithDeclaration(component
,
1627 "Non-ABSTRACT extension of ABSTRACT derived type '%s' lacks a binding for DEFERRED procedure '%s'"_err_en_US
,
1628 parentDerived
->typeSymbol().name(), component
.name());
1633 DerivedTypeSpec derived
{derivedType
.name(), derivedType
};
1634 derived
.set_scope(*scope
);
1635 if (FindCoarrayUltimateComponent(derived
) && // C736
1636 !(parentDerived
&& FindCoarrayUltimateComponent(*parentDerived
))) {
1638 "Type '%s' has a coarray ultimate component so the type at the base "
1639 "of its type extension chain ('%s') must be a type that has a "
1640 "coarray ultimate component"_err_en_US
,
1641 derivedType
.name(), scope
->GetDerivedTypeBase().GetSymbol()->name());
1643 if (FindEventOrLockPotentialComponent(derived
) && // C737
1644 !(FindEventOrLockPotentialComponent(*parentDerived
) ||
1645 IsEventTypeOrLockType(parentDerived
))) {
1647 "Type '%s' has an EVENT_TYPE or LOCK_TYPE component, so the type "
1648 "at the base of its type extension chain ('%s') must either have an "
1649 "EVENT_TYPE or LOCK_TYPE component, or be EVENT_TYPE or "
1650 "LOCK_TYPE"_err_en_US
,
1651 derivedType
.name(), scope
->GetDerivedTypeBase().GetSymbol()->name());
1654 if (HasIntrinsicTypeName(derivedType
)) { // C729
1655 messages_
.Say("A derived type name cannot be the name of an intrinsic"
1658 std::map
<SourceName
, SymbolRef
> previous
;
1659 for (const auto &pair
: details
.finals()) {
1660 SourceName source
{pair
.first
};
1661 const Symbol
&ref
{*pair
.second
};
1662 if (CheckFinal(ref
, source
, derivedType
) &&
1663 std::all_of(previous
.begin(), previous
.end(),
1664 [&](std::pair
<SourceName
, SymbolRef
> prev
) {
1665 return CheckDistinguishableFinals(
1666 ref
, source
, *prev
.second
, prev
.first
, derivedType
);
1668 previous
.emplace(source
, ref
);
1674 bool CheckHelper::CheckFinal(
1675 const Symbol
&subroutine
, SourceName finalName
, const Symbol
&derivedType
) {
1676 if (!IsModuleProcedure(subroutine
)) {
1677 SayWithDeclaration(subroutine
, finalName
,
1678 "FINAL subroutine '%s' of derived type '%s' must be a module procedure"_err_en_US
,
1679 subroutine
.name(), derivedType
.name());
1682 const Procedure
*proc
{Characterize(subroutine
)};
1684 return false; // error recovery
1686 if (!proc
->IsSubroutine()) {
1687 SayWithDeclaration(subroutine
, finalName
,
1688 "FINAL subroutine '%s' of derived type '%s' must be a subroutine"_err_en_US
,
1689 subroutine
.name(), derivedType
.name());
1692 if (proc
->dummyArguments
.size() != 1) {
1693 SayWithDeclaration(subroutine
, finalName
,
1694 "FINAL subroutine '%s' of derived type '%s' must have a single dummy argument"_err_en_US
,
1695 subroutine
.name(), derivedType
.name());
1698 const auto &arg
{proc
->dummyArguments
[0]};
1699 const Symbol
*errSym
{&subroutine
};
1700 if (const auto *details
{subroutine
.detailsIf
<SubprogramDetails
>()}) {
1701 if (!details
->dummyArgs().empty()) {
1702 if (const Symbol
*argSym
{details
->dummyArgs()[0]}) {
1707 const auto *ddo
{std::get_if
<DummyDataObject
>(&arg
.u
)};
1709 SayWithDeclaration(subroutine
, finalName
,
1710 "FINAL subroutine '%s' of derived type '%s' must have a single dummy argument that is a data object"_err_en_US
,
1711 subroutine
.name(), derivedType
.name());
1715 if (arg
.IsOptional()) {
1716 SayWithDeclaration(*errSym
, finalName
,
1717 "FINAL subroutine '%s' of derived type '%s' must not have an OPTIONAL dummy argument"_err_en_US
,
1718 subroutine
.name(), derivedType
.name());
1721 if (ddo
->attrs
.test(DummyDataObject::Attr::Allocatable
)) {
1722 SayWithDeclaration(*errSym
, finalName
,
1723 "FINAL subroutine '%s' of derived type '%s' must not have an ALLOCATABLE dummy argument"_err_en_US
,
1724 subroutine
.name(), derivedType
.name());
1727 if (ddo
->attrs
.test(DummyDataObject::Attr::Pointer
)) {
1728 SayWithDeclaration(*errSym
, finalName
,
1729 "FINAL subroutine '%s' of derived type '%s' must not have a POINTER dummy argument"_err_en_US
,
1730 subroutine
.name(), derivedType
.name());
1733 if (ddo
->intent
== common::Intent::Out
) {
1734 SayWithDeclaration(*errSym
, finalName
,
1735 "FINAL subroutine '%s' of derived type '%s' must not have a dummy argument with INTENT(OUT)"_err_en_US
,
1736 subroutine
.name(), derivedType
.name());
1739 if (ddo
->attrs
.test(DummyDataObject::Attr::Value
)) {
1740 SayWithDeclaration(*errSym
, finalName
,
1741 "FINAL subroutine '%s' of derived type '%s' must not have a dummy argument with the VALUE attribute"_err_en_US
,
1742 subroutine
.name(), derivedType
.name());
1745 if (ddo
->type
.corank() > 0) {
1746 SayWithDeclaration(*errSym
, finalName
,
1747 "FINAL subroutine '%s' of derived type '%s' must not have a coarray dummy argument"_err_en_US
,
1748 subroutine
.name(), derivedType
.name());
1751 if (ddo
->type
.type().IsPolymorphic()) {
1752 SayWithDeclaration(*errSym
, finalName
,
1753 "FINAL subroutine '%s' of derived type '%s' must not have a polymorphic dummy argument"_err_en_US
,
1754 subroutine
.name(), derivedType
.name());
1756 } else if (ddo
->type
.type().category() != TypeCategory::Derived
||
1757 &ddo
->type
.type().GetDerivedTypeSpec().typeSymbol() != &derivedType
) {
1758 SayWithDeclaration(*errSym
, finalName
,
1759 "FINAL subroutine '%s' of derived type '%s' must have a TYPE(%s) dummy argument"_err_en_US
,
1760 subroutine
.name(), derivedType
.name(), derivedType
.name());
1762 } else { // check that all LEN type parameters are assumed
1763 for (auto ref
: OrderParameterDeclarations(derivedType
)) {
1764 if (IsLenTypeParameter(*ref
)) {
1766 ddo
->type
.type().GetDerivedTypeSpec().FindParameter(ref
->name())};
1767 if (!value
|| !value
->isAssumed()) {
1768 SayWithDeclaration(*errSym
, finalName
,
1769 "FINAL subroutine '%s' of derived type '%s' must have a dummy argument with an assumed LEN type parameter '%s=*'"_err_en_US
,
1770 subroutine
.name(), derivedType
.name(), ref
->name());
1779 bool CheckHelper::CheckDistinguishableFinals(const Symbol
&f1
,
1780 SourceName f1Name
, const Symbol
&f2
, SourceName f2Name
,
1781 const Symbol
&derivedType
) {
1782 const Procedure
*p1
{Characterize(f1
)};
1783 const Procedure
*p2
{Characterize(f2
)};
1785 std::optional
<bool> areDistinct
{characteristics::Distinguishable(
1786 context_
.languageFeatures(), *p1
, *p2
)};
1787 if (areDistinct
.value_or(false)) {
1790 if (auto *msg
{messages_
.Say(f1Name
,
1791 "FINAL subroutines '%s' and '%s' of derived type '%s' cannot be distinguished by rank or KIND type parameter value"_err_en_US
,
1792 f1Name
, f2Name
, derivedType
.name())}) {
1793 msg
->Attach(f2Name
, "FINAL declaration of '%s'"_en_US
, f2
.name())
1794 .Attach(f1
.name(), "Definition of '%s'"_en_US
, f1Name
)
1795 .Attach(f2
.name(), "Definition of '%s'"_en_US
, f2Name
);
1801 void CheckHelper::CheckHostAssoc(
1802 const Symbol
&symbol
, const HostAssocDetails
&details
) {
1803 const Symbol
&hostSymbol
{details
.symbol()};
1804 if (hostSymbol
.test(Symbol::Flag::ImplicitOrError
)) {
1805 if (details
.implicitOrSpecExprError
) {
1806 messages_
.Say("Implicitly typed local entity '%s' not allowed in"
1807 " specification expression"_err_en_US
,
1809 } else if (details
.implicitOrExplicitTypeError
) {
1811 "No explicit type declared for '%s'"_err_en_US
, symbol
.name());
1816 void CheckHelper::CheckGeneric(
1817 const Symbol
&symbol
, const GenericDetails
&details
) {
1818 CheckSpecifics(symbol
, details
);
1819 common::visit(common::visitors
{
1820 [&](const common::DefinedIo
&io
) {
1821 CheckDefinedIoProc(symbol
, details
, io
);
1823 [&](const GenericKind::OtherKind
&other
) {
1824 if (other
== GenericKind::OtherKind::Name
) {
1825 CheckGenericVsIntrinsic(symbol
, details
);
1828 [](const auto &) {},
1831 // Ensure that shadowed symbols are checked
1832 if (details
.specific()) {
1833 Check(*details
.specific());
1835 if (details
.derivedType()) {
1836 Check(*details
.derivedType());
1840 // Check that the specifics of this generic are distinguishable from each other
1841 void CheckHelper::CheckSpecifics(
1842 const Symbol
&generic
, const GenericDetails
&details
) {
1843 GenericKind kind
{details
.kind()};
1844 DistinguishabilityHelper helper
{context_
};
1845 for (const Symbol
&specific
: details
.specificProcs()) {
1846 if (specific
.attrs().test(Attr::ABSTRACT
)) {
1847 if (auto *msg
{messages_
.Say(generic
.name(),
1848 "Generic interface '%s' must not use abstract interface '%s' as a specific procedure"_err_en_US
,
1849 generic
.name(), specific
.name())}) {
1851 specific
.name(), "Definition of '%s'"_en_US
, specific
.name());
1855 if (specific
.attrs().test(Attr::INTRINSIC
)) {
1856 // GNU Fortran allows INTRINSIC procedures in generics.
1857 auto intrinsic
{context_
.intrinsics().IsSpecificIntrinsicFunction(
1858 specific
.name().ToString())};
1859 if (intrinsic
&& !intrinsic
->isRestrictedSpecific
) {
1860 if (auto *msg
{Warn(common::LanguageFeature::IntrinsicAsSpecific
,
1862 "Specific procedure '%s' of generic interface '%s' should not be INTRINSIC"_port_en_US
,
1863 specific
.name(), generic
.name())}) {
1865 generic
.name(), "Definition of '%s'"_en_US
, generic
.name());
1868 if (auto *msg
{Warn(common::LanguageFeature::IntrinsicAsSpecific
,
1870 "Procedure '%s' of generic interface '%s' is INTRINSIC but not an unrestricted specific intrinsic function"_port_en_US
,
1871 specific
.name(), generic
.name())}) {
1873 generic
.name(), "Definition of '%s'"_en_US
, generic
.name());
1878 if (IsStmtFunction(specific
)) {
1879 if (auto *msg
{messages_
.Say(specific
.name(),
1880 "Specific procedure '%s' of generic interface '%s' may not be a statement function"_err_en_US
,
1881 specific
.name(), generic
.name())}) {
1882 msg
->Attach(generic
.name(), "Definition of '%s'"_en_US
, generic
.name());
1886 if (const Procedure
*procedure
{Characterize(specific
)}) {
1887 if (procedure
->HasExplicitInterface()) {
1888 helper
.Add(generic
, kind
, specific
, *procedure
);
1890 if (auto *msg
{messages_
.Say(specific
.name(),
1891 "Specific procedure '%s' of generic interface '%s' must have an explicit interface"_err_en_US
,
1892 specific
.name(), generic
.name())}) {
1894 generic
.name(), "Definition of '%s'"_en_US
, generic
.name());
1899 helper
.Check(generic
.owner());
1902 static bool CUDAHostDeviceDiffer(
1903 const Procedure
&proc
, const DummyDataObject
&arg
) {
1905 proc
.cudaSubprogramAttrs
.value_or(common::CUDASubprogramAttrs::Host
)};
1906 bool procIsHostOnly
{procCUDA
== common::CUDASubprogramAttrs::Host
};
1907 bool procIsDeviceOnly
{
1908 !procIsHostOnly
&& procCUDA
!= common::CUDASubprogramAttrs::HostDevice
};
1909 const auto &argCUDA
{arg
.cudaDataAttr
};
1910 bool argIsHostOnly
{!argCUDA
|| *argCUDA
== common::CUDADataAttr::Pinned
};
1911 bool argIsDeviceOnly
{(!argCUDA
&& procIsDeviceOnly
) ||
1913 (*argCUDA
!= common::CUDADataAttr::Managed
&&
1914 *argCUDA
!= common::CUDADataAttr::Pinned
&&
1915 *argCUDA
!= common::CUDADataAttr::Unified
))};
1916 return (procIsHostOnly
&& argIsDeviceOnly
) ||
1917 (procIsDeviceOnly
&& argIsHostOnly
);
1920 static bool ConflictsWithIntrinsicAssignment(const Procedure
&proc
) {
1921 const auto &lhsData
{std::get
<DummyDataObject
>(proc
.dummyArguments
[0].u
)};
1922 const auto &lhsTnS
{lhsData
.type
};
1923 const auto &rhsData
{std::get
<DummyDataObject
>(proc
.dummyArguments
[1].u
)};
1924 const auto &rhsTnS
{rhsData
.type
};
1925 return !CUDAHostDeviceDiffer(proc
, lhsData
) &&
1926 !CUDAHostDeviceDiffer(proc
, rhsData
) &&
1928 IsDefinedAssignment(
1929 lhsTnS
.type(), lhsTnS
.Rank(), rhsTnS
.type(), rhsTnS
.Rank());
1932 static bool ConflictsWithIntrinsicOperator(
1933 const GenericKind
&kind
, const Procedure
&proc
) {
1934 if (!kind
.IsIntrinsicOperator()) {
1937 const auto &arg0Data
{std::get
<DummyDataObject
>(proc
.dummyArguments
[0].u
)};
1938 if (CUDAHostDeviceDiffer(proc
, arg0Data
)) {
1941 const auto &arg0TnS
{arg0Data
.type
};
1942 auto type0
{arg0TnS
.type()};
1943 if (proc
.dummyArguments
.size() == 1) { // unary
1944 return common::visit(
1946 [&](common::NumericOperator
) { return IsIntrinsicNumeric(type0
); },
1947 [&](common::LogicalOperator
) { return IsIntrinsicLogical(type0
); },
1948 [](const auto &) -> bool { DIE("bad generic kind"); },
1952 int rank0
{arg0TnS
.Rank()};
1953 const auto &arg1Data
{std::get
<DummyDataObject
>(proc
.dummyArguments
[1].u
)};
1954 if (CUDAHostDeviceDiffer(proc
, arg1Data
)) {
1957 const auto &arg1TnS
{arg1Data
.type
};
1958 auto type1
{arg1TnS
.type()};
1959 int rank1
{arg1TnS
.Rank()};
1960 return common::visit(
1962 [&](common::NumericOperator
) {
1963 return IsIntrinsicNumeric(type0
, rank0
, type1
, rank1
);
1965 [&](common::LogicalOperator
) {
1966 return IsIntrinsicLogical(type0
, rank0
, type1
, rank1
);
1968 [&](common::RelationalOperator opr
) {
1969 return IsIntrinsicRelational(opr
, type0
, rank0
, type1
, rank1
);
1971 [&](GenericKind::OtherKind x
) {
1972 CHECK(x
== GenericKind::OtherKind::Concat
);
1973 return IsIntrinsicConcat(type0
, rank0
, type1
, rank1
);
1975 [](const auto &) -> bool { DIE("bad generic kind"); },
1981 // Check if this procedure can be used for defined operators (see 15.4.3.4.2).
1982 bool CheckHelper::CheckDefinedOperator(SourceName opName
, GenericKind kind
,
1983 const Symbol
&specific
, const Procedure
&proc
) {
1984 if (context_
.HasError(specific
)) {
1987 std::optional
<parser::MessageFixedText
> msg
;
1988 auto checkDefinedOperatorArgs
{
1989 [&](SourceName opName
, const Symbol
&specific
, const Procedure
&proc
) {
1990 bool arg0Defined
{CheckDefinedOperatorArg(opName
, specific
, proc
, 0)};
1991 bool arg1Defined
{CheckDefinedOperatorArg(opName
, specific
, proc
, 1)};
1992 return arg0Defined
&& arg1Defined
;
1994 if (specific
.attrs().test(Attr::NOPASS
)) { // C774
1995 msg
= "%s procedure '%s' may not have NOPASS attribute"_err_en_US
;
1996 } else if (!proc
.functionResult
.has_value()) {
1997 msg
= "%s procedure '%s' must be a function"_err_en_US
;
1998 } else if (proc
.functionResult
->IsAssumedLengthCharacter()) {
1999 const auto *subpDetails
{specific
.detailsIf
<SubprogramDetails
>()};
2000 if (subpDetails
&& !subpDetails
->isDummy() && subpDetails
->isInterface()) {
2001 // Error is caught by more general test for interfaces with
2002 // assumed-length character function results
2005 msg
= "%s function '%s' may not have assumed-length CHARACTER(*)"
2006 " result"_err_en_US
;
2007 } else if (auto m
{CheckNumberOfArgs(kind
, proc
.dummyArguments
.size())}) {
2011 evaluate::AttachDeclaration(
2012 Warn(common::UsageWarning::DefinedOperatorArgs
, specific
.name(),
2013 std::move(*m
), MakeOpName(opName
), specific
.name()),
2017 } else if (!checkDefinedOperatorArgs(opName
, specific
, proc
)) {
2018 return false; // error was reported
2019 } else if (ConflictsWithIntrinsicOperator(kind
, proc
)) {
2020 msg
= "%s function '%s' conflicts with intrinsic operator"_err_en_US
;
2024 specific
, std::move(*msg
), MakeOpName(opName
), specific
.name());
2025 context_
.SetError(specific
);
2031 // If the number of arguments is wrong for this intrinsic operator, return
2032 // false and return the error message in msg.
2033 std::optional
<parser::MessageFixedText
> CheckHelper::CheckNumberOfArgs(
2034 const GenericKind
&kind
, std::size_t nargs
) {
2035 if (!kind
.IsIntrinsicOperator()) {
2036 if (nargs
< 1 || nargs
> 2) {
2037 if (context_
.ShouldWarn(common::UsageWarning::DefinedOperatorArgs
)) {
2038 return "%s function '%s' should have 1 or 2 dummy arguments"_warn_en_US
;
2041 return std::nullopt
;
2043 std::size_t min
{2}, max
{2}; // allowed number of args; default is binary
2044 common::visit(common::visitors
{
2045 [&](const common::NumericOperator
&x
) {
2046 if (x
== common::NumericOperator::Add
||
2047 x
== common::NumericOperator::Subtract
) {
2048 min
= 1; // + and - are unary or binary
2051 [&](const common::LogicalOperator
&x
) {
2052 if (x
== common::LogicalOperator::Not
) {
2053 min
= 1; // .NOT. is unary
2057 [](const common::RelationalOperator
&) {
2060 [](const GenericKind::OtherKind
&x
) {
2061 CHECK(x
== GenericKind::OtherKind::Concat
);
2063 [](const auto &) { DIE("expected intrinsic operator"); },
2066 if (nargs
>= min
&& nargs
<= max
) {
2067 return std::nullopt
;
2068 } else if (max
== 1) {
2069 return "%s function '%s' must have one dummy argument"_err_en_US
;
2070 } else if (min
== 2) {
2071 return "%s function '%s' must have two dummy arguments"_err_en_US
;
2073 return "%s function '%s' must have one or two dummy arguments"_err_en_US
;
2077 bool CheckHelper::CheckDefinedOperatorArg(const SourceName
&opName
,
2078 const Symbol
&symbol
, const Procedure
&proc
, std::size_t pos
) {
2079 if (pos
>= proc
.dummyArguments
.size()) {
2082 auto &arg
{proc
.dummyArguments
.at(pos
)};
2083 std::optional
<parser::MessageFixedText
> msg
;
2084 if (arg
.IsOptional()) {
2086 "In %s function '%s', dummy argument '%s' may not be OPTIONAL"_err_en_US
;
2087 } else if (const auto *dataObject
{std::get_if
<DummyDataObject
>(&arg
.u
)};
2088 dataObject
== nullptr) {
2090 "In %s function '%s', dummy argument '%s' must be a data object"_err_en_US
;
2091 } else if (dataObject
->intent
== common::Intent::Out
) {
2093 "In %s function '%s', dummy argument '%s' may not be INTENT(OUT)"_err_en_US
;
2094 } else if (dataObject
->intent
!= common::Intent::In
&&
2095 !dataObject
->attrs
.test(DummyDataObject::Attr::Value
)) {
2096 evaluate::AttachDeclaration(
2097 Warn(common::UsageWarning::DefinedOperatorArgs
,
2098 "In %s function '%s', dummy argument '%s' should have INTENT(IN) or VALUE attribute"_warn_en_US
,
2099 parser::ToUpperCaseLetters(opName
.ToString()), symbol
.name(),
2105 SayWithDeclaration(symbol
, std::move(*msg
),
2106 parser::ToUpperCaseLetters(opName
.ToString()), symbol
.name(), arg
.name
);
2112 // Check if this procedure can be used for defined assignment (see 15.4.3.4.3).
2113 bool CheckHelper::CheckDefinedAssignment(
2114 const Symbol
&specific
, const Procedure
&proc
) {
2115 if (context_
.HasError(specific
)) {
2118 std::optional
<parser::MessageFixedText
> msg
;
2119 if (specific
.attrs().test(Attr::NOPASS
)) { // C774
2120 msg
= "Defined assignment procedure '%s' may not have"
2121 " NOPASS attribute"_err_en_US
;
2122 } else if (!proc
.IsSubroutine()) {
2123 msg
= "Defined assignment procedure '%s' must be a subroutine"_err_en_US
;
2124 } else if (proc
.dummyArguments
.size() != 2) {
2125 msg
= "Defined assignment subroutine '%s' must have"
2126 " two dummy arguments"_err_en_US
;
2128 // Check both arguments even if the first has an error.
2129 bool ok0
{CheckDefinedAssignmentArg(specific
, proc
.dummyArguments
[0], 0)};
2130 bool ok1
{CheckDefinedAssignmentArg(specific
, proc
.dummyArguments
[1], 1)};
2131 if (!(ok0
&& ok1
)) {
2132 return false; // error was reported
2133 } else if (ConflictsWithIntrinsicAssignment(proc
)) {
2135 "Defined assignment subroutine '%s' conflicts with intrinsic assignment"_err_en_US
;
2140 SayWithDeclaration(specific
, std::move(msg
.value()), specific
.name());
2141 context_
.SetError(specific
);
2145 bool CheckHelper::CheckDefinedAssignmentArg(
2146 const Symbol
&symbol
, const DummyArgument
&arg
, int pos
) {
2147 std::optional
<parser::MessageFixedText
> msg
;
2148 if (arg
.IsOptional()) {
2149 msg
= "In defined assignment subroutine '%s', dummy argument '%s'"
2150 " may not be OPTIONAL"_err_en_US
;
2151 } else if (const auto *dataObject
{std::get_if
<DummyDataObject
>(&arg
.u
)}) {
2153 if (dataObject
->intent
== common::Intent::In
) {
2154 msg
= "In defined assignment subroutine '%s', first dummy argument '%s'"
2155 " may not have INTENT(IN)"_err_en_US
;
2156 } else if (dataObject
->intent
!= common::Intent::Out
&&
2157 dataObject
->intent
!= common::Intent::InOut
) {
2159 "In defined assignment subroutine '%s', first dummy argument '%s' should have INTENT(OUT) or INTENT(INOUT)"_warn_en_US
;
2161 } else if (pos
== 1) {
2162 if (dataObject
->intent
== common::Intent::Out
) {
2163 msg
= "In defined assignment subroutine '%s', second dummy"
2164 " argument '%s' may not have INTENT(OUT)"_err_en_US
;
2165 } else if (dataObject
->intent
!= common::Intent::In
&&
2166 !dataObject
->attrs
.test(DummyDataObject::Attr::Value
)) {
2168 "In defined assignment subroutine '%s', second dummy argument '%s' should have INTENT(IN) or VALUE attribute"_warn_en_US
;
2169 } else if (dataObject
->attrs
.test(DummyDataObject::Attr::Pointer
)) {
2171 "In defined assignment subroutine '%s', second dummy argument '%s' must not be a pointer"_err_en_US
;
2172 } else if (dataObject
->attrs
.test(DummyDataObject::Attr::Allocatable
)) {
2174 "In defined assignment subroutine '%s', second dummy argument '%s' must not be an allocatable"_err_en_US
;
2177 DIE("pos must be 0 or 1");
2180 msg
= "In defined assignment subroutine '%s', dummy argument '%s'"
2181 " must be a data object"_err_en_US
;
2184 if (msg
->IsFatal()) {
2185 SayWithDeclaration(symbol
, std::move(*msg
), symbol
.name(), arg
.name
);
2186 context_
.SetError(symbol
);
2189 evaluate::AttachDeclaration(
2190 Warn(common::UsageWarning::DefinedOperatorArgs
, std::move(*msg
),
2191 symbol
.name(), arg
.name
),
2198 // Report a conflicting attribute error if symbol has both of these attributes
2199 bool CheckHelper::CheckConflicting(const Symbol
&symbol
, Attr a1
, Attr a2
) {
2200 if (symbol
.attrs().test(a1
) && symbol
.attrs().test(a2
)) {
2201 messages_
.Say("'%s' may not have both the %s and %s attributes"_err_en_US
,
2202 symbol
.name(), AttrToString(a1
), AttrToString(a2
));
2209 void CheckHelper::WarnMissingFinal(const Symbol
&symbol
) {
2210 const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()};
2211 if (!object
|| object
->IsAssumedRank() ||
2212 (!IsAutomaticallyDestroyed(symbol
) &&
2213 symbol
.owner().kind() != Scope::Kind::DerivedType
)) {
2216 const DeclTypeSpec
*type
{object
->type()};
2217 const DerivedTypeSpec
*derived
{type
? type
->AsDerived() : nullptr};
2218 const Symbol
*derivedSym
{derived
? &derived
->typeSymbol() : nullptr};
2219 int rank
{object
->shape().Rank()};
2220 const Symbol
*initialDerivedSym
{derivedSym
};
2221 while (const auto *derivedDetails
{
2222 derivedSym
? derivedSym
->detailsIf
<DerivedTypeDetails
>() : nullptr}) {
2223 if (!derivedDetails
->finals().empty() &&
2224 !derivedDetails
->GetFinalForRank(rank
)) {
2225 if (auto *msg
{derivedSym
== initialDerivedSym
2226 ? Warn(common::UsageWarning::Final
, symbol
.name(),
2227 "'%s' of derived type '%s' does not have a FINAL subroutine for its rank (%d)"_warn_en_US
,
2228 symbol
.name(), derivedSym
->name(), rank
)
2229 : Warn(common::UsageWarning::Final
, symbol
.name(),
2230 "'%s' of derived type '%s' extended from '%s' does not have a FINAL subroutine for its rank (%d)"_warn_en_US
,
2231 symbol
.name(), initialDerivedSym
->name(),
2232 derivedSym
->name(), rank
)}) {
2233 msg
->Attach(derivedSym
->name(),
2234 "Declaration of derived type '%s'"_en_US
, derivedSym
->name());
2238 derived
= derivedSym
->GetParentTypeSpec();
2239 derivedSym
= derived
? &derived
->typeSymbol() : nullptr;
2243 const Procedure
*CheckHelper::Characterize(const Symbol
&symbol
) {
2244 auto it
{characterizeCache_
.find(symbol
)};
2245 if (it
== characterizeCache_
.end()) {
2246 auto pair
{characterizeCache_
.emplace(SymbolRef
{symbol
},
2247 Procedure::Characterize(symbol
, context_
.foldingContext()))};
2250 return common::GetPtrFromOptional(it
->second
);
2253 void CheckHelper::CheckVolatile(const Symbol
&symbol
,
2254 const DerivedTypeSpec
*derived
) { // C866 - C868
2255 if (IsIntentIn(symbol
)) {
2257 "VOLATILE attribute may not apply to an INTENT(IN) argument"_err_en_US
);
2259 if (IsProcedure(symbol
)) {
2260 messages_
.Say("VOLATILE attribute may apply only to a variable"_err_en_US
);
2262 if (symbol
.has
<UseDetails
>() || symbol
.has
<HostAssocDetails
>()) {
2263 const Symbol
&ultimate
{symbol
.GetUltimate()};
2264 if (evaluate::IsCoarray(ultimate
)) {
2266 "VOLATILE attribute may not apply to a coarray accessed by USE or host association"_err_en_US
);
2269 if (FindCoarrayUltimateComponent(*derived
)) {
2271 "VOLATILE attribute may not apply to a type with a coarray ultimate component accessed by USE or host association"_err_en_US
);
2277 void CheckHelper::CheckContiguous(const Symbol
&symbol
) {
2278 if (evaluate::IsVariable(symbol
) &&
2279 ((IsPointer(symbol
) && symbol
.Rank() > 0) || IsAssumedShape(symbol
) ||
2280 evaluate::IsAssumedRank(symbol
))) {
2282 parser::MessageFixedText msg
{symbol
.owner().IsDerivedType()
2283 ? "CONTIGUOUS component '%s' should be an array with the POINTER attribute"_port_en_US
2284 : "CONTIGUOUS entity '%s' should be an array pointer, assumed-shape, or assumed-rank"_port_en_US
};
2285 if (!context_
.IsEnabled(common::LanguageFeature::RedundantContiguous
)) {
2286 msg
.set_severity(parser::Severity::Error
);
2287 messages_
.Say(std::move(msg
), symbol
.name());
2289 Warn(common::LanguageFeature::RedundantContiguous
, std::move(msg
),
2295 void CheckHelper::CheckPointer(const Symbol
&symbol
) { // C852
2296 CheckConflicting(symbol
, Attr::POINTER
, Attr::TARGET
);
2297 CheckConflicting(symbol
, Attr::POINTER
, Attr::ALLOCATABLE
); // C751
2298 CheckConflicting(symbol
, Attr::POINTER
, Attr::INTRINSIC
);
2299 // Prohibit constant pointers. The standard does not explicitly prohibit
2300 // them, but the PARAMETER attribute requires a entity-decl to have an
2301 // initialization that is a constant-expr, and the only form of
2302 // initialization that allows a constant-expr is the one that's not a "=>"
2303 // pointer initialization. See C811, C807, and section 8.5.13.
2304 CheckConflicting(symbol
, Attr::POINTER
, Attr::PARAMETER
);
2305 if (symbol
.Corank() > 0) {
2307 "'%s' may not have the POINTER attribute because it is a coarray"_err_en_US
,
2312 // C760 constraints on the passed-object dummy argument
2313 // C757 constraints on procedure pointer components
2314 void CheckHelper::CheckPassArg(
2315 const Symbol
&proc
, const Symbol
*interface0
, const WithPassArg
&details
) {
2316 if (proc
.attrs().test(Attr::NOPASS
)) {
2319 const auto &name
{proc
.name()};
2320 const Symbol
*interface
{
2321 interface0
? FindInterface(*interface0
) : nullptr
2325 "Procedure component '%s' must have NOPASS attribute or explicit interface"_err_en_US
,
2329 const auto *subprogram
{interface
->detailsIf
<SubprogramDetails
>()};
2332 "Procedure component '%s' has invalid interface '%s'"_err_en_US
, name
,
2336 std::optional
<SourceName
> passName
{details
.passName()};
2337 const auto &dummyArgs
{subprogram
->dummyArgs()};
2339 if (dummyArgs
.empty()) {
2341 proc
.has
<ProcEntityDetails
>()
2342 ? "Procedure component '%s' with no dummy arguments"
2343 " must have NOPASS attribute"_err_en_US
2344 : "Procedure binding '%s' with no dummy arguments"
2345 " must have NOPASS attribute"_err_en_US
,
2347 context_
.SetError(*interface
);
2350 Symbol
*argSym
{dummyArgs
[0]};
2352 messages_
.Say(interface
->name(),
2353 "Cannot use an alternate return as the passed-object dummy "
2354 "argument"_err_en_US
);
2357 passName
= dummyArgs
[0]->name();
2359 std::optional
<int> passArgIndex
{};
2360 for (std::size_t i
{0}; i
< dummyArgs
.size(); ++i
) {
2361 if (dummyArgs
[i
] && dummyArgs
[i
]->name() == *passName
) {
2366 if (!passArgIndex
) { // C758
2367 messages_
.Say(*passName
,
2368 "'%s' is not a dummy argument of procedure interface '%s'"_err_en_US
,
2369 *passName
, interface
->name());
2372 const Symbol
&passArg
{*dummyArgs
[*passArgIndex
]};
2373 std::optional
<parser::MessageFixedText
> msg
;
2374 if (!passArg
.has
<ObjectEntityDetails
>()) {
2375 msg
= "Passed-object dummy argument '%s' of procedure '%s'"
2376 " must be a data object"_err_en_US
;
2377 } else if (passArg
.attrs().test(Attr::POINTER
)) {
2378 msg
= "Passed-object dummy argument '%s' of procedure '%s'"
2379 " may not have the POINTER attribute"_err_en_US
;
2380 } else if (passArg
.attrs().test(Attr::ALLOCATABLE
)) {
2381 msg
= "Passed-object dummy argument '%s' of procedure '%s'"
2382 " may not have the ALLOCATABLE attribute"_err_en_US
;
2383 } else if (passArg
.attrs().test(Attr::VALUE
)) {
2384 msg
= "Passed-object dummy argument '%s' of procedure '%s'"
2385 " may not have the VALUE attribute"_err_en_US
;
2386 } else if (passArg
.Rank() > 0) {
2387 msg
= "Passed-object dummy argument '%s' of procedure '%s'"
2388 " must be scalar"_err_en_US
;
2391 messages_
.Say(name
, std::move(*msg
), passName
.value(), name
);
2394 const DeclTypeSpec
*type
{passArg
.GetType()};
2396 return; // an error already occurred
2398 const Symbol
&typeSymbol
{*proc
.owner().GetSymbol()};
2399 const DerivedTypeSpec
*derived
{type
->AsDerived()};
2400 if (!derived
|| derived
->typeSymbol() != typeSymbol
) {
2402 "Passed-object dummy argument '%s' of procedure '%s'"
2403 " must be of type '%s' but is '%s'"_err_en_US
,
2404 passName
.value(), name
, typeSymbol
.name(), type
->AsFortran());
2407 if (IsExtensibleType(derived
) != type
->IsPolymorphic()) {
2409 type
->IsPolymorphic()
2410 ? "Passed-object dummy argument '%s' of procedure '%s'"
2411 " may not be polymorphic because '%s' is not extensible"_err_en_US
2412 : "Passed-object dummy argument '%s' of procedure '%s'"
2413 " must be polymorphic because '%s' is extensible"_err_en_US
,
2414 passName
.value(), name
, typeSymbol
.name());
2417 for (const auto &[paramName
, paramValue
] : derived
->parameters()) {
2418 if (paramValue
.isLen() && !paramValue
.isAssumed()) {
2420 "Passed-object dummy argument '%s' of procedure '%s'"
2421 " has non-assumed length parameter '%s'"_err_en_US
,
2422 passName
.value(), name
, paramName
);
2427 void CheckHelper::CheckProcBinding(
2428 const Symbol
&symbol
, const ProcBindingDetails
&binding
) {
2429 const Scope
&dtScope
{symbol
.owner()};
2430 CHECK(dtScope
.kind() == Scope::Kind::DerivedType
);
2431 if (symbol
.attrs().test(Attr::DEFERRED
)) {
2432 if (const Symbol
*dtSymbol
{dtScope
.symbol()}) {
2433 if (!dtSymbol
->attrs().test(Attr::ABSTRACT
)) { // C733
2434 SayWithDeclaration(*dtSymbol
,
2435 "Procedure bound to non-ABSTRACT derived type '%s' may not be DEFERRED"_err_en_US
,
2439 if (symbol
.attrs().test(Attr::NON_OVERRIDABLE
)) {
2441 "Type-bound procedure '%s' may not be both DEFERRED and NON_OVERRIDABLE"_err_en_US
,
2445 if (binding
.symbol().attrs().test(Attr::INTRINSIC
) &&
2446 !context_
.intrinsics().IsSpecificIntrinsicFunction(
2447 binding
.symbol().name().ToString())) {
2449 "Intrinsic procedure '%s' is not a specific intrinsic permitted for use in the definition of binding '%s'"_err_en_US
,
2450 binding
.symbol().name(), symbol
.name());
2452 bool isInaccessibleDeferred
{false};
2454 overridden
{FindOverriddenBinding(symbol
, isInaccessibleDeferred
)}) {
2455 if (isInaccessibleDeferred
) {
2456 SayWithDeclaration(*overridden
,
2457 "Override of PRIVATE DEFERRED '%s' must appear in its module"_err_en_US
,
2460 if (overridden
->attrs().test(Attr::NON_OVERRIDABLE
)) {
2461 SayWithDeclaration(*overridden
,
2462 "Override of NON_OVERRIDABLE '%s' is not permitted"_err_en_US
,
2465 if (const auto *overriddenBinding
{
2466 overridden
->detailsIf
<ProcBindingDetails
>()}) {
2467 if (!IsPureProcedure(symbol
) && IsPureProcedure(*overridden
)) {
2468 SayWithDeclaration(*overridden
,
2469 "An overridden pure type-bound procedure binding must also be pure"_err_en_US
);
2472 if (!IsElementalProcedure(binding
.symbol()) &&
2473 IsElementalProcedure(*overridden
)) {
2474 SayWithDeclaration(*overridden
,
2475 "A type-bound procedure and its override must both, or neither, be ELEMENTAL"_err_en_US
);
2478 bool isNopass
{symbol
.attrs().test(Attr::NOPASS
)};
2479 if (isNopass
!= overridden
->attrs().test(Attr::NOPASS
)) {
2480 SayWithDeclaration(*overridden
,
2482 ? "A NOPASS type-bound procedure may not override a passed-argument procedure"_err_en_US
2483 : "A passed-argument type-bound procedure may not override a NOPASS procedure"_err_en_US
);
2485 const auto *bindingChars
{Characterize(symbol
)};
2486 const auto *overriddenChars
{Characterize(*overridden
)};
2487 if (bindingChars
&& overriddenChars
) {
2489 if (!bindingChars
->CanOverride(*overriddenChars
, std::nullopt
)) {
2490 SayWithDeclaration(*overridden
,
2491 "A NOPASS type-bound procedure and its override must have identical interfaces"_err_en_US
);
2493 } else if (!context_
.HasError(binding
.symbol())) {
2494 auto passIndex
{bindingChars
->FindPassIndex(binding
.passName())};
2495 auto overriddenPassIndex
{
2496 overriddenChars
->FindPassIndex(overriddenBinding
->passName())};
2497 if (passIndex
&& overriddenPassIndex
) {
2498 if (*passIndex
!= *overriddenPassIndex
) {
2499 SayWithDeclaration(*overridden
,
2500 "A type-bound procedure and its override must use the same PASS argument"_err_en_US
);
2501 } else if (!bindingChars
->CanOverride(
2502 *overriddenChars
, passIndex
)) {
2503 SayWithDeclaration(*overridden
,
2504 "A type-bound procedure and its override must have compatible interfaces"_err_en_US
);
2510 if (symbol
.attrs().test(Attr::PRIVATE
)) {
2511 if (FindModuleContaining(dtScope
) ==
2512 FindModuleContaining(overridden
->owner())) {
2513 // types declared in same madule
2514 if (!overridden
->attrs().test(Attr::PRIVATE
)) {
2515 SayWithDeclaration(*overridden
,
2516 "A PRIVATE procedure may not override a PUBLIC procedure"_err_en_US
);
2518 } else { // types declared in distinct madules
2519 if (!CheckAccessibleSymbol(dtScope
.parent(), *overridden
)) {
2520 SayWithDeclaration(*overridden
,
2521 "A PRIVATE procedure may not override an accessible procedure"_err_en_US
);
2526 SayWithDeclaration(*overridden
,
2527 "A type-bound procedure binding may not have the same name as a parent component"_err_en_US
);
2530 CheckPassArg(symbol
, &binding
.symbol(), binding
);
2533 void CheckHelper::Check(const Scope
&scope
) {
2535 common::Restorer
<const Symbol
*> restorer
{innermostSymbol_
, innermostSymbol_
};
2536 if (const Symbol
*symbol
{scope
.symbol()}) {
2537 innermostSymbol_
= symbol
;
2539 if (scope
.IsParameterizedDerivedTypeInstantiation()) {
2540 auto restorer
{common::ScopedSet(scopeIsUninstantiatedPDT_
, false)};
2541 auto restorer2
{context_
.foldingContext().messages().SetContext(
2542 scope
.instantiationContext().get())};
2543 for (const auto &pair
: scope
) {
2544 CheckPointerInitialization(*pair
.second
);
2547 auto restorer
{common::ScopedSet(
2548 scopeIsUninstantiatedPDT_
, scope
.IsParameterizedDerivedType())};
2549 for (const auto &set
: scope
.equivalenceSets()) {
2550 CheckEquivalenceSet(set
);
2552 for (const auto &pair
: scope
) {
2553 Check(*pair
.second
);
2555 if (scope
.IsSubmodule() && scope
.symbol()) {
2556 // Submodule names are not in their parent's scopes
2557 Check(*scope
.symbol());
2559 for (const auto &pair
: scope
.commonBlocks()) {
2560 CheckCommonBlock(*pair
.second
);
2563 for (const Scope
&child
: scope
.children()) {
2565 // A program shall consist of exactly one main program (5.2.2).
2566 if (child
.kind() == Scope::Kind::MainProgram
) {
2568 if (mainProgCnt
> 1) {
2569 messages_
.Say(child
.sourceRange(),
2570 "A source file cannot contain more than one main program"_err_en_US
);
2574 if (scope
.kind() == Scope::Kind::BlockData
) {
2575 CheckBlockData(scope
);
2577 if (auto name
{scope
.GetName()}) {
2578 auto iter
{scope
.find(*name
)};
2579 if (iter
!= scope
.end()) {
2580 const char *kind
{nullptr};
2581 switch (scope
.kind()) {
2582 case Scope::Kind::Module
:
2583 kind
= scope
.symbol()->get
<ModuleDetails
>().isSubmodule()
2587 case Scope::Kind::MainProgram
:
2588 kind
= "main program";
2590 case Scope::Kind::BlockData
:
2591 kind
= "BLOCK DATA subprogram";
2596 Warn(common::LanguageFeature::BenignNameClash
, iter
->second
->name(),
2597 "Name '%s' declared in a %s should not have the same name as the %s"_port_en_US
,
2602 CheckGenericOps(scope
);
2606 void CheckHelper::CheckEquivalenceSet(const EquivalenceSet
&set
) {
2608 std::find_if(set
.begin(), set
.end(), [](const EquivalenceObject
&object
) {
2609 return FindCommonBlockContaining(object
.symbol
) != nullptr;
2611 if (iter
!= set
.end()) {
2612 const Symbol
&commonBlock
{DEREF(FindCommonBlockContaining(iter
->symbol
))};
2613 for (auto &object
: set
) {
2614 if (&object
!= &*iter
) {
2615 if (auto *details
{object
.symbol
.detailsIf
<ObjectEntityDetails
>()}) {
2616 if (details
->commonBlock()) {
2617 if (details
->commonBlock() != &commonBlock
) { // 8.10.3 paragraph 1
2618 if (auto *msg
{messages_
.Say(object
.symbol
.name(),
2619 "Two objects in the same EQUIVALENCE set may not be members of distinct COMMON blocks"_err_en_US
)}) {
2620 msg
->Attach(iter
->symbol
.name(),
2621 "Other object in EQUIVALENCE set"_en_US
)
2622 .Attach(details
->commonBlock()->name(),
2623 "COMMON block containing '%s'"_en_US
,
2624 object
.symbol
.name())
2625 .Attach(commonBlock
.name(),
2626 "COMMON block containing '%s'"_en_US
,
2627 iter
->symbol
.name());
2631 // Mark all symbols in the equivalence set with the same COMMON
2632 // block to prevent spurious error messages about initialization
2633 // in BLOCK DATA outside COMMON
2634 details
->set_commonBlock(commonBlock
);
2640 for (const EquivalenceObject
&object
: set
) {
2641 CheckEquivalenceObject(object
);
2645 static bool InCommonWithBind(const Symbol
&symbol
) {
2646 if (const auto *details
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
2647 const Symbol
*commonBlock
{details
->commonBlock()};
2648 return commonBlock
&& commonBlock
->attrs().test(Attr::BIND_C
);
2654 void CheckHelper::CheckEquivalenceObject(const EquivalenceObject
&object
) {
2655 parser::MessageFixedText msg
;
2656 const Symbol
&symbol
{object
.symbol
};
2657 if (symbol
.owner().IsDerivedType()) {
2659 "Derived type component '%s' is not allowed in an equivalence set"_err_en_US
;
2660 } else if (IsDummy(symbol
)) {
2661 msg
= "Dummy argument '%s' is not allowed in an equivalence set"_err_en_US
;
2662 } else if (symbol
.IsFuncResult()) {
2663 msg
= "Function result '%s' is not allow in an equivalence set"_err_en_US
;
2664 } else if (IsPointer(symbol
)) {
2665 msg
= "Pointer '%s' is not allowed in an equivalence set"_err_en_US
;
2666 } else if (IsAllocatable(symbol
)) {
2668 "Allocatable variable '%s' is not allowed in an equivalence set"_err_en_US
;
2669 } else if (symbol
.Corank() > 0) {
2670 msg
= "Coarray '%s' is not allowed in an equivalence set"_err_en_US
;
2671 } else if (symbol
.has
<UseDetails
>()) {
2673 "Use-associated variable '%s' is not allowed in an equivalence set"_err_en_US
;
2674 } else if (symbol
.attrs().test(Attr::BIND_C
)) {
2676 "Variable '%s' with BIND attribute is not allowed in an equivalence set"_err_en_US
;
2677 } else if (symbol
.attrs().test(Attr::TARGET
)) {
2679 "Variable '%s' with TARGET attribute is not allowed in an equivalence set"_err_en_US
;
2680 } else if (IsNamedConstant(symbol
)) {
2681 msg
= "Named constant '%s' is not allowed in an equivalence set"_err_en_US
;
2682 } else if (InCommonWithBind(symbol
)) {
2684 "Variable '%s' in common block with BIND attribute is not allowed in an equivalence set"_err_en_US
;
2685 } else if (!symbol
.has
<ObjectEntityDetails
>()) {
2686 msg
= "'%s' in equivalence set is not a data object"_err_en_US
;
2687 } else if (const auto *type
{symbol
.GetType()}) {
2688 const auto *derived
{type
->AsDerived()};
2689 if (derived
&& !derived
->IsVectorType()) {
2690 if (const auto *comp
{
2691 FindUltimateComponent(*derived
, IsAllocatableOrPointer
)}) {
2692 msg
= IsPointer(*comp
)
2693 ? "Derived type object '%s' with pointer ultimate component is not allowed in an equivalence set"_err_en_US
2694 : "Derived type object '%s' with allocatable ultimate component is not allowed in an equivalence set"_err_en_US
;
2695 } else if (!derived
->typeSymbol().get
<DerivedTypeDetails
>().sequence()) {
2697 "Nonsequence derived type object '%s' is not allowed in an equivalence set"_err_en_US
;
2699 } else if (IsAutomatic(symbol
)) {
2701 "Automatic object '%s' is not allowed in an equivalence set"_err_en_US
;
2702 } else if (symbol
.test(Symbol::Flag::CrayPointee
)) {
2703 messages_
.Say(object
.symbol
.name(),
2704 "Cray pointee '%s' may not be a member of an EQUIVALENCE group"_err_en_US
,
2705 object
.symbol
.name());
2708 if (!msg
.text().empty()) {
2709 context_
.Say(object
.source
, std::move(msg
), symbol
.name());
2713 void CheckHelper::CheckBlockData(const Scope
&scope
) {
2714 // BLOCK DATA subprograms should contain only named common blocks.
2715 // C1415 presents a list of statements that shouldn't appear in
2716 // BLOCK DATA, but so long as the subprogram contains no executable
2717 // code and allocates no storage outside named COMMON, we're happy
2718 // (e.g., an ENUM is strictly not allowed).
2719 for (const auto &pair
: scope
) {
2720 const Symbol
&symbol
{*pair
.second
};
2721 if (!(symbol
.has
<CommonBlockDetails
>() || symbol
.has
<UseDetails
>() ||
2722 symbol
.has
<UseErrorDetails
>() || symbol
.has
<DerivedTypeDetails
>() ||
2723 symbol
.has
<SubprogramDetails
>() ||
2724 symbol
.has
<ObjectEntityDetails
>() ||
2725 (symbol
.has
<ProcEntityDetails
>() &&
2726 !symbol
.attrs().test(Attr::POINTER
)))) {
2727 messages_
.Say(symbol
.name(),
2728 "'%s' may not appear in a BLOCK DATA subprogram"_err_en_US
,
2734 // Check distinguishability of generic assignment and operators.
2735 // For these, generics and generic bindings must be considered together.
2736 void CheckHelper::CheckGenericOps(const Scope
&scope
) {
2737 DistinguishabilityHelper helper
{context_
};
2738 auto addSpecifics
{[&](const Symbol
&generic
) {
2739 const auto *details
{generic
.GetUltimate().detailsIf
<GenericDetails
>()};
2741 // Not a generic; ensure characteristics are defined if a function.
2742 auto restorer
{messages_
.SetLocation(generic
.name())};
2743 if (IsFunction(generic
) && !context_
.HasError(generic
)) {
2744 if (const Symbol
*result
{FindFunctionResult(generic
)};
2745 result
&& !context_
.HasError(*result
)) {
2746 Characterize(generic
);
2751 GenericKind kind
{details
->kind()};
2752 if (!kind
.IsAssignment() && !kind
.IsOperator()) {
2755 const SymbolVector
&specifics
{details
->specificProcs()};
2756 const std::vector
<SourceName
> &bindingNames
{details
->bindingNames()};
2757 for (std::size_t i
{0}; i
< specifics
.size(); ++i
) {
2758 const Symbol
&specific
{*specifics
[i
]};
2759 auto restorer
{messages_
.SetLocation(bindingNames
[i
])};
2760 if (const Procedure
*proc
{Characterize(specific
)}) {
2761 if (kind
.IsAssignment()) {
2762 if (!CheckDefinedAssignment(specific
, *proc
)) {
2766 if (!CheckDefinedOperator(generic
.name(), kind
, specific
, *proc
)) {
2770 helper
.Add(generic
, kind
, specific
, *proc
);
2774 for (const auto &pair
: scope
) {
2775 const Symbol
&symbol
{*pair
.second
};
2776 addSpecifics(symbol
);
2777 const Symbol
&ultimate
{symbol
.GetUltimate()};
2778 if (ultimate
.has
<DerivedTypeDetails
>()) {
2779 if (const Scope
*typeScope
{ultimate
.scope()}) {
2780 for (const auto &pair2
: *typeScope
) {
2781 addSpecifics(*pair2
.second
);
2786 helper
.Check(scope
);
2789 static bool IsSubprogramDefinition(const Symbol
&symbol
) {
2790 const auto *subp
{symbol
.detailsIf
<SubprogramDetails
>()};
2791 return subp
&& !subp
->isInterface() && symbol
.scope() &&
2792 symbol
.scope()->kind() == Scope::Kind::Subprogram
;
2795 static bool IsExternalProcedureDefinition(const Symbol
&symbol
) {
2796 return IsBlockData(symbol
) ||
2797 (IsSubprogramDefinition(symbol
) &&
2798 (IsExternal(symbol
) || symbol
.GetBindName()));
2801 static std::optional
<std::string
> DefinesGlobalName(const Symbol
&symbol
) {
2802 if (const auto *module
{symbol
.detailsIf
<ModuleDetails
>()}) {
2803 if (!module
->isSubmodule() && !symbol
.owner().IsIntrinsicModules()) {
2804 return symbol
.name().ToString();
2806 } else if (IsBlockData(symbol
)) {
2807 return symbol
.name().ToString();
2809 const std::string
*bindC
{symbol
.GetBindName()};
2810 if (symbol
.has
<CommonBlockDetails
>() ||
2811 IsExternalProcedureDefinition(symbol
) ||
2812 (symbol
.owner().IsGlobal() && IsExternal(symbol
))) {
2813 return bindC
? *bindC
: symbol
.name().ToString();
2815 (symbol
.has
<ObjectEntityDetails
>() || IsModuleProcedure(symbol
))) {
2819 return std::nullopt
;
2823 void CheckHelper::CheckGlobalName(const Symbol
&symbol
) {
2824 if (auto global
{DefinesGlobalName(symbol
)}) {
2825 auto pair
{globalNames_
.emplace(std::move(*global
), symbol
)};
2827 const Symbol
&other
{*pair
.first
->second
};
2828 if (context_
.HasError(symbol
) || context_
.HasError(other
)) {
2830 } else if (symbol
.has
<CommonBlockDetails
>() &&
2831 other
.has
<CommonBlockDetails
>() && symbol
.name() == other
.name()) {
2832 // Two common blocks can have the same global name so long as
2833 // they're not in the same scope.
2834 } else if ((IsProcedure(symbol
) || IsBlockData(symbol
)) &&
2835 (IsProcedure(other
) || IsBlockData(other
)) &&
2836 (!IsExternalProcedureDefinition(symbol
) ||
2837 !IsExternalProcedureDefinition(other
))) {
2838 // both are procedures/BLOCK DATA, not both definitions
2839 } else if (symbol
.has
<ModuleDetails
>()) {
2840 Warn(common::LanguageFeature::BenignNameClash
, symbol
.name(),
2841 "Module '%s' conflicts with a global name"_port_en_US
,
2843 } else if (other
.has
<ModuleDetails
>()) {
2844 Warn(common::LanguageFeature::BenignNameClash
, symbol
.name(),
2845 "Global name '%s' conflicts with a module"_port_en_US
,
2847 } else if (auto *msg
{messages_
.Say(symbol
.name(),
2848 "Two entities have the same global name '%s'"_err_en_US
,
2849 pair
.first
->first
)}) {
2850 msg
->Attach(other
.name(), "Conflicting declaration"_en_US
);
2851 context_
.SetError(symbol
);
2852 context_
.SetError(other
);
2858 void CheckHelper::CheckProcedureAssemblyName(const Symbol
&symbol
) {
2859 if (!IsProcedure(symbol
) || symbol
!= symbol
.GetUltimate())
2861 const std::string
*bindName
{symbol
.GetBindName()};
2862 const bool hasExplicitBindingLabel
{
2863 symbol
.GetIsExplicitBindName() && bindName
};
2864 if (hasExplicitBindingLabel
|| IsExternal(symbol
)) {
2865 const std::string assemblyName
{hasExplicitBindingLabel
2867 : common::GetExternalAssemblyName(
2868 symbol
.name().ToString(), context_
.underscoring())};
2869 auto pair
{procedureAssemblyNames_
.emplace(std::move(assemblyName
), symbol
)};
2871 const Symbol
&other
{*pair
.first
->second
};
2872 const bool otherHasExplicitBindingLabel
{
2873 other
.GetIsExplicitBindName() && other
.GetBindName()};
2874 if (otherHasExplicitBindingLabel
!= hasExplicitBindingLabel
) {
2875 // The BIND(C,NAME="...") binding label is the same as the name that
2876 // will be used in LLVM IR for an external procedure declared without
2877 // BIND(C) in the same file. While this is not forbidden by the
2878 // standard, this name collision would lead to a crash when producing
2880 if (auto *msg
{messages_
.Say(symbol
.name(),
2881 "%s procedure assembly name conflicts with %s procedure assembly name"_err_en_US
,
2882 hasExplicitBindingLabel
? "BIND(C)" : "Non BIND(C)",
2883 hasExplicitBindingLabel
? "non BIND(C)" : "BIND(C)")}) {
2884 msg
->Attach(other
.name(), "Conflicting declaration"_en_US
);
2886 context_
.SetError(symbol
);
2887 context_
.SetError(other
);
2889 // Otherwise, the global names also match and the conflict is analyzed
2890 // by CheckGlobalName.
2895 parser::Messages
CheckHelper::WhyNotInteroperableDerivedType(
2896 const Symbol
&symbol
) {
2897 parser::Messages msgs
;
2898 if (examinedByWhyNotInteroperable_
.find(symbol
) !=
2899 examinedByWhyNotInteroperable_
.end()) {
2902 examinedByWhyNotInteroperable_
.insert(symbol
);
2903 if (const auto *derived
{symbol
.detailsIf
<DerivedTypeDetails
>()}) {
2904 if (derived
->sequence()) { // C1801
2905 msgs
.Say(symbol
.name(),
2906 "An interoperable derived type cannot have the SEQUENCE attribute"_err_en_US
);
2907 } else if (!derived
->paramNameOrder().empty()) { // C1802
2908 msgs
.Say(symbol
.name(),
2909 "An interoperable derived type cannot have a type parameter"_err_en_US
);
2910 } else if (const auto *parent
{
2911 symbol
.scope()->GetDerivedTypeParent()}) { // C1803
2912 if (symbol
.attrs().test(Attr::BIND_C
)) {
2913 msgs
.Say(symbol
.name(),
2914 "A derived type with the BIND attribute cannot be an extended derived type"_err_en_US
);
2916 bool interoperableParent
{true};
2917 if (parent
->symbol()) {
2918 auto bad
{WhyNotInteroperableDerivedType(*parent
->symbol())};
2919 if (bad
.AnyFatalError()) {
2920 auto &msg
{msgs
.Say(symbol
.name(),
2921 "The parent of an interoperable type is not interoperable"_err_en_US
)};
2922 bad
.AttachTo(msg
, parser::Severity::None
);
2923 interoperableParent
= false;
2926 if (interoperableParent
) {
2927 msgs
.Say(symbol
.name(),
2928 "An interoperable type should not be an extended derived type"_warn_en_US
);
2932 const Symbol
*parentComponent
{symbol
.scope()
2933 ? derived
->GetParentComponent(*symbol
.scope())
2935 for (const auto &pair
: *symbol
.scope()) {
2936 const Symbol
&component
{*pair
.second
};
2937 if (&component
== parentComponent
) {
2938 continue; // was checked above
2940 if (IsProcedure(component
)) { // C1804
2941 msgs
.Say(component
.name(),
2942 "An interoperable derived type cannot have a type bound procedure"_err_en_US
);
2943 } else if (IsAllocatableOrPointer(component
)) { // C1806
2944 msgs
.Say(component
.name(),
2945 "An interoperable derived type cannot have a pointer or allocatable component"_err_en_US
);
2946 } else if (const auto *type
{component
.GetType()}) {
2947 if (const auto *derived
{type
->AsDerived()}) {
2948 auto bad
{WhyNotInteroperableDerivedType(derived
->typeSymbol())};
2949 if (bad
.AnyFatalError()) {
2950 auto &msg
{msgs
.Say(component
.name(),
2951 "Component '%s' of an interoperable derived type must have an interoperable type but does not"_err_en_US
,
2953 bad
.AttachTo(msg
, parser::Severity::None
);
2954 } else if (!derived
->typeSymbol().GetUltimate().attrs().test(
2957 msgs
.Say(component
.name(),
2958 "Derived type of component '%s' of an interoperable derived type should have the BIND attribute"_warn_en_US
,
2960 .Attach(derived
->typeSymbol().name(),
2961 "Non-BIND(C) component type"_en_US
)};
2962 bad
.AttachTo(msg
, parser::Severity::None
);
2964 msgs
.Annex(std::move(bad
));
2966 } else if (auto dyType
{evaluate::DynamicType::From(*type
)}; dyType
&&
2967 !evaluate::IsInteroperableIntrinsicType(
2968 *dyType
, &context_
.languageFeatures())
2970 if (type
->category() == DeclTypeSpec::Logical
) {
2971 if (context_
.ShouldWarn(common::UsageWarning::LogicalVsCBool
)) {
2972 msgs
.Say(common::UsageWarning::LogicalVsCBool
, component
.name(),
2973 "A LOGICAL component of an interoperable type should have the interoperable KIND=C_BOOL"_port_en_US
);
2975 } else if (type
->category() == DeclTypeSpec::Character
&& dyType
&&
2976 dyType
->kind() == 1) {
2977 if (context_
.ShouldWarn(common::UsageWarning::BindCCharLength
)) {
2978 msgs
.Say(common::UsageWarning::BindCCharLength
, component
.name(),
2979 "A CHARACTER component of an interoperable type should have length 1"_port_en_US
);
2982 msgs
.Say(component
.name(),
2983 "Each component of an interoperable derived type must have an interoperable type"_err_en_US
);
2988 evaluate::GetConstantExtents(foldingContext_
, &component
)};
2989 extents
&& evaluate::GetSize(*extents
) == 0) {
2990 msgs
.Say(component
.name(),
2991 "An array component of an interoperable type must have at least one element"_err_en_US
);
2994 if (derived
->componentNames().empty()) { // F'2023 C1805
2995 if (context_
.ShouldWarn(common::LanguageFeature::EmptyBindCDerivedType
)) {
2996 msgs
.Say(common::LanguageFeature::EmptyBindCDerivedType
, symbol
.name(),
2997 "A derived type with the BIND attribute should not be empty"_warn_en_US
);
3001 if (msgs
.AnyFatalError()) {
3002 examinedByWhyNotInteroperable_
.erase(symbol
);
3007 parser::Messages
CheckHelper::WhyNotInteroperableObject(
3008 const Symbol
&symbol
, bool allowNonInteroperableType
) {
3009 parser::Messages msgs
;
3010 if (examinedByWhyNotInteroperable_
.find(symbol
) !=
3011 examinedByWhyNotInteroperable_
.end()) {
3014 bool isExplicitBindC
{symbol
.attrs().test(Attr::BIND_C
)};
3015 examinedByWhyNotInteroperable_
.insert(symbol
);
3016 CHECK(symbol
.has
<ObjectEntityDetails
>());
3017 if (isExplicitBindC
&& !symbol
.owner().IsModule()) {
3018 msgs
.Say(symbol
.name(),
3019 "A variable with BIND(C) attribute may only appear in the specification part of a module"_err_en_US
);
3021 auto shape
{evaluate::GetShape(foldingContext_
, symbol
)};
3023 if (evaluate::GetRank(*shape
) == 0) { // 18.3.4
3024 if (IsAllocatableOrPointer(symbol
) && !IsDummy(symbol
)) {
3025 msgs
.Say(symbol
.name(),
3026 "A scalar interoperable variable may not be ALLOCATABLE or POINTER"_err_en_US
);
3028 } else if (auto extents
{
3029 evaluate::AsConstantExtents(foldingContext_
, *shape
)}) {
3030 if (evaluate::GetSize(*extents
) == 0) {
3031 msgs
.Say(symbol
.name(),
3032 "Interoperable array must have at least one element"_err_en_US
);
3034 } else if (!evaluate::IsExplicitShape(symbol
) &&
3035 !IsAssumedSizeArray(symbol
) &&
3036 !(IsDummy(symbol
) && !symbol
.attrs().test(Attr::VALUE
))) {
3037 msgs
.Say(symbol
.name(),
3038 "BIND(C) array must have explicit shape or be assumed-size unless a dummy argument without the VALUE attribute"_err_en_US
);
3041 if (const auto *type
{symbol
.GetType()}) {
3042 const auto *derived
{type
->AsDerived()};
3043 if (derived
&& !derived
->typeSymbol().attrs().test(Attr::BIND_C
)) {
3044 if (allowNonInteroperableType
) { // portability warning only
3045 evaluate::AttachDeclaration(
3046 context_
.Warn(common::UsageWarning::Portability
, symbol
.name(),
3047 "The derived type of this interoperable object should be BIND(C)"_port_en_US
),
3048 derived
->typeSymbol());
3049 } else if (!context_
.IsEnabled(
3050 common::LanguageFeature::NonBindCInteroperability
)) {
3051 msgs
.Say(symbol
.name(),
3052 "The derived type of an interoperable object must be BIND(C)"_err_en_US
)
3053 .Attach(derived
->typeSymbol().name(), "Non-BIND(C) type"_en_US
);
3054 } else if (auto bad
{
3055 WhyNotInteroperableDerivedType(derived
->typeSymbol())};
3056 bad
.AnyFatalError()) {
3058 msgs
.Say(symbol
.name(),
3059 "The derived type of an interoperable object must be interoperable, but is not"_err_en_US
)
3060 .Attach(derived
->typeSymbol().name(),
3061 "Non-interoperable type"_en_US
),
3062 parser::Severity::None
);
3064 msgs
.Say(symbol
.name(),
3065 "The derived type of an interoperable object should be BIND(C)"_warn_en_US
)
3066 .Attach(derived
->typeSymbol().name(), "Non-BIND(C) type"_en_US
);
3069 if (type
->IsAssumedType()) { // ok
3070 } else if (IsAssumedLengthCharacter(symbol
)) {
3071 } else if (IsAllocatableOrPointer(symbol
) &&
3072 type
->category() == DeclTypeSpec::Character
&&
3073 type
->characterTypeSpec().length().isDeferred()) {
3074 // ok; F'2023 18.3.7 p2(6)
3075 } else if (derived
) { // type has been checked
3076 } else if (auto dyType
{evaluate::DynamicType::From(*type
)}; dyType
&&
3077 evaluate::IsInteroperableIntrinsicType(*dyType
,
3078 InModuleFile() ? nullptr : &context_
.languageFeatures())
3080 // F'2023 18.3.7 p2(4,5)
3081 // N.B. Language features are not passed to IsInteroperableIntrinsicType
3082 // when processing a module file, since the module file might have been
3083 // compiled with CUDA while the client is not.
3084 } else if (type
->category() == DeclTypeSpec::Logical
) {
3085 if (context_
.ShouldWarn(common::UsageWarning::LogicalVsCBool
)) {
3086 if (IsDummy(symbol
)) {
3087 msgs
.Say(common::UsageWarning::LogicalVsCBool
, symbol
.name(),
3088 "A BIND(C) LOGICAL dummy argument should have the interoperable KIND=C_BOOL"_port_en_US
);
3090 msgs
.Say(common::UsageWarning::LogicalVsCBool
, symbol
.name(),
3091 "A BIND(C) LOGICAL object should have the interoperable KIND=C_BOOL"_port_en_US
);
3094 } else if (symbol
.attrs().test(Attr::VALUE
)) {
3095 msgs
.Say(symbol
.name(),
3096 "A BIND(C) VALUE dummy argument must have an interoperable type"_err_en_US
);
3098 msgs
.Say(symbol
.name(),
3099 "A BIND(C) object must have an interoperable type"_err_en_US
);
3102 if (IsOptional(symbol
) && !symbol
.attrs().test(Attr::VALUE
)) {
3103 msgs
.Say(symbol
.name(),
3104 "An interoperable procedure with an OPTIONAL dummy argument might not be portable"_port_en_US
);
3106 if (IsDescriptor(symbol
) && IsPointer(symbol
) &&
3107 symbol
.attrs().test(Attr::CONTIGUOUS
)) {
3108 msgs
.Say(symbol
.name(),
3109 "An interoperable pointer must not be CONTIGUOUS"_err_en_US
);
3111 if (msgs
.AnyFatalError()) {
3112 examinedByWhyNotInteroperable_
.erase(symbol
);
3117 parser::Messages
CheckHelper::WhyNotInteroperableFunctionResult(
3118 const Symbol
&symbol
) {
3119 parser::Messages msgs
;
3120 if (IsPointer(symbol
) || IsAllocatable(symbol
)) {
3121 msgs
.Say(symbol
.name(),
3122 "Interoperable function result may not have ALLOCATABLE or POINTER attribute"_err_en_US
);
3124 if (const DeclTypeSpec
* type
{symbol
.GetType()};
3125 type
&& type
->category() == DeclTypeSpec::Character
) {
3126 bool isConstOne
{false}; // 18.3.1(1)
3127 if (const auto &len
{type
->characterTypeSpec().length().GetExplicit()}) {
3128 if (auto constLen
{evaluate::ToInt64(*len
)}) {
3129 isConstOne
= constLen
== 1;
3133 msgs
.Say(symbol
.name(),
3134 "Interoperable character function result must have length one"_err_en_US
);
3137 if (symbol
.Rank() > 0) {
3138 msgs
.Say(symbol
.name(),
3139 "Interoperable function result must be scalar"_err_en_US
);
3141 if (symbol
.Corank()) {
3142 msgs
.Say(symbol
.name(),
3143 "Interoperable function result may not be a coarray"_err_en_US
);
3148 parser::Messages
CheckHelper::WhyNotInteroperableProcedure(
3149 const Symbol
&symbol
, bool isError
) {
3150 parser::Messages msgs
;
3151 if (examinedByWhyNotInteroperable_
.find(symbol
) !=
3152 examinedByWhyNotInteroperable_
.end()) {
3155 isError
|= symbol
.attrs().test(Attr::BIND_C
);
3156 examinedByWhyNotInteroperable_
.insert(symbol
);
3157 if (const auto *proc
{symbol
.detailsIf
<ProcEntityDetails
>()}) {
3159 if (!proc
->procInterface() ||
3160 !proc
->procInterface()->attrs().test(Attr::BIND_C
)) {
3161 msgs
.Say(symbol
.name(),
3162 "An interface name with the BIND attribute must appear if the BIND attribute appears in a procedure declaration"_err_en_US
);
3164 } else if (!proc
->procInterface()) {
3165 msgs
.Say(symbol
.name(),
3166 "An interoperable procedure should have an interface"_port_en_US
);
3167 } else if (!proc
->procInterface()->attrs().test(Attr::BIND_C
)) {
3168 auto bad
{WhyNotInteroperableProcedure(
3169 *proc
->procInterface(), /*isError=*/false)};
3170 if (bad
.AnyFatalError()) {
3171 bad
.AttachTo(msgs
.Say(symbol
.name(),
3172 "An interoperable procedure must have an interoperable interface"_err_en_US
));
3174 msgs
.Say(symbol
.name(),
3175 "An interoperable procedure should have an interface with the BIND attribute"_warn_en_US
);
3178 } else if (const auto *subp
{symbol
.detailsIf
<SubprogramDetails
>()}) {
3179 for (const Symbol
*dummy
: subp
->dummyArgs()) {
3181 parser::Messages dummyMsgs
;
3182 if (dummy
->has
<ProcEntityDetails
>() ||
3183 dummy
->has
<SubprogramDetails
>()) {
3184 dummyMsgs
= WhyNotInteroperableProcedure(*dummy
, /*isError=*/false);
3185 if (dummyMsgs
.empty() && !dummy
->attrs().test(Attr::BIND_C
)) {
3186 dummyMsgs
.Say(dummy
->name(),
3187 "A dummy procedure of an interoperable procedure should be BIND(C)"_warn_en_US
);
3189 } else if (dummy
->has
<ObjectEntityDetails
>()) {
3190 // Emit only optional portability warnings for non-interoperable
3191 // types when the dummy argument is not VALUE and will be implemented
3192 // on the C side by either a cdesc_t * or a void *. F'2023 18.3.7 (5)
3193 bool allowNonInteroperableType
{!dummy
->attrs().test(Attr::VALUE
) &&
3194 (IsDescriptor(*dummy
) || IsAssumedType(*dummy
))};
3196 WhyNotInteroperableObject(*dummy
, allowNonInteroperableType
);
3200 msgs
.Annex(std::move(dummyMsgs
));
3202 msgs
.Say(symbol
.name(),
3203 "A subprogram interface with the BIND attribute may not have an alternate return argument"_err_en_US
);
3206 if (subp
->isFunction()) {
3207 if (subp
->result().has
<ObjectEntityDetails
>()) {
3208 msgs
.Annex(WhyNotInteroperableFunctionResult(subp
->result()));
3210 msgs
.Say(subp
->result().name(),
3211 "The result of an interoperable function must be a data object"_err_en_US
);
3215 if (msgs
.AnyFatalError()) {
3216 examinedByWhyNotInteroperable_
.erase(symbol
);
3221 void CheckHelper::CheckBindC(const Symbol
&symbol
) {
3222 bool isExplicitBindC
{symbol
.attrs().test(Attr::BIND_C
)};
3223 if (isExplicitBindC
) {
3224 CheckConflicting(symbol
, Attr::BIND_C
, Attr::ELEMENTAL
);
3225 CheckConflicting(symbol
, Attr::BIND_C
, Attr::INTRINSIC
);
3226 CheckConflicting(symbol
, Attr::BIND_C
, Attr::PARAMETER
);
3228 // symbol must be interoperable (e.g., dummy argument of interoperable
3229 // procedure interface) but is not itself BIND(C).
3231 parser::Messages whyNot
;
3232 if (const std::string
* bindName
{symbol
.GetBindName()};
3233 bindName
) { // has a binding name
3234 if (!bindName
->empty()) {
3235 bool ok
{bindName
->front() == '_' || parser::IsLetter(bindName
->front())};
3236 for (char ch
: *bindName
) {
3237 ok
&= ch
== '_' || parser::IsLetter(ch
) || parser::IsDecimalDigit(ch
);
3240 messages_
.Say(symbol
.name(),
3241 "Symbol has a BIND(C) name that is not a valid C language identifier"_err_en_US
);
3242 context_
.SetError(symbol
);
3246 if (symbol
.GetIsExplicitBindName()) { // BIND(C,NAME=...); C1552, C1529
3247 auto defClass
{ClassifyProcedure(symbol
)};
3248 if (IsProcedurePointer(symbol
)) {
3249 messages_
.Say(symbol
.name(),
3250 "A procedure pointer may not have a BIND attribute with a name"_err_en_US
);
3251 context_
.SetError(symbol
);
3252 } else if (defClass
== ProcedureDefinitionClass::None
||
3253 IsExternal(symbol
)) {
3254 } else if (symbol
.attrs().test(Attr::ABSTRACT
)) {
3255 messages_
.Say(symbol
.name(),
3256 "An ABSTRACT interface may not have a BIND attribute with a name"_err_en_US
);
3257 context_
.SetError(symbol
);
3258 } else if (defClass
== ProcedureDefinitionClass::Internal
||
3259 defClass
== ProcedureDefinitionClass::Dummy
) {
3260 messages_
.Say(symbol
.name(),
3261 "An internal or dummy procedure may not have a BIND(C,NAME=) binding label"_err_en_US
);
3262 context_
.SetError(symbol
);
3265 if (symbol
.has
<ObjectEntityDetails
>()) {
3266 whyNot
= WhyNotInteroperableObject(symbol
);
3267 } else if (symbol
.has
<ProcEntityDetails
>() ||
3268 symbol
.has
<SubprogramDetails
>()) {
3269 whyNot
= WhyNotInteroperableProcedure(symbol
, /*isError=*/isExplicitBindC
);
3270 } else if (symbol
.has
<DerivedTypeDetails
>()) {
3271 whyNot
= WhyNotInteroperableDerivedType(symbol
);
3273 if (!whyNot
.empty()) {
3274 bool anyFatal
{whyNot
.AnyFatalError()};
3277 context_
.ShouldWarn(
3278 common::LanguageFeature::NonBindCInteroperability
))) {
3279 context_
.messages().Annex(std::move(whyNot
));
3282 context_
.SetError(symbol
);
3287 bool CheckHelper::CheckDioDummyIsData(
3288 const Symbol
&subp
, const Symbol
*arg
, std::size_t position
) {
3289 if (arg
&& arg
->detailsIf
<ObjectEntityDetails
>()) {
3293 messages_
.Say(arg
->name(),
3294 "Dummy argument '%s' must be a data object"_err_en_US
, arg
->name());
3296 messages_
.Say(subp
.name(),
3297 "Dummy argument %d of '%s' must be a data object"_err_en_US
, position
,
3304 void CheckHelper::CheckAlreadySeenDefinedIo(const DerivedTypeSpec
&derivedType
,
3305 common::DefinedIo ioKind
, const Symbol
&proc
, const Symbol
&generic
) {
3306 // Check for conflict between non-type-bound defined I/O and type-bound
3307 // generics. It's okay to have two or more distinct defined I/O procedures for
3308 // the same type if they're coming from distinct non-type-bound interfaces.
3309 // (The non-type-bound interfaces would have been merged into a single generic
3310 // -- with errors where indistinguishable -- when both were visible from the
3312 if (generic
.owner().IsDerivedType()) {
3315 if (const Scope
* dtScope
{derivedType
.scope()}) {
3316 if (auto iter
{dtScope
->find(generic
.name())}; iter
!= dtScope
->end()) {
3317 for (auto specRef
: iter
->second
->get
<GenericDetails
>().specificProcs()) {
3318 const Symbol
&specific
{specRef
->get
<ProcBindingDetails
>().symbol()};
3319 if (specific
== proc
) { // unambiguous, accept
3322 if (const auto *specDT
{GetDtvArgDerivedType(specific
)};
3323 specDT
&& evaluate::AreSameDerivedType(derivedType
, *specDT
)) {
3324 SayWithDeclaration(*specRef
, proc
.name(),
3325 "Derived type '%s' has conflicting type-bound input/output procedure '%s'"_err_en_US
,
3326 derivedType
.name(), GenericKind::AsFortran(ioKind
));
3334 void CheckHelper::CheckDioDummyIsDerived(const Symbol
&subp
, const Symbol
&arg
,
3335 common::DefinedIo ioKind
, const Symbol
&generic
) {
3336 if (const DeclTypeSpec
*type
{arg
.GetType()}) {
3337 if (const DerivedTypeSpec
*derivedType
{type
->AsDerived()}) {
3338 CheckAlreadySeenDefinedIo(*derivedType
, ioKind
, subp
, generic
);
3339 bool isPolymorphic
{type
->IsPolymorphic()};
3340 if (isPolymorphic
!= IsExtensibleType(derivedType
)) {
3341 messages_
.Say(arg
.name(),
3342 "Dummy argument '%s' of a defined input/output procedure must be %s when the derived type is %s"_err_en_US
,
3343 arg
.name(), isPolymorphic
? "TYPE()" : "CLASS()",
3344 isPolymorphic
? "not extensible" : "extensible");
3347 messages_
.Say(arg
.name(),
3348 "Dummy argument '%s' of a defined input/output procedure must have a"
3349 " derived type"_err_en_US
,
3355 void CheckHelper::CheckDioDummyIsDefaultInteger(
3356 const Symbol
&subp
, const Symbol
&arg
) {
3357 if (const DeclTypeSpec
*type
{arg
.GetType()};
3358 type
&& type
->IsNumeric(TypeCategory::Integer
)) {
3359 if (const auto kind
{evaluate::ToInt64(type
->numericTypeSpec().kind())};
3360 kind
&& *kind
== context_
.GetDefaultKind(TypeCategory::Integer
)) {
3364 messages_
.Say(arg
.name(),
3365 "Dummy argument '%s' of a defined input/output procedure"
3366 " must be an INTEGER of default KIND"_err_en_US
,
3370 void CheckHelper::CheckDioDummyIsScalar(const Symbol
&subp
, const Symbol
&arg
) {
3371 if (arg
.Rank() > 0 || arg
.Corank() > 0) {
3372 messages_
.Say(arg
.name(),
3373 "Dummy argument '%s' of a defined input/output procedure"
3374 " must be a scalar"_err_en_US
,
3379 void CheckHelper::CheckDioDtvArg(const Symbol
&subp
, const Symbol
*arg
,
3380 common::DefinedIo ioKind
, const Symbol
&generic
) {
3381 // Dtv argument looks like: dtv-type-spec, INTENT(INOUT) :: dtv
3382 if (CheckDioDummyIsData(subp
, arg
, 0)) {
3383 CheckDioDummyIsDerived(subp
, *arg
, ioKind
, generic
);
3384 CheckDioDummyAttrs(subp
, *arg
,
3385 ioKind
== common::DefinedIo::ReadFormatted
||
3386 ioKind
== common::DefinedIo::ReadUnformatted
3387 ? Attr::INTENT_INOUT
3392 // If an explicit INTRINSIC name is a function, so must all the specifics be,
3393 // and similarly for subroutines
3394 void CheckHelper::CheckGenericVsIntrinsic(
3395 const Symbol
&symbol
, const GenericDetails
&generic
) {
3396 if (symbol
.attrs().test(Attr::INTRINSIC
)) {
3397 const evaluate::IntrinsicProcTable
&table
{
3398 context_
.foldingContext().intrinsics()};
3399 bool isSubroutine
{table
.IsIntrinsicSubroutine(symbol
.name().ToString())};
3400 if (isSubroutine
|| table
.IsIntrinsicFunction(symbol
.name().ToString())) {
3401 for (const SymbolRef
&ref
: generic
.specificProcs()) {
3402 const Symbol
&ultimate
{ref
->GetUltimate()};
3403 bool specificFunc
{ultimate
.test(Symbol::Flag::Function
)};
3404 bool specificSubr
{ultimate
.test(Symbol::Flag::Subroutine
)};
3405 if (!specificFunc
&& !specificSubr
) {
3406 if (const auto *proc
{ultimate
.detailsIf
<SubprogramDetails
>()}) {
3407 if (proc
->isFunction()) {
3408 specificFunc
= true;
3410 specificSubr
= true;
3414 if ((specificFunc
|| specificSubr
) &&
3415 isSubroutine
!= specificSubr
) { // C848
3416 messages_
.Say(symbol
.name(),
3417 "Generic interface '%s' with explicit intrinsic %s of the same name may not have specific procedure '%s' that is a %s"_err_en_US
,
3418 symbol
.name(), isSubroutine
? "subroutine" : "function",
3419 ref
->name(), isSubroutine
? "function" : "subroutine");
3426 void CheckHelper::CheckDefaultIntegerArg(
3427 const Symbol
&subp
, const Symbol
*arg
, Attr intent
) {
3428 // Argument looks like: INTEGER, INTENT(intent) :: arg
3429 if (CheckDioDummyIsData(subp
, arg
, 1)) {
3430 CheckDioDummyIsDefaultInteger(subp
, *arg
);
3431 CheckDioDummyIsScalar(subp
, *arg
);
3432 CheckDioDummyAttrs(subp
, *arg
, intent
);
3436 void CheckHelper::CheckDioAssumedLenCharacterArg(const Symbol
&subp
,
3437 const Symbol
*arg
, std::size_t argPosition
, Attr intent
) {
3438 // Argument looks like: CHARACTER (LEN=*), INTENT(intent) :: (iotype OR iomsg)
3439 if (CheckDioDummyIsData(subp
, arg
, argPosition
)) {
3440 CheckDioDummyAttrs(subp
, *arg
, intent
);
3441 const DeclTypeSpec
*type
{arg
? arg
->GetType() : nullptr};
3442 const IntrinsicTypeSpec
*intrinsic
{type
? type
->AsIntrinsic() : nullptr};
3444 intrinsic
? evaluate::ToInt64(intrinsic
->kind()) : std::nullopt
};
3445 if (!IsAssumedLengthCharacter(*arg
) ||
3448 context_
.defaultKinds().GetDefaultKind(
3449 TypeCategory::Character
))) {
3450 messages_
.Say(arg
->name(),
3451 "Dummy argument '%s' of a defined input/output procedure"
3452 " must be assumed-length CHARACTER of default kind"_err_en_US
,
3458 void CheckHelper::CheckDioVlistArg(
3459 const Symbol
&subp
, const Symbol
*arg
, std::size_t argPosition
) {
3460 // Vlist argument looks like: INTEGER, INTENT(IN) :: v_list(:)
3461 if (CheckDioDummyIsData(subp
, arg
, argPosition
)) {
3462 CheckDioDummyIsDefaultInteger(subp
, *arg
);
3463 CheckDioDummyAttrs(subp
, *arg
, Attr::INTENT_IN
);
3464 const auto *objectDetails
{arg
->detailsIf
<ObjectEntityDetails
>()};
3465 if (!objectDetails
|| !objectDetails
->shape().CanBeDeferredShape()) {
3466 messages_
.Say(arg
->name(),
3467 "Dummy argument '%s' of a defined input/output procedure must be"
3468 " deferred shape"_err_en_US
,
3474 void CheckHelper::CheckDioArgCount(
3475 const Symbol
&subp
, common::DefinedIo ioKind
, std::size_t argCount
) {
3476 const std::size_t requiredArgCount
{
3477 (std::size_t)(ioKind
== common::DefinedIo::ReadFormatted
||
3478 ioKind
== common::DefinedIo::WriteFormatted
3481 if (argCount
!= requiredArgCount
) {
3482 SayWithDeclaration(subp
,
3483 "Defined input/output procedure '%s' must have"
3484 " %d dummy arguments rather than %d"_err_en_US
,
3485 subp
.name(), requiredArgCount
, argCount
);
3486 context_
.SetError(subp
);
3490 void CheckHelper::CheckDioDummyAttrs(
3491 const Symbol
&subp
, const Symbol
&arg
, Attr goodIntent
) {
3492 // Defined I/O procedures can't have attributes other than INTENT
3493 Attrs attrs
{arg
.attrs()};
3494 if (!attrs
.test(goodIntent
)) {
3495 messages_
.Say(arg
.name(),
3496 "Dummy argument '%s' of a defined input/output procedure"
3497 " must have intent '%s'"_err_en_US
,
3498 arg
.name(), AttrToString(goodIntent
));
3500 attrs
= attrs
- Attr::INTENT_IN
- Attr::INTENT_OUT
- Attr::INTENT_INOUT
;
3501 if (!attrs
.empty()) {
3502 messages_
.Say(arg
.name(),
3503 "Dummy argument '%s' of a defined input/output procedure may not have"
3504 " any attributes"_err_en_US
,
3509 // Enforce semantics for defined input/output procedures (12.6.4.8.2) and C777
3510 void CheckHelper::CheckDefinedIoProc(const Symbol
&symbol
,
3511 const GenericDetails
&details
, common::DefinedIo ioKind
) {
3512 for (auto ref
: details
.specificProcs()) {
3513 const Symbol
&ultimate
{ref
->GetUltimate()};
3514 const auto *binding
{ultimate
.detailsIf
<ProcBindingDetails
>()};
3515 const Symbol
&specific
{*(binding
? &binding
->symbol() : &ultimate
)};
3516 if (ultimate
.attrs().test(Attr::NOPASS
)) { // C774
3517 messages_
.Say("Defined input/output procedure '%s' may not have NOPASS "
3518 "attribute"_err_en_US
,
3520 context_
.SetError(ultimate
);
3522 if (const auto *subpDetails
{specific
.detailsIf
<SubprogramDetails
>()}) {
3523 const std::vector
<Symbol
*> &dummyArgs
{subpDetails
->dummyArgs()};
3524 CheckDioArgCount(specific
, ioKind
, dummyArgs
.size());
3526 for (auto *arg
: dummyArgs
) {
3527 switch (argCount
++) {
3529 // dtv-type-spec, INTENT(INOUT) :: dtv
3530 CheckDioDtvArg(specific
, arg
, ioKind
, symbol
);
3533 // INTEGER, INTENT(IN) :: unit
3534 CheckDefaultIntegerArg(specific
, arg
, Attr::INTENT_IN
);
3537 if (ioKind
== common::DefinedIo::ReadFormatted
||
3538 ioKind
== common::DefinedIo::WriteFormatted
) {
3539 // CHARACTER (LEN=*), INTENT(IN) :: iotype
3540 CheckDioAssumedLenCharacterArg(
3541 specific
, arg
, argCount
, Attr::INTENT_IN
);
3543 // INTEGER, INTENT(OUT) :: iostat
3544 CheckDefaultIntegerArg(specific
, arg
, Attr::INTENT_OUT
);
3548 if (ioKind
== common::DefinedIo::ReadFormatted
||
3549 ioKind
== common::DefinedIo::WriteFormatted
) {
3550 // INTEGER, INTENT(IN) :: v_list(:)
3551 CheckDioVlistArg(specific
, arg
, argCount
);
3553 // CHARACTER (LEN=*), INTENT(INOUT) :: iomsg
3554 CheckDioAssumedLenCharacterArg(
3555 specific
, arg
, argCount
, Attr::INTENT_INOUT
);
3559 // INTEGER, INTENT(OUT) :: iostat
3560 CheckDefaultIntegerArg(specific
, arg
, Attr::INTENT_OUT
);
3563 // CHARACTER (LEN=*), INTENT(INOUT) :: iomsg
3564 CheckDioAssumedLenCharacterArg(
3565 specific
, arg
, argCount
, Attr::INTENT_INOUT
);
3574 void CheckHelper::CheckSymbolType(const Symbol
&symbol
) {
3575 const Symbol
*result
{FindFunctionResult(symbol
)};
3576 const Symbol
&relevant
{result
? *result
: symbol
};
3577 if (IsAllocatable(relevant
)) { // always ok
3578 } else if (IsProcedurePointer(symbol
) && result
&& IsPointer(*result
)) {
3579 // procedure pointer returning allocatable or pointer: ok
3580 } else if (IsPointer(relevant
) && !IsProcedure(relevant
)) {
3581 // object pointers are always ok
3582 } else if (auto dyType
{evaluate::DynamicType::From(relevant
)}) {
3583 if (dyType
->IsPolymorphic() && !dyType
->IsAssumedType() &&
3584 !(IsDummy(symbol
) && !IsProcedure(relevant
))) { // C708
3586 "CLASS entity '%s' must be a dummy argument, allocatable, or object pointer"_err_en_US
,
3589 if (dyType
->HasDeferredTypeParameter()) { // C702
3591 "'%s' has a type %s with a deferred type parameter but is neither an allocatable nor an object pointer"_err_en_US
,
3592 symbol
.name(), dyType
->AsFortran());
3597 void CheckHelper::CheckModuleProcedureDef(const Symbol
&symbol
) {
3598 auto procClass
{ClassifyProcedure(symbol
)};
3599 if (const auto *subprogram
{symbol
.detailsIf
<SubprogramDetails
>()};
3601 (procClass
== ProcedureDefinitionClass::Module
&&
3602 symbol
.attrs().test(Attr::MODULE
)) &&
3603 !subprogram
->bindName() && !subprogram
->isInterface()) {
3604 const Symbol
&interface
{
3605 subprogram
->moduleInterface() ? *subprogram
->moduleInterface() : symbol
3608 module
{interface
.owner().kind() == Scope::Kind::Module
3609 ? interface
.owner().symbol()
3611 module
&& module
->has
<ModuleDetails
>()) {
3612 std::pair
<SourceName
, const Symbol
*> key
{symbol
.name(), module
};
3613 auto iter
{moduleProcs_
.find(key
)};
3614 if (iter
== moduleProcs_
.end()) {
3615 moduleProcs_
.emplace(std::move(key
), symbol
);
3617 auto *msg
{messages_
.Say(symbol
.name(),
3618 "Module procedure '%s' in '%s' has multiple definitions"_err_en_US
,
3619 symbol
.name(), GetModuleOrSubmoduleName(*module
))}) {
3620 msg
->Attach(iter
->second
->name(), "Previous definition of '%s'"_en_US
,
3627 void SubprogramMatchHelper::Check(
3628 const Symbol
&symbol1
, const Symbol
&symbol2
) {
3629 const auto details1
{symbol1
.get
<SubprogramDetails
>()};
3630 const auto details2
{symbol2
.get
<SubprogramDetails
>()};
3631 if (details1
.isFunction() != details2
.isFunction()) {
3632 Say(symbol1
, symbol2
,
3633 details1
.isFunction()
3634 ? "Module function '%s' was declared as a subroutine in the"
3635 " corresponding interface body"_err_en_US
3636 : "Module subroutine '%s' was declared as a function in the"
3637 " corresponding interface body"_err_en_US
);
3640 const auto &args1
{details1
.dummyArgs()};
3641 const auto &args2
{details2
.dummyArgs()};
3642 int nargs1
{static_cast<int>(args1
.size())};
3643 int nargs2
{static_cast<int>(args2
.size())};
3644 if (nargs1
!= nargs2
) {
3645 Say(symbol1
, symbol2
,
3646 "Module subprogram '%s' has %d args but the corresponding interface"
3647 " body has %d"_err_en_US
,
3651 bool nonRecursive1
{symbol1
.attrs().test(Attr::NON_RECURSIVE
)};
3652 if (nonRecursive1
!= symbol2
.attrs().test(Attr::NON_RECURSIVE
)) { // C1551
3653 Say(symbol1
, symbol2
,
3655 ? "Module subprogram '%s' has NON_RECURSIVE prefix but"
3656 " the corresponding interface body does not"_err_en_US
3657 : "Module subprogram '%s' does not have NON_RECURSIVE prefix but "
3658 "the corresponding interface body does"_err_en_US
);
3660 const std::string
*bindName1
{details1
.bindName()};
3661 const std::string
*bindName2
{details2
.bindName()};
3662 if (!bindName1
&& !bindName2
) {
3663 // OK - neither has a binding label
3664 } else if (!bindName1
) {
3665 Say(symbol1
, symbol2
,
3666 "Module subprogram '%s' does not have a binding label but the"
3667 " corresponding interface body does"_err_en_US
);
3668 } else if (!bindName2
) {
3669 Say(symbol1
, symbol2
,
3670 "Module subprogram '%s' has a binding label but the"
3671 " corresponding interface body does not"_err_en_US
);
3672 } else if (*bindName1
!= *bindName2
) {
3673 Say(symbol1
, symbol2
,
3674 "Module subprogram '%s' has binding label '%s' but the corresponding"
3675 " interface body has '%s'"_err_en_US
,
3676 *details1
.bindName(), *details2
.bindName());
3678 const Procedure
*proc1
{checkHelper
.Characterize(symbol1
)};
3679 const Procedure
*proc2
{checkHelper
.Characterize(symbol2
)};
3680 if (!proc1
|| !proc2
) {
3683 if (proc1
->attrs
.test(Procedure::Attr::Pure
) !=
3684 proc2
->attrs
.test(Procedure::Attr::Pure
)) {
3685 Say(symbol1
, symbol2
,
3686 "Module subprogram '%s' and its corresponding interface body are not both PURE"_err_en_US
);
3688 if (proc1
->attrs
.test(Procedure::Attr::Elemental
) !=
3689 proc2
->attrs
.test(Procedure::Attr::Elemental
)) {
3690 Say(symbol1
, symbol2
,
3691 "Module subprogram '%s' and its corresponding interface body are not both ELEMENTAL"_err_en_US
);
3693 if (proc1
->attrs
.test(Procedure::Attr::BindC
) !=
3694 proc2
->attrs
.test(Procedure::Attr::BindC
)) {
3695 Say(symbol1
, symbol2
,
3696 "Module subprogram '%s' and its corresponding interface body are not both BIND(C)"_err_en_US
);
3698 if (proc1
->functionResult
&& proc2
->functionResult
) {
3700 if (!proc1
->functionResult
->IsCompatibleWith(
3701 *proc2
->functionResult
, &whyNot
)) {
3702 Say(symbol1
, symbol2
,
3703 "Result of function '%s' is not compatible with the result of the corresponding interface body: %s"_err_en_US
,
3707 for (int i
{0}; i
< nargs1
; ++i
) {
3708 const Symbol
*arg1
{args1
[i
]};
3709 const Symbol
*arg2
{args2
[i
]};
3710 if (arg1
&& !arg2
) {
3711 Say(symbol1
, symbol2
,
3712 "Dummy argument %2$d of '%1$s' is not an alternate return indicator"
3713 " but the corresponding argument in the interface body is"_err_en_US
,
3715 } else if (!arg1
&& arg2
) {
3716 Say(symbol1
, symbol2
,
3717 "Dummy argument %2$d of '%1$s' is an alternate return indicator but"
3718 " the corresponding argument in the interface body is not"_err_en_US
,
3720 } else if (arg1
&& arg2
) {
3721 SourceName name1
{arg1
->name()};
3722 SourceName name2
{arg2
->name()};
3723 if (name1
!= name2
) {
3725 "Dummy argument name '%s' does not match corresponding name '%s'"
3726 " in interface body"_err_en_US
,
3730 *arg1
, *arg2
, proc1
->dummyArguments
[i
], proc2
->dummyArguments
[i
]);
3736 void SubprogramMatchHelper::CheckDummyArg(const Symbol
&symbol1
,
3737 const Symbol
&symbol2
, const DummyArgument
&arg1
,
3738 const DummyArgument
&arg2
) {
3741 [&](const DummyDataObject
&obj1
, const DummyDataObject
&obj2
) {
3742 CheckDummyDataObject(symbol1
, symbol2
, obj1
, obj2
);
3744 [&](const DummyProcedure
&proc1
, const DummyProcedure
&proc2
) {
3745 CheckDummyProcedure(symbol1
, symbol2
, proc1
, proc2
);
3747 [&](const DummyDataObject
&, const auto &) {
3748 Say(symbol1
, symbol2
,
3749 "Dummy argument '%s' is a data object; the corresponding"
3750 " argument in the interface body is not"_err_en_US
);
3752 [&](const DummyProcedure
&, const auto &) {
3753 Say(symbol1
, symbol2
,
3754 "Dummy argument '%s' is a procedure; the corresponding"
3755 " argument in the interface body is not"_err_en_US
);
3757 [&](const auto &, const auto &) {
3758 llvm_unreachable("Dummy arguments are not data objects or"
3765 void SubprogramMatchHelper::CheckDummyDataObject(const Symbol
&symbol1
,
3766 const Symbol
&symbol2
, const DummyDataObject
&obj1
,
3767 const DummyDataObject
&obj2
) {
3768 if (!CheckSameIntent(symbol1
, symbol2
, obj1
.intent
, obj2
.intent
)) {
3769 } else if (!CheckSameAttrs(symbol1
, symbol2
, obj1
.attrs
, obj2
.attrs
)) {
3770 } else if (!obj1
.type
.type().IsEquivalentTo(obj2
.type
.type())) {
3771 Say(symbol1
, symbol2
,
3772 "Dummy argument '%s' has type %s; the corresponding argument in the interface body has distinct type %s"_err_en_US
,
3773 obj1
.type
.type().AsFortran(), obj2
.type
.type().AsFortran());
3774 } else if (!ShapesAreCompatible(obj1
, obj2
)) {
3775 Say(symbol1
, symbol2
,
3776 "The shape of dummy argument '%s' does not match the shape of the"
3777 " corresponding argument in the interface body"_err_en_US
);
3782 void SubprogramMatchHelper::CheckDummyProcedure(const Symbol
&symbol1
,
3783 const Symbol
&symbol2
, const DummyProcedure
&proc1
,
3784 const DummyProcedure
&proc2
) {
3786 if (!CheckSameIntent(symbol1
, symbol2
, proc1
.intent
, proc2
.intent
)) {
3787 } else if (!CheckSameAttrs(symbol1
, symbol2
, proc1
.attrs
, proc2
.attrs
)) {
3788 } else if (!proc2
.IsCompatibleWith(proc1
, &whyNot
)) {
3789 Say(symbol1
, symbol2
,
3790 "Dummy procedure '%s' is not compatible with the corresponding argument in the interface body: %s"_err_en_US
,
3792 } else if (proc1
!= proc2
) {
3793 evaluate::AttachDeclaration(
3794 symbol1
.owner().context().Warn(
3795 common::UsageWarning::MismatchingDummyProcedure
,
3796 "Dummy procedure '%s' does not exactly match the corresponding argument in the interface body"_warn_en_US
,
3802 bool SubprogramMatchHelper::CheckSameIntent(const Symbol
&symbol1
,
3803 const Symbol
&symbol2
, common::Intent intent1
, common::Intent intent2
) {
3804 if (intent1
== intent2
) {
3807 Say(symbol1
, symbol2
,
3808 "The intent of dummy argument '%s' does not match the intent"
3809 " of the corresponding argument in the interface body"_err_en_US
);
3814 // Report an error referring to first symbol with declaration of second symbol
3815 template <typename
... A
>
3816 void SubprogramMatchHelper::Say(const Symbol
&symbol1
, const Symbol
&symbol2
,
3817 parser::MessageFixedText
&&text
, A
&&...args
) {
3818 auto &message
{context().Say(symbol1
.name(), std::move(text
), symbol1
.name(),
3819 std::forward
<A
>(args
)...)};
3820 evaluate::AttachDeclaration(message
, symbol2
);
3823 template <typename ATTRS
>
3824 bool SubprogramMatchHelper::CheckSameAttrs(
3825 const Symbol
&symbol1
, const Symbol
&symbol2
, ATTRS attrs1
, ATTRS attrs2
) {
3826 if (attrs1
== attrs2
) {
3829 attrs1
.IterateOverMembers([&](auto attr
) {
3830 if (!attrs2
.test(attr
)) {
3831 Say(symbol1
, symbol2
,
3832 "Dummy argument '%s' has the %s attribute; the corresponding"
3833 " argument in the interface body does not"_err_en_US
,
3837 attrs2
.IterateOverMembers([&](auto attr
) {
3838 if (!attrs1
.test(attr
)) {
3839 Say(symbol1
, symbol2
,
3840 "Dummy argument '%s' does not have the %s attribute; the"
3841 " corresponding argument in the interface body does"_err_en_US
,
3848 bool SubprogramMatchHelper::ShapesAreCompatible(
3849 const DummyDataObject
&obj1
, const DummyDataObject
&obj2
) {
3850 return characteristics::ShapesAreCompatible(
3851 FoldShape(obj1
.type
.shape()), FoldShape(obj2
.type
.shape()));
3854 evaluate::Shape
SubprogramMatchHelper::FoldShape(const evaluate::Shape
&shape
) {
3855 evaluate::Shape result
;
3856 for (const auto &extent
: shape
) {
3857 result
.emplace_back(
3858 evaluate::Fold(context().foldingContext(), common::Clone(extent
)));
3863 void DistinguishabilityHelper::Add(const Symbol
&generic
, GenericKind kind
,
3864 const Symbol
&ultimateSpecific
, const Procedure
&procedure
) {
3865 if (!context_
.HasError(ultimateSpecific
)) {
3866 nameToSpecifics_
[generic
.name()].emplace(
3867 &ultimateSpecific
, ProcedureInfo
{kind
, procedure
});
3871 void DistinguishabilityHelper::Check(const Scope
&scope
) {
3872 if (FindModuleFileContaining(scope
)) {
3873 // Distinguishability was checked when the module was created;
3874 // don't let optional warnings then become errors now.
3877 for (const auto &[name
, info
] : nameToSpecifics_
) {
3878 for (auto iter1
{info
.begin()}; iter1
!= info
.end(); ++iter1
) {
3879 const auto &[ultimate
, procInfo
]{*iter1
};
3880 const auto &[kind
, proc
]{procInfo
};
3881 for (auto iter2
{iter1
}; ++iter2
!= info
.end();) {
3882 auto distinguishable
{kind
.IsName()
3883 ? evaluate::characteristics::Distinguishable
3884 : evaluate::characteristics::DistinguishableOpOrAssign
};
3885 std::optional
<bool> distinct
{distinguishable(
3886 context_
.languageFeatures(), proc
, iter2
->second
.procedure
)};
3887 if (!distinct
.value_or(false)) {
3888 SayNotDistinguishable(GetTopLevelUnitContaining(scope
), name
, kind
,
3889 *ultimate
, *iter2
->first
, distinct
.has_value());
3896 void DistinguishabilityHelper::SayNotDistinguishable(const Scope
&scope
,
3897 const SourceName
&name
, GenericKind kind
, const Symbol
&proc1
,
3898 const Symbol
&proc2
, bool isHardConflict
) {
3899 bool isUseAssociated
{!scope
.sourceRange().Contains(name
)};
3900 // The rules for distinguishing specific procedures (F'2023 15.4.3.4.5)
3901 // are inadequate for some real-world cases like pFUnit.
3902 // When there are optional dummy arguments or unlimited polymorphic
3903 // dummy data object arguments, the best that we can do is emit an optional
3904 // portability warning. Also, named generics created by USE association
3905 // merging shouldn't receive hard errors for ambiguity.
3906 // (Non-named generics might be defined I/O procedures or defined
3907 // assignments that need to be used by the runtime.)
3908 bool isWarning
{!isHardConflict
|| (isUseAssociated
&& kind
.IsName())};
3910 (!context_
.ShouldWarn(
3911 common::LanguageFeature::IndistinguishableSpecifics
) ||
3912 FindModuleFileContaining(scope
))) {
3915 std::string name1
{proc1
.name().ToString()};
3916 std::string name2
{proc2
.name().ToString()};
3917 if (kind
.IsOperator() || kind
.IsAssignment()) {
3918 // proc1 and proc2 may come from different scopes so qualify their names
3919 if (proc1
.owner().IsDerivedType()) {
3920 name1
= proc1
.owner().GetName()->ToString() + '%' + name1
;
3922 if (proc2
.owner().IsDerivedType()) {
3923 name2
= proc2
.owner().GetName()->ToString() + '%' + name2
;
3926 parser::Message
*msg
;
3927 if (!isUseAssociated
) {
3928 CHECK(isWarning
== !isHardConflict
);
3929 msg
= &context_
.Say(name
,
3931 ? "Generic '%s' may not have specific procedures '%s' and '%s' as their interfaces are not distinguishable"_err_en_US
3932 : "Generic '%s' should not have specific procedures '%s' and '%s' as their interfaces are not distinguishable by the rules in the standard"_port_en_US
,
3933 MakeOpName(name
), name1
, name2
);
3935 msg
= &context_
.Say(*GetTopLevelUnitContaining(proc1
).GetName(),
3938 ? "USE-associated generic '%s' should not have specific procedures '%s' and '%s' as their interfaces are not distinguishable"_warn_en_US
3939 : "USE-associated generic '%s' may not have specific procedures '%s' and '%s' as their interfaces are not distinguishable"_err_en_US
)
3940 : "USE-associated generic '%s' should not have specific procedures '%s' and '%s' as their interfaces are not distinguishable by the rules in the standard"_port_en_US
,
3941 MakeOpName(name
), name1
, name2
);
3943 AttachDeclaration(*msg
, scope
, proc1
);
3944 AttachDeclaration(*msg
, scope
, proc2
);
3947 // `evaluate::AttachDeclaration` doesn't handle the generic case where `proc`
3948 // comes from a different module but is not necessarily use-associated.
3949 void DistinguishabilityHelper::AttachDeclaration(
3950 parser::Message
&msg
, const Scope
&scope
, const Symbol
&proc
) {
3951 const Scope
&unit
{GetTopLevelUnitContaining(proc
)};
3952 if (unit
== scope
) {
3953 evaluate::AttachDeclaration(msg
, proc
);
3955 msg
.Attach(unit
.GetName().value(),
3956 "'%s' is USE-associated from module '%s'"_en_US
, proc
.name(),
3957 unit
.GetName().value());
3961 void CheckDeclarations(SemanticsContext
&context
) {
3962 CheckHelper
{context
}.Check();
3964 } // namespace Fortran::semantics