9#ifndef FORTRAN_EVALUATE_TOOLS_H_
10#define FORTRAN_EVALUATE_TOOLS_H_
13#include "flang/Common/idioms.h"
14#include "flang/Common/template.h"
15#include "flang/Common/unwrap.h"
16#include "flang/Evaluate/constant.h"
17#include "flang/Evaluate/expression.h"
18#include "flang/Evaluate/shape.h"
19#include "flang/Evaluate/type.h"
20#include "flang/Parser/message.h"
21#include "flang/Semantics/attr.h"
22#include "flang/Semantics/scope.h"
23#include "flang/Semantics/symbol.h"
39 :
public AnyTraverse<IsVariableHelper, std::optional<bool>> {
40 using Result = std::optional<bool>;
43 using Base::operator();
45 Result operator()(
const Symbol &)
const;
46 Result operator()(
const Component &)
const;
47 Result operator()(
const ArrayRef &)
const;
48 Result operator()(
const Substring &)
const;
49 Result operator()(
const CoarrayRef &)
const {
return true; }
50 Result operator()(
const ComplexPart &)
const {
return true; }
52 template <
typename T> Result operator()(
const Expr<T> &x)
const {
53 if constexpr (common::HasMember<T, AllIntrinsicTypes> ||
54 std::is_same_v<T, SomeDerived>) {
57 std::holds_alternative<FunctionRef<T>>(x.u)) {
58 if (
auto known{(*this)(x.u)}) {
63 }
else if constexpr (std::is_same_v<T, SomeType>) {
64 if (std::holds_alternative<ProcedureDesignator>(x.u) ||
65 std::holds_alternative<ProcedureRef>(x.u)) {
76template <
typename A>
bool IsVariable(
const A &x) {
85bool IsAssumedRank(
const Symbol &);
86bool IsAssumedRank(
const ActualArgument &);
87template <
typename A>
bool IsAssumedRank(
const A &) {
return false; }
88template <
typename A>
bool IsAssumedRank(
const Designator<A> &designator) {
89 if (
const auto *symbol{std::get_if<SymbolRef>(&designator.u)}) {
90 return IsAssumedRank(symbol->get());
95template <
typename T>
bool IsAssumedRank(
const Expr<T> &expr) {
96 return common::visit([](
const auto &x) {
return IsAssumedRank(x); }, expr.u);
98template <
typename A>
bool IsAssumedRank(
const std::optional<A> &x) {
99 return x && IsAssumedRank(*x);
101template <
typename A>
bool IsAssumedRank(
const A *x) {
102 return x && IsAssumedRank(*x);
107int GetCorank(
const ActualArgument &);
108static inline int GetCorank(
const Symbol &symbol) {
return symbol.Corank(); }
109template <
typename A>
int GetCorank(
const A &) {
return 0; }
110template <
typename T>
int GetCorank(
const Designator<T> &designator) {
111 return designator.Corank();
113template <
typename T>
int GetCorank(
const Expr<T> &expr) {
114 return common::visit([](
const auto &x) {
return GetCorank(x); }, expr.u);
116template <
typename A>
int GetCorank(
const std::optional<A> &x) {
117 return x ? GetCorank(*x) : 0;
119template <
typename A>
int GetCorank(
const A *x) {
120 return x ? GetCorank(*x) : 0;
124template <
typename A>
bool IsCoarray(
const A &x) {
return GetCorank(x) > 0; }
129template <
typename A> common::IfNoLvalue<Expr<ResultType<A>>, A> AsExpr(A &&x) {
130 return Expr<ResultType<A>>{std::move(x)};
133template <
typename T> Expr<T> AsExpr(Expr<T> &&x) {
134 static_assert(IsSpecificIntrinsicType<T>);
138template <TypeCategory CATEGORY>
139Expr<SomeKind<CATEGORY>> AsCategoryExpr(Expr<SomeKind<CATEGORY>> &&x) {
144common::IfNoLvalue<Expr<SomeType>, A> AsGenericExpr(A &&x) {
145 if constexpr (common::HasMember<A, TypelessExpression>) {
146 return Expr<SomeType>{std::move(x)};
148 return Expr<SomeType>{AsCategoryExpr(std::move(x))};
152inline Expr<SomeType> AsGenericExpr(Expr<SomeType> &&x) {
return std::move(x); }
156std::optional<Expr<SomeType>> AsGenericExpr(DataRef &&);
157std::optional<Expr<SomeType>> AsGenericExpr(
const Symbol &);
161std::optional<Expr<SomeType>> AsGenericExpr(std::optional<A> &&x) {
163 return AsGenericExpr(std::move(*x));
170common::IfNoLvalue<Expr<SomeKind<ResultType<A>::category>>, A> AsCategoryExpr(
172 return Expr<SomeKind<ResultType<A>::category>>{AsExpr(std::move(x))};
175Expr<SomeType> Parenthesize(Expr<SomeType> &&);
177template <
typename A>
constexpr bool IsNumericCategoryExpr() {
178 if constexpr (common::HasMember<A, TypelessExpression>) {
181 return common::HasMember<ResultType<A>, NumericCategoryTypes>;
188template <
typename A,
typename B>
189auto UnwrapExpr(B &x) -> common::Constify<A, B> * {
190 using Ty = std::decay_t<B>;
191 if constexpr (std::is_same_v<A, Ty>) {
193 }
else if constexpr (std::is_same_v<Ty, ActualArgument>) {
194 if (
auto *expr{x.UnwrapExpr()}) {
195 return UnwrapExpr<A>(*expr);
197 }
else if constexpr (std::is_same_v<Ty, Expr<SomeType>>) {
198 return common::visit([](
auto &x) {
return UnwrapExpr<A>(x); }, x.u);
199 }
else if constexpr (!common::HasMember<A, TypelessExpression>) {
200 if constexpr (std::is_same_v<Ty, Expr<ResultType<A>>> ||
201 std::is_same_v<Ty, Expr<SomeKind<ResultType<A>::category>>>) {
202 return common::visit([](
auto &x) {
return UnwrapExpr<A>(x); }, x.u);
208template <
typename A,
typename B>
209const A *UnwrapExpr(
const std::optional<B> &x) {
211 return UnwrapExpr<A>(*x);
217template <
typename A,
typename B> A *UnwrapExpr(std::optional<B> &x) {
219 return UnwrapExpr<A>(*x);
225template <
typename A,
typename B>
const A *UnwrapExpr(
const B *x) {
227 return UnwrapExpr<A>(*x);
233template <
typename A,
typename B> A *UnwrapExpr(B *x) {
235 return UnwrapExpr<A>(*x);
244template <
typename A,
typename B>
245auto UnwrapConvertedExpr(B &x) -> common::Constify<A, B> * {
246 using Ty = std::decay_t<B>;
247 if constexpr (std::is_same_v<A, Ty>) {
249 }
else if constexpr (std::is_same_v<Ty, ActualArgument>) {
250 if (
auto *expr{x.UnwrapExpr()}) {
251 return UnwrapConvertedExpr<A>(*expr);
253 }
else if constexpr (std::is_same_v<Ty, Expr<SomeType>>) {
254 return common::visit(
255 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.u);
257 using DesiredResult = ResultType<A>;
258 if constexpr (std::is_same_v<Ty, Expr<DesiredResult>> ||
259 std::is_same_v<Ty, Expr<SomeKind<DesiredResult::category>>>) {
260 return common::visit(
261 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.u);
263 using ThisResult = ResultType<B>;
264 if constexpr (std::is_same_v<Ty, Expr<ThisResult>>) {
265 return common::visit(
266 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.u);
267 }
else if constexpr (std::is_same_v<Ty, Parentheses<ThisResult>> ||
268 std::is_same_v<Ty, Convert<ThisResult, DesiredResult::category>>) {
269 return common::visit(
270 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.left().u);
279template <
typename A>
inline const ProcedureRef *UnwrapProcedureRef(
const A &) {
283inline const ProcedureRef *UnwrapProcedureRef(
const ProcedureRef &proc) {
290inline const ProcedureRef *UnwrapProcedureRef(
const FunctionRef<T> &func) {
295inline const ProcedureRef *UnwrapProcedureRef(
const Expr<T> &expr) {
296 return common::visit(
297 [](
const auto &x) {
return UnwrapProcedureRef(x); }, expr.u);
303template <
typename A>
const Symbol *ExtractBareLenParameter(
const A &expr) {
304 if (
const auto *typeParam{
305 UnwrapConvertedExpr<evaluate::TypeParamInquiry>(expr)}) {
306 if (!typeParam->base()) {
307 const Symbol &symbol{typeParam->parameter()};
308 if (
const auto *tpd{symbol.detailsIf<semantics::TypeParamDetails>()}) {
309 if (tpd->attr() == common::TypeParamAttr::Len) {
323common::IfNoLvalue<std::optional<DataRef>, A> ExtractDataRef(
324 const A &,
bool intoSubstring,
bool intoComplexPart) {
328std::optional<DataRef> ExtractDataRef(
const Designator<T> &d,
329 bool intoSubstring =
false,
bool intoComplexPart =
false) {
330 return common::visit(
331 [=](
const auto &x) -> std::optional<DataRef> {
332 if constexpr (common::HasMember<
decltype(x),
decltype(DataRef::u)>) {
335 if constexpr (std::is_same_v<std::decay_t<
decltype(x)>, Substring>) {
337 return ExtractSubstringBase(x);
340 if constexpr (std::is_same_v<std::decay_t<
decltype(x)>, ComplexPart>) {
341 if (intoComplexPart) {
350std::optional<DataRef> ExtractDataRef(
const Expr<T> &expr,
351 bool intoSubstring =
false,
bool intoComplexPart =
false) {
352 return common::visit(
354 return ExtractDataRef(x, intoSubstring, intoComplexPart);
359std::optional<DataRef> ExtractDataRef(
const std::optional<A> &x,
360 bool intoSubstring =
false,
bool intoComplexPart =
false) {
362 return ExtractDataRef(*x, intoSubstring, intoComplexPart);
368std::optional<DataRef> ExtractDataRef(
369 A *p,
bool intoSubstring =
false,
bool intoComplexPart =
false) {
371 return ExtractDataRef(std::as_const(*p), intoSubstring, intoComplexPart);
376std::optional<DataRef> ExtractDataRef(
const ActualArgument &,
377 bool intoSubstring =
false,
bool intoComplexPart =
false);
379std::optional<DataRef> ExtractSubstringBase(
const Substring &);
383bool IsArrayElement(
const Expr<T> &expr,
bool intoSubstring =
true,
384 bool skipComponents =
false) {
385 if (
auto dataRef{ExtractDataRef(expr, intoSubstring)}) {
386 const DataRef *ref{&*dataRef};
387 if (skipComponents) {
388 while (
const Component * component{std::get_if<Component>(&ref->u)}) {
389 ref = &component->base();
392 if (
const auto *coarrayRef{std::get_if<CoarrayRef>(&ref->u)}) {
393 return !coarrayRef->subscript().empty();
395 return std::holds_alternative<ArrayRef>(ref->u);
403std::optional<NamedEntity> ExtractNamedEntity(
const A &x) {
404 if (
auto dataRef{ExtractDataRef(x)}) {
405 return common::visit(
407 [](SymbolRef &&symbol) -> std::optional<NamedEntity> {
408 return NamedEntity{symbol};
410 [](Component &&component) -> std::optional<NamedEntity> {
411 return NamedEntity{std::move(component)};
413 [](CoarrayRef &&co) -> std::optional<NamedEntity> {
416 [](
auto &&) {
return std::optional<NamedEntity>{}; },
418 std::move(dataRef->u));
425 template <
typename A> std::optional<CoarrayRef> operator()(
const A &)
const {
428 std::optional<CoarrayRef> operator()(
const CoarrayRef &x)
const {
return x; }
429 template <
typename A>
430 std::optional<CoarrayRef> operator()(
const Expr<A> &expr)
const {
431 return common::visit(*
this, expr.u);
433 std::optional<CoarrayRef> operator()(
const DataRef &dataRef)
const {
434 return common::visit(*
this, dataRef.u);
436 std::optional<CoarrayRef> operator()(
const NamedEntity &named)
const {
437 if (
const Component * component{named.UnwrapComponent()}) {
438 return (*
this)(*component);
444 if (
const auto *component{
445 std::get_if<common::CopyableIndirection<Component>>(&des.u)}) {
446 return (*
this)(component->value());
451 std::optional<CoarrayRef> operator()(
const Component &component)
const {
452 return (*
this)(component.base());
454 std::optional<CoarrayRef> operator()(
const ArrayRef &arrayRef)
const {
455 return (*
this)(arrayRef.base());
459template <
typename A> std::optional<CoarrayRef> ExtractCoarrayRef(
const A &x) {
460 if (
auto dataRef{ExtractDataRef(x,
true)}) {
461 return ExtractCoindexedObjectHelper{}(*dataRef);
463 return ExtractCoindexedObjectHelper{}(x);
468 template <
typename T>
static std::optional<Substring> visit(T &&) {
472 static std::optional<Substring> visit(
const Substring &e) {
return e; }
474 template <
typename T>
475 static std::optional<Substring> visit(
const Designator<T> &e) {
476 return common::visit([](
auto &&s) {
return visit(s); }, e.u);
479 template <
typename T>
480 static std::optional<Substring> visit(
const Expr<T> &e) {
481 return common::visit([](
auto &&s) {
return visit(s); }, e.u);
485template <
typename A> std::optional<Substring> ExtractSubstring(
const A &x) {
486 return ExtractSubstringHelper::visit(x);
491template <
typename A>
const Symbol *UnwrapWholeSymbolDataRef(
const A &x) {
492 if (
auto dataRef{ExtractDataRef(x)}) {
493 if (
const SymbolRef * p{std::get_if<SymbolRef>(&dataRef->u)}) {
503const Symbol *UnwrapWholeSymbolOrComponentDataRef(
const A &x) {
504 if (
auto dataRef{ExtractDataRef(x)}) {
505 if (
const SymbolRef * p{std::get_if<SymbolRef>(&dataRef->u)}) {
507 }
else if (
const Component * c{std::get_if<Component>(&dataRef->u)}) {
508 if (c->base().Rank() == 0) {
509 return &c->GetLastSymbol();
520const Symbol *UnwrapWholeSymbolOrComponentOrCoarrayRef(
const A &x) {
521 if (
auto dataRef{ExtractDataRef(x)}) {
522 if (
const SymbolRef * p{std::get_if<SymbolRef>(&dataRef->u)}) {
524 }
else if (
const Component * c{std::get_if<Component>(&dataRef->u)}) {
525 if (c->base().Rank() == 0) {
526 return &c->GetLastSymbol();
528 }
else if (
const CoarrayRef * c{std::get_if<CoarrayRef>(&dataRef->u)}) {
529 if (c->subscript().empty()) {
530 return &c->GetLastSymbol();
538template <
typename A>
const Symbol *GetFirstSymbol(
const A &x) {
539 if (
auto dataRef{ExtractDataRef(x,
true)}) {
540 return &dataRef->GetFirstSymbol();
547const Symbol *GetLastPointerSymbol(
const evaluate::DataRef &);
553template <
typename TO, TypeCategory FROMCAT>
554Expr<TO> ConvertToType(Expr<SomeKind<FROMCAT>> &&x) {
555 static_assert(IsSpecificIntrinsicType<TO>);
556 if constexpr (FROMCAT == TO::category) {
557 if (
auto *already{std::get_if<Expr<TO>>(&x.u)}) {
558 return std::move(*already);
560 return Expr<TO>{Convert<TO, FROMCAT>{std::move(x)}};
562 }
else if constexpr (TO::category == TypeCategory::Complex) {
563 using Part =
typename TO::Part;
565 return Expr<TO>{ComplexConstructor<TO::kind>{
566 ConvertToType<Part>(std::move(x)), Expr<Part>{Constant<Part>{zero}}}};
567 }
else if constexpr (FROMCAT == TypeCategory::Complex) {
569 return common::visit(
571 using ZType = ResultType<
decltype(z)>;
572 using Part =
typename ZType::Part;
573 return ConvertToType<TO, TypeCategory::Real>(Expr<SomeReal>{
574 Expr<Part>{ComplexComponent<Part::kind>{
false, std::move(z)}}});
578 return Expr<TO>{Convert<TO, FROMCAT>{std::move(x)}};
582template <
typename TO, TypeCategory FROMCAT,
int FROMKIND>
583Expr<TO> ConvertToType(Expr<Type<FROMCAT, FROMKIND>> &&x) {
584 return ConvertToType<TO, FROMCAT>(Expr<SomeKind<FROMCAT>>{std::move(x)});
587template <
typename TO> Expr<TO> ConvertToType(BOZLiteralConstant &&x) {
588 static_assert(IsSpecificIntrinsicType<TO>);
589 if constexpr (TO::category == TypeCategory::Integer ||
590 TO::category == TypeCategory::Unsigned) {
592 Constant<TO>{Scalar<TO>::ConvertUnsigned(std::move(x)).value}};
594 static_assert(TO::category == TypeCategory::Real);
595 using Word =
typename Scalar<TO>::Word;
597 Constant<TO>{Scalar<TO>{Word::ConvertUnsigned(std::move(x)).value}}};
601template <
typename T>
bool IsBOZLiteral(
const Expr<T> &expr) {
602 return std::holds_alternative<BOZLiteralConstant>(expr.u);
606std::optional<Expr<SomeType>> ConvertToType(
607 const DynamicType &, Expr<SomeType> &&);
608std::optional<Expr<SomeType>> ConvertToType(
609 const DynamicType &, std::optional<Expr<SomeType>> &&);
610std::optional<Expr<SomeType>> ConvertToType(
const Symbol &, Expr<SomeType> &&);
611std::optional<Expr<SomeType>> ConvertToType(
612 const Symbol &, std::optional<Expr<SomeType>> &&);
615template <TypeCategory TC,
int TK,
typename FROM>
616common::IfNoLvalue<Expr<Type<TC, TK>>, FROM> ConvertTo(
617 const Expr<Type<TC, TK>> &, FROM &&x) {
618 return ConvertToType<Type<TC, TK>>(std::move(x));
621template <TypeCategory TC,
typename FROM>
622common::IfNoLvalue<Expr<SomeKind<TC>>, FROM> ConvertTo(
623 const Expr<SomeKind<TC>> &to, FROM &&from) {
624 return common::visit(
625 [&](
const auto &toKindExpr) {
626 using KindExpr = std::decay_t<
decltype(toKindExpr)>;
627 return AsCategoryExpr(
628 ConvertToType<ResultType<KindExpr>>(std::move(from)));
633template <
typename FROM>
634common::IfNoLvalue<Expr<SomeType>, FROM> ConvertTo(
635 const Expr<SomeType> &to, FROM &&from) {
636 return common::visit(
637 [&](
const auto &toCatExpr) {
638 return AsGenericExpr(ConvertTo(toCatExpr, std::move(from)));
646 using Result = std::optional<Expr<SomeKind<TOCAT>>>;
647 using Types = CategoryTypes<TOCAT>;
649 template <
typename T> Result Test() {
650 if (kind == T::kind) {
651 return std::make_optional(
652 AsCategoryExpr(ConvertToType<T>(std::move(value))));
660template <TypeCategory TOCAT,
typename VALUE>
661common::IfNoLvalue<Expr<SomeKind<TOCAT>>, VALUE> ConvertToKind(
662 int kind, VALUE &&x) {
663 auto result{common::SearchTypes(
665 CHECK(result.has_value());
672template <
typename A,
int N = 2>
using SameExprs = std::array<Expr<A>, N>;
674 template <
typename A>
using SameExprs = std::array<Expr<A>, N>;
676template <TypeCategory CAT,
int N = 2>
678 common::MapTemplate<SameKindExprsHelper<N>::template SameExprs,
684template <TypeCategory CAT>
685SameKindExprs<CAT, 2> AsSameKindExprs(
687 return common::visit(
688 [&](
auto &&kx,
auto &&ky) -> SameKindExprs<CAT, 2> {
689 using XTy = ResultType<
decltype(kx)>;
690 using YTy = ResultType<
decltype(ky)>;
691 if constexpr (std::is_same_v<XTy, YTy>) {
692 return {SameExprs<XTy>{std::move(kx), std::move(ky)}};
693 }
else if constexpr (XTy::kind < YTy::kind) {
694 return {SameExprs<YTy>{ConvertTo(ky, std::move(kx)), std::move(ky)}};
696 return {SameExprs<XTy>{std::move(kx), ConvertTo(kx, std::move(ky))}};
698#if !__clang__ && 100 * __GNUC__ + __GNUC_MINOR__ == 801
701 CHECK(!
"can't happen");
702 return {SameExprs<XTy>{std::move(kx), std::move(kx)}};
705 std::move(x.u), std::move(y.u));
711using ConvertRealOperandsResult =
712 std::optional<SameKindExprs<TypeCategory::Real, 2>>;
713ConvertRealOperandsResult ConvertRealOperands(parser::ContextualMessages &,
714 Expr<SomeType> &&, Expr<SomeType> &&,
int defaultRealKind);
720std::optional<Expr<SomeComplex>> ConstructComplex(parser::ContextualMessages &,
721 Expr<SomeType> &&, Expr<SomeType> &&,
int defaultRealKind);
722std::optional<Expr<SomeComplex>> ConstructComplex(parser::ContextualMessages &,
723 std::optional<Expr<SomeType>> &&, std::optional<Expr<SomeType>> &&,
724 int defaultRealKind);
726template <
typename A> Expr<TypeOf<A>> ScalarConstantToExpr(
const A &x) {
727 using Ty = TypeOf<A>;
729 std::is_same_v<Scalar<Ty>, std::decay_t<A>>,
"TypeOf<> is broken");
730 return Expr<TypeOf<A>>{Constant<Ty>{x}};
735template <
template <
typename>
class OPR,
typename SPECIFIC>
736Expr<SPECIFIC> Combine(Expr<SPECIFIC> &&x, Expr<SPECIFIC> &&y) {
737 static_assert(IsSpecificIntrinsicType<SPECIFIC>);
738 return AsExpr(OPR<SPECIFIC>{std::move(x), std::move(y)});
745template <
template <
typename>
class OPR, TypeCategory CAT>
746Expr<SomeKind<CAT>> PromoteAndCombine(
747 Expr<SomeKind<CAT>> &&x, Expr<SomeKind<CAT>> &&y) {
748 return common::visit(
750 using Ty = ResultType<
decltype(xy[0])>;
751 return AsCategoryExpr(
752 Combine<OPR, Ty>(std::move(xy[0]), std::move(xy[1])));
754 AsSameKindExprs(std::move(x), std::move(y)));
762template <
template <
typename>
class OPR,
bool CAN_BE_UNSIGNED =
true>
763std::optional<Expr<SomeType>> NumericOperation(parser::ContextualMessages &,
764 Expr<SomeType> &&, Expr<SomeType> &&,
int defaultRealKind);
766extern template std::optional<Expr<SomeType>> NumericOperation<Power, false>(
767 parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&,
768 int defaultRealKind);
769extern template std::optional<Expr<SomeType>> NumericOperation<Multiply>(
770 parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&,
771 int defaultRealKind);
772extern template std::optional<Expr<SomeType>> NumericOperation<Divide>(
773 parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&,
774 int defaultRealKind);
775extern template std::optional<Expr<SomeType>> NumericOperation<Add>(
776 parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&,
777 int defaultRealKind);
778extern template std::optional<Expr<SomeType>> NumericOperation<Subtract>(
779 parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&,
780 int defaultRealKind);
782std::optional<Expr<SomeType>> Negation(
783 parser::ContextualMessages &, Expr<SomeType> &&);
787std::optional<Expr<LogicalResult>> Relate(parser::ContextualMessages &,
788 RelationalOperator, Expr<SomeType> &&, Expr<SomeType> &&);
793Expr<LogicalResult> PackageRelation(
794 RelationalOperator opr, Expr<T> &&x, Expr<T> &&y) {
795 static_assert(IsSpecificIntrinsicType<T>);
796 return Expr<LogicalResult>{
797 Relational<SomeType>{Relational<T>{opr, std::move(x), std::move(y)}}};
801Expr<Type<TypeCategory::Logical, K>> LogicalNegation(
802 Expr<Type<TypeCategory::Logical, K>> &&x) {
803 return AsExpr(Not<K>{std::move(x)});
806Expr<SomeLogical> LogicalNegation(Expr<SomeLogical> &&);
809Expr<Type<TypeCategory::Logical, K>> BinaryLogicalOperation(LogicalOperator opr,
810 Expr<Type<TypeCategory::Logical, K>> &&x,
811 Expr<Type<TypeCategory::Logical, K>> &&y) {
812 return AsExpr(LogicalOperation<K>{opr, std::move(x), std::move(y)});
815Expr<SomeLogical> BinaryLogicalOperation(
816 LogicalOperator, Expr<SomeLogical> &&, Expr<SomeLogical> &&);
823template <TypeCategory C,
int K>
824Expr<Type<C, K>> operator-(Expr<Type<C, K>> &&x) {
825 return AsExpr(Negate<Type<C, K>>{std::move(x)});
828template <TypeCategory C,
int K>
829Expr<Type<C, K>> operator+(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
830 return AsExpr(Combine<Add, Type<C, K>>(std::move(x), std::move(y)));
833template <TypeCategory C,
int K>
834Expr<Type<C, K>> operator-(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
835 return AsExpr(Combine<Subtract, Type<C, K>>(std::move(x), std::move(y)));
838template <TypeCategory C,
int K>
839Expr<Type<C, K>> operator*(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
840 return AsExpr(Combine<Multiply, Type<C, K>>(std::move(x), std::move(y)));
843template <TypeCategory C,
int K>
844Expr<Type<C, K>> operator/(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
845 return AsExpr(Combine<Divide, Type<C, K>>(std::move(x), std::move(y)));
848template <TypeCategory C> Expr<SomeKind<C>> operator-(Expr<SomeKind<C>> &&x) {
849 return common::visit(
850 [](
auto &xk) {
return Expr<SomeKind<C>>{-std::move(xk)}; }, x.u);
853template <TypeCategory CAT>
854Expr<SomeKind<CAT>> operator+(
855 Expr<SomeKind<CAT>> &&x, Expr<SomeKind<CAT>> &&y) {
856 return PromoteAndCombine<Add, CAT>(std::move(x), std::move(y));
859template <TypeCategory CAT>
860Expr<SomeKind<CAT>> operator-(
861 Expr<SomeKind<CAT>> &&x, Expr<SomeKind<CAT>> &&y) {
862 return PromoteAndCombine<Subtract, CAT>(std::move(x), std::move(y));
865template <TypeCategory CAT>
866Expr<SomeKind<CAT>> operator*(
867 Expr<SomeKind<CAT>> &&x, Expr<SomeKind<CAT>> &&y) {
868 return PromoteAndCombine<Multiply, CAT>(std::move(x), std::move(y));
871template <TypeCategory CAT>
872Expr<SomeKind<CAT>> operator/(
873 Expr<SomeKind<CAT>> &&x, Expr<SomeKind<CAT>> &&y) {
874 return PromoteAndCombine<Divide, CAT>(std::move(x), std::move(y));
880template <TypeCategory CAT,
template <
typename>
class TEMPLATE,
typename VALUE>
882 using Result = std::optional<Expr<SomeType>>;
883 using Types = CategoryTypes<CAT>;
888 template <
typename T> Result Test() {
889 if (kind == T::kind) {
890 return AsGenericExpr(TEMPLATE<T>{std::move(value)});
902template <TypeCategory CATEGORY,
template <
typename>
typename WRAPPER,
904common::IfNoLvalue<std::optional<Expr<SomeType>>, WRAPPED> WrapperHelper(
905 int kind, WRAPPED &&x) {
906 return common::SearchTypes(
910template <
template <
typename>
typename WRAPPER,
typename WRAPPED>
911common::IfNoLvalue<std::optional<Expr<SomeType>>, WRAPPED> TypedWrapper(
912 const DynamicType &dyType, WRAPPED &&x) {
913 switch (dyType.category()) {
914 SWITCH_COVERS_ALL_CASES
915 case TypeCategory::Integer:
916 return WrapperHelper<TypeCategory::Integer, WRAPPER, WRAPPED>(
917 dyType.kind(), std::move(x));
918 case TypeCategory::Unsigned:
919 return WrapperHelper<TypeCategory::Unsigned, WRAPPER, WRAPPED>(
920 dyType.kind(), std::move(x));
921 case TypeCategory::Real:
922 return WrapperHelper<TypeCategory::Real, WRAPPER, WRAPPED>(
923 dyType.kind(), std::move(x));
924 case TypeCategory::Complex:
925 return WrapperHelper<TypeCategory::Complex, WRAPPER, WRAPPED>(
926 dyType.kind(), std::move(x));
927 case TypeCategory::Character:
928 return WrapperHelper<TypeCategory::Character, WRAPPER, WRAPPED>(
929 dyType.kind(), std::move(x));
930 case TypeCategory::Logical:
931 return WrapperHelper<TypeCategory::Logical, WRAPPER, WRAPPED>(
932 dyType.kind(), std::move(x));
933 case TypeCategory::Derived:
934 return AsGenericExpr(Expr<SomeDerived>{WRAPPER<SomeDerived>{std::move(x)}});
943 :
public AnyTraverse<GetLastSymbolHelper, std::optional<const Symbol *>> {
944 using Result = std::optional<const Symbol *>;
947 using Base::operator();
948 Result operator()(
const Symbol &x)
const {
return &x; }
949 Result operator()(
const Component &x)
const {
return &x.GetLastSymbol(); }
950 Result operator()(
const NamedEntity &x)
const {
return &x.GetLastSymbol(); }
952 return x.GetSymbol();
954 template <
typename T> Result operator()(
const Expr<T> &x)
const {
955 if constexpr (common::HasMember<T, AllIntrinsicTypes> ||
956 std::is_same_v<T, SomeDerived>) {
957 if (
const auto *designator{std::get_if<Designator<T>>(&x.u)}) {
958 if (
auto known{(*this)(*designator)}) {
969template <
typename A>
const Symbol *GetLastSymbol(
const A &x) {
980template <
typename A> semantics::Attrs GetAttrs(
const A &x) {
981 if (
const Symbol * symbol{GetLastSymbol(x)}) {
982 return symbol->attrs();
989inline semantics::Attrs GetAttrs<Expr<SomeType>>(
const Expr<SomeType> &x) {
991 if (
const auto *procRef{UnwrapProcedureRef(x)}) {
992 if (
const Symbol * interface{procRef->proc().GetInterfaceSymbol()}) {
993 if (
const auto *details{
994 interface->detailsIf<semantics::SubprogramDetails>()}) {
995 if (details->isFunction() &&
996 details->result().attrs().test(semantics::Attr::POINTER)) {
998 return details->result().attrs();
1004 if (
const Symbol * symbol{GetLastSymbol(x)}) {
1005 return symbol->attrs();
1011template <
typename A> semantics::Attrs GetAttrs(
const std::optional<A> &x) {
1013 return GetAttrs(*x);
1020template <
typename A> std::optional<BaseObject> GetBaseObject(
const A &) {
1021 return std::nullopt;
1023template <
typename T>
1024std::optional<BaseObject> GetBaseObject(
const Designator<T> &x) {
1025 return x.GetBaseObject();
1027template <
typename T>
1028std::optional<BaseObject> GetBaseObject(
const Expr<T> &x) {
1029 return common::visit([](
const auto &y) {
return GetBaseObject(y); }, x.u);
1031template <
typename A>
1032std::optional<BaseObject> GetBaseObject(
const std::optional<A> &x) {
1034 return GetBaseObject(*x);
1036 return std::nullopt;
1042bool IsAllocatableOrPointerObject(
const Expr<SomeType> &);
1044bool IsAllocatableDesignator(
const Expr<SomeType> &);
1047bool IsProcedureDesignator(
const Expr<SomeType> &);
1048bool IsFunctionDesignator(
const Expr<SomeType> &);
1049bool IsPointer(
const Expr<SomeType> &);
1050bool IsProcedurePointer(
const Expr<SomeType> &);
1051bool IsProcedure(
const Expr<SomeType> &);
1052bool IsProcedurePointerTarget(
const Expr<SomeType> &);
1053bool IsBareNullPointer(
const Expr<SomeType> *);
1054bool IsNullObjectPointer(
const Expr<SomeType> &);
1055bool IsNullProcedurePointer(
const Expr<SomeType> &);
1056bool IsNullPointer(
const Expr<SomeType> &);
1057bool IsObjectPointer(
const Expr<SomeType> &);
1061bool MayBePassedAsAbsentOptional(
const Expr<SomeType> &);
1067 :
public Traverse<GetSymbolVectorHelper, SymbolVector> {
1068 using Result = SymbolVector;
1070 using Base::operator();
1072 Result Default() {
return {}; }
1073 Result Combine(Result &&a, Result &&b) {
1074 a.insert(a.end(), b.begin(), b.end());
1075 return std::move(a);
1077 Result operator()(
const Symbol &)
const;
1078 Result operator()(
const Component &)
const;
1079 Result operator()(
const ArrayRef &)
const;
1082template <
typename A> SymbolVector GetSymbolVector(
const A &x) {
1089const Symbol *GetLastTarget(
const SymbolVector &);
1092template <
typename A> semantics::UnorderedSymbolSet CollectSymbols(
const A &);
1093extern template semantics::UnorderedSymbolSet CollectSymbols(
1094 const Expr<SomeType> &);
1095extern template semantics::UnorderedSymbolSet CollectSymbols(
1096 const Expr<SomeInteger> &);
1097extern template semantics::UnorderedSymbolSet CollectSymbols(
1098 const Expr<SubscriptInteger> &);
1101template <
typename A>
1102semantics::UnorderedSymbolSet CollectCudaSymbols(
const A &);
1103extern template semantics::UnorderedSymbolSet CollectCudaSymbols(
1104 const Expr<SomeType> &);
1105extern template semantics::UnorderedSymbolSet CollectCudaSymbols(
1106 const Expr<SomeInteger> &);
1107extern template semantics::UnorderedSymbolSet CollectCudaSymbols(
1108 const Expr<SubscriptInteger> &);
1111bool HasVectorSubscript(
const Expr<SomeType> &);
1114bool HasConstant(
const Expr<SomeType> &);
1118parser::Message *AttachDeclaration(parser::Message &,
const Symbol &);
1119parser::Message *AttachDeclaration(parser::Message *,
const Symbol &);
1120template <
typename MESSAGES,
typename... A>
1121parser::Message *SayWithDeclaration(
1122 MESSAGES &messages,
const Symbol &symbol, A &&...x) {
1123 return AttachDeclaration(messages.Say(std::forward<A>(x)...), symbol);
1128std::optional<std::string> FindImpureCall(
1129 FoldingContext &,
const Expr<SomeType> &);
1130std::optional<std::string> FindImpureCall(
1131 FoldingContext &,
const ProcedureRef &);
1137 :
public AnyTraverse<UnexpandabilityFindingVisitor> {
1140 using Base::operator();
1142 :
Base{*
this}, admitPureCall_{admitPureCall} {}
1143 template <
typename T>
bool operator()(
const FunctionRef<T> &procRef) {
1144 return !admitPureCall_ || !procRef.proc().IsPure();
1146 bool operator()(
const CoarrayRef &) {
return true; }
1149 bool admitPureCall_{
false};
1152template <
typename T>
1154 const Shape &shape,
bool admitPureCall =
false) {
1156 auto extents{AsConstantExtents(context, shape)};
1157 return extents && !HasNegativeExtent(*extents) && GetSize(*extents) == 1;
1166std::optional<parser::MessageFixedText> CheckProcCompatibility(
bool isCall,
1167 const std::optional<characteristics::Procedure> &lhsProcedure,
1169 const SpecificIntrinsic *specificIntrinsic, std::string &whyNotCompatible,
1170 std::optional<std::string> &warning,
bool ignoreImplicitVsExplicit);
1176 : extents_{std::move(extents)} {}
1178 ConstantSubscripts &&extents, std::optional<ConstantSubscripts> &&lbounds)
1179 : extents_{std::move(extents)}, lbounds_{std::move(lbounds)} {}
1181 ConstantSubscripts &&extents, ConstantSubscripts &&lbounds)
1182 : extents_{std::move(extents)}, lbounds_{std::move(lbounds)} {}
1184 template <
typename A> A Expand(A &&x)
const {
1185 return std::move(x);
1188 auto expanded{x.Reshape(std::move(extents_))};
1190 expanded.set_lbounds(std::move(*lbounds_));
1195 return Expand(std::move(x.left()));
1198 return common::visit(
1199 [&](
auto &&x) {
return Expr<T>{Expand(std::move(x))}; },
1204 ConstantSubscripts extents_;
1205 std::optional<ConstantSubscripts> lbounds_;
1211template <
typename T>
1212Constant<T> PackageConstant(std::vector<Scalar<T>> &&elements,
1213 const Constant<T> &reference,
const ConstantSubscripts &shape) {
1214 if constexpr (T::category == TypeCategory::Character) {
1216 reference.LEN(), std::move(elements), ConstantSubscripts{shape}};
1217 }
else if constexpr (T::category == TypeCategory::Derived) {
1218 return Constant<T>{reference.GetType().GetDerivedTypeSpec(),
1219 std::move(elements), ConstantSubscripts{shape}};
1221 return Constant<T>{std::move(elements), ConstantSubscripts{shape}};
1227std::optional<Expr<SomeType>> DataConstantConversionExtension(
1228 FoldingContext &,
const DynamicType &,
const Expr<SomeType> &);
1232std::optional<Expr<SomeType>> HollerithToBOZ(
1233 FoldingContext &,
const Expr<SomeType> &,
const DynamicType &);
1239 : lbounds_{std::move(lbounds)} {}
1241 template <
typename A> A ChangeLbounds(A &&x)
const {
1242 return std::move(x);
1245 x.set_lbounds(std::move(lbounds_));
1246 return std::move(x);
1249 return ChangeLbounds(
1250 std::move(x.left()));
1253 return common::visit(
1254 [&](
auto &&x) {
return Expr<T>{ChangeLbounds(std::move(x))}; },
1259 ConstantSubscripts &&lbounds_;
1265template <
typename T>
1266std::optional<bool> AreEquivalentInInterface(
const Expr<T> &,
const Expr<T> &);
1267extern template std::optional<bool> AreEquivalentInInterface<SubscriptInteger>(
1269extern template std::optional<bool> AreEquivalentInInterface<SomeInteger>(
1273 const std::optional<ActualArgument> &,
const std::string &procName,
1274 const std::string &argName);
1276inline bool CanCUDASymbolHaveSaveAttr(
const Symbol &sym) {
1277 if (
const auto *details =
1279 if (details->cudaDataAttr() &&
1280 *details->cudaDataAttr() != common::CUDADataAttr::Unified) {
1287inline bool IsCUDADeviceSymbol(
const Symbol &sym) {
1288 if (
const auto *details =
1289 sym.GetUltimate().detailsIf<semantics::ObjectEntityDetails>()) {
1290 if (details->cudaDataAttr() &&
1291 *details->cudaDataAttr() != common::CUDADataAttr::Pinned) {
1300template <
typename A>
inline int GetNbOfCUDADeviceSymbols(
const A &expr) {
1301 semantics::UnorderedSymbolSet symbols;
1302 for (
const Symbol &sym : CollectCudaSymbols(expr)) {
1303 if (IsCUDADeviceSymbol(sym)) {
1304 symbols.insert(sym);
1307 return symbols.size();
1312template <
typename A>
inline bool HasCUDADeviceAttrs(
const A &expr) {
1313 return GetNbOfCUDADeviceSymbols(expr) > 0;
1319 unsigned hostSymbols{0};
1320 unsigned deviceSymbols{0};
1321 for (
const Symbol &sym : CollectCudaSymbols(expr)) {
1322 if (IsCUDADeviceSymbol(sym)) {
1325 if (sym.owner().IsDerivedType()) {
1326 if (IsCUDADeviceSymbol(sym.owner().GetSymbol()->GetUltimate())) {
1333 bool hasConstant{HasConstant(expr)};
1334 return (hasConstant || (hostSymbols > 0)) && deviceSymbols > 0;
1339namespace Fortran::semantics {
1345const Symbol *GetMainEntry(
const Symbol *);
1350bool IsVariableName(
const Symbol &);
1351bool IsPureProcedure(
const Symbol &);
1352bool IsPureProcedure(
const Scope &);
1353bool IsExplicitlyImpureProcedure(
const Symbol &);
1354bool IsElementalProcedure(
const Symbol &);
1355bool IsFunction(
const Symbol &);
1356bool IsFunction(
const Scope &);
1357bool IsProcedure(
const Symbol &);
1358bool IsProcedure(
const Scope &);
1359bool IsProcedurePointer(
const Symbol *);
1360bool IsProcedurePointer(
const Symbol &);
1361bool IsObjectPointer(
const Symbol *);
1362bool IsAllocatableOrObjectPointer(
const Symbol *);
1363bool IsAutomatic(
const Symbol &);
1364bool IsSaved(
const Symbol &);
1365bool IsDummy(
const Symbol &);
1366bool IsAssumedShape(
const Symbol &);
1367bool IsDeferredShape(
const Symbol &);
1368bool IsFunctionResult(
const Symbol &);
1369bool IsKindTypeParameter(
const Symbol &);
1370bool IsLenTypeParameter(
const Symbol &);
1371bool IsExtensibleType(
const DerivedTypeSpec *);
1372bool IsSequenceOrBindCType(
const DerivedTypeSpec *);
1373bool IsBuiltinDerivedType(
const DerivedTypeSpec *derived,
const char *name);
1374bool IsBuiltinCPtr(
const Symbol &);
1375bool IsEventType(
const DerivedTypeSpec *);
1376bool IsLockType(
const DerivedTypeSpec *);
1377bool IsNotifyType(
const DerivedTypeSpec *);
1379bool IsIeeeFlagType(
const DerivedTypeSpec *);
1381bool IsIeeeRoundType(
const DerivedTypeSpec *);
1383bool IsTeamType(
const DerivedTypeSpec *);
1385bool IsBadCoarrayType(
const DerivedTypeSpec *);
1387bool IsIsoCType(
const DerivedTypeSpec *);
1388bool IsEventTypeOrLockType(
const DerivedTypeSpec *);
1389inline bool IsAssumedSizeArray(
const Symbol &symbol) {
1390 if (
const auto *
object{symbol.detailsIf<ObjectEntityDetails>()}) {
1391 return (object->isDummy() || symbol.test(Symbol::Flag::CrayPointee)) &&
1392 object->shape().CanBeAssumedSize();
1393 }
else if (
const auto *assoc{symbol.detailsIf<AssocEntityDetails>()}) {
1394 return assoc->IsAssumedSize();
1412const Symbol &ResolveAssociations(
const Symbol &);
1413const Symbol &GetAssociationRoot(
const Symbol &);
1415const Symbol *FindCommonBlockContaining(
const Symbol &);
1416int CountLenParameters(
const DerivedTypeSpec &);
1417int CountNonConstantLenParameters(
const DerivedTypeSpec &);
1419const Symbol &GetUsedModule(
const UseDetails &);
1420const Symbol *FindFunctionResult(
const Symbol &);
1425bool AreTkCompatibleTypes(
const DeclTypeSpec *x,
const DeclTypeSpec *y);
1427common::IgnoreTKRSet GetIgnoreTKR(
const Symbol &);
1429std::optional<int> GetDummyArgumentNumber(
const Symbol *);
1431const Symbol *FindAncestorModuleProcedure(
const Symbol *symInSubmodule);
Definition: traverse.h:305
Definition: variable.h:208
Definition: variable.h:255
Definition: variable.h:369
Definition: variable.h:74
Definition: constant.h:141
Definition: variable.h:393
Definition: variable.h:104
Definition: static-data.h:29
Definition: variable.h:316
Definition: traverse.h:50
Definition: message.h:363
bool HasCUDAImplicitTransfer(const Expr< SomeType > &expr)
Definition: tools.h:1318
Definition: variable.h:300
Definition: expression.h:229
Definition: characteristics.h:355