9#ifndef FORTRAN_EVALUATE_TOOLS_H_
10#define FORTRAN_EVALUATE_TOOLS_H_
13#include "flang/Common/enum-set.h"
14#include "flang/Common/idioms.h"
15#include "flang/Common/template.h"
16#include "flang/Common/unwrap.h"
17#include "flang/Evaluate/constant.h"
18#include "flang/Evaluate/expression.h"
19#include "flang/Evaluate/shape.h"
20#include "flang/Evaluate/type.h"
21#include "flang/Parser/message.h"
22#include "flang/Semantics/attr.h"
23#include "flang/Semantics/scope.h"
24#include "flang/Semantics/symbol.h"
39struct IsVariableHelper
40 :
public AnyTraverse<IsVariableHelper, std::optional<bool>> {
41 using Result = std::optional<bool>;
42 using Base = AnyTraverse<IsVariableHelper, Result>;
43 IsVariableHelper() : Base{*
this} {}
44 using Base::operator();
46 Result operator()(
const Symbol &)
const;
47 Result operator()(
const Component &)
const;
48 Result operator()(
const ArrayRef &)
const;
49 Result operator()(
const Substring &)
const;
50 Result operator()(
const CoarrayRef &)
const {
return true; }
51 Result operator()(
const ComplexPart &)
const {
return true; }
56 template <
typename T> Result operator()(
const Expr<T> &x)
const {
57 if constexpr (common::HasMember<T, AllIntrinsicTypes> ||
58 std::is_same_v<T, SomeDerived>) {
62 if (
auto known{(*this)(x.u)}) {
67 }
else if constexpr (std::is_same_v<T, SomeType>) {
68 if (std::holds_alternative<ProcedureDesignator>(x.u) ||
69 std::holds_alternative<ProcedureRef>(x.u)) {
80template <
typename A>
bool IsVariable(
const A &x) {
91static inline int GetCorank(
const Symbol &symbol) {
return symbol.Corank(); }
92template <
typename A>
int GetCorank(
const A &) {
return 0; }
93template <
typename T>
int GetCorank(
const Designator<T> &designator) {
94 return designator.Corank();
96template <
typename T>
int GetCorank(
const Expr<T> &expr) {
97 return common::visit([](
const auto &x) {
return GetCorank(x); }, expr.u);
99template <
typename A>
int GetCorank(
const std::optional<A> &x) {
100 return x ? GetCorank(*x) : 0;
102template <
typename A>
int GetCorank(
const A *x) {
103 return x ? GetCorank(*x) : 0;
107template <
typename A>
bool IsCoarray(
const A &x) {
return GetCorank(x) > 0; }
112template <
typename A> common::IfNoLvalue<Expr<ResultType<A>>, A> AsExpr(A &&x) {
116template <typename T, typename U = typename Relational<T>::Result>
125 static_assert(IsSpecificIntrinsicType<T>);
129template <TypeCategory CATEGORY>
135common::IfNoLvalue<Expr<SomeType>, A> AsGenericExpr(A &&x) {
136 if constexpr (common::HasMember<A, TypelessExpression>) {
147std::optional<Expr<SomeType>> AsGenericExpr(
DataRef &&);
148std::optional<Expr<SomeType>> AsGenericExpr(
const Symbol &);
152std::optional<Expr<SomeType>> AsGenericExpr(std::optional<A> &&x) {
154 return AsGenericExpr(std::move(*x));
161common::IfNoLvalue<Expr<SomeKind<ResultType<A>::category>>, A> AsCategoryExpr(
168template <
typename A>
constexpr bool IsNumericCategoryExpr() {
169 if constexpr (common::HasMember<A, TypelessExpression>) {
172 return common::HasMember<ResultType<A>, NumericCategoryTypes>;
179template <
typename A,
typename B>
180auto UnwrapExpr(B &x) -> common::Constify<A, B> * {
181 using Ty = std::decay_t<B>;
182 if constexpr (std::is_same_v<A, Ty>) {
184 }
else if constexpr (std::is_same_v<Ty, ActualArgument>) {
185 if (
auto *expr{x.UnwrapExpr()}) {
186 return UnwrapExpr<A>(*expr);
188 }
else if constexpr (std::is_same_v<Ty, Expr<SomeType>>) {
189 return common::visit([](
auto &x) {
return UnwrapExpr<A>(x); }, x.u);
190 }
else if constexpr (!common::HasMember<A, TypelessExpression>) {
191 if constexpr (std::is_same_v<Ty, Expr<ResultType<A>>> ||
192 std::is_same_v<Ty, Expr<SomeKind<ResultType<A>::category>>>) {
193 return common::visit([](
auto &x) {
return UnwrapExpr<A>(x); }, x.u);
199template <
typename A,
typename B>
200const A *UnwrapExpr(
const std::optional<B> &x) {
202 return UnwrapExpr<A>(*x);
208template <
typename A,
typename B> A *UnwrapExpr(std::optional<B> &x) {
210 return UnwrapExpr<A>(*x);
216template <
typename A,
typename B>
const A *UnwrapExpr(
const B *x) {
218 return UnwrapExpr<A>(*x);
224template <
typename A,
typename B> A *UnwrapExpr(B *x) {
226 return UnwrapExpr<A>(*x);
235template <
typename A,
typename B>
236auto UnwrapConvertedExpr(B &x) -> common::Constify<A, B> * {
237 using Ty = std::decay_t<B>;
238 if constexpr (std::is_same_v<A, Ty>) {
240 }
else if constexpr (std::is_same_v<Ty, ActualArgument>) {
241 if (
auto *expr{x.UnwrapExpr()}) {
242 return UnwrapConvertedExpr<A>(*expr);
244 }
else if constexpr (std::is_same_v<Ty, Expr<SomeType>>) {
245 return common::visit(
246 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.u);
248 using DesiredResult = ResultType<A>;
249 if constexpr (std::is_same_v<Ty, Expr<DesiredResult>> ||
250 std::is_same_v<Ty, Expr<SomeKind<DesiredResult::category>>>) {
251 return common::visit(
252 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.u);
254 using ThisResult = ResultType<B>;
255 if constexpr (std::is_same_v<Ty, Expr<ThisResult>>) {
256 return common::visit(
257 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.u);
258 }
else if constexpr (std::is_same_v<Ty, Parentheses<ThisResult>> ||
259 std::is_same_v<Ty, Convert<ThisResult, DesiredResult::category>>) {
260 return common::visit(
261 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.left().u);
270template <
typename A>
inline const ProcedureRef *UnwrapProcedureRef(
const A &) {
287 return common::visit(
288 [](
const auto &x) {
return UnwrapProcedureRef(x); }, expr.u);
294template <
typename A>
const Symbol *ExtractBareLenParameter(
const A &expr) {
295 if (
const auto *typeParam{
296 UnwrapConvertedExpr<evaluate::TypeParamInquiry>(expr)}) {
297 if (!typeParam->base()) {
298 const Symbol &symbol{typeParam->parameter()};
299 if (
const auto *tpd{symbol.detailsIf<semantics::TypeParamDetails>()}) {
300 if (tpd->attr() == common::TypeParamAttr::Len) {
314common::IfNoLvalue<std::optional<DataRef>, A> ExtractDataRef(
315 const A &x,
bool intoSubstring,
bool intoComplexPart) {
316 if constexpr (common::HasMember<
decltype(x),
decltype(DataRef::u)>) {
323std::optional<DataRef> ExtractSubstringBase(
const Substring &);
325inline std::optional<DataRef> ExtractDataRef(
const Substring &x,
326 bool intoSubstring =
false,
bool intoComplexPart =
false) {
328 return ExtractSubstringBase(x);
333inline std::optional<DataRef> ExtractDataRef(
const ComplexPart &x,
334 bool intoSubstring =
false,
bool intoComplexPart =
false) {
335 if (intoComplexPart) {
343 bool intoSubstring =
false,
bool intoComplexPart =
false) {
344 return common::visit(
345 [=](
const auto &x) -> std::optional<DataRef> {
346 return ExtractDataRef(x, intoSubstring, intoComplexPart);
351std::optional<DataRef> ExtractDataRef(
const Expr<T> &expr,
352 bool intoSubstring =
false,
bool intoComplexPart =
false) {
353 return common::visit(
355 return ExtractDataRef(x, intoSubstring, intoComplexPart);
360std::optional<DataRef> ExtractDataRef(
const std::optional<A> &x,
361 bool intoSubstring =
false,
bool intoComplexPart =
false) {
363 return ExtractDataRef(*x, intoSubstring, intoComplexPart);
369std::optional<DataRef> ExtractDataRef(
370 A *p,
bool intoSubstring =
false,
bool intoComplexPart =
false) {
372 return ExtractDataRef(std::as_const(*p), intoSubstring, intoComplexPart);
378 bool intoSubstring =
false,
bool intoComplexPart =
false);
382const Symbol *IsArrayElement(
const Expr<T> &expr,
bool intoSubstring =
true,
383 bool skipComponents =
false) {
384 if (
auto dataRef{ExtractDataRef(expr, intoSubstring)}) {
385 for (
const DataRef *ref{&*dataRef}; ref;) {
386 if (
const Component * component{std::get_if<Component>(&ref->u)}) {
387 ref = skipComponents ? &component->base() :
nullptr;
388 }
else if (
const auto *coarrayRef{std::get_if<CoarrayRef>(&ref->u)}) {
389 ref = &coarrayRef->base();
390 }
else if (
const auto *arrayRef{std::get_if<ArrayRef>(&ref->u)}) {
391 return &arrayRef->GetLastSymbol();
401bool isStructureComponent(
const Fortran::evaluate::Expr<T> &expr) {
402 if (
auto dataRef{ExtractDataRef(expr,
false)}) {
403 const Fortran::evaluate::DataRef *ref{&*dataRef};
404 return std::holds_alternative<Fortran::evaluate::Component>(ref->u);
411std::optional<NamedEntity> ExtractNamedEntity(
const A &x) {
412 if (
auto dataRef{ExtractDataRef(x)}) {
413 return common::visit(
415 [](SymbolRef &&symbol) -> std::optional<NamedEntity> {
418 [](
Component &&component) -> std::optional<NamedEntity> {
421 [](
auto &&) {
return std::optional<NamedEntity>{}; },
423 std::move(dataRef->u));
430 template <
typename A> std::optional<CoarrayRef> operator()(
const A &)
const {
433 std::optional<CoarrayRef> operator()(
const CoarrayRef &x)
const {
return x; }
434 template <
typename A>
435 std::optional<CoarrayRef> operator()(
const Expr<A> &expr)
const {
436 return common::visit(*
this, expr.u);
438 std::optional<CoarrayRef> operator()(
const DataRef &dataRef)
const {
439 return common::visit(*
this, dataRef.u);
441 std::optional<CoarrayRef> operator()(
const NamedEntity &named)
const {
442 if (
const Component * component{named.UnwrapComponent()}) {
443 return (*
this)(*component);
449 if (
const auto *component{
450 std::get_if<common::CopyableIndirection<Component>>(&des.u)}) {
451 return (*
this)(component->value());
456 std::optional<CoarrayRef> operator()(
const Component &component)
const {
457 return (*
this)(component.base());
459 std::optional<CoarrayRef> operator()(
const ArrayRef &arrayRef)
const {
460 return (*
this)(arrayRef.base());
464static inline std::optional<CoarrayRef> ExtractCoarrayRef(
const DataRef &x) {
468template <
typename A> std::optional<CoarrayRef> ExtractCoarrayRef(
const A &x) {
469 if (
auto dataRef{ExtractDataRef(x,
true)}) {
470 return ExtractCoarrayRef(*dataRef);
477 template <
typename T>
static std::optional<TARGET> visit(T &&) {
481 static std::optional<TARGET> visit(
const TARGET &t) {
return t; }
483 template <
typename T>
485 return common::visit([](
auto &&s) {
return visit(s); }, e.u);
488 template <
typename T>
static std::optional<TARGET> visit(
const Expr<T> &e) {
489 return common::visit([](
auto &&s) {
return visit(s); }, e.u);
493template <
typename A> std::optional<Substring> ExtractSubstring(
const A &x) {
494 return ExtractFromExprDesignatorHelper<Substring>::visit(x);
498std::optional<ComplexPart> ExtractComplexPart(
const A &x) {
499 return ExtractFromExprDesignatorHelper<ComplexPart>::visit(x);
504const Symbol *UnwrapWholeSymbolDataRef(
const DataRef &);
505const Symbol *UnwrapWholeSymbolDataRef(
const std::optional<DataRef> &);
506template <
typename A>
const Symbol *UnwrapWholeSymbolDataRef(
const A &x) {
507 return UnwrapWholeSymbolDataRef(ExtractDataRef(x));
512const Symbol *UnwrapWholeSymbolOrComponentDataRef(
const DataRef &);
513const Symbol *UnwrapWholeSymbolOrComponentDataRef(
514 const std::optional<DataRef> &);
516const Symbol *UnwrapWholeSymbolOrComponentDataRef(
const A &x) {
517 return UnwrapWholeSymbolOrComponentDataRef(ExtractDataRef(x));
523const Symbol *UnwrapWholeSymbolOrComponentOrCoarrayRef(
const DataRef &);
524const Symbol *UnwrapWholeSymbolOrComponentOrCoarrayRef(
525 const std::optional<DataRef> &);
527const Symbol *UnwrapWholeSymbolOrComponentOrCoarrayRef(
const A &x) {
528 return UnwrapWholeSymbolOrComponentOrCoarrayRef(ExtractDataRef(x));
532template <
typename A>
const Symbol *GetFirstSymbol(
const A &x) {
533 if (
auto dataRef{ExtractDataRef(x,
true)}) {
534 return &dataRef->GetFirstSymbol();
541const Symbol *GetLastPointerSymbol(
const evaluate::DataRef &);
547template <
typename TO, TypeCategory FROMCAT>
549 static_assert(IsSpecificIntrinsicType<TO>);
550 if constexpr (FROMCAT == TO::category) {
551 if (
auto *already{std::get_if<Expr<TO>>(&x.u)}) {
552 return std::move(*already);
556 }
else if constexpr (TO::category == TypeCategory::Complex) {
557 using Part =
typename TO::Part;
561 }
else if constexpr (FROMCAT == TypeCategory::Complex) {
563 return common::visit(
565 using ZType = ResultType<
decltype(z)>;
566 using Part =
typename ZType::Part;
576template <
typename TO, TypeCategory FROMCAT,
int FROMKIND>
581template <
typename TO>
Expr<TO> ConvertToType(BOZLiteralConstant &&x) {
582 static_assert(IsSpecificIntrinsicType<TO>);
583 if constexpr (TO::category == TypeCategory::Integer ||
584 TO::category == TypeCategory::Unsigned) {
586 Constant<TO>{Scalar<TO>::ConvertUnsigned(std::move(x)).value}};
588 static_assert(TO::category == TypeCategory::Real);
589 using Word =
typename Scalar<TO>::Word;
591 Constant<TO>{Scalar<TO>{Word::ConvertUnsigned(std::move(x)).value}}};
595template <
typename T>
bool IsBOZLiteral(
const Expr<T> &expr) {
596 return std::holds_alternative<BOZLiteralConstant>(expr.u);
600std::optional<Expr<SomeType>> ConvertToType(
602std::optional<Expr<SomeType>> ConvertToType(
605std::optional<Expr<SomeType>> ConvertToType(
609template <TypeCategory TC,
int TK,
typename FROM>
610common::IfNoLvalue<Expr<Type<TC, TK>>, FROM> ConvertTo(
612 return ConvertToType<Type<TC, TK>>(std::move(x));
615template <TypeCategory TC,
typename FROM>
616common::IfNoLvalue<Expr<SomeKind<TC>>, FROM> ConvertTo(
618 return common::visit(
619 [&](
const auto &toKindExpr) {
620 using KindExpr = std::decay_t<
decltype(toKindExpr)>;
621 return AsCategoryExpr(
622 ConvertToType<ResultType<KindExpr>>(std::move(from)));
627template <
typename FROM>
628common::IfNoLvalue<Expr<SomeType>, FROM> ConvertTo(
630 return common::visit(
631 [&](
const auto &toCatExpr) {
632 return AsGenericExpr(ConvertTo(toCatExpr, std::move(from)));
639template <TypeCategory TOCAT,
typename VALUE>
struct ConvertToKindHelper {
640 using Result = std::optional<Expr<SomeKind<TOCAT>>>;
641 using Types = CategoryTypes<TOCAT>;
642 ConvertToKindHelper(
int k, VALUE &&x) : kind{k}, value{std::move(x)} {}
643 template <
typename T> Result Test() {
644 if (kind == T::kind) {
645 return std::make_optional(
646 AsCategoryExpr(ConvertToType<T>(std::move(value))));
654template <TypeCategory TOCAT,
typename VALUE>
655common::IfNoLvalue<Expr<SomeKind<TOCAT>>, VALUE> ConvertToKind(
656 int kind, VALUE &&x) {
657 auto result{common::SearchTypes(
659 CHECK(result.has_value());
666template <
typename A,
int N = 2>
using SameExprs = std::array<Expr<A>, N>;
668 template <
typename A>
using SameExprs = std::array<Expr<A>, N>;
670template <TypeCategory CAT,
int N = 2>
672 common::MapTemplate<SameKindExprsHelper<N>::template SameExprs,
678template <TypeCategory CAT>
679SameKindExprs<CAT, 2> AsSameKindExprs(
681 return common::visit(
682 [&](
auto &&kx,
auto &&ky) -> SameKindExprs<CAT, 2> {
683 using XTy = ResultType<
decltype(kx)>;
684 using YTy = ResultType<
decltype(ky)>;
685 if constexpr (std::is_same_v<XTy, YTy>) {
686 return {SameExprs<XTy>{std::move(kx), std::move(ky)}};
687 }
else if constexpr (XTy::kind < YTy::kind) {
688 return {SameExprs<YTy>{ConvertTo(ky, std::move(kx)), std::move(ky)}};
690 return {SameExprs<XTy>{std::move(kx), ConvertTo(kx, std::move(ky))}};
692#if !__clang__ && 100 * __GNUC__ + __GNUC_MINOR__ == 801
695 CHECK(!
"can't happen");
696 return {SameExprs<XTy>{std::move(kx), std::move(kx)}};
699 std::move(x.u), std::move(y.u));
705using ConvertRealOperandsResult =
706 std::optional<SameKindExprs<TypeCategory::Real, 2>>;
707ConvertRealOperandsResult ConvertRealOperands(parser::ContextualMessages &,
714std::optional<Expr<SomeComplex>> ConstructComplex(parser::ContextualMessages &,
716std::optional<Expr<SomeComplex>> ConstructComplex(parser::ContextualMessages &,
718 int defaultRealKind);
720template <
typename A>
Expr<TypeOf<A>> ScalarConstantToExpr(
const A &x) {
721 using Ty = TypeOf<A>;
723 std::is_same_v<Scalar<Ty>, std::decay_t<A>>,
"TypeOf<> is broken");
729template <
template <
typename>
class OPR,
typename SPECIFIC>
731 static_assert(IsSpecificIntrinsicType<SPECIFIC>);
732 return AsExpr(OPR<SPECIFIC>{std::move(x), std::move(y)});
739template <
template <
typename>
class OPR, TypeCategory CAT>
742 return common::visit(
744 using Ty = ResultType<
decltype(xy[0])>;
745 return AsCategoryExpr(
746 Combine<OPR, Ty>(std::move(xy[0]), std::move(xy[1])));
748 AsSameKindExprs(std::move(x), std::move(y)));
756template <
template <
typename>
class OPR>
757std::optional<Expr<SomeType>> NumericOperation(parser::ContextualMessages &,
760extern template std::optional<Expr<SomeType>> NumericOperation<Power>(
762 int defaultRealKind);
763extern template std::optional<Expr<SomeType>> NumericOperation<Multiply>(
765 int defaultRealKind);
766extern template std::optional<Expr<SomeType>> NumericOperation<Divide>(
768 int defaultRealKind);
769extern template std::optional<Expr<SomeType>> NumericOperation<Add>(
771 int defaultRealKind);
772extern template std::optional<Expr<SomeType>> NumericOperation<Subtract>(
774 int defaultRealKind);
776std::optional<Expr<SomeType>> Negation(
781std::optional<Expr<LogicalResult>> Relate(parser::ContextualMessages &,
789 static_assert(IsSpecificIntrinsicType<T>);
797 return AsExpr(
Not<K>{std::move(x)});
817template <TypeCategory C,
int K>
822template <TypeCategory C,
int K>
824 return AsExpr(Combine<
Add,
Type<C, K>>(std::move(x), std::move(y)));
827template <TypeCategory C,
int K>
832template <TypeCategory C,
int K>
837template <TypeCategory C,
int K>
843 return common::visit(
847template <TypeCategory CAT>
850 return PromoteAndCombine<Add, CAT>(std::move(x), std::move(y));
853template <TypeCategory CAT>
856 return PromoteAndCombine<Subtract, CAT>(std::move(x), std::move(y));
859template <TypeCategory CAT>
862 return PromoteAndCombine<Multiply, CAT>(std::move(x), std::move(y));
865template <TypeCategory CAT>
868 return PromoteAndCombine<Divide, CAT>(std::move(x), std::move(y));
874template <TypeCategory CAT,
template <
typename>
class TEMPLATE,
typename VALUE>
875struct TypeKindVisitor {
876 using Result = std::optional<Expr<SomeType>>;
877 using Types = CategoryTypes<CAT>;
879 TypeKindVisitor(
int k, VALUE &&x) : kind{k}, value{std::move(x)} {}
880 TypeKindVisitor(
int k,
const VALUE &x) : kind{k}, value{x} {}
882 template <
typename T> Result Test() {
883 if (kind == T::kind) {
884 return AsGenericExpr(TEMPLATE<T>{std::move(value)});
896template <TypeCategory CATEGORY,
template <
typename>
typename WRAPPER,
898common::IfNoLvalue<std::optional<Expr<SomeType>>, WRAPPED> WrapperHelper(
899 int kind, WRAPPED &&x) {
900 return common::SearchTypes(
904template <
template <
typename>
typename WRAPPER,
typename WRAPPED>
905common::IfNoLvalue<std::optional<Expr<SomeType>>, WRAPPED> TypedWrapper(
906 const DynamicType &dyType, WRAPPED &&x) {
907 switch (dyType.category()) {
908 SWITCH_COVERS_ALL_CASES
909 case TypeCategory::Integer:
910 return WrapperHelper<TypeCategory::Integer, WRAPPER, WRAPPED>(
911 dyType.kind(), std::move(x));
912 case TypeCategory::Unsigned:
913 return WrapperHelper<TypeCategory::Unsigned, WRAPPER, WRAPPED>(
914 dyType.kind(), std::move(x));
915 case TypeCategory::Real:
916 return WrapperHelper<TypeCategory::Real, WRAPPER, WRAPPED>(
917 dyType.kind(), std::move(x));
918 case TypeCategory::Complex:
919 return WrapperHelper<TypeCategory::Complex, WRAPPER, WRAPPED>(
920 dyType.kind(), std::move(x));
921 case TypeCategory::Character:
922 return WrapperHelper<TypeCategory::Character, WRAPPER, WRAPPED>(
923 dyType.kind(), std::move(x));
924 case TypeCategory::Logical:
925 return WrapperHelper<TypeCategory::Logical, WRAPPER, WRAPPED>(
926 dyType.kind(), std::move(x));
927 case TypeCategory::Derived:
928 return AsGenericExpr(Expr<SomeDerived>{WRAPPER<SomeDerived>{std::move(x)}});
936struct GetLastSymbolHelper
937 :
public AnyTraverse<GetLastSymbolHelper, std::optional<const Symbol *>> {
938 using Result = std::optional<const Symbol *>;
939 using Base = AnyTraverse<GetLastSymbolHelper, Result>;
940 GetLastSymbolHelper() : Base{*
this} {}
941 using Base::operator();
942 Result operator()(
const Symbol &x)
const {
return &x; }
943 Result operator()(
const Component &x)
const {
return &x.GetLastSymbol(); }
944 Result operator()(
const NamedEntity &x)
const {
return &x.GetLastSymbol(); }
946 return x.GetSymbol();
948 template <
typename T> Result operator()(
const Expr<T> &x)
const {
949 if constexpr (common::HasMember<T, AllIntrinsicTypes> ||
950 std::is_same_v<T, SomeDerived>) {
951 if (
const auto *designator{std::get_if<Designator<T>>(&x.u)}) {
952 if (
auto known{(*this)(*designator)}) {
963template <
typename A>
const Symbol *GetLastSymbol(
const A &x) {
974template <
typename A> semantics::Attrs GetAttrs(
const A &x) {
975 if (
const Symbol * symbol{GetLastSymbol(x)}) {
976 return symbol->attrs();
983inline semantics::Attrs GetAttrs<Expr<SomeType>>(
const Expr<SomeType> &x) {
985 if (
const auto *procRef{UnwrapProcedureRef(x)}) {
986 if (
const Symbol * interface{procRef->proc().GetInterfaceSymbol()}) {
987 if (
const auto *details{
988 interface->detailsIf<semantics::SubprogramDetails>()}) {
989 if (details->isFunction() &&
990 details->result().attrs().test(semantics::Attr::POINTER)) {
992 return details->result().attrs();
998 if (
const Symbol * symbol{GetLastSymbol(x)}) {
999 return symbol->attrs();
1005template <
typename A> semantics::Attrs GetAttrs(
const std::optional<A> &x) {
1007 return GetAttrs(*x);
1014template <
typename A> std::optional<BaseObject> GetBaseObject(
const A &) {
1015 return std::nullopt;
1017template <
typename T>
1018std::optional<BaseObject> GetBaseObject(
const Designator<T> &x) {
1019 return x.GetBaseObject();
1021template <
typename T>
1022std::optional<BaseObject> GetBaseObject(
const Expr<T> &x) {
1023 return common::visit([](
const auto &y) {
return GetBaseObject(y); }, x.u);
1025template <
typename A>
1026std::optional<BaseObject> GetBaseObject(
const std::optional<A> &x) {
1028 return GetBaseObject(*x);
1030 return std::nullopt;
1062struct GetSymbolVectorHelper
1063 :
public Traverse<GetSymbolVectorHelper, SymbolVector> {
1064 using Result = SymbolVector;
1065 using Base = Traverse<GetSymbolVectorHelper, Result>;
1066 using Base::operator();
1067 GetSymbolVectorHelper() : Base{*
this} {}
1068 Result Default() {
return {}; }
1069 Result Combine(Result &&a, Result &&b) {
1070 a.insert(a.end(), b.begin(), b.end());
1071 return std::move(a);
1073 Result operator()(
const Symbol &)
const;
1074 Result operator()(
const Component &)
const;
1075 Result operator()(
const ArrayRef &)
const;
1078template <
typename A> SymbolVector GetSymbolVector(
const A &x) {
1085const Symbol *GetLastTarget(
const SymbolVector &);
1088template <
typename A> semantics::UnorderedSymbolSet CollectSymbols(
const A &);
1089extern template semantics::UnorderedSymbolSet CollectSymbols(
1090 const Expr<SomeType> &);
1091extern template semantics::UnorderedSymbolSet CollectSymbols(
1092 const Expr<SomeInteger> &);
1093extern template semantics::UnorderedSymbolSet CollectSymbols(
1094 const Expr<SubscriptInteger> &);
1095extern template semantics::UnorderedSymbolSet CollectSymbols(
1096 const ProcedureDesignator &);
1097extern template semantics::UnorderedSymbolSet CollectSymbols(
1098 const Assignment &);
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> &);
1112bool HasVectorSubscript(
const ActualArgument &);
1115bool IsArraySection(
const Expr<SomeType> &expr);
1118bool HasConstant(
const Expr<SomeType> &);
1121bool HasStructureComponent(
const Expr<SomeType> &expr);
1125parser::Message *AttachDeclaration(parser::Message &,
const Symbol &);
1126parser::Message *AttachDeclaration(parser::Message *,
const Symbol &);
1127template <
typename MESSAGES,
typename... A>
1128parser::Message *SayWithDeclaration(
1129 MESSAGES &messages,
const Symbol &symbol, A &&...x) {
1130 return AttachDeclaration(messages.Say(std::forward<A>(x)...), symbol);
1132template <
typename... A>
1134 const Symbol &symbol, common::LanguageFeature feature, A &&...x) {
1135 return AttachDeclaration(
1136 context.Warn(feature, std::forward<A>(x)...), symbol);
1138template <
typename... A>
1140 const Symbol &symbol, common::UsageWarning warning, A &&...x) {
1141 return AttachDeclaration(
1142 context.Warn(warning, std::forward<A>(x)...), symbol);
1147std::optional<std::string> FindImpureCall(
1149std::optional<std::string> FindImpureCall(
1155class UnsafeToCopyVisitor :
public AnyTraverse<UnsafeToCopyVisitor> {
1157 using Base = AnyTraverse<UnsafeToCopyVisitor>;
1158 using Base::operator();
1159 explicit UnsafeToCopyVisitor(
bool admitPureCall)
1160 : Base{*
this}, admitPureCall_{admitPureCall} {}
1161 template <
typename T>
bool operator()(
const FunctionRef<T> &procRef) {
1162 return !admitPureCall_ || !procRef.proc().IsPure();
1164 bool operator()(
const CoarrayRef &) {
return true; }
1167 bool admitPureCall_{
false};
1170template <
typename A>
1171bool IsSafelyCopyable(
const A &x,
bool admitPureCall =
false) {
1178template <
typename T>
1179bool IsExpandableScalar(
const Expr<T> &expr, FoldingContext &context,
1180 const Shape &shape,
bool admitPureCall =
false) {
1181 if (IsSafelyCopyable(expr, admitPureCall)) {
1184 auto extents{AsConstantExtents(context, shape)};
1185 return extents && !HasNegativeExtent(*extents) && GetSize(*extents) == 1;
1192std::optional<parser::MessageFixedText> CheckProcCompatibility(
bool isCall,
1193 const std::optional<characteristics::Procedure> &lhsProcedure,
1196 std::optional<std::string> &warning,
bool ignoreImplicitVsExplicit);
1199class ScalarConstantExpander {
1201 explicit ScalarConstantExpander(ConstantSubscripts &&extents)
1202 : extents_{std::move(extents)} {}
1203 ScalarConstantExpander(
1204 ConstantSubscripts &&extents, std::optional<ConstantSubscripts> &&lbounds)
1205 : extents_{std::move(extents)}, lbounds_{std::move(lbounds)} {}
1206 ScalarConstantExpander(
1207 ConstantSubscripts &&extents, ConstantSubscripts &&lbounds)
1208 : extents_{std::move(extents)}, lbounds_{std::move(lbounds)} {}
1210 template <
typename A> A Expand(A &&x)
const {
1211 return std::move(x);
1214 auto expanded{x.Reshape(std::move(extents_))};
1216 expanded.set_lbounds(std::move(*lbounds_));
1221 return Expand(std::move(x.left()));
1224 return common::visit(
1225 [&](
auto &&x) {
return Expr<T>{Expand(std::move(x))}; },
1230 ConstantSubscripts extents_;
1231 std::optional<ConstantSubscripts> lbounds_;
1237template <
typename T>
1238Constant<T> PackageConstant(std::vector<Scalar<T>> &&elements,
1239 const Constant<T> &reference,
const ConstantSubscripts &shape) {
1240 if constexpr (T::category == TypeCategory::Character) {
1242 reference.LEN(), std::move(elements), ConstantSubscripts{shape}};
1243 }
else if constexpr (T::category == TypeCategory::Derived) {
1244 return Constant<T>{reference.GetType().GetDerivedTypeSpec(),
1245 std::move(elements), ConstantSubscripts{shape}};
1247 return Constant<T>{std::move(elements), ConstantSubscripts{shape}};
1253std::optional<Expr<SomeType>> DataConstantConversionExtension(
1258std::optional<Expr<SomeType>> HollerithToBOZ(
1262class ArrayConstantBoundChanger {
1264 explicit ArrayConstantBoundChanger(ConstantSubscripts &&lbounds)
1265 : lbounds_{std::move(lbounds)} {}
1267 template <
typename A> A ChangeLbounds(A &&x)
const {
1268 return std::move(x);
1271 x.set_lbounds(std::move(lbounds_));
1272 return std::move(x);
1275 return ChangeLbounds(
1276 std::move(x.left()));
1279 return common::visit(
1280 [&](
auto &&x) {
return Expr<T>{ChangeLbounds(std::move(x))}; },
1285 ConstantSubscripts &&lbounds_;
1291template <
typename T>
1292std::optional<bool> AreEquivalentInInterface(
const Expr<T> &,
const Expr<T> &);
1293extern template std::optional<bool> AreEquivalentInInterface<SubscriptInteger>(
1295extern template std::optional<bool> AreEquivalentInInterface<SomeInteger>(
1299 const std::optional<ActualArgument> &,
const std::string &procName,
1300 const std::string &argName);
1307std::vector<SymbolVector> GetSymbolVectors(
const Expr<SomeType> &expr);
1309bool IsCUDADeviceSymbol(
const Symbol &sym);
1310bool IsCUDADeviceOnlySymbol(
const Symbol &sym);
1312inline bool IsCUDAManagedOrUnifiedSymbol(
const Symbol &sym) {
1313 if (
const auto *details =
1315 if (details->cudaDataAttr() &&
1316 (*details->cudaDataAttr() == common::CUDADataAttr::Managed ||
1317 *details->cudaDataAttr() == common::CUDADataAttr::Unified)) {
1329inline bool IsNonAllocatableModuleCUDAManagedSymbol(
const Symbol &sym) {
1330 const Symbol &ultimate = sym.GetUltimate();
1331 if (!IsCUDAManagedOrUnifiedSymbol(ultimate))
1333 if (ultimate.attrs().test(semantics::Attr::ALLOCATABLE))
1335 return ultimate.owner().IsModule();
1338template <
typename A>
1339inline bool HasNonAllocatableModuleCUDAManagedSymbols(
const A &expr) {
1340 for (
const Symbol &sym : CollectCudaSymbols(expr))
1341 if (IsNonAllocatableModuleCUDAManagedSymbol(sym))
1348template <
typename A>
inline int GetNbOfCUDADeviceSymbols(
const A &expr) {
1349 semantics::UnorderedSymbolSet symbols;
1350 for (
const Symbol &sym : CollectCudaSymbols(expr)) {
1351 if (IsCUDADeviceSymbol(sym)) {
1352 symbols.insert(sym);
1355 return symbols.size();
1363template <
typename A>
1364inline int GetNbOfCUDAManagedOrUnifiedSymbols(
const A &expr) {
1365 semantics::UnorderedSymbolSet symbols;
1366 for (
const Symbol &sym : CollectCudaSymbols(expr)) {
1367 if (IsCUDAManagedOrUnifiedSymbol(sym)) {
1368 symbols.insert(sym);
1371 return symbols.size();
1376template <
typename A>
inline bool HasCUDADeviceAttrs(
const A &expr) {
1377 return GetNbOfCUDADeviceSymbols(expr) > 0;
1382template <
typename A,
typename B>
1383inline bool IsCUDADataTransfer(
const A &lhs,
const B &rhs) {
1384 int lhsNbManagedSymbols{GetNbOfCUDAManagedOrUnifiedSymbols(lhs)};
1385 int rhsNbManagedSymbols{GetNbOfCUDAManagedOrUnifiedSymbols(rhs)};
1386 int rhsNbSymbols{GetNbOfCUDADeviceSymbols(rhs)};
1388 if (HasNonAllocatableModuleCUDAManagedSymbols(lhs))
1391 if (lhsNbManagedSymbols >= 1 && lhs.Rank() > 0 && rhsNbSymbols == 0 &&
1392 rhsNbManagedSymbols == 0 && (IsVariable(rhs) || IsConstantExpr(rhs))) {
1400 if ((lhsNbManagedSymbols >= 1 && rhsNbManagedSymbols == rhsNbSymbols) ||
1401 (lhsNbManagedSymbols == 0 && !HasCUDADeviceAttrs(lhs) &&
1402 rhsNbManagedSymbols >= 1 && rhsNbManagedSymbols == rhsNbSymbols) ||
1403 (lhsNbManagedSymbols >= 1 && rhsNbSymbols == 0)) {
1406 return HasCUDADeviceAttrs(lhs) || rhsNbSymbols > 0;
1416namespace operation {
1418enum class Operator {
1450using OperatorSet = common::EnumSet<Operator, 32>;
1452std::string ToString(Operator op);
1454template <
int Kind> Operator OperationCode(
const LogicalOperation<Kind> &op) {
1455 switch (op.logicalOperator) {
1456 case common::LogicalOperator::And:
1457 return Operator::And;
1458 case common::LogicalOperator::Or:
1459 return Operator::Or;
1460 case common::LogicalOperator::Eqv:
1461 return Operator::Eqv;
1462 case common::LogicalOperator::Neqv:
1463 return Operator::Neqv;
1464 case common::LogicalOperator::Not:
1465 return Operator::Not;
1467 return Operator::Unknown;
1470Operator OperationCode(
const Relational<SomeType> &op);
1472template <
typename T> Operator OperationCode(
const Relational<T> &op) {
1474 case common::RelationalOperator::LT:
1475 return Operator::Lt;
1476 case common::RelationalOperator::LE:
1477 return Operator::Le;
1478 case common::RelationalOperator::EQ:
1479 return Operator::Eq;
1480 case common::RelationalOperator::NE:
1481 return Operator::Ne;
1482 case common::RelationalOperator::GE:
1483 return Operator::Ge;
1484 case common::RelationalOperator::GT:
1485 return Operator::Gt;
1487 return Operator::Unknown;
1490template <
typename T> Operator OperationCode(
const Add<T> &op) {
1491 return Operator::Add;
1494template <
typename T> Operator OperationCode(
const Subtract<T> &op) {
1495 return Operator::Sub;
1498template <
typename T> Operator OperationCode(
const Multiply<T> &op) {
1499 return Operator::Mul;
1502template <
typename T> Operator OperationCode(
const Divide<T> &op) {
1503 return Operator::Div;
1506template <
typename T> Operator OperationCode(
const Power<T> &op) {
1507 return Operator::Pow;
1510template <
typename T> Operator OperationCode(
const RealToIntPower<T> &op) {
1511 return Operator::Pow;
1514template <
typename T, common::TypeCategory C>
1515Operator OperationCode(
const Convert<T, C> &op) {
1516 if constexpr (C == T::category) {
1517 return Operator::Resize;
1519 return Operator::Convert;
1523template <
typename T> Operator OperationCode(
const Extremum<T> &op) {
1524 if (op.ordering == Ordering::Greater) {
1525 return Operator::Max;
1527 return Operator::Min;
1531template <
typename T> Operator OperationCode(
const Constant<T> &x) {
1532 return Operator::Constant;
1535template <
typename T> Operator OperationCode(
const Designator<T> &x) {
1536 return Operator::Identity;
1539template <
typename T> Operator OperationCode(
const T &) {
1540 return Operator::Unknown;
1543Operator OperationCode(
const ProcedureDesignator &proc);
1549std::pair<operation::Operator, std::vector<Expr<SomeType>>>
1554std::pair<operation::Operator, std::vector<Expr<SomeType>>>
1561bool IsVarSubexpressionOf(
1569std::optional<Expr<SomeType>> GetConvertInput(
const Expr<SomeType> &x);
1572std::optional<int> CountDerivedTypeAncestors(
const semantics::Scope &);
1576namespace Fortran::semantics {
1584inline bool IsAlternateEntry(
const Symbol *symbol) {
1587 return symbol && GetMainEntry(symbol) != symbol;
1593bool IsVariableName(
const Symbol &);
1594bool IsPureProcedure(
const Symbol &);
1595bool IsPureProcedure(
const Scope &);
1596bool IsExplicitlyImpureProcedure(
const Symbol &);
1597bool IsElementalProcedure(
const Symbol &);
1598bool IsFunction(
const Symbol &);
1599bool IsFunction(
const Scope &);
1600bool IsProcedure(
const Symbol &);
1601bool IsProcedure(
const Scope &);
1602bool IsProcedurePointer(
const Symbol *);
1603bool IsProcedurePointer(
const Symbol &);
1604bool IsObjectPointer(
const Symbol *);
1605bool IsAllocatableOrObjectPointer(
const Symbol *);
1606bool IsAutomatic(
const Symbol &);
1607bool IsSaved(
const Symbol &);
1608bool IsDummy(
const Symbol &);
1610bool IsAssumedRank(
const Symbol &);
1611template <
typename A>
bool IsAssumedRank(
const A &x) {
1612 auto *symbol{UnwrapWholeSymbolDataRef(x)};
1613 return symbol && IsAssumedRank(*symbol);
1616bool IsAssumedShape(
const Symbol &);
1617template <
typename A>
bool IsAssumedShape(
const A &x) {
1618 auto *symbol{UnwrapWholeSymbolDataRef(x)};
1619 return symbol && IsAssumedShape(*symbol);
1622bool IsDeferredShape(
const Symbol &);
1623bool IsFunctionResult(
const Symbol &);
1624bool IsKindTypeParameter(
const Symbol &);
1625bool IsLenTypeParameter(
const Symbol &);
1628bool IsBuiltinDerivedType(
const DerivedTypeSpec *derived,
const char *name);
1629bool IsBuiltinCPtr(
const Symbol &);
1630bool IsFromBuiltinModule(
const Symbol &);
1645inline bool IsAssumedSizeArray(
const Symbol &symbol) {
1647 return (object->isDummy() || symbol.test(Symbol::Flag::CrayPointee)) &&
1648 object->shape().CanBeAssumedSize();
1650 return assoc->IsAssumedSize();
1668const Symbol &ResolveAssociations(
const Symbol &,
bool stopAtTypeGuard =
false);
1669const Symbol &GetAssociationRoot(
const Symbol &,
bool stopAtTypeGuard =
false);
1671const Symbol *FindCommonBlockContaining(
const Symbol &);
1683common::IgnoreTKRSet GetIgnoreTKR(
const Symbol &);
1685std::optional<int> GetDummyArgumentNumber(
const Symbol *);
1687const Symbol *FindAncestorModuleProcedure(
const Symbol *symInSubmodule);
1690const Symbol &GetCrayPointer(
const Symbol &crayPointee);
Definition variable.h:205
Definition variable.h:243
Definition variable.h:357
Definition expression.h:395
Definition constant.h:147
Definition variable.h:381
Definition variable.h:101
Definition expression.h:685
Definition static-data.h:29
Definition variable.h:304
bool HasCUDAImplicitTransfer(const Expr< SomeType > &expr)
Definition tools.cpp:1167
Definition expression.h:296
Definition expression.h:257
Definition expression.h:357
Definition expression.h:211
Definition variable.h:288
Definition expression.h:317
Definition expression.h:379
Definition expression.h:310
Definition expression.h:247
Definition expression.h:272
Definition expression.h:229
Definition expression.h:303
Definition characteristics.h:367