1 //===-- lib/Semantics/resolve-names-utils.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 #include "resolve-names-utils.h"
10 #include "flang/Common/Fortran-features.h"
11 #include "flang/Common/Fortran.h"
12 #include "flang/Common/idioms.h"
13 #include "flang/Common/indirection.h"
14 #include "flang/Evaluate/fold.h"
15 #include "flang/Evaluate/tools.h"
16 #include "flang/Evaluate/traverse.h"
17 #include "flang/Evaluate/type.h"
18 #include "flang/Parser/char-block.h"
19 #include "flang/Parser/parse-tree.h"
20 #include "flang/Semantics/expression.h"
21 #include "flang/Semantics/semantics.h"
22 #include "flang/Semantics/tools.h"
23 #include <initializer_list>
26 namespace Fortran::semantics
{
28 using common::LanguageFeature
;
29 using common::LogicalOperator
;
30 using common::NumericOperator
;
31 using common::RelationalOperator
;
32 using IntrinsicOperator
= parser::DefinedOperator::IntrinsicOperator
;
34 static constexpr const char *operatorPrefix
{"operator("};
36 static GenericKind
MapIntrinsicOperator(IntrinsicOperator
);
38 Symbol
*Resolve(const parser::Name
&name
, Symbol
*symbol
) {
39 if (symbol
&& !name
.symbol
) {
44 Symbol
&Resolve(const parser::Name
&name
, Symbol
&symbol
) {
45 return *Resolve(name
, &symbol
);
48 parser::MessageFixedText
WithSeverity(
49 const parser::MessageFixedText
&msg
, parser::Severity severity
) {
50 return parser::MessageFixedText
{
51 msg
.text().begin(), msg
.text().size(), severity
};
54 bool IsIntrinsicOperator(
55 const SemanticsContext
&context
, const SourceName
&name
) {
56 std::string str
{name
.ToString()};
57 for (int i
{0}; i
!= common::LogicalOperator_enumSize
; ++i
) {
58 auto names
{context
.languageFeatures().GetNames(LogicalOperator
{i
})};
59 if (llvm::is_contained(names
, str
)) {
63 for (int i
{0}; i
!= common::RelationalOperator_enumSize
; ++i
) {
64 auto names
{context
.languageFeatures().GetNames(RelationalOperator
{i
})};
65 if (llvm::is_contained(names
, str
)) {
73 std::forward_list
<std::string
> GetOperatorNames(
74 const SemanticsContext
&context
, E opr
) {
75 std::forward_list
<std::string
> result
;
76 for (const char *name
: context
.languageFeatures().GetNames(opr
)) {
77 result
.emplace_front(std::string
{operatorPrefix
} + name
+ ')');
82 std::forward_list
<std::string
> GetAllNames(
83 const SemanticsContext
&context
, const SourceName
&name
) {
84 std::string str
{name
.ToString()};
85 if (!name
.empty() && name
.end()[-1] == ')' &&
86 name
.ToString().rfind(std::string
{operatorPrefix
}, 0) == 0) {
87 for (int i
{0}; i
!= common::LogicalOperator_enumSize
; ++i
) {
88 auto names
{GetOperatorNames(context
, LogicalOperator
{i
})};
89 if (llvm::is_contained(names
, str
)) {
93 for (int i
{0}; i
!= common::RelationalOperator_enumSize
; ++i
) {
94 auto names
{GetOperatorNames(context
, RelationalOperator
{i
})};
95 if (llvm::is_contained(names
, str
)) {
103 bool IsLogicalConstant(
104 const SemanticsContext
&context
, const SourceName
&name
) {
105 std::string str
{name
.ToString()};
106 return str
== ".true." || str
== ".false." ||
107 (context
.IsEnabled(LanguageFeature::LogicalAbbreviations
) &&
108 (str
== ".t" || str
== ".f."));
111 void GenericSpecInfo::Resolve(Symbol
*symbol
) const {
113 if (auto *details
{symbol
->detailsIf
<GenericDetails
>()}) {
114 details
->set_kind(kind_
);
117 semantics::Resolve(*parseName_
, symbol
);
122 void GenericSpecInfo::Analyze(const parser::DefinedOpName
&name
) {
123 kind_
= GenericKind::OtherKind::DefinedOp
;
124 parseName_
= &name
.v
;
125 symbolName_
= name
.v
.source
;
128 void GenericSpecInfo::Analyze(const parser::GenericSpec
&x
) {
129 symbolName_
= x
.source
;
130 kind_
= common::visit(
132 [&](const parser::Name
&y
) -> GenericKind
{
134 symbolName_
= y
.source
;
135 return GenericKind::OtherKind::Name
;
137 [&](const parser::DefinedOperator
&y
) {
138 return common::visit(
140 [&](const parser::DefinedOpName
&z
) -> GenericKind
{
142 return GenericKind::OtherKind::DefinedOp
;
144 [&](const IntrinsicOperator
&z
) {
145 return MapIntrinsicOperator(z
);
150 [&](const parser::GenericSpec::Assignment
&) -> GenericKind
{
151 return GenericKind::OtherKind::Assignment
;
153 [&](const parser::GenericSpec::ReadFormatted
&) -> GenericKind
{
154 return GenericKind::DefinedIo::ReadFormatted
;
156 [&](const parser::GenericSpec::ReadUnformatted
&) -> GenericKind
{
157 return GenericKind::DefinedIo::ReadUnformatted
;
159 [&](const parser::GenericSpec::WriteFormatted
&) -> GenericKind
{
160 return GenericKind::DefinedIo::WriteFormatted
;
162 [&](const parser::GenericSpec::WriteUnformatted
&) -> GenericKind
{
163 return GenericKind::DefinedIo::WriteUnformatted
;
169 llvm::raw_ostream
&operator<<(
170 llvm::raw_ostream
&os
, const GenericSpecInfo
&info
) {
171 os
<< "GenericSpecInfo: kind=" << info
.kind_
.ToString();
173 << (info
.parseName_
? info
.parseName_
->ToString() : "null");
175 << (info
.symbolName_
? info
.symbolName_
->ToString() : "null");
179 // parser::DefinedOperator::IntrinsicOperator -> GenericKind
180 static GenericKind
MapIntrinsicOperator(IntrinsicOperator op
) {
182 SWITCH_COVERS_ALL_CASES
183 case IntrinsicOperator::Concat
:
184 return GenericKind::OtherKind::Concat
;
185 case IntrinsicOperator::Power
:
186 return NumericOperator::Power
;
187 case IntrinsicOperator::Multiply
:
188 return NumericOperator::Multiply
;
189 case IntrinsicOperator::Divide
:
190 return NumericOperator::Divide
;
191 case IntrinsicOperator::Add
:
192 return NumericOperator::Add
;
193 case IntrinsicOperator::Subtract
:
194 return NumericOperator::Subtract
;
195 case IntrinsicOperator::AND
:
196 return LogicalOperator::And
;
197 case IntrinsicOperator::OR
:
198 return LogicalOperator::Or
;
199 case IntrinsicOperator::EQV
:
200 return LogicalOperator::Eqv
;
201 case IntrinsicOperator::NEQV
:
202 return LogicalOperator::Neqv
;
203 case IntrinsicOperator::NOT
:
204 return LogicalOperator::Not
;
205 case IntrinsicOperator::LT
:
206 return RelationalOperator::LT
;
207 case IntrinsicOperator::LE
:
208 return RelationalOperator::LE
;
209 case IntrinsicOperator::EQ
:
210 return RelationalOperator::EQ
;
211 case IntrinsicOperator::NE
:
212 return RelationalOperator::NE
;
213 case IntrinsicOperator::GE
:
214 return RelationalOperator::GE
;
215 case IntrinsicOperator::GT
:
216 return RelationalOperator::GT
;
220 class ArraySpecAnalyzer
{
222 ArraySpecAnalyzer(SemanticsContext
&context
) : context_
{context
} {}
223 ArraySpec
Analyze(const parser::ArraySpec
&);
224 ArraySpec
AnalyzeDeferredShapeSpecList(const parser::DeferredShapeSpecList
&);
225 ArraySpec
Analyze(const parser::ComponentArraySpec
&);
226 ArraySpec
Analyze(const parser::CoarraySpec
&);
229 SemanticsContext
&context_
;
230 ArraySpec arraySpec_
;
232 template <typename T
> void Analyze(const std::list
<T
> &list
) {
233 for (const auto &elem
: list
) {
237 void Analyze(const parser::AssumedShapeSpec
&);
238 void Analyze(const parser::ExplicitShapeSpec
&);
239 void Analyze(const parser::AssumedImpliedSpec
&);
240 void Analyze(const parser::DeferredShapeSpecList
&);
241 void Analyze(const parser::AssumedRankSpec
&);
242 void MakeExplicit(const std::optional
<parser::SpecificationExpr
> &,
243 const parser::SpecificationExpr
&);
244 void MakeImplied(const std::optional
<parser::SpecificationExpr
> &);
245 void MakeDeferred(int);
246 Bound
GetBound(const std::optional
<parser::SpecificationExpr
> &);
247 Bound
GetBound(const parser::SpecificationExpr
&);
250 ArraySpec
AnalyzeArraySpec(
251 SemanticsContext
&context
, const parser::ArraySpec
&arraySpec
) {
252 return ArraySpecAnalyzer
{context
}.Analyze(arraySpec
);
254 ArraySpec
AnalyzeArraySpec(
255 SemanticsContext
&context
, const parser::ComponentArraySpec
&arraySpec
) {
256 return ArraySpecAnalyzer
{context
}.Analyze(arraySpec
);
258 ArraySpec
AnalyzeDeferredShapeSpecList(SemanticsContext
&context
,
259 const parser::DeferredShapeSpecList
&deferredShapeSpecs
) {
260 return ArraySpecAnalyzer
{context
}.AnalyzeDeferredShapeSpecList(
263 ArraySpec
AnalyzeCoarraySpec(
264 SemanticsContext
&context
, const parser::CoarraySpec
&coarraySpec
) {
265 return ArraySpecAnalyzer
{context
}.Analyze(coarraySpec
);
268 ArraySpec
ArraySpecAnalyzer::Analyze(const parser::ComponentArraySpec
&x
) {
269 common::visit([this](const auto &y
) { Analyze(y
); }, x
.u
);
270 CHECK(!arraySpec_
.empty());
273 ArraySpec
ArraySpecAnalyzer::Analyze(const parser::ArraySpec
&x
) {
274 common::visit(common::visitors
{
275 [&](const parser::AssumedSizeSpec
&y
) {
277 std::get
<std::list
<parser::ExplicitShapeSpec
>>(y
.t
));
278 Analyze(std::get
<parser::AssumedImpliedSpec
>(y
.t
));
280 [&](const parser::ImpliedShapeSpec
&y
) { Analyze(y
.v
); },
281 [&](const auto &y
) { Analyze(y
); },
284 CHECK(!arraySpec_
.empty());
287 ArraySpec
ArraySpecAnalyzer::AnalyzeDeferredShapeSpecList(
288 const parser::DeferredShapeSpecList
&x
) {
290 CHECK(!arraySpec_
.empty());
293 ArraySpec
ArraySpecAnalyzer::Analyze(const parser::CoarraySpec
&x
) {
296 [&](const parser::DeferredCoshapeSpecList
&y
) { MakeDeferred(y
.v
); },
297 [&](const parser::ExplicitCoshapeSpec
&y
) {
298 Analyze(std::get
<std::list
<parser::ExplicitShapeSpec
>>(y
.t
));
300 std::get
<std::optional
<parser::SpecificationExpr
>>(y
.t
));
304 CHECK(!arraySpec_
.empty());
308 void ArraySpecAnalyzer::Analyze(const parser::AssumedShapeSpec
&x
) {
309 arraySpec_
.push_back(ShapeSpec::MakeAssumedShape(GetBound(x
.v
)));
311 void ArraySpecAnalyzer::Analyze(const parser::ExplicitShapeSpec
&x
) {
312 MakeExplicit(std::get
<std::optional
<parser::SpecificationExpr
>>(x
.t
),
313 std::get
<parser::SpecificationExpr
>(x
.t
));
315 void ArraySpecAnalyzer::Analyze(const parser::AssumedImpliedSpec
&x
) {
318 void ArraySpecAnalyzer::Analyze(const parser::DeferredShapeSpecList
&x
) {
321 void ArraySpecAnalyzer::Analyze(const parser::AssumedRankSpec
&) {
322 arraySpec_
.push_back(ShapeSpec::MakeAssumedRank());
325 void ArraySpecAnalyzer::MakeExplicit(
326 const std::optional
<parser::SpecificationExpr
> &lb
,
327 const parser::SpecificationExpr
&ub
) {
328 arraySpec_
.push_back(ShapeSpec::MakeExplicit(GetBound(lb
), GetBound(ub
)));
330 void ArraySpecAnalyzer::MakeImplied(
331 const std::optional
<parser::SpecificationExpr
> &lb
) {
332 arraySpec_
.push_back(ShapeSpec::MakeImplied(GetBound(lb
)));
334 void ArraySpecAnalyzer::MakeDeferred(int n
) {
335 for (int i
= 0; i
< n
; ++i
) {
336 arraySpec_
.push_back(ShapeSpec::MakeDeferred());
340 Bound
ArraySpecAnalyzer::GetBound(
341 const std::optional
<parser::SpecificationExpr
> &x
) {
342 return x
? GetBound(*x
) : Bound
{1};
344 Bound
ArraySpecAnalyzer::GetBound(const parser::SpecificationExpr
&x
) {
345 MaybeSubscriptIntExpr expr
;
346 if (MaybeExpr maybeExpr
{AnalyzeExpr(context_
, x
.v
)}) {
347 if (auto *intExpr
{evaluate::UnwrapExpr
<SomeIntExpr
>(*maybeExpr
)}) {
348 expr
= evaluate::Fold(context_
.foldingContext(),
349 evaluate::ConvertToType
<evaluate::SubscriptInteger
>(
350 std::move(*intExpr
)));
353 return Bound
{std::move(expr
)};
356 // If SAVE is set on src, set it on all members of dst
357 static void PropagateSaveAttr(
358 const EquivalenceObject
&src
, EquivalenceSet
&dst
) {
359 if (src
.symbol
.attrs().test(Attr::SAVE
)) {
360 for (auto &obj
: dst
) {
361 obj
.symbol
.attrs().set(Attr::SAVE
);
365 static void PropagateSaveAttr(const EquivalenceSet
&src
, EquivalenceSet
&dst
) {
367 PropagateSaveAttr(src
.front(), dst
);
371 void EquivalenceSets::AddToSet(const parser::Designator
&designator
) {
372 if (CheckDesignator(designator
)) {
373 Symbol
&symbol
{*currObject_
.symbol
};
374 if (!currSet_
.empty()) {
375 // check this symbol against first of set for compatibility
376 Symbol
&first
{currSet_
.front().symbol
};
377 CheckCanEquivalence(designator
.source
, first
, symbol
) &&
378 CheckCanEquivalence(designator
.source
, symbol
, first
);
380 auto subscripts
{currObject_
.subscripts
};
381 if (subscripts
.empty() && symbol
.IsObjectArray()) {
382 // record a whole array as its first element
383 for (const ShapeSpec
&spec
: symbol
.get
<ObjectEntityDetails
>().shape()) {
384 auto &lbound
{spec
.lbound().GetExplicit().value()};
385 subscripts
.push_back(evaluate::ToInt64(lbound
).value());
388 auto substringStart
{currObject_
.substringStart
};
389 currSet_
.emplace_back(
390 symbol
, subscripts
, substringStart
, designator
.source
);
391 PropagateSaveAttr(currSet_
.back(), currSet_
);
396 void EquivalenceSets::FinishSet(const parser::CharBlock
&source
) {
397 std::set
<std::size_t> existing
; // indices of sets intersecting this one
398 for (auto &obj
: currSet_
) {
399 auto it
{objectToSet_
.find(obj
)};
400 if (it
!= objectToSet_
.end()) {
401 existing
.insert(it
->second
); // symbol already in this set
404 if (existing
.empty()) {
405 sets_
.push_back({}); // create a new equivalence set
406 MergeInto(source
, currSet_
, sets_
.size() - 1);
408 auto it
{existing
.begin()};
409 std::size_t dstIndex
{*it
};
410 MergeInto(source
, currSet_
, dstIndex
);
411 while (++it
!= existing
.end()) {
412 MergeInto(source
, sets_
[*it
], dstIndex
);
418 // Report an error or warning if sym1 and sym2 cannot be in the same equivalence
420 bool EquivalenceSets::CheckCanEquivalence(
421 const parser::CharBlock
&source
, const Symbol
&sym1
, const Symbol
&sym2
) {
422 std::optional
<parser::MessageFixedText
> msg
;
423 const DeclTypeSpec
*type1
{sym1
.GetType()};
424 const DeclTypeSpec
*type2
{sym2
.GetType()};
425 bool isDefaultNum1
{IsDefaultNumericSequenceType(type1
)};
426 bool isAnyNum1
{IsAnyNumericSequenceType(type1
)};
427 bool isDefaultNum2
{IsDefaultNumericSequenceType(type2
)};
428 bool isAnyNum2
{IsAnyNumericSequenceType(type2
)};
429 bool isChar1
{IsCharacterSequenceType(type1
)};
430 bool isChar2
{IsCharacterSequenceType(type2
)};
431 if (sym1
.attrs().test(Attr::PROTECTED
) &&
432 !sym2
.attrs().test(Attr::PROTECTED
)) { // C8114
433 msg
= "Equivalence set cannot contain '%s'"
434 " with PROTECTED attribute and '%s' without"_err_en_US
;
435 } else if ((isDefaultNum1
&& isDefaultNum2
) || (isChar1
&& isChar2
)) {
436 // ok & standard conforming
437 } else if (!(isAnyNum1
|| isChar1
) &&
438 !(isAnyNum2
|| isChar2
)) { // C8110 - C8113
439 if (AreTkCompatibleTypes(type1
, type2
)) {
440 if (context_
.ShouldWarn(LanguageFeature::EquivalenceSameNonSequence
)) {
442 "nonstandard: Equivalence set contains '%s' and '%s' with same "
443 "type that is neither numeric nor character sequence type"_port_en_US
;
446 msg
= "Equivalence set cannot contain '%s' and '%s' with distinct types "
447 "that are not both numeric or character sequence types"_err_en_US
;
449 } else if (isAnyNum1
) {
451 if (context_
.ShouldWarn(
452 LanguageFeature::EquivalenceNumericWithCharacter
)) {
453 msg
= "nonstandard: Equivalence set contains '%s' that is numeric "
454 "sequence type and '%s' that is character"_port_en_US
;
456 } else if (isAnyNum2
&&
457 context_
.ShouldWarn(LanguageFeature::EquivalenceNonDefaultNumeric
)) {
460 "nonstandard: Equivalence set contains '%s' that is a default "
461 "numeric sequence type and '%s' that is numeric with non-default kind"_port_en_US
;
462 } else if (!isDefaultNum2
) {
463 msg
= "nonstandard: Equivalence set contains '%s' and '%s' that are "
464 "numeric sequence types with non-default kinds"_port_en_US
;
469 (!context_
.IsInModuleFile(source
) ||
470 msg
->severity() == parser::Severity::Error
)) {
471 context_
.Say(source
, std::move(*msg
), sym1
.name(), sym2
.name());
477 // Move objects from src to sets_[dstIndex]
478 void EquivalenceSets::MergeInto(const parser::CharBlock
&source
,
479 EquivalenceSet
&src
, std::size_t dstIndex
) {
480 EquivalenceSet
&dst
{sets_
[dstIndex
]};
481 PropagateSaveAttr(dst
, src
);
482 for (const auto &obj
: src
) {
484 objectToSet_
[obj
] = dstIndex
;
486 PropagateSaveAttr(src
, dst
);
490 // If set has an object with this symbol, return it.
491 const EquivalenceObject
*EquivalenceSets::Find(
492 const EquivalenceSet
&set
, const Symbol
&symbol
) {
493 for (const auto &obj
: set
) {
494 if (obj
.symbol
== symbol
) {
501 bool EquivalenceSets::CheckDesignator(const parser::Designator
&designator
) {
502 return common::visit(
504 [&](const parser::DataRef
&x
) {
505 return CheckDataRef(designator
.source
, x
);
507 [&](const parser::Substring
&x
) {
508 const auto &dataRef
{std::get
<parser::DataRef
>(x
.t
)};
509 const auto &range
{std::get
<parser::SubstringRange
>(x
.t
)};
510 bool ok
{CheckDataRef(designator
.source
, dataRef
)};
511 if (const auto &lb
{std::get
<0>(range
.t
)}) {
512 ok
&= CheckSubstringBound(lb
->thing
.thing
.value(), true);
514 currObject_
.substringStart
= 1;
516 if (const auto &ub
{std::get
<1>(range
.t
)}) {
517 ok
&= CheckSubstringBound(ub
->thing
.thing
.value(), false);
525 bool EquivalenceSets::CheckDataRef(
526 const parser::CharBlock
&source
, const parser::DataRef
&x
) {
527 return common::visit(
529 [&](const parser::Name
&name
) { return CheckObject(name
); },
530 [&](const common::Indirection
<parser::StructureComponent
> &) {
531 context_
.Say(source
, // C8107
532 "Derived type component '%s' is not allowed in an equivalence set"_err_en_US
,
536 [&](const common::Indirection
<parser::ArrayElement
> &elem
) {
537 bool ok
{CheckDataRef(source
, elem
.value().base
)};
538 for (const auto &subscript
: elem
.value().subscripts
) {
541 [&](const parser::SubscriptTriplet
&) {
542 context_
.Say(source
, // C924, R872
543 "Array section '%s' is not allowed in an equivalence set"_err_en_US
,
547 [&](const parser::IntExpr
&y
) {
548 return CheckArrayBound(y
.thing
.value());
555 [&](const common::Indirection
<parser::CoindexedNamedObject
> &) {
556 context_
.Say(source
, // C924 (R872)
557 "Coindexed object '%s' is not allowed in an equivalence set"_err_en_US
,
565 static bool InCommonWithBind(const Symbol
&symbol
) {
566 if (const auto *details
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
567 const Symbol
*commonBlock
{details
->commonBlock()};
568 return commonBlock
&& commonBlock
->attrs().test(Attr::BIND_C
);
574 // If symbol can't be in equivalence set report error and return false;
575 bool EquivalenceSets::CheckObject(const parser::Name
&name
) {
577 return false; // an error has already occurred
579 currObject_
.symbol
= name
.symbol
;
580 parser::MessageFixedText msg
;
581 const Symbol
&symbol
{*name
.symbol
};
582 if (symbol
.owner().IsDerivedType()) { // C8107
583 msg
= "Derived type component '%s'"
584 " is not allowed in an equivalence set"_err_en_US
;
585 } else if (IsDummy(symbol
)) { // C8106
586 msg
= "Dummy argument '%s' is not allowed in an equivalence set"_err_en_US
;
587 } else if (symbol
.IsFuncResult()) { // C8106
588 msg
= "Function result '%s' is not allow in an equivalence set"_err_en_US
;
589 } else if (IsPointer(symbol
)) { // C8106
590 msg
= "Pointer '%s' is not allowed in an equivalence set"_err_en_US
;
591 } else if (IsAllocatable(symbol
)) { // C8106
592 msg
= "Allocatable variable '%s'"
593 " is not allowed in an equivalence set"_err_en_US
;
594 } else if (symbol
.Corank() > 0) { // C8106
595 msg
= "Coarray '%s' is not allowed in an equivalence set"_err_en_US
;
596 } else if (symbol
.has
<UseDetails
>()) { // C8115
597 msg
= "Use-associated variable '%s'"
598 " is not allowed in an equivalence set"_err_en_US
;
599 } else if (symbol
.attrs().test(Attr::BIND_C
)) { // C8106
600 msg
= "Variable '%s' with BIND attribute"
601 " is not allowed in an equivalence set"_err_en_US
;
602 } else if (symbol
.attrs().test(Attr::TARGET
)) { // C8108
603 msg
= "Variable '%s' with TARGET attribute"
604 " is not allowed in an equivalence set"_err_en_US
;
605 } else if (IsNamedConstant(symbol
)) { // C8106
606 msg
= "Named constant '%s' is not allowed in an equivalence set"_err_en_US
;
607 } else if (InCommonWithBind(symbol
)) { // C8106
608 msg
= "Variable '%s' in common block with BIND attribute"
609 " is not allowed in an equivalence set"_err_en_US
;
610 } else if (const auto *type
{symbol
.GetType()}) {
611 if (const auto *derived
{type
->AsDerived()}) {
612 if (const auto *comp
{FindUltimateComponent(
613 *derived
, IsAllocatableOrPointer
)}) { // C8106
614 msg
= IsPointer(*comp
)
615 ? "Derived type object '%s' with pointer ultimate component"
616 " is not allowed in an equivalence set"_err_en_US
617 : "Derived type object '%s' with allocatable ultimate component"
618 " is not allowed in an equivalence set"_err_en_US
;
619 } else if (!derived
->typeSymbol().get
<DerivedTypeDetails
>().sequence()) {
620 msg
= "Nonsequence derived type object '%s'"
621 " is not allowed in an equivalence set"_err_en_US
;
623 } else if (IsAutomatic(symbol
)) {
624 msg
= "Automatic object '%s'"
625 " is not allowed in an equivalence set"_err_en_US
;
628 if (!msg
.text().empty()) {
629 context_
.Say(name
.source
, std::move(msg
), name
.source
);
635 bool EquivalenceSets::CheckArrayBound(const parser::Expr
&bound
) {
637 evaluate::Fold(context_
.foldingContext(), AnalyzeExpr(context_
, bound
))};
641 if (expr
->Rank() > 0) {
642 context_
.Say(bound
.source
, // C924, R872
643 "Array with vector subscript '%s' is not allowed in an equivalence set"_err_en_US
,
647 auto subscript
{evaluate::ToInt64(*expr
)};
649 context_
.Say(bound
.source
, // C8109
650 "Array with nonconstant subscript '%s' is not allowed in an equivalence set"_err_en_US
,
654 currObject_
.subscripts
.push_back(*subscript
);
658 bool EquivalenceSets::CheckSubstringBound(
659 const parser::Expr
&bound
, bool isStart
) {
661 evaluate::Fold(context_
.foldingContext(), AnalyzeExpr(context_
, bound
))};
665 auto subscript
{evaluate::ToInt64(*expr
)};
667 context_
.Say(bound
.source
, // C8109
668 "Substring with nonconstant bound '%s' is not allowed in an equivalence set"_err_en_US
,
673 auto start
{currObject_
.substringStart
};
674 if (*subscript
< (start
? *start
: 1)) {
675 context_
.Say(bound
.source
, // C8116
676 "Substring with zero length is not allowed in an equivalence set"_err_en_US
);
679 } else if (*subscript
!= 1) {
680 currObject_
.substringStart
= *subscript
;
685 bool EquivalenceSets::IsCharacterSequenceType(const DeclTypeSpec
*type
) {
686 return IsSequenceType(type
, [&](const IntrinsicTypeSpec
&type
) {
687 auto kind
{evaluate::ToInt64(type
.kind())};
688 return type
.category() == TypeCategory::Character
&& kind
&&
689 kind
.value() == context_
.GetDefaultKind(TypeCategory::Character
);
693 // Numeric or logical type of default kind or DOUBLE PRECISION or DOUBLE COMPLEX
694 bool EquivalenceSets::IsDefaultKindNumericType(const IntrinsicTypeSpec
&type
) {
695 if (auto kind
{evaluate::ToInt64(type
.kind())}) {
696 switch (type
.category()) {
697 case TypeCategory::Integer
:
698 case TypeCategory::Logical
:
699 return *kind
== context_
.GetDefaultKind(TypeCategory::Integer
);
700 case TypeCategory::Real
:
701 case TypeCategory::Complex
:
702 return *kind
== context_
.GetDefaultKind(TypeCategory::Real
) ||
703 *kind
== context_
.doublePrecisionKind();
711 bool EquivalenceSets::IsDefaultNumericSequenceType(const DeclTypeSpec
*type
) {
712 return IsSequenceType(type
, [&](const IntrinsicTypeSpec
&type
) {
713 return IsDefaultKindNumericType(type
);
717 bool EquivalenceSets::IsAnyNumericSequenceType(const DeclTypeSpec
*type
) {
718 return IsSequenceType(type
, [&](const IntrinsicTypeSpec
&type
) {
719 return type
.category() == TypeCategory::Logical
||
720 common::IsNumericTypeCategory(type
.category());
724 // Is type an intrinsic type that satisfies predicate or a sequence type
725 // whose components do.
726 bool EquivalenceSets::IsSequenceType(const DeclTypeSpec
*type
,
727 std::function
<bool(const IntrinsicTypeSpec
&)> predicate
) {
730 } else if (const IntrinsicTypeSpec
* intrinsic
{type
->AsIntrinsic()}) {
731 return predicate(*intrinsic
);
732 } else if (const DerivedTypeSpec
* derived
{type
->AsDerived()}) {
733 for (const auto &pair
: *derived
->typeSymbol().scope()) {
734 const Symbol
&component
{*pair
.second
};
735 if (IsAllocatableOrPointer(component
) ||
736 !IsSequenceType(component
.GetType(), predicate
)) {
746 // MapSubprogramToNewSymbols() relies on the following recursive symbol/scope
747 // copying infrastructure to duplicate an interface's symbols and map all
748 // of the symbol references in their contained expressions and interfaces
749 // to the new symbols.
751 struct SymbolAndTypeMappings
{
752 std::map
<const Symbol
*, const Symbol
*> symbolMap
;
753 std::map
<const DeclTypeSpec
*, const DeclTypeSpec
*> typeMap
;
756 class SymbolMapper
: public evaluate::AnyTraverse
<SymbolMapper
, bool> {
758 using Base
= evaluate::AnyTraverse
<SymbolMapper
, bool>;
759 SymbolMapper(Scope
&scope
, SymbolAndTypeMappings
&map
)
760 : Base
{*this}, scope_
{scope
}, map_
{map
} {}
761 using Base::operator();
762 bool operator()(const SymbolRef
&ref
) const {
763 if (const Symbol
*mapped
{MapSymbol(*ref
)}) {
764 const_cast<SymbolRef
&>(ref
) = *mapped
;
768 bool operator()(const Symbol
&x
) const {
770 DIE("SymbolMapper hit symbol outside SymbolRef");
774 void MapSymbolExprs(Symbol
&);
777 void MapParamValue(ParamValue
¶m
) const { (*this)(param
.GetExplicit()); }
778 void MapBound(Bound
&bound
) const { (*this)(bound
.GetExplicit()); }
779 void MapShapeSpec(ShapeSpec
&spec
) const {
780 MapBound(spec
.lbound());
781 MapBound(spec
.ubound());
783 const Symbol
*MapSymbol(const Symbol
&) const;
784 const Symbol
*MapSymbol(const Symbol
*) const;
785 const DeclTypeSpec
*MapType(const DeclTypeSpec
&);
786 const DeclTypeSpec
*MapType(const DeclTypeSpec
*);
787 const Symbol
*MapInterface(const Symbol
*);
790 SymbolAndTypeMappings
&map_
;
793 void SymbolMapper::MapSymbolExprs(Symbol
&symbol
) {
794 if (auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
795 if (const DeclTypeSpec
*type
{object
->type()}) {
796 if (const DeclTypeSpec
*newType
{MapType(*type
)}) {
797 object
->ReplaceType(*newType
);
802 common::visitors
{[&](ObjectEntityDetails
&object
) {
803 for (ShapeSpec
&spec
: object
.shape()) {
806 for (ShapeSpec
&spec
: object
.coshape()) {
810 [&](ProcEntityDetails
&proc
) {
812 mappedSymbol
{MapInterface(proc
.procInterface())}) {
813 proc
.set_procInterface(*mappedSymbol
);
814 } else if (const DeclTypeSpec
* mappedType
{MapType(proc
.type())}) {
815 proc
.set_type(*mappedType
);
818 if (const Symbol
* mapped
{MapSymbol(*proc
.init())}) {
819 proc
.set_init(*mapped
);
823 [&](const HostAssocDetails
&hostAssoc
) {
824 if (const Symbol
* mapped
{MapSymbol(hostAssoc
.symbol())}) {
825 symbol
.set_details(HostAssocDetails
{*mapped
});
828 [](const auto &) {}},
832 const Symbol
*SymbolMapper::MapSymbol(const Symbol
&symbol
) const {
833 if (auto iter
{map_
.symbolMap
.find(&symbol
)}; iter
!= map_
.symbolMap
.end()) {
839 const Symbol
*SymbolMapper::MapSymbol(const Symbol
*symbol
) const {
840 return symbol
? MapSymbol(*symbol
) : nullptr;
843 const DeclTypeSpec
*SymbolMapper::MapType(const DeclTypeSpec
&type
) {
844 if (auto iter
{map_
.typeMap
.find(&type
)}; iter
!= map_
.typeMap
.end()) {
847 const DeclTypeSpec
*newType
{nullptr};
848 if (type
.category() == DeclTypeSpec::Category::Character
) {
849 const CharacterTypeSpec
&charType
{type
.characterTypeSpec()};
850 if (charType
.length().GetExplicit()) {
851 ParamValue newLen
{charType
.length()};
852 (*this)(newLen
.GetExplicit());
853 newType
= &scope_
.MakeCharacterType(
854 std::move(newLen
), KindExpr
{charType
.kind()});
856 } else if (const DerivedTypeSpec
*derived
{type
.AsDerived()}) {
857 if (!derived
->parameters().empty()) {
858 DerivedTypeSpec newDerived
{derived
->name(), derived
->typeSymbol()};
859 newDerived
.CookParameters(scope_
.context().foldingContext());
860 for (const auto &[paramName
, paramValue
] : derived
->parameters()) {
861 ParamValue newParamValue
{paramValue
};
862 MapParamValue(newParamValue
);
863 newDerived
.AddParamValue(paramName
, std::move(newParamValue
));
865 // Scope::InstantiateDerivedTypes() instantiates it later.
866 newType
= &scope_
.MakeDerivedType(type
.category(), std::move(newDerived
));
870 map_
.typeMap
[&type
] = newType
;
875 const DeclTypeSpec
*SymbolMapper::MapType(const DeclTypeSpec
*type
) {
876 return type
? MapType(*type
) : nullptr;
879 const Symbol
*SymbolMapper::MapInterface(const Symbol
*interface
) {
880 if (const Symbol
*mapped
{MapSymbol(interface
)}) {
884 if (&interface
->owner() != &scope_
) {
886 } else if (const auto *subp
{interface
->detailsIf
<SubprogramDetails
>()};
887 subp
&& subp
->isInterface()) {
888 if (Symbol
*newSymbol
{scope_
.CopySymbol(*interface
)}) {
889 newSymbol
->get
<SubprogramDetails
>().set_isInterface(true);
890 map_
.symbolMap
[interface
] = newSymbol
;
891 Scope
&newScope
{scope_
.MakeScope(Scope::Kind::Subprogram
, newSymbol
)};
892 MapSubprogramToNewSymbols(*interface
, *newSymbol
, newScope
, &map_
);
900 void MapSubprogramToNewSymbols(const Symbol
&oldSymbol
, Symbol
&newSymbol
,
901 Scope
&newScope
, SymbolAndTypeMappings
*mappings
) {
902 SymbolAndTypeMappings newMappings
;
904 mappings
= &newMappings
;
906 mappings
->symbolMap
[&oldSymbol
] = &newSymbol
;
907 const auto &oldDetails
{oldSymbol
.get
<SubprogramDetails
>()};
908 auto &newDetails
{newSymbol
.get
<SubprogramDetails
>()};
909 for (const Symbol
*dummyArg
: oldDetails
.dummyArgs()) {
911 newDetails
.add_alternateReturn();
912 } else if (Symbol
*copy
{newScope
.CopySymbol(*dummyArg
)}) {
913 newDetails
.add_dummyArg(*copy
);
914 mappings
->symbolMap
[dummyArg
] = copy
;
917 if (oldDetails
.isFunction()) {
918 newScope
.erase(newSymbol
.name());
919 if (Symbol
*copy
{newScope
.CopySymbol(oldDetails
.result())}) {
920 newDetails
.set_result(*copy
);
921 mappings
->symbolMap
[&oldDetails
.result()] = copy
;
924 SymbolMapper mapper
{newScope
, *mappings
};
925 for (auto &[_
, ref
] : newScope
) {
926 mapper
.MapSymbolExprs(*ref
);
928 newScope
.InstantiateDerivedTypes();
931 } // namespace Fortran::semantics