1 //===-- lib/Evaluate/tools.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 "flang/Evaluate/tools.h"
10 #include "flang/Common/idioms.h"
11 #include "flang/Evaluate/characteristics.h"
12 #include "flang/Evaluate/traverse.h"
13 #include "flang/Parser/message.h"
14 #include "flang/Semantics/tools.h"
18 using namespace Fortran::parser::literals
;
20 namespace Fortran::evaluate
{
22 // Can x*(a,b) be represented as (x*a,x*b)? This code duplication
23 // of the subexpression "x" cannot (yet?) be reliably undone by
24 // common subexpression elimination in lowering, so it's disabled
25 // here for now to avoid the risk of potential duplication of
26 // expensive subexpressions (e.g., large array expressions, references
27 // to expensive functions) in generate code.
28 static constexpr bool allowOperandDuplication
{false};
30 std::optional
<Expr
<SomeType
>> AsGenericExpr(DataRef
&&ref
) {
31 const Symbol
&symbol
{ref
.GetLastSymbol()};
32 if (auto dyType
{DynamicType::From(symbol
)}) {
33 return TypedWrapper
<Designator
, DataRef
>(*dyType
, std::move(ref
));
38 std::optional
<Expr
<SomeType
>> AsGenericExpr(const Symbol
&symbol
) {
39 return AsGenericExpr(DataRef
{symbol
});
42 Expr
<SomeType
> Parenthesize(Expr
<SomeType
> &&expr
) {
45 using T
= std::decay_t
<decltype(x
)>;
46 if constexpr (common::HasMember
<T
, TypelessExpression
>) {
47 return expr
; // no parentheses around typeless
48 } else if constexpr (std::is_same_v
<T
, Expr
<SomeDerived
>>) {
49 return AsGenericExpr(Parentheses
<SomeDerived
>{std::move(x
)});
53 using T
= ResultType
<decltype(y
)>;
54 return AsGenericExpr(Parentheses
<T
>{std::move(y
)});
62 std::optional
<DataRef
> ExtractDataRef(
63 const ActualArgument
&arg
, bool intoSubstring
, bool intoComplexPart
) {
64 return ExtractDataRef(arg
.UnwrapExpr(), intoSubstring
, intoComplexPart
);
67 std::optional
<DataRef
> ExtractSubstringBase(const Substring
&substring
) {
70 [&](const DataRef
&x
) -> std::optional
<DataRef
> { return x
; },
71 [&](const StaticDataObject::Pointer
&) -> std::optional
<DataRef
> {
80 auto IsVariableHelper::operator()(const Symbol
&symbol
) const -> Result
{
81 // ASSOCIATE(x => expr) -- x counts as a variable, but undefinable
82 const Symbol
&ultimate
{symbol
.GetUltimate()};
83 return !IsNamedConstant(ultimate
) &&
84 (ultimate
.has
<semantics::ObjectEntityDetails
>() ||
85 ultimate
.has
<semantics::AssocEntityDetails
>());
87 auto IsVariableHelper::operator()(const Component
&x
) const -> Result
{
88 const Symbol
&comp
{x
.GetLastSymbol()};
89 return (*this)(comp
) && (IsPointer(comp
) || (*this)(x
.base()));
91 auto IsVariableHelper::operator()(const ArrayRef
&x
) const -> Result
{
92 return (*this)(x
.base());
94 auto IsVariableHelper::operator()(const Substring
&x
) const -> Result
{
95 return (*this)(x
.GetBaseObject());
97 auto IsVariableHelper::operator()(const ProcedureDesignator
&x
) const
99 if (const Symbol
* symbol
{x
.GetSymbol()}) {
100 const Symbol
*result
{FindFunctionResult(*symbol
)};
101 return result
&& IsPointer(*result
) && !IsProcedurePointer(*result
);
106 // Conversions of COMPLEX component expressions to REAL.
107 ConvertRealOperandsResult
ConvertRealOperands(
108 parser::ContextualMessages
&messages
, Expr
<SomeType
> &&x
,
109 Expr
<SomeType
> &&y
, int defaultRealKind
) {
110 return common::visit(
112 [&](Expr
<SomeInteger
> &&ix
,
113 Expr
<SomeInteger
> &&iy
) -> ConvertRealOperandsResult
{
114 // Can happen in a CMPLX() constructor. Per F'2018,
115 // both integer operands are converted to default REAL.
116 return {AsSameKindExprs
<TypeCategory::Real
>(
117 ConvertToKind
<TypeCategory::Real
>(
118 defaultRealKind
, std::move(ix
)),
119 ConvertToKind
<TypeCategory::Real
>(
120 defaultRealKind
, std::move(iy
)))};
122 [&](Expr
<SomeInteger
> &&ix
,
123 Expr
<SomeReal
> &&ry
) -> ConvertRealOperandsResult
{
124 return {AsSameKindExprs
<TypeCategory::Real
>(
125 ConvertTo(ry
, std::move(ix
)), std::move(ry
))};
127 [&](Expr
<SomeReal
> &&rx
,
128 Expr
<SomeInteger
> &&iy
) -> ConvertRealOperandsResult
{
129 return {AsSameKindExprs
<TypeCategory::Real
>(
130 std::move(rx
), ConvertTo(rx
, std::move(iy
)))};
132 [&](Expr
<SomeReal
> &&rx
,
133 Expr
<SomeReal
> &&ry
) -> ConvertRealOperandsResult
{
134 return {AsSameKindExprs
<TypeCategory::Real
>(
135 std::move(rx
), std::move(ry
))};
137 [&](Expr
<SomeInteger
> &&ix
,
138 BOZLiteralConstant
&&by
) -> ConvertRealOperandsResult
{
139 return {AsSameKindExprs
<TypeCategory::Real
>(
140 ConvertToKind
<TypeCategory::Real
>(
141 defaultRealKind
, std::move(ix
)),
142 ConvertToKind
<TypeCategory::Real
>(
143 defaultRealKind
, std::move(by
)))};
145 [&](BOZLiteralConstant
&&bx
,
146 Expr
<SomeInteger
> &&iy
) -> ConvertRealOperandsResult
{
147 return {AsSameKindExprs
<TypeCategory::Real
>(
148 ConvertToKind
<TypeCategory::Real
>(
149 defaultRealKind
, std::move(bx
)),
150 ConvertToKind
<TypeCategory::Real
>(
151 defaultRealKind
, std::move(iy
)))};
153 [&](Expr
<SomeReal
> &&rx
,
154 BOZLiteralConstant
&&by
) -> ConvertRealOperandsResult
{
155 return {AsSameKindExprs
<TypeCategory::Real
>(
156 std::move(rx
), ConvertTo(rx
, std::move(by
)))};
158 [&](BOZLiteralConstant
&&bx
,
159 Expr
<SomeReal
> &&ry
) -> ConvertRealOperandsResult
{
160 return {AsSameKindExprs
<TypeCategory::Real
>(
161 ConvertTo(ry
, std::move(bx
)), std::move(ry
))};
163 [&](auto &&, auto &&) -> ConvertRealOperandsResult
{ // C718
164 messages
.Say("operands must be INTEGER or REAL"_err_en_US
);
168 std::move(x
.u
), std::move(y
.u
));
171 // Helpers for NumericOperation and its subroutines below.
172 static std::optional
<Expr
<SomeType
>> NoExpr() { return std::nullopt
; }
174 template <TypeCategory CAT
>
175 std::optional
<Expr
<SomeType
>> Package(Expr
<SomeKind
<CAT
>> &&catExpr
) {
176 return {AsGenericExpr(std::move(catExpr
))};
178 template <TypeCategory CAT
>
179 std::optional
<Expr
<SomeType
>> Package(
180 std::optional
<Expr
<SomeKind
<CAT
>>> &&catExpr
) {
182 return {AsGenericExpr(std::move(*catExpr
))};
187 // Mixed REAL+INTEGER operations. REAL**INTEGER is a special case that
188 // does not require conversion of the exponent expression.
189 template <template <typename
> class OPR
>
190 std::optional
<Expr
<SomeType
>> MixedRealLeft(
191 Expr
<SomeReal
> &&rx
, Expr
<SomeInteger
> &&iy
) {
192 return Package(common::visit(
193 [&](auto &&rxk
) -> Expr
<SomeReal
> {
194 using resultType
= ResultType
<decltype(rxk
)>;
195 if constexpr (std::is_same_v
<OPR
<resultType
>, Power
<resultType
>>) {
196 return AsCategoryExpr(
197 RealToIntPower
<resultType
>{std::move(rxk
), std::move(iy
)});
199 // G++ 8.1.0 emits bogus warnings about missing return statements if
200 // this statement is wrapped in an "else", as it should be.
201 return AsCategoryExpr(OPR
<resultType
>{
202 std::move(rxk
), ConvertToType
<resultType
>(std::move(iy
))});
207 std::optional
<Expr
<SomeComplex
>> ConstructComplex(
208 parser::ContextualMessages
&messages
, Expr
<SomeType
> &&real
,
209 Expr
<SomeType
> &&imaginary
, int defaultRealKind
) {
210 if (auto converted
{ConvertRealOperands(
211 messages
, std::move(real
), std::move(imaginary
), defaultRealKind
)}) {
212 return {common::visit(
214 return MakeComplex(std::move(pair
[0]), std::move(pair
[1]));
216 std::move(*converted
))};
221 std::optional
<Expr
<SomeComplex
>> ConstructComplex(
222 parser::ContextualMessages
&messages
, std::optional
<Expr
<SomeType
>> &&real
,
223 std::optional
<Expr
<SomeType
>> &&imaginary
, int defaultRealKind
) {
224 if (auto parts
{common::AllPresent(std::move(real
), std::move(imaginary
))}) {
225 return ConstructComplex(messages
, std::get
<0>(std::move(*parts
)),
226 std::get
<1>(std::move(*parts
)), defaultRealKind
);
231 Expr
<SomeReal
> GetComplexPart(const Expr
<SomeComplex
> &z
, bool isImaginary
) {
232 return common::visit(
233 [&](const auto &zk
) {
234 static constexpr int kind
{ResultType
<decltype(zk
)>::kind
};
235 return AsCategoryExpr(ComplexComponent
<kind
>{isImaginary
, zk
});
240 Expr
<SomeReal
> GetComplexPart(Expr
<SomeComplex
> &&z
, bool isImaginary
) {
241 return common::visit(
243 static constexpr int kind
{ResultType
<decltype(zk
)>::kind
};
244 return AsCategoryExpr(
245 ComplexComponent
<kind
>{isImaginary
, std::move(zk
)});
250 // Convert REAL to COMPLEX of the same kind. Preserving the real operand kind
251 // and then applying complex operand promotion rules allows the result to have
252 // the highest precision of REAL and COMPLEX operands as required by Fortran
254 Expr
<SomeComplex
> PromoteRealToComplex(Expr
<SomeReal
> &&someX
) {
255 return common::visit(
257 using RT
= ResultType
<decltype(x
)>;
258 return AsCategoryExpr(ComplexConstructor
<RT::kind
>{
259 std::move(x
), AsExpr(Constant
<RT
>{Scalar
<RT
>{}})});
264 // Handle mixed COMPLEX+REAL (or INTEGER) operations in a better way
265 // than just converting the second operand to COMPLEX and performing the
266 // corresponding COMPLEX+COMPLEX operation.
267 template <template <typename
> class OPR
, TypeCategory RCAT
>
268 std::optional
<Expr
<SomeType
>> MixedComplexLeft(
269 parser::ContextualMessages
&messages
, Expr
<SomeComplex
> &&zx
,
270 Expr
<SomeKind
<RCAT
>> &&iry
, [[maybe_unused
]] int defaultRealKind
) {
271 Expr
<SomeReal
> zr
{GetComplexPart(zx
, false)};
272 Expr
<SomeReal
> zi
{GetComplexPart(zx
, true)};
273 if constexpr (std::is_same_v
<OPR
<LargestReal
>, Add
<LargestReal
>> ||
274 std::is_same_v
<OPR
<LargestReal
>, Subtract
<LargestReal
>>) {
275 // (a,b) + x -> (a+x, b)
276 // (a,b) - x -> (a-x, b)
277 if (std::optional
<Expr
<SomeType
>> rr
{
278 NumericOperation
<OPR
>(messages
, AsGenericExpr(std::move(zr
)),
279 AsGenericExpr(std::move(iry
)), defaultRealKind
)}) {
280 return Package(ConstructComplex(messages
, std::move(*rr
),
281 AsGenericExpr(std::move(zi
)), defaultRealKind
));
283 } else if constexpr (allowOperandDuplication
&&
284 (std::is_same_v
<OPR
<LargestReal
>, Multiply
<LargestReal
>> ||
285 std::is_same_v
<OPR
<LargestReal
>, Divide
<LargestReal
>>)) {
286 // (a,b) * x -> (a*x, b*x)
287 // (a,b) / x -> (a/x, b/x)
289 auto rr
{NumericOperation
<OPR
>(messages
, AsGenericExpr(std::move(zr
)),
290 AsGenericExpr(std::move(iry
)), defaultRealKind
)};
291 auto ri
{NumericOperation
<OPR
>(messages
, AsGenericExpr(std::move(zi
)),
292 AsGenericExpr(std::move(copy
)), defaultRealKind
)};
293 if (auto parts
{common::AllPresent(std::move(rr
), std::move(ri
))}) {
294 return Package(ConstructComplex(messages
, std::get
<0>(std::move(*parts
)),
295 std::get
<1>(std::move(*parts
)), defaultRealKind
));
297 } else if constexpr (RCAT
== TypeCategory::Integer
&&
298 std::is_same_v
<OPR
<LargestReal
>, Power
<LargestReal
>>) {
299 // COMPLEX**INTEGER is a special case that doesn't convert the exponent.
300 static_assert(RCAT
== TypeCategory::Integer
);
301 return Package(common::visit(
303 using Ty
= ResultType
<decltype(zxk
)>;
304 return AsCategoryExpr(
305 AsExpr(RealToIntPower
<Ty
>{std::move(zxk
), std::move(iry
)}));
309 // (a,b) ** x -> (a,b) ** (x,0)
310 if constexpr (RCAT
== TypeCategory::Integer
) {
311 Expr
<SomeComplex
> zy
{ConvertTo(zx
, std::move(iry
))};
312 return Package(PromoteAndCombine
<OPR
>(std::move(zx
), std::move(zy
)));
314 Expr
<SomeComplex
> zy
{PromoteRealToComplex(std::move(iry
))};
315 return Package(PromoteAndCombine
<OPR
>(std::move(zx
), std::move(zy
)));
321 // Mixed COMPLEX operations with the COMPLEX operand on the right.
322 // x + (a,b) -> (x+a, b)
323 // x - (a,b) -> (x-a, -b)
324 // x * (a,b) -> (x*a, x*b)
325 // x / (a,b) -> (x,0) / (a,b) (and **)
326 template <template <typename
> class OPR
, TypeCategory LCAT
>
327 std::optional
<Expr
<SomeType
>> MixedComplexRight(
328 parser::ContextualMessages
&messages
, Expr
<SomeKind
<LCAT
>> &&irx
,
329 Expr
<SomeComplex
> &&zy
, [[maybe_unused
]] int defaultRealKind
) {
330 if constexpr (std::is_same_v
<OPR
<LargestReal
>, Add
<LargestReal
>>) {
331 // x + (a,b) -> (a,b) + x -> (a+x, b)
332 return MixedComplexLeft
<OPR
, LCAT
>(
333 messages
, std::move(zy
), std::move(irx
), defaultRealKind
);
334 } else if constexpr (allowOperandDuplication
&&
335 std::is_same_v
<OPR
<LargestReal
>, Multiply
<LargestReal
>>) {
336 // x * (a,b) -> (a,b) * x -> (a*x, b*x)
337 return MixedComplexLeft
<OPR
, LCAT
>(
338 messages
, std::move(zy
), std::move(irx
), defaultRealKind
);
339 } else if constexpr (std::is_same_v
<OPR
<LargestReal
>,
340 Subtract
<LargestReal
>>) {
341 // x - (a,b) -> (x-a, -b)
342 Expr
<SomeReal
> zr
{GetComplexPart(zy
, false)};
343 Expr
<SomeReal
> zi
{GetComplexPart(zy
, true)};
344 if (std::optional
<Expr
<SomeType
>> rr
{
345 NumericOperation
<Subtract
>(messages
, AsGenericExpr(std::move(irx
)),
346 AsGenericExpr(std::move(zr
)), defaultRealKind
)}) {
347 return Package(ConstructComplex(messages
, std::move(*rr
),
348 AsGenericExpr(-std::move(zi
)), defaultRealKind
));
351 // x / (a,b) -> (x,0) / (a,b)
352 if constexpr (LCAT
== TypeCategory::Integer
) {
353 Expr
<SomeComplex
> zx
{ConvertTo(zy
, std::move(irx
))};
354 return Package(PromoteAndCombine
<OPR
>(std::move(zx
), std::move(zy
)));
356 Expr
<SomeComplex
> zx
{PromoteRealToComplex(std::move(irx
))};
357 return Package(PromoteAndCombine
<OPR
>(std::move(zx
), std::move(zy
)));
363 // N.B. When a "typeless" BOZ literal constant appears as one (not both!) of
364 // the operands to a dyadic operation where one is permitted, it assumes the
365 // type and kind of the other operand.
366 template <template <typename
> class OPR
>
367 std::optional
<Expr
<SomeType
>> NumericOperation(
368 parser::ContextualMessages
&messages
, Expr
<SomeType
> &&x
,
369 Expr
<SomeType
> &&y
, int defaultRealKind
) {
370 return common::visit(
372 [](Expr
<SomeInteger
> &&ix
, Expr
<SomeInteger
> &&iy
) {
373 return Package(PromoteAndCombine
<OPR
, TypeCategory::Integer
>(
374 std::move(ix
), std::move(iy
)));
376 [](Expr
<SomeReal
> &&rx
, Expr
<SomeReal
> &&ry
) {
377 return Package(PromoteAndCombine
<OPR
, TypeCategory::Real
>(
378 std::move(rx
), std::move(ry
)));
380 // Mixed REAL/INTEGER operations
381 [](Expr
<SomeReal
> &&rx
, Expr
<SomeInteger
> &&iy
) {
382 return MixedRealLeft
<OPR
>(std::move(rx
), std::move(iy
));
384 [](Expr
<SomeInteger
> &&ix
, Expr
<SomeReal
> &&ry
) {
385 return Package(common::visit(
386 [&](auto &&ryk
) -> Expr
<SomeReal
> {
387 using resultType
= ResultType
<decltype(ryk
)>;
388 return AsCategoryExpr(
389 OPR
<resultType
>{ConvertToType
<resultType
>(std::move(ix
)),
394 // Homogeneous and mixed COMPLEX operations
395 [](Expr
<SomeComplex
> &&zx
, Expr
<SomeComplex
> &&zy
) {
396 return Package(PromoteAndCombine
<OPR
, TypeCategory::Complex
>(
397 std::move(zx
), std::move(zy
)));
399 [&](Expr
<SomeComplex
> &&zx
, Expr
<SomeInteger
> &&iy
) {
400 return MixedComplexLeft
<OPR
>(
401 messages
, std::move(zx
), std::move(iy
), defaultRealKind
);
403 [&](Expr
<SomeComplex
> &&zx
, Expr
<SomeReal
> &&ry
) {
404 return MixedComplexLeft
<OPR
>(
405 messages
, std::move(zx
), std::move(ry
), defaultRealKind
);
407 [&](Expr
<SomeInteger
> &&ix
, Expr
<SomeComplex
> &&zy
) {
408 return MixedComplexRight
<OPR
>(
409 messages
, std::move(ix
), std::move(zy
), defaultRealKind
);
411 [&](Expr
<SomeReal
> &&rx
, Expr
<SomeComplex
> &&zy
) {
412 return MixedComplexRight
<OPR
>(
413 messages
, std::move(rx
), std::move(zy
), defaultRealKind
);
415 // Operations with one typeless operand
416 [&](BOZLiteralConstant
&&bx
, Expr
<SomeInteger
> &&iy
) {
417 return NumericOperation
<OPR
>(messages
,
418 AsGenericExpr(ConvertTo(iy
, std::move(bx
))), std::move(y
),
421 [&](BOZLiteralConstant
&&bx
, Expr
<SomeReal
> &&ry
) {
422 return NumericOperation
<OPR
>(messages
,
423 AsGenericExpr(ConvertTo(ry
, std::move(bx
))), std::move(y
),
426 [&](Expr
<SomeInteger
> &&ix
, BOZLiteralConstant
&&by
) {
427 return NumericOperation
<OPR
>(messages
, std::move(x
),
428 AsGenericExpr(ConvertTo(ix
, std::move(by
))), defaultRealKind
);
430 [&](Expr
<SomeReal
> &&rx
, BOZLiteralConstant
&&by
) {
431 return NumericOperation
<OPR
>(messages
, std::move(x
),
432 AsGenericExpr(ConvertTo(rx
, std::move(by
))), defaultRealKind
);
435 [&](auto &&, auto &&) {
436 // TODO: defined operator
437 messages
.Say("non-numeric operands to numeric operation"_err_en_US
);
441 std::move(x
.u
), std::move(y
.u
));
444 template std::optional
<Expr
<SomeType
>> NumericOperation
<Power
>(
445 parser::ContextualMessages
&, Expr
<SomeType
> &&, Expr
<SomeType
> &&,
446 int defaultRealKind
);
447 template std::optional
<Expr
<SomeType
>> NumericOperation
<Multiply
>(
448 parser::ContextualMessages
&, Expr
<SomeType
> &&, Expr
<SomeType
> &&,
449 int defaultRealKind
);
450 template std::optional
<Expr
<SomeType
>> NumericOperation
<Divide
>(
451 parser::ContextualMessages
&, Expr
<SomeType
> &&, Expr
<SomeType
> &&,
452 int defaultRealKind
);
453 template std::optional
<Expr
<SomeType
>> NumericOperation
<Add
>(
454 parser::ContextualMessages
&, Expr
<SomeType
> &&, Expr
<SomeType
> &&,
455 int defaultRealKind
);
456 template std::optional
<Expr
<SomeType
>> NumericOperation
<Subtract
>(
457 parser::ContextualMessages
&, Expr
<SomeType
> &&, Expr
<SomeType
> &&,
458 int defaultRealKind
);
460 std::optional
<Expr
<SomeType
>> Negation(
461 parser::ContextualMessages
&messages
, Expr
<SomeType
> &&x
) {
462 return common::visit(
464 [&](BOZLiteralConstant
&&) {
465 messages
.Say("BOZ literal cannot be negated"_err_en_US
);
468 [&](NullPointer
&&) {
469 messages
.Say("NULL() cannot be negated"_err_en_US
);
472 [&](ProcedureDesignator
&&) {
473 messages
.Say("Subroutine cannot be negated"_err_en_US
);
476 [&](ProcedureRef
&&) {
477 messages
.Say("Pointer to subroutine cannot be negated"_err_en_US
);
480 [&](Expr
<SomeInteger
> &&x
) { return Package(-std::move(x
)); },
481 [&](Expr
<SomeReal
> &&x
) { return Package(-std::move(x
)); },
482 [&](Expr
<SomeComplex
> &&x
) { return Package(-std::move(x
)); },
483 [&](Expr
<SomeCharacter
> &&) {
484 // TODO: defined operator
485 messages
.Say("CHARACTER cannot be negated"_err_en_US
);
488 [&](Expr
<SomeLogical
> &&) {
489 // TODO: defined operator
490 messages
.Say("LOGICAL cannot be negated"_err_en_US
);
493 [&](Expr
<SomeDerived
> &&) {
494 // TODO: defined operator
495 messages
.Say("Operand cannot be negated"_err_en_US
);
502 Expr
<SomeLogical
> LogicalNegation(Expr
<SomeLogical
> &&x
) {
503 return common::visit(
504 [](auto &&xk
) { return AsCategoryExpr(LogicalNegation(std::move(xk
))); },
508 template <TypeCategory CAT
>
509 Expr
<LogicalResult
> PromoteAndRelate(
510 RelationalOperator opr
, Expr
<SomeKind
<CAT
>> &&x
, Expr
<SomeKind
<CAT
>> &&y
) {
511 return common::visit(
513 return PackageRelation(opr
, std::move(xy
[0]), std::move(xy
[1]));
515 AsSameKindExprs(std::move(x
), std::move(y
)));
518 std::optional
<Expr
<LogicalResult
>> Relate(parser::ContextualMessages
&messages
,
519 RelationalOperator opr
, Expr
<SomeType
> &&x
, Expr
<SomeType
> &&y
) {
520 return common::visit(
522 [=](Expr
<SomeInteger
> &&ix
,
523 Expr
<SomeInteger
> &&iy
) -> std::optional
<Expr
<LogicalResult
>> {
524 return PromoteAndRelate(opr
, std::move(ix
), std::move(iy
));
526 [=](Expr
<SomeReal
> &&rx
,
527 Expr
<SomeReal
> &&ry
) -> std::optional
<Expr
<LogicalResult
>> {
528 return PromoteAndRelate(opr
, std::move(rx
), std::move(ry
));
530 [&](Expr
<SomeReal
> &&rx
, Expr
<SomeInteger
> &&iy
) {
531 return Relate(messages
, opr
, std::move(x
),
532 AsGenericExpr(ConvertTo(rx
, std::move(iy
))));
534 [&](Expr
<SomeInteger
> &&ix
, Expr
<SomeReal
> &&ry
) {
535 return Relate(messages
, opr
,
536 AsGenericExpr(ConvertTo(ry
, std::move(ix
))), std::move(y
));
538 [&](Expr
<SomeComplex
> &&zx
,
539 Expr
<SomeComplex
> &&zy
) -> std::optional
<Expr
<LogicalResult
>> {
540 if (opr
== RelationalOperator::EQ
||
541 opr
== RelationalOperator::NE
) {
542 return PromoteAndRelate(opr
, std::move(zx
), std::move(zy
));
545 "COMPLEX data may be compared only for equality"_err_en_US
);
549 [&](Expr
<SomeComplex
> &&zx
, Expr
<SomeInteger
> &&iy
) {
550 return Relate(messages
, opr
, std::move(x
),
551 AsGenericExpr(ConvertTo(zx
, std::move(iy
))));
553 [&](Expr
<SomeComplex
> &&zx
, Expr
<SomeReal
> &&ry
) {
554 return Relate(messages
, opr
, std::move(x
),
555 AsGenericExpr(ConvertTo(zx
, std::move(ry
))));
557 [&](Expr
<SomeInteger
> &&ix
, Expr
<SomeComplex
> &&zy
) {
558 return Relate(messages
, opr
,
559 AsGenericExpr(ConvertTo(zy
, std::move(ix
))), std::move(y
));
561 [&](Expr
<SomeReal
> &&rx
, Expr
<SomeComplex
> &&zy
) {
562 return Relate(messages
, opr
,
563 AsGenericExpr(ConvertTo(zy
, std::move(rx
))), std::move(y
));
565 [&](Expr
<SomeCharacter
> &&cx
, Expr
<SomeCharacter
> &&cy
) {
566 return common::visit(
568 auto &&cyk
) -> std::optional
<Expr
<LogicalResult
>> {
569 using Ty
= ResultType
<decltype(cxk
)>;
570 if constexpr (std::is_same_v
<Ty
, ResultType
<decltype(cyk
)>>) {
571 return PackageRelation(opr
, std::move(cxk
), std::move(cyk
));
574 "CHARACTER operands do not have same KIND"_err_en_US
);
578 std::move(cx
.u
), std::move(cy
.u
));
581 [&](auto &&, auto &&) {
582 DIE("invalid types for relational operator");
583 return std::optional
<Expr
<LogicalResult
>>{};
586 std::move(x
.u
), std::move(y
.u
));
589 Expr
<SomeLogical
> BinaryLogicalOperation(
590 LogicalOperator opr
, Expr
<SomeLogical
> &&x
, Expr
<SomeLogical
> &&y
) {
591 CHECK(opr
!= LogicalOperator::Not
);
592 return common::visit(
594 using Ty
= ResultType
<decltype(xy
[0])>;
595 return Expr
<SomeLogical
>{BinaryLogicalOperation
<Ty::kind
>(
596 opr
, std::move(xy
[0]), std::move(xy
[1]))};
598 AsSameKindExprs(std::move(x
), std::move(y
)));
601 template <TypeCategory TO
>
602 std::optional
<Expr
<SomeType
>> ConvertToNumeric(int kind
, Expr
<SomeType
> &&x
) {
603 static_assert(common::IsNumericTypeCategory(TO
));
604 return common::visit(
605 [=](auto &&cx
) -> std::optional
<Expr
<SomeType
>> {
606 using cxType
= std::decay_t
<decltype(cx
)>;
607 if constexpr (!common::HasMember
<cxType
, TypelessExpression
>) {
608 if constexpr (IsNumericTypeCategory(ResultType
<cxType
>::category
)) {
609 return Expr
<SomeType
>{ConvertToKind
<TO
>(kind
, std::move(cx
))};
617 std::optional
<Expr
<SomeType
>> ConvertToType(
618 const DynamicType
&type
, Expr
<SomeType
> &&x
) {
619 if (type
.IsTypelessIntrinsicArgument()) {
622 switch (type
.category()) {
623 case TypeCategory::Integer
:
624 if (auto *boz
{std::get_if
<BOZLiteralConstant
>(&x
.u
)}) {
625 // Extension to C7109: allow BOZ literals to appear in integer contexts
626 // when the type is unambiguous.
627 return Expr
<SomeType
>{
628 ConvertToKind
<TypeCategory::Integer
>(type
.kind(), std::move(*boz
))};
630 return ConvertToNumeric
<TypeCategory::Integer
>(type
.kind(), std::move(x
));
631 case TypeCategory::Real
:
632 if (auto *boz
{std::get_if
<BOZLiteralConstant
>(&x
.u
)}) {
633 return Expr
<SomeType
>{
634 ConvertToKind
<TypeCategory::Real
>(type
.kind(), std::move(*boz
))};
636 return ConvertToNumeric
<TypeCategory::Real
>(type
.kind(), std::move(x
));
637 case TypeCategory::Complex
:
638 return ConvertToNumeric
<TypeCategory::Complex
>(type
.kind(), std::move(x
));
639 case TypeCategory::Character
:
640 if (auto *cx
{UnwrapExpr
<Expr
<SomeCharacter
>>(x
)}) {
642 ConvertToKind
<TypeCategory::Character
>(type
.kind(), std::move(*cx
))};
643 if (auto length
{type
.GetCharLength()}) {
644 converted
= common::visit(
646 using Ty
= std::decay_t
<decltype(x
)>;
647 using CharacterType
= typename
Ty::Result
;
648 return Expr
<SomeCharacter
>{
649 Expr
<CharacterType
>{SetLength
<CharacterType::kind
>{
650 std::move(x
), std::move(*length
)}}};
652 std::move(converted
.u
));
654 return Expr
<SomeType
>{std::move(converted
)};
657 case TypeCategory::Logical
:
658 if (auto *cx
{UnwrapExpr
<Expr
<SomeLogical
>>(x
)}) {
659 return Expr
<SomeType
>{
660 ConvertToKind
<TypeCategory::Logical
>(type
.kind(), std::move(*cx
))};
663 case TypeCategory::Derived
:
664 if (auto fromType
{x
.GetType()}) {
665 if (type
.IsTkCompatibleWith(*fromType
)) {
666 // "x" could be assigned or passed to "type", or appear in a
667 // structure constructor as a value for a component with "type"
676 std::optional
<Expr
<SomeType
>> ConvertToType(
677 const DynamicType
&to
, std::optional
<Expr
<SomeType
>> &&x
) {
679 return ConvertToType(to
, std::move(*x
));
685 std::optional
<Expr
<SomeType
>> ConvertToType(
686 const Symbol
&symbol
, Expr
<SomeType
> &&x
) {
687 if (auto symType
{DynamicType::From(symbol
)}) {
688 return ConvertToType(*symType
, std::move(x
));
693 std::optional
<Expr
<SomeType
>> ConvertToType(
694 const Symbol
&to
, std::optional
<Expr
<SomeType
>> &&x
) {
696 return ConvertToType(to
, std::move(*x
));
702 bool IsAssumedRank(const Symbol
&original
) {
703 if (const auto *assoc
{original
.detailsIf
<semantics::AssocEntityDetails
>()}) {
705 return false; // in SELECT RANK case
708 const Symbol
&symbol
{semantics::ResolveAssociations(original
)};
709 if (const auto *details
{symbol
.detailsIf
<semantics::ObjectEntityDetails
>()}) {
710 return details
->IsAssumedRank();
716 bool IsAssumedRank(const ActualArgument
&arg
) {
717 if (const auto *expr
{arg
.UnwrapExpr()}) {
718 return IsAssumedRank(*expr
);
720 const Symbol
*assumedTypeDummy
{arg
.GetAssumedTypeDummy()};
721 CHECK(assumedTypeDummy
);
722 return IsAssumedRank(*assumedTypeDummy
);
726 bool IsCoarray(const ActualArgument
&arg
) {
727 const auto *expr
{arg
.UnwrapExpr()};
728 return expr
&& IsCoarray(*expr
);
731 bool IsCoarray(const Symbol
&symbol
) {
732 return GetAssociationRoot(symbol
).Corank() > 0;
735 bool IsProcedure(const Expr
<SomeType
> &expr
) {
736 return std::holds_alternative
<ProcedureDesignator
>(expr
.u
);
738 bool IsFunction(const Expr
<SomeType
> &expr
) {
739 const auto *designator
{std::get_if
<ProcedureDesignator
>(&expr
.u
)};
740 return designator
&& designator
->GetType().has_value();
743 bool IsProcedurePointer(const Expr
<SomeType
> &expr
) {
744 return common::visit(common::visitors
{
745 [](const NullPointer
&) { return true; },
746 [](const ProcedureRef
&) { return false; },
748 const Symbol
*last
{GetLastSymbol(expr
)};
749 return last
&& IsProcedurePointer(*last
);
755 bool IsProcedurePointerTarget(const Expr
<SomeType
> &expr
) {
756 return common::visit(common::visitors
{
757 [](const NullPointer
&) { return true; },
758 [](const ProcedureDesignator
&) { return true; },
759 [](const ProcedureRef
&) { return true; },
761 const Symbol
*last
{GetLastSymbol(expr
)};
762 return last
&& IsProcedurePointer(*last
);
768 template <typename A
> inline const ProcedureRef
*UnwrapProcedureRef(const A
&) {
772 template <typename T
>
773 inline const ProcedureRef
*UnwrapProcedureRef(const FunctionRef
<T
> &func
) {
777 template <typename T
>
778 inline const ProcedureRef
*UnwrapProcedureRef(const Expr
<T
> &expr
) {
779 return common::visit(
780 [](const auto &x
) { return UnwrapProcedureRef(x
); }, expr
.u
);
784 bool IsObjectPointer(const Expr
<SomeType
> &expr
, FoldingContext
&context
) {
785 if (IsNullObjectPointer(expr
)) {
787 } else if (IsProcedurePointerTarget(expr
)) {
789 } else if (const auto *funcRef
{UnwrapProcedureRef(expr
)}) {
790 return IsVariable(*funcRef
);
791 } else if (const Symbol
* symbol
{UnwrapWholeSymbolOrComponentDataRef(expr
)}) {
792 return IsPointer(symbol
->GetUltimate());
798 const ProcedureRef
*GetProcedureRef(const Expr
<SomeType
> &expr
) {
799 return UnwrapProcedureRef(expr
);
802 // IsNullPointer() & variations
804 template <bool IS_PROC_PTR
> struct IsNullPointerHelper
{
805 template <typename A
> bool operator()(const A
&) const { return false; }
806 bool operator()(const ProcedureRef
&call
) const {
807 if constexpr (IS_PROC_PTR
) {
808 const auto *intrinsic
{call
.proc().GetSpecificIntrinsic()};
810 intrinsic
->characteristics
.value().attrs
.test(
811 characteristics::Procedure::Attr::NullPointer
);
816 template <typename T
> bool operator()(const FunctionRef
<T
> &call
) const {
817 if constexpr (IS_PROC_PTR
) {
820 const auto *intrinsic
{call
.proc().GetSpecificIntrinsic()};
822 intrinsic
->characteristics
.value().attrs
.test(
823 characteristics::Procedure::Attr::NullPointer
);
826 template <typename T
> bool operator()(const Designator
<T
> &x
) const {
827 if (const auto *component
{std::get_if
<Component
>(&x
.u
)}) {
828 if (const auto *baseSym
{std::get_if
<SymbolRef
>(&component
->base().u
)}) {
829 const Symbol
&base
{**baseSym
};
830 if (const auto *object
{
831 base
.detailsIf
<semantics::ObjectEntityDetails
>()}) {
832 // TODO: nested component and array references
833 if (IsNamedConstant(base
) && object
->init()) {
835 GetScalarConstantValue
<SomeDerived
>(*object
->init())}) {
836 auto iter
{structCons
->values().find(component
->GetLastSymbol())};
837 if (iter
!= structCons
->values().end()) {
838 return (*this)(iter
->second
.value());
847 bool operator()(const NullPointer
&) const { return true; }
848 template <typename T
> bool operator()(const Parentheses
<T
> &x
) const {
849 return (*this)(x
.left());
851 template <typename T
> bool operator()(const Expr
<T
> &x
) const {
852 return common::visit(*this, x
.u
);
856 bool IsNullObjectPointer(const Expr
<SomeType
> &expr
) {
857 return IsNullPointerHelper
<false>{}(expr
);
860 bool IsNullProcedurePointer(const Expr
<SomeType
> &expr
) {
861 return IsNullPointerHelper
<true>{}(expr
);
864 bool IsNullPointer(const Expr
<SomeType
> &expr
) {
865 return IsNullObjectPointer(expr
) || IsNullProcedurePointer(expr
);
868 bool IsBareNullPointer(const Expr
<SomeType
> *expr
) {
869 return expr
&& std::holds_alternative
<NullPointer
>(expr
->u
);
873 auto GetSymbolVectorHelper::operator()(const Symbol
&x
) const -> Result
{
874 if (const auto *details
{x
.detailsIf
<semantics::AssocEntityDetails
>()}) {
875 if (IsVariable(details
->expr()) && !GetProcedureRef(*details
->expr())) {
876 // associate(x => variable that is not a pointer returned by a function)
877 return (*this)(details
->expr());
880 return {x
.GetUltimate()};
882 auto GetSymbolVectorHelper::operator()(const Component
&x
) const -> Result
{
883 Result result
{(*this)(x
.base())};
884 result
.emplace_back(x
.GetLastSymbol());
887 auto GetSymbolVectorHelper::operator()(const ArrayRef
&x
) const -> Result
{
888 return GetSymbolVector(x
.base());
890 auto GetSymbolVectorHelper::operator()(const CoarrayRef
&x
) const -> Result
{
894 const Symbol
*GetLastTarget(const SymbolVector
&symbols
) {
895 auto end
{std::crend(symbols
)};
896 // N.B. Neither clang nor g++ recognizes "symbols.crbegin()" here.
897 auto iter
{std::find_if(std::crbegin(symbols
), end
, [](const Symbol
&x
) {
898 return x
.attrs().HasAny(
899 {semantics::Attr::POINTER
, semantics::Attr::TARGET
});
901 return iter
== end
? nullptr : &**iter
;
904 struct CollectSymbolsHelper
905 : public SetTraverse
<CollectSymbolsHelper
, semantics::UnorderedSymbolSet
> {
906 using Base
= SetTraverse
<CollectSymbolsHelper
, semantics::UnorderedSymbolSet
>;
907 CollectSymbolsHelper() : Base
{*this} {}
908 using Base::operator();
909 semantics::UnorderedSymbolSet
operator()(const Symbol
&symbol
) const {
913 template <typename A
> semantics::UnorderedSymbolSet
CollectSymbols(const A
&x
) {
914 return CollectSymbolsHelper
{}(x
);
916 template semantics::UnorderedSymbolSet
CollectSymbols(const Expr
<SomeType
> &);
917 template semantics::UnorderedSymbolSet
CollectSymbols(
918 const Expr
<SomeInteger
> &);
919 template semantics::UnorderedSymbolSet
CollectSymbols(
920 const Expr
<SubscriptInteger
> &);
922 // HasVectorSubscript()
923 struct HasVectorSubscriptHelper
: public AnyTraverse
<HasVectorSubscriptHelper
> {
924 using Base
= AnyTraverse
<HasVectorSubscriptHelper
>;
925 HasVectorSubscriptHelper() : Base
{*this} {}
926 using Base::operator();
927 bool operator()(const Subscript
&ss
) const {
928 return !std::holds_alternative
<Triplet
>(ss
.u
) && ss
.Rank() > 0;
930 bool operator()(const ProcedureRef
&) const {
931 return false; // don't descend into function call arguments
935 bool HasVectorSubscript(const Expr
<SomeType
> &expr
) {
936 return HasVectorSubscriptHelper
{}(expr
);
939 parser::Message
*AttachDeclaration(
940 parser::Message
&message
, const Symbol
&symbol
) {
941 const Symbol
*unhosted
{&symbol
};
943 const auto *assoc
{unhosted
->detailsIf
<semantics::HostAssocDetails
>()}) {
944 unhosted
= &assoc
->symbol();
946 if (const auto *binding
{
947 unhosted
->detailsIf
<semantics::ProcBindingDetails
>()}) {
948 if (binding
->symbol().name() != symbol
.name()) {
949 message
.Attach(binding
->symbol().name(),
950 "Procedure '%s' of type '%s' is bound to '%s'"_en_US
, symbol
.name(),
951 symbol
.owner().GetName().value(), binding
->symbol().name());
954 unhosted
= &binding
->symbol();
956 if (const auto *use
{symbol
.detailsIf
<semantics::UseDetails
>()}) {
957 message
.Attach(use
->location(),
958 "'%s' is USE-associated with '%s' in module '%s'"_en_US
, symbol
.name(),
959 unhosted
->name(), GetUsedModule(*use
).name());
962 unhosted
->name(), "Declaration of '%s'"_en_US
, unhosted
->name());
967 parser::Message
*AttachDeclaration(
968 parser::Message
*message
, const Symbol
&symbol
) {
969 return message
? AttachDeclaration(*message
, symbol
) : nullptr;
972 class FindImpureCallHelper
973 : public AnyTraverse
<FindImpureCallHelper
, std::optional
<std::string
>> {
974 using Result
= std::optional
<std::string
>;
975 using Base
= AnyTraverse
<FindImpureCallHelper
, Result
>;
978 explicit FindImpureCallHelper(FoldingContext
&c
) : Base
{*this}, context_
{c
} {}
979 using Base::operator();
980 Result
operator()(const ProcedureRef
&call
) const {
982 characteristics::Procedure::Characterize(call
.proc(), context_
)}) {
983 if (chars
->attrs
.test(characteristics::Procedure::Attr::Pure
)) {
984 return (*this)(call
.arguments());
987 return call
.proc().GetName();
991 FoldingContext
&context_
;
994 std::optional
<std::string
> FindImpureCall(
995 FoldingContext
&context
, const Expr
<SomeType
> &expr
) {
996 return FindImpureCallHelper
{context
}(expr
);
998 std::optional
<std::string
> FindImpureCall(
999 FoldingContext
&context
, const ProcedureRef
&proc
) {
1000 return FindImpureCallHelper
{context
}(proc
);
1003 // Common handling for procedure pointer compatibility of left- and right-hand
1004 // sides. Returns nullopt if they're compatible. Otherwise, it returns a
1005 // message that needs to be augmented by the names of the left and right sides
1006 // and the content of the "whyNotCompatible" string.
1007 std::optional
<parser::MessageFixedText
> CheckProcCompatibility(bool isCall
,
1008 const std::optional
<characteristics::Procedure
> &lhsProcedure
,
1009 const characteristics::Procedure
*rhsProcedure
,
1010 const SpecificIntrinsic
*specificIntrinsic
, std::string
&whyNotCompatible
) {
1011 std::optional
<parser::MessageFixedText
> msg
;
1012 if (!lhsProcedure
) {
1013 msg
= "In assignment to object %s, the target '%s' is a procedure"
1014 " designator"_err_en_US
;
1015 } else if (!rhsProcedure
) {
1016 msg
= "In assignment to procedure %s, the characteristics of the target"
1017 " procedure '%s' could not be determined"_err_en_US
;
1018 } else if (!isCall
&& lhsProcedure
->functionResult
&&
1019 rhsProcedure
->functionResult
&&
1020 !lhsProcedure
->functionResult
->IsCompatibleWith(
1021 *rhsProcedure
->functionResult
, &whyNotCompatible
)) {
1023 "Function %s associated with incompatible function designator '%s': %s"_err_en_US
;
1024 } else if (lhsProcedure
->IsCompatibleWith(
1025 *rhsProcedure
, &whyNotCompatible
, specificIntrinsic
)) {
1027 } else if (isCall
) {
1028 msg
= "Procedure %s associated with result of reference to function '%s'"
1029 " that is an incompatible procedure pointer: %s"_err_en_US
;
1030 } else if (lhsProcedure
->IsPure() && !rhsProcedure
->IsPure()) {
1031 msg
= "PURE procedure %s may not be associated with non-PURE"
1032 " procedure designator '%s'"_err_en_US
;
1033 } else if (lhsProcedure
->IsFunction() && rhsProcedure
->IsSubroutine()) {
1034 msg
= "Function %s may not be associated with subroutine"
1035 " designator '%s'"_err_en_US
;
1036 } else if (lhsProcedure
->IsSubroutine() && rhsProcedure
->IsFunction()) {
1037 msg
= "Subroutine %s may not be associated with function"
1038 " designator '%s'"_err_en_US
;
1039 } else if (lhsProcedure
->HasExplicitInterface() &&
1040 !rhsProcedure
->HasExplicitInterface()) {
1041 // Section 10.2.2.4, paragraph 3 prohibits associating a procedure pointer
1042 // that has an explicit interface with a procedure whose characteristics
1043 // don't match. That's the case if the target procedure has an implicit
1044 // interface. But this case is allowed by several other compilers as long
1045 // as the explicit interface can be called via an implicit interface.
1046 if (!lhsProcedure
->CanBeCalledViaImplicitInterface()) {
1047 msg
= "Procedure %s with explicit interface that cannot be called via "
1048 "an implicit interface cannot be associated with procedure "
1049 "designator with an implicit interface"_err_en_US
;
1051 } else if (!lhsProcedure
->HasExplicitInterface() &&
1052 rhsProcedure
->HasExplicitInterface()) {
1053 // OK if the target can be called via an implicit interface
1054 if (!rhsProcedure
->CanBeCalledViaImplicitInterface() &&
1055 !specificIntrinsic
) {
1056 msg
= "Procedure %s with implicit interface may not be associated "
1057 "with procedure designator '%s' with explicit interface that "
1058 "cannot be called via an implicit interface"_err_en_US
;
1061 msg
= "Procedure %s associated with incompatible procedure"
1062 " designator '%s': %s"_err_en_US
;
1067 // GetLastPointerSymbol()
1068 static const Symbol
*GetLastPointerSymbol(const Symbol
&symbol
) {
1069 return IsPointer(GetAssociationRoot(symbol
)) ? &symbol
: nullptr;
1071 static const Symbol
*GetLastPointerSymbol(const SymbolRef
&symbol
) {
1072 return GetLastPointerSymbol(*symbol
);
1074 static const Symbol
*GetLastPointerSymbol(const Component
&x
) {
1075 const Symbol
&c
{x
.GetLastSymbol()};
1076 return IsPointer(c
) ? &c
: GetLastPointerSymbol(x
.base());
1078 static const Symbol
*GetLastPointerSymbol(const NamedEntity
&x
) {
1079 const auto *c
{x
.UnwrapComponent()};
1080 return c
? GetLastPointerSymbol(*c
) : GetLastPointerSymbol(x
.GetLastSymbol());
1082 static const Symbol
*GetLastPointerSymbol(const ArrayRef
&x
) {
1083 return GetLastPointerSymbol(x
.base());
1085 static const Symbol
*GetLastPointerSymbol(const CoarrayRef
&x
) {
1088 const Symbol
*GetLastPointerSymbol(const DataRef
&x
) {
1089 return common::visit(
1090 [](const auto &y
) { return GetLastPointerSymbol(y
); }, x
.u
);
1093 template <TypeCategory TO
, TypeCategory FROM
>
1094 static std::optional
<Expr
<SomeType
>> DataConstantConversionHelper(
1095 FoldingContext
&context
, const DynamicType
&toType
,
1096 const Expr
<SomeType
> &expr
) {
1097 DynamicType sizedType
{FROM
, toType
.kind()};
1099 Fold(context
, ConvertToType(sizedType
, Expr
<SomeType
>{expr
}))}) {
1100 if (const auto *someExpr
{UnwrapExpr
<Expr
<SomeKind
<FROM
>>>(*sized
)}) {
1101 return common::visit(
1102 [](const auto &w
) -> std::optional
<Expr
<SomeType
>> {
1103 using FromType
= typename
std::decay_t
<decltype(w
)>::Result
;
1104 static constexpr int kind
{FromType::kind
};
1105 if constexpr (IsValidKindOfIntrinsicType(TO
, kind
)) {
1106 if (const auto *fromConst
{UnwrapExpr
<Constant
<FromType
>>(w
)}) {
1107 using FromWordType
= typename
FromType::Scalar
;
1108 using LogicalType
= value::Logical
<FromWordType::bits
>;
1110 std::conditional_t
<TO
== TypeCategory::Logical
, LogicalType
,
1111 typename
LogicalType::Word
>;
1112 std::vector
<ElementType
> values
;
1113 auto at
{fromConst
->lbounds()};
1114 auto shape
{fromConst
->shape()};
1115 for (auto n
{GetSize(shape
)}; n
-- > 0;
1116 fromConst
->IncrementSubscripts(at
)) {
1117 auto elt
{fromConst
->At(at
)};
1118 if constexpr (TO
== TypeCategory::Logical
) {
1119 values
.emplace_back(std::move(elt
));
1121 values
.emplace_back(elt
.word());
1124 return {AsGenericExpr(AsExpr(Constant
<Type
<TO
, kind
>>{
1125 std::move(values
), std::move(shape
)}))};
1128 return std::nullopt
;
1133 return std::nullopt
;
1136 std::optional
<Expr
<SomeType
>> DataConstantConversionExtension(
1137 FoldingContext
&context
, const DynamicType
&toType
,
1138 const Expr
<SomeType
> &expr0
) {
1139 Expr
<SomeType
> expr
{Fold(context
, Expr
<SomeType
>{expr0
})};
1140 if (!IsActuallyConstant(expr
)) {
1141 return std::nullopt
;
1143 if (auto fromType
{expr
.GetType()}) {
1144 if (toType
.category() == TypeCategory::Logical
&&
1145 fromType
->category() == TypeCategory::Integer
) {
1146 return DataConstantConversionHelper
<TypeCategory::Logical
,
1147 TypeCategory::Integer
>(context
, toType
, expr
);
1149 if (toType
.category() == TypeCategory::Integer
&&
1150 fromType
->category() == TypeCategory::Logical
) {
1151 return DataConstantConversionHelper
<TypeCategory::Integer
,
1152 TypeCategory::Logical
>(context
, toType
, expr
);
1155 return std::nullopt
;
1158 bool IsAllocatableOrPointerObject(
1159 const Expr
<SomeType
> &expr
, FoldingContext
&context
) {
1160 const semantics::Symbol
*sym
{UnwrapWholeSymbolOrComponentDataRef(expr
)};
1161 return (sym
&& semantics::IsAllocatableOrPointer(*sym
)) ||
1162 evaluate::IsObjectPointer(expr
, context
);
1165 bool IsAllocatableDesignator(const Expr
<SomeType
> &expr
) {
1166 // Allocatable sub-objects are not themselves allocatable (9.5.3.1 NOTE 2).
1167 if (const semantics::Symbol
*
1168 sym
{UnwrapWholeSymbolOrComponentOrCoarrayRef(expr
)}) {
1169 return semantics::IsAllocatable(sym
->GetUltimate());
1174 bool MayBePassedAsAbsentOptional(
1175 const Expr
<SomeType
> &expr
, FoldingContext
&context
) {
1176 const semantics::Symbol
*sym
{UnwrapWholeSymbolOrComponentDataRef(expr
)};
1177 // 15.5.2.12 1. is pretty clear that an unallocated allocatable/pointer actual
1178 // may be passed to a non-allocatable/non-pointer optional dummy. Note that
1179 // other compilers (like nag, nvfortran, ifort, gfortran and xlf) seems to
1180 // ignore this point in intrinsic contexts (e.g CMPLX argument).
1181 return (sym
&& semantics::IsOptional(*sym
)) ||
1182 IsAllocatableOrPointerObject(expr
, context
);
1185 std::optional
<Expr
<SomeType
>> HollerithToBOZ(FoldingContext
&context
,
1186 const Expr
<SomeType
> &expr
, const DynamicType
&type
) {
1187 if (std::optional
<std::string
> chValue
{GetScalarConstantValue
<Ascii
>(expr
)}) {
1188 // Pad on the right with spaces when short, truncate the right if long.
1189 // TODO: big-endian targets
1190 auto bytes
{static_cast<std::size_t>(
1191 ToInt64(type
.MeasureSizeInBytes(context
, false)).value())};
1192 BOZLiteralConstant bits
{0};
1193 for (std::size_t j
{0}; j
< bytes
; ++j
) {
1194 char ch
{j
>= chValue
->size() ? ' ' : chValue
->at(j
)};
1195 BOZLiteralConstant chBOZ
{static_cast<unsigned char>(ch
)};
1196 bits
= bits
.IOR(chBOZ
.SHIFTL(8 * j
));
1198 return ConvertToType(type
, Expr
<SomeType
>{bits
});
1200 return std::nullopt
;
1204 } // namespace Fortran::evaluate
1206 namespace Fortran::semantics
{
1208 const Symbol
&ResolveAssociations(const Symbol
&original
) {
1209 const Symbol
&symbol
{original
.GetUltimate()};
1210 if (const auto *details
{symbol
.detailsIf
<AssocEntityDetails
>()}) {
1211 if (const Symbol
* nested
{UnwrapWholeSymbolDataRef(details
->expr())}) {
1212 return ResolveAssociations(*nested
);
1218 const Symbol
&ResolveAssociationsExceptSelectRank(const Symbol
&original
) {
1219 const Symbol
&symbol
{original
.GetUltimate()};
1220 if (const auto *details
{symbol
.detailsIf
<AssocEntityDetails
>()}) {
1221 if (!details
->rank()) {
1222 if (const Symbol
* nested
{UnwrapWholeSymbolDataRef(details
->expr())}) {
1223 return ResolveAssociations(*nested
);
1230 // When a construct association maps to a variable, and that variable
1231 // is not an array with a vector-valued subscript, return the base
1232 // Symbol of that variable, else nullptr. Descends into other construct
1233 // associations when one associations maps to another.
1234 static const Symbol
*GetAssociatedVariable(const AssocEntityDetails
&details
) {
1235 if (const auto &expr
{details
.expr()}) {
1236 if (IsVariable(*expr
) && !HasVectorSubscript(*expr
)) {
1237 if (const Symbol
* varSymbol
{GetFirstSymbol(*expr
)}) {
1238 return &GetAssociationRoot(*varSymbol
);
1245 const Symbol
&GetAssociationRoot(const Symbol
&original
) {
1246 const Symbol
&symbol
{ResolveAssociations(original
)};
1247 if (const auto *details
{symbol
.detailsIf
<AssocEntityDetails
>()}) {
1248 if (const Symbol
* root
{GetAssociatedVariable(*details
)}) {
1255 const Symbol
*GetMainEntry(const Symbol
*symbol
) {
1257 if (const auto *subpDetails
{symbol
->detailsIf
<SubprogramDetails
>()}) {
1258 if (const Scope
* scope
{subpDetails
->entryScope()}) {
1259 if (const Symbol
* main
{scope
->symbol()}) {
1268 bool IsVariableName(const Symbol
&original
) {
1269 const Symbol
&ultimate
{original
.GetUltimate()};
1270 return !IsNamedConstant(ultimate
) &&
1271 (ultimate
.has
<ObjectEntityDetails
>() ||
1272 ultimate
.has
<AssocEntityDetails
>());
1275 bool IsPureProcedure(const Symbol
&original
) {
1276 // An ENTRY is pure if its containing subprogram is
1277 const Symbol
&symbol
{DEREF(GetMainEntry(&original
.GetUltimate()))};
1278 if (const auto *procDetails
{symbol
.detailsIf
<ProcEntityDetails
>()}) {
1279 if (procDetails
->procInterface()) {
1280 // procedure with a pure interface
1281 return IsPureProcedure(*procDetails
->procInterface());
1283 } else if (const auto *details
{symbol
.detailsIf
<ProcBindingDetails
>()}) {
1284 return IsPureProcedure(details
->symbol());
1285 } else if (!IsProcedure(symbol
)) {
1288 if (IsStmtFunction(symbol
)) {
1289 // Section 15.7(1) states that a statement function is PURE if it does not
1290 // reference an IMPURE procedure or a VOLATILE variable
1291 if (const auto &expr
{symbol
.get
<SubprogramDetails
>().stmtFunction()}) {
1292 for (const SymbolRef
&ref
: evaluate::CollectSymbols(*expr
)) {
1293 if (&*ref
== &symbol
) {
1294 return false; // error recovery, recursion is caught elsewhere
1296 if (IsFunction(*ref
) && !IsPureProcedure(*ref
)) {
1299 if (ref
->GetUltimate().attrs().test(Attr::VOLATILE
)) {
1304 return true; // statement function was not found to be impure
1306 return symbol
.attrs().test(Attr::PURE
) ||
1307 (symbol
.attrs().test(Attr::ELEMENTAL
) &&
1308 !symbol
.attrs().test(Attr::IMPURE
));
1311 bool IsPureProcedure(const Scope
&scope
) {
1312 const Symbol
*symbol
{scope
.GetSymbol()};
1313 return symbol
&& IsPureProcedure(*symbol
);
1316 bool IsElementalProcedure(const Symbol
&original
) {
1317 // An ENTRY is elemental if its containing subprogram is
1318 const Symbol
&symbol
{DEREF(GetMainEntry(&original
.GetUltimate()))};
1319 if (const auto *procDetails
{symbol
.detailsIf
<ProcEntityDetails
>()}) {
1320 if (const Symbol
* procInterface
{procDetails
->procInterface()}) {
1321 // procedure with an elemental interface, ignoring the elemental
1322 // aspect of intrinsic functions
1323 return !procInterface
->attrs().test(Attr::INTRINSIC
) &&
1324 IsElementalProcedure(*procInterface
);
1326 } else if (const auto *details
{symbol
.detailsIf
<ProcBindingDetails
>()}) {
1327 return !details
->symbol().attrs().test(Attr::INTRINSIC
) &&
1328 IsElementalProcedure(details
->symbol());
1329 } else if (!IsProcedure(symbol
)) {
1332 return symbol
.attrs().test(Attr::ELEMENTAL
);
1335 bool IsFunction(const Symbol
&symbol
) {
1336 const Symbol
&ultimate
{symbol
.GetUltimate()};
1337 return ultimate
.test(Symbol::Flag::Function
) ||
1338 (!ultimate
.test(Symbol::Flag::Subroutine
) &&
1341 [](const SubprogramDetails
&x
) { return x
.isFunction(); },
1342 [](const ProcEntityDetails
&x
) {
1343 const Symbol
*ifc
{x
.procInterface()};
1344 return x
.type() || (ifc
&& IsFunction(*ifc
));
1346 [](const ProcBindingDetails
&x
) {
1347 return IsFunction(x
.symbol());
1349 [](const auto &) { return false; },
1351 ultimate
.details()));
1354 bool IsFunction(const Scope
&scope
) {
1355 const Symbol
*symbol
{scope
.GetSymbol()};
1356 return symbol
&& IsFunction(*symbol
);
1359 bool IsProcedure(const Symbol
&symbol
) {
1360 return common::visit(common::visitors
{
1361 [&symbol
](const SubprogramDetails
&) {
1362 const Scope
*scope
{symbol
.scope()};
1363 // Main programs & BLOCK DATA are not procedures.
1365 scope
->kind() == Scope::Kind::Subprogram
;
1367 [](const SubprogramNameDetails
&) { return true; },
1368 [](const ProcEntityDetails
&) { return true; },
1369 [](const GenericDetails
&) { return true; },
1370 [](const ProcBindingDetails
&) { return true; },
1371 [](const auto &) { return false; },
1373 symbol
.GetUltimate().details());
1376 bool IsProcedure(const Scope
&scope
) {
1377 const Symbol
*symbol
{scope
.GetSymbol()};
1378 return symbol
&& IsProcedure(*symbol
);
1381 const Symbol
*FindCommonBlockContaining(const Symbol
&original
) {
1382 const Symbol
&root
{GetAssociationRoot(original
)};
1383 const auto *details
{root
.detailsIf
<ObjectEntityDetails
>()};
1384 return details
? details
->commonBlock() : nullptr;
1387 bool IsProcedurePointer(const Symbol
&original
) {
1388 const Symbol
&symbol
{GetAssociationRoot(original
)};
1389 return IsPointer(symbol
) && IsProcedure(symbol
);
1392 // 3.11 automatic data object
1393 bool IsAutomatic(const Symbol
&original
) {
1394 const Symbol
&symbol
{original
.GetUltimate()};
1395 if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()}) {
1396 if (!object
->isDummy() && !IsAllocatable(symbol
) && !IsPointer(symbol
)) {
1397 if (const DeclTypeSpec
* type
{symbol
.GetType()}) {
1398 // If a type parameter value is not a constant expression, the
1399 // object is automatic.
1400 if (type
->category() == DeclTypeSpec::Character
) {
1401 if (const auto &length
{
1402 type
->characterTypeSpec().length().GetExplicit()}) {
1403 if (!evaluate::IsConstantExpr(*length
)) {
1407 } else if (const DerivedTypeSpec
* derived
{type
->AsDerived()}) {
1408 for (const auto &pair
: derived
->parameters()) {
1409 if (const auto &value
{pair
.second
.GetExplicit()}) {
1410 if (!evaluate::IsConstantExpr(*value
)) {
1417 // If an array bound is not a constant expression, the object is
1419 for (const ShapeSpec
&dim
: object
->shape()) {
1420 if (const auto &lb
{dim
.lbound().GetExplicit()}) {
1421 if (!evaluate::IsConstantExpr(*lb
)) {
1425 if (const auto &ub
{dim
.ubound().GetExplicit()}) {
1426 if (!evaluate::IsConstantExpr(*ub
)) {
1436 bool IsSaved(const Symbol
&original
) {
1437 const Symbol
&symbol
{GetAssociationRoot(original
)};
1438 const Scope
&scope
{symbol
.owner()};
1439 const common::LanguageFeatureControl
&features
{
1440 scope
.context().languageFeatures()};
1441 auto scopeKind
{scope
.kind()};
1442 if (symbol
.has
<AssocEntityDetails
>()) {
1443 return false; // ASSOCIATE(non-variable)
1444 } else if (scopeKind
== Scope::Kind::DerivedType
) {
1445 return false; // this is a component
1446 } else if (symbol
.attrs().test(Attr::SAVE
)) {
1447 return true; // explicit SAVE attribute
1448 } else if (IsDummy(symbol
) || IsFunctionResult(symbol
) ||
1449 IsAutomatic(symbol
) || IsNamedConstant(symbol
)) {
1451 } else if (scopeKind
== Scope::Kind::Module
||
1452 (scopeKind
== Scope::Kind::MainProgram
&&
1453 (symbol
.attrs().test(Attr::TARGET
) || evaluate::IsCoarray(symbol
)))) {
1455 // In main programs, implied SAVE matters only for pointer
1456 // initialization targets and coarrays.
1457 // BLOCK DATA entities must all be in COMMON,
1458 // which was checked above.
1460 } else if (scopeKind
== Scope::Kind::MainProgram
&&
1461 (features
.IsEnabled(common::LanguageFeature::SaveMainProgram
) ||
1462 (features
.IsEnabled(
1463 common::LanguageFeature::SaveBigMainProgramVariables
) &&
1464 symbol
.size() > 32))) {
1465 // With SaveBigMainProgramVariables, keeping all unsaved main program
1466 // variables of 32 bytes or less on the stack allows keeping numerical and
1467 // logical scalars, small scalar characters or derived, small arrays, and
1468 // scalar descriptors on the stack. This leaves more room for lower level
1469 // optimizers to do register promotion or get easy aliasing information.
1471 } else if (features
.IsEnabled(common::LanguageFeature::DefaultSave
) &&
1472 (scopeKind
== Scope::Kind::MainProgram
||
1473 (scope
.kind() == Scope::Kind::Subprogram
&&
1475 scope
.symbol()->attrs().test(Attr::RECURSIVE
))))) {
1476 // -fno-automatic/-save/-Msave option applies to all objects in executable
1477 // main programs and subprograms unless they are explicitly RECURSIVE.
1479 } else if (symbol
.test(Symbol::Flag::InDataStmt
)) {
1481 } else if (const auto *object
{symbol
.detailsIf
<ObjectEntityDetails
>()};
1482 object
&& object
->init()) {
1484 } else if (IsProcedurePointer(symbol
) && symbol
.has
<ProcEntityDetails
>() &&
1485 symbol
.get
<ProcEntityDetails
>().init()) {
1487 } else if (scope
.hasSAVE()) {
1488 return true; // bare SAVE statement
1489 } else if (const Symbol
* block
{FindCommonBlockContaining(symbol
)};
1490 block
&& block
->attrs().test(Attr::SAVE
)) {
1491 return true; // in COMMON with SAVE
1497 bool IsDummy(const Symbol
&symbol
) {
1498 return common::visit(
1499 common::visitors
{[](const EntityDetails
&x
) { return x
.isDummy(); },
1500 [](const ObjectEntityDetails
&x
) { return x
.isDummy(); },
1501 [](const ProcEntityDetails
&x
) { return x
.isDummy(); },
1502 [](const SubprogramDetails
&x
) { return x
.isDummy(); },
1503 [](const auto &) { return false; }},
1504 ResolveAssociations(symbol
).details());
1507 bool IsAssumedShape(const Symbol
&symbol
) {
1508 const Symbol
&ultimate
{ResolveAssociations(symbol
)};
1509 const auto *object
{ultimate
.detailsIf
<ObjectEntityDetails
>()};
1510 return object
&& object
->CanBeAssumedShape() &&
1511 !semantics::IsAllocatableOrPointer(ultimate
);
1514 bool IsDeferredShape(const Symbol
&symbol
) {
1515 const Symbol
&ultimate
{ResolveAssociations(symbol
)};
1516 const auto *object
{ultimate
.detailsIf
<ObjectEntityDetails
>()};
1517 return object
&& object
->CanBeDeferredShape() &&
1518 semantics::IsAllocatableOrPointer(ultimate
);
1521 bool IsFunctionResult(const Symbol
&original
) {
1522 const Symbol
&symbol
{GetAssociationRoot(original
)};
1523 return common::visit(
1525 [](const EntityDetails
&x
) { return x
.isFuncResult(); },
1526 [](const ObjectEntityDetails
&x
) { return x
.isFuncResult(); },
1527 [](const ProcEntityDetails
&x
) { return x
.isFuncResult(); },
1528 [](const auto &) { return false; },
1533 bool IsKindTypeParameter(const Symbol
&symbol
) {
1534 const auto *param
{symbol
.GetUltimate().detailsIf
<TypeParamDetails
>()};
1535 return param
&& param
->attr() == common::TypeParamAttr::Kind
;
1538 bool IsLenTypeParameter(const Symbol
&symbol
) {
1539 const auto *param
{symbol
.GetUltimate().detailsIf
<TypeParamDetails
>()};
1540 return param
&& param
->attr() == common::TypeParamAttr::Len
;
1543 bool IsExtensibleType(const DerivedTypeSpec
*derived
) {
1544 return derived
&& !IsIsoCType(derived
) &&
1545 !derived
->typeSymbol().attrs().test(Attr::BIND_C
) &&
1546 !derived
->typeSymbol().get
<DerivedTypeDetails
>().sequence();
1549 bool IsBuiltinDerivedType(const DerivedTypeSpec
*derived
, const char *name
) {
1553 const auto &symbol
{derived
->typeSymbol()};
1554 return &symbol
.owner() == symbol
.owner().context().GetBuiltinsScope() &&
1555 symbol
.name() == "__builtin_"s
+ name
;
1559 bool IsBuiltinCPtr(const Symbol
&symbol
) {
1560 if (const DeclTypeSpec
*declType
= symbol
.GetType())
1561 if (const DerivedTypeSpec
*derived
= declType
->AsDerived())
1562 return IsIsoCType(derived
);
1566 bool IsIsoCType(const DerivedTypeSpec
*derived
) {
1567 return IsBuiltinDerivedType(derived
, "c_ptr") ||
1568 IsBuiltinDerivedType(derived
, "c_funptr");
1571 bool IsTeamType(const DerivedTypeSpec
*derived
) {
1572 return IsBuiltinDerivedType(derived
, "team_type");
1575 bool IsBadCoarrayType(const DerivedTypeSpec
*derived
) {
1576 return IsTeamType(derived
) || IsIsoCType(derived
);
1579 bool IsEventTypeOrLockType(const DerivedTypeSpec
*derivedTypeSpec
) {
1580 return IsBuiltinDerivedType(derivedTypeSpec
, "event_type") ||
1581 IsBuiltinDerivedType(derivedTypeSpec
, "lock_type");
1584 int CountLenParameters(const DerivedTypeSpec
&type
) {
1585 return llvm::count_if(
1586 type
.parameters(), [](const auto &pair
) { return pair
.second
.isLen(); });
1589 int CountNonConstantLenParameters(const DerivedTypeSpec
&type
) {
1590 return llvm::count_if(type
.parameters(), [](const auto &pair
) {
1591 if (!pair
.second
.isLen()) {
1593 } else if (const auto &expr
{pair
.second
.GetExplicit()}) {
1594 return !IsConstantExpr(*expr
);
1601 // Are the type parameters of type1 compile-time compatible with the
1602 // corresponding kind type parameters of type2? Return true if all constant
1603 // valued parameters are equal.
1604 // Used to check assignment statements and argument passing. See 15.5.2.4(4)
1605 bool AreTypeParamCompatible(const semantics::DerivedTypeSpec
&type1
,
1606 const semantics::DerivedTypeSpec
&type2
) {
1607 for (const auto &[name
, param1
] : type1
.parameters()) {
1608 if (semantics::MaybeIntExpr paramExpr1
{param1
.GetExplicit()}) {
1609 if (IsConstantExpr(*paramExpr1
)) {
1610 const semantics::ParamValue
*param2
{type2
.FindParameter(name
)};
1612 if (semantics::MaybeIntExpr paramExpr2
{param2
->GetExplicit()}) {
1613 if (IsConstantExpr(*paramExpr2
)) {
1614 if (ToInt64(*paramExpr1
) != ToInt64(*paramExpr2
)) {
1626 const Symbol
&GetUsedModule(const UseDetails
&details
) {
1627 return DEREF(details
.symbol().owner().symbol());
1630 static const Symbol
*FindFunctionResult(
1631 const Symbol
&original
, UnorderedSymbolSet
&seen
) {
1632 const Symbol
&root
{GetAssociationRoot(original
)};
1634 if (!seen
.insert(root
).second
) {
1635 return nullptr; // don't loop
1637 return common::visit(
1638 common::visitors
{[](const SubprogramDetails
&subp
) {
1639 return subp
.isFunction() ? &subp
.result() : nullptr;
1641 [&](const ProcEntityDetails
&proc
) {
1642 const Symbol
*iface
{proc
.procInterface()};
1643 return iface
? FindFunctionResult(*iface
, seen
) : nullptr;
1645 [&](const ProcBindingDetails
&binding
) {
1646 return FindFunctionResult(binding
.symbol(), seen
);
1648 [](const auto &) -> const Symbol
* { return nullptr; }},
1652 const Symbol
*FindFunctionResult(const Symbol
&symbol
) {
1653 UnorderedSymbolSet seen
;
1654 return FindFunctionResult(symbol
, seen
);
1657 // These are here in Evaluate/tools.cpp so that Evaluate can use
1658 // them; they cannot be defined in symbol.h due to the dependence
1661 bool SymbolSourcePositionCompare::operator()(
1662 const SymbolRef
&x
, const SymbolRef
&y
) const {
1663 return x
->GetSemanticsContext().allCookedSources().Precedes(
1664 x
->name(), y
->name());
1666 bool SymbolSourcePositionCompare::operator()(
1667 const MutableSymbolRef
&x
, const MutableSymbolRef
&y
) const {
1668 return x
->GetSemanticsContext().allCookedSources().Precedes(
1669 x
->name(), y
->name());
1672 SemanticsContext
&Symbol::GetSemanticsContext() const {
1673 return DEREF(owner_
).context();
1676 bool AreTkCompatibleTypes(const DeclTypeSpec
*x
, const DeclTypeSpec
*y
) {
1678 if (auto xDt
{evaluate::DynamicType::From(*x
)}) {
1679 if (auto yDt
{evaluate::DynamicType::From(*y
)}) {
1680 return xDt
->IsTkCompatibleWith(*yDt
);
1687 } // namespace Fortran::semantics