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"
40struct IsVariableHelper
41 :
public AnyTraverse<IsVariableHelper, std::optional<bool>> {
42 using Result = std::optional<bool>;
43 using Base = AnyTraverse<IsVariableHelper, Result>;
44 IsVariableHelper() : Base{*
this} {}
45 using Base::operator();
47 Result operator()(
const Symbol &)
const;
48 Result operator()(
const Component &)
const;
49 Result operator()(
const ArrayRef &)
const;
50 Result operator()(
const Substring &)
const;
51 Result operator()(
const CoarrayRef &)
const {
return true; }
52 Result operator()(
const ComplexPart &)
const {
return true; }
57 template <
typename T> Result operator()(
const Expr<T> &x)
const {
58 if constexpr (common::HasMember<T, AllIntrinsicTypes> ||
59 std::is_same_v<T, SomeDerived>) {
63 if (
auto known{(*this)(x.u)}) {
68 }
else if constexpr (std::is_same_v<T, SomeType>) {
69 if (std::holds_alternative<ProcedureDesignator>(x.u) ||
70 std::holds_alternative<ProcedureRef>(x.u)) {
81template <
typename A>
bool IsVariable(
const A &x) {
92static inline int GetCorank(
const Symbol &symbol) {
return symbol.Corank(); }
93template <
typename A>
int GetCorank(
const A &) {
return 0; }
94template <
typename T>
int GetCorank(
const Designator<T> &designator) {
95 return designator.Corank();
97template <
typename T>
int GetCorank(
const Expr<T> &expr) {
98 return common::visit([](
const auto &x) {
return GetCorank(x); }, expr.u);
100template <
typename A>
int GetCorank(
const std::optional<A> &x) {
101 return x ? GetCorank(*x) : 0;
103template <
typename A>
int GetCorank(
const A *x) {
104 return x ? GetCorank(*x) : 0;
108template <
typename A>
bool IsCoarray(
const A &x) {
return GetCorank(x) > 0; }
113template <
typename A> common::IfNoLvalue<Expr<ResultType<A>>, A> AsExpr(A &&x) {
117template <typename T, typename U = typename Relational<T>::Result>
126 static_assert(IsSpecificIntrinsicType<T>);
130template <TypeCategory CATEGORY>
136common::IfNoLvalue<Expr<SomeType>, A> AsGenericExpr(A &&x) {
137 if constexpr (common::HasMember<A, TypelessExpression>) {
148std::optional<Expr<SomeType>> AsGenericExpr(
DataRef &&);
149std::optional<Expr<SomeType>> AsGenericExpr(
const Symbol &);
153std::optional<Expr<SomeType>> AsGenericExpr(std::optional<A> &&x) {
155 return AsGenericExpr(std::move(*x));
162common::IfNoLvalue<Expr<SomeKind<ResultType<A>::category>>, A> AsCategoryExpr(
169template <
typename A>
constexpr bool IsNumericCategoryExpr() {
170 if constexpr (common::HasMember<A, TypelessExpression>) {
173 return common::HasMember<ResultType<A>, NumericCategoryTypes>;
180template <
typename A,
typename B>
181auto UnwrapExpr(B &x) -> common::Constify<A, B> * {
182 using Ty = std::decay_t<B>;
183 if constexpr (std::is_same_v<A, Ty>) {
185 }
else if constexpr (std::is_same_v<Ty, ActualArgument>) {
186 if (
auto *expr{x.UnwrapExpr()}) {
187 return UnwrapExpr<A>(*expr);
189 }
else if constexpr (std::is_same_v<Ty, Expr<SomeType>>) {
190 return common::visit([](
auto &x) {
return UnwrapExpr<A>(x); }, x.u);
191 }
else if constexpr (!common::HasMember<A, TypelessExpression>) {
192 if constexpr (std::is_same_v<Ty, Expr<ResultType<A>>> ||
193 std::is_same_v<Ty, Expr<SomeKind<ResultType<A>::category>>>) {
194 return common::visit([](
auto &x) {
return UnwrapExpr<A>(x); }, x.u);
200template <
typename A,
typename B>
201const A *UnwrapExpr(
const std::optional<B> &x) {
203 return UnwrapExpr<A>(*x);
209template <
typename A,
typename B> A *UnwrapExpr(std::optional<B> &x) {
211 return UnwrapExpr<A>(*x);
217template <
typename A,
typename B>
const A *UnwrapExpr(
const B *x) {
219 return UnwrapExpr<A>(*x);
225template <
typename A,
typename B> A *UnwrapExpr(B *x) {
227 return UnwrapExpr<A>(*x);
236template <
typename A,
typename B>
237auto UnwrapConvertedExpr(B &x) -> common::Constify<A, B> * {
238 using Ty = std::decay_t<B>;
239 if constexpr (std::is_same_v<A, Ty>) {
241 }
else if constexpr (std::is_same_v<Ty, ActualArgument>) {
242 if (
auto *expr{x.UnwrapExpr()}) {
243 return UnwrapConvertedExpr<A>(*expr);
245 }
else if constexpr (std::is_same_v<Ty, Expr<SomeType>>) {
246 return common::visit(
247 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.u);
249 using DesiredResult = ResultType<A>;
250 if constexpr (std::is_same_v<Ty, Expr<DesiredResult>> ||
251 std::is_same_v<Ty, Expr<SomeKind<DesiredResult::category>>>) {
252 return common::visit(
253 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.u);
255 using ThisResult = ResultType<B>;
256 if constexpr (std::is_same_v<Ty, Expr<ThisResult>>) {
257 return common::visit(
258 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.u);
259 }
else if constexpr (std::is_same_v<Ty, Parentheses<ThisResult>> ||
260 std::is_same_v<Ty, Convert<ThisResult, DesiredResult::category>>) {
261 return common::visit(
262 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.left().u);
271template <
typename A>
inline const ProcedureRef *UnwrapProcedureRef(
const A &) {
288 return common::visit(
289 [](
const auto &x) {
return UnwrapProcedureRef(x); }, expr.u);
295template <
typename A>
const Symbol *ExtractBareLenParameter(
const A &expr) {
296 if (
const auto *typeParam{
297 UnwrapConvertedExpr<evaluate::TypeParamInquiry>(expr)}) {
298 if (!typeParam->base()) {
299 const Symbol &symbol{typeParam->parameter()};
300 if (
const auto *tpd{symbol.detailsIf<semantics::TypeParamDetails>()}) {
301 if (tpd->attr() == common::TypeParamAttr::Len) {
315common::IfNoLvalue<std::optional<DataRef>, A> ExtractDataRef(
316 const A &x,
bool intoSubstring,
bool intoComplexPart) {
317 if constexpr (common::HasMember<
decltype(x),
decltype(DataRef::u)>) {
324std::optional<DataRef> ExtractSubstringBase(
const Substring &);
326inline std::optional<DataRef> ExtractDataRef(
const Substring &x,
327 bool intoSubstring =
false,
bool intoComplexPart =
false) {
329 return ExtractSubstringBase(x);
334inline std::optional<DataRef> ExtractDataRef(
const ComplexPart &x,
335 bool intoSubstring =
false,
bool intoComplexPart =
false) {
336 if (intoComplexPart) {
344 bool intoSubstring =
false,
bool intoComplexPart =
false) {
345 return common::visit(
346 [=](
const auto &x) -> std::optional<DataRef> {
347 return ExtractDataRef(x, intoSubstring, intoComplexPart);
352std::optional<DataRef> ExtractDataRef(
const Expr<T> &expr,
353 bool intoSubstring =
false,
bool intoComplexPart =
false) {
354 return common::visit(
356 return ExtractDataRef(x, intoSubstring, intoComplexPart);
361std::optional<DataRef> ExtractDataRef(
const std::optional<A> &x,
362 bool intoSubstring =
false,
bool intoComplexPart =
false) {
364 return ExtractDataRef(*x, intoSubstring, intoComplexPart);
370std::optional<DataRef> ExtractDataRef(
371 A *p,
bool intoSubstring =
false,
bool intoComplexPart =
false) {
373 return ExtractDataRef(std::as_const(*p), intoSubstring, intoComplexPart);
379 bool intoSubstring =
false,
bool intoComplexPart =
false);
383const Symbol *IsArrayElement(
const Expr<T> &expr,
bool intoSubstring =
true,
384 bool skipComponents =
false) {
385 if (
auto dataRef{ExtractDataRef(expr, intoSubstring)}) {
386 for (
const DataRef *ref{&*dataRef}; ref;) {
387 if (
const Component * component{std::get_if<Component>(&ref->u)}) {
388 ref = skipComponents ? &component->base() :
nullptr;
389 }
else if (
const auto *coarrayRef{std::get_if<CoarrayRef>(&ref->u)}) {
390 ref = &coarrayRef->base();
391 }
else if (
const auto *arrayRef{std::get_if<ArrayRef>(&ref->u)}) {
392 return &arrayRef->GetLastSymbol();
402bool isStructureComponent(
const Fortran::evaluate::Expr<T> &expr) {
403 if (
auto dataRef{ExtractDataRef(expr,
false)}) {
404 const Fortran::evaluate::DataRef *ref{&*dataRef};
405 return std::holds_alternative<Fortran::evaluate::Component>(ref->u);
412std::optional<NamedEntity> ExtractNamedEntity(
const A &x) {
413 if (
auto dataRef{ExtractDataRef(x)}) {
414 return common::visit(
416 [](SymbolRef &&symbol) -> std::optional<NamedEntity> {
419 [](
Component &&component) -> std::optional<NamedEntity> {
422 [](
auto &&) {
return std::optional<NamedEntity>{}; },
424 std::move(dataRef->u));
431 template <
typename A> std::optional<CoarrayRef> operator()(
const A &)
const {
434 std::optional<CoarrayRef> operator()(
const CoarrayRef &x)
const {
return x; }
435 template <
typename A>
436 std::optional<CoarrayRef> operator()(
const Expr<A> &expr)
const {
437 return common::visit(*
this, expr.u);
439 std::optional<CoarrayRef> operator()(
const DataRef &dataRef)
const {
440 return common::visit(*
this, dataRef.u);
442 std::optional<CoarrayRef> operator()(
const NamedEntity &named)
const {
443 if (
const Component * component{named.UnwrapComponent()}) {
444 return (*
this)(*component);
450 if (
const auto *component{
451 std::get_if<common::CopyableIndirection<Component>>(&des.u)}) {
452 return (*
this)(component->value());
457 std::optional<CoarrayRef> operator()(
const Component &component)
const {
458 return (*
this)(component.base());
460 std::optional<CoarrayRef> operator()(
const ArrayRef &arrayRef)
const {
461 return (*
this)(arrayRef.base());
465static inline std::optional<CoarrayRef> ExtractCoarrayRef(
const DataRef &x) {
469template <
typename A> std::optional<CoarrayRef> ExtractCoarrayRef(
const A &x) {
470 if (
auto dataRef{ExtractDataRef(x,
true)}) {
471 return ExtractCoarrayRef(*dataRef);
478 template <
typename T>
static std::optional<TARGET> visit(T &&) {
482 static std::optional<TARGET> visit(
const TARGET &t) {
return t; }
484 template <
typename T>
486 return common::visit([](
auto &&s) {
return visit(s); }, e.u);
489 template <
typename T>
static std::optional<TARGET> visit(
const Expr<T> &e) {
490 return common::visit([](
auto &&s) {
return visit(s); }, e.u);
494template <
typename A> std::optional<Substring> ExtractSubstring(
const A &x) {
495 return ExtractFromExprDesignatorHelper<Substring>::visit(x);
499std::optional<ComplexPart> ExtractComplexPart(
const A &x) {
500 return ExtractFromExprDesignatorHelper<ComplexPart>::visit(x);
505const Symbol *UnwrapWholeSymbolDataRef(
const DataRef &);
506const Symbol *UnwrapWholeSymbolDataRef(
const std::optional<DataRef> &);
507template <
typename A>
const Symbol *UnwrapWholeSymbolDataRef(
const A &x) {
508 return UnwrapWholeSymbolDataRef(ExtractDataRef(x));
513const Symbol *UnwrapWholeSymbolOrComponentDataRef(
const DataRef &);
514const Symbol *UnwrapWholeSymbolOrComponentDataRef(
515 const std::optional<DataRef> &);
517const Symbol *UnwrapWholeSymbolOrComponentDataRef(
const A &x) {
518 return UnwrapWholeSymbolOrComponentDataRef(ExtractDataRef(x));
524const Symbol *UnwrapWholeSymbolOrComponentOrCoarrayRef(
const DataRef &);
525const Symbol *UnwrapWholeSymbolOrComponentOrCoarrayRef(
526 const std::optional<DataRef> &);
528const Symbol *UnwrapWholeSymbolOrComponentOrCoarrayRef(
const A &x) {
529 return UnwrapWholeSymbolOrComponentOrCoarrayRef(ExtractDataRef(x));
533template <
typename A>
const Symbol *GetFirstSymbol(
const A &x) {
534 if (
auto dataRef{ExtractDataRef(x,
true)}) {
535 return &dataRef->GetFirstSymbol();
542const Symbol *GetLastPointerSymbol(
const evaluate::DataRef &);
548template <
typename TO, TypeCategory FROMCAT>
550 static_assert(IsSpecificIntrinsicType<TO>);
551 if constexpr (FROMCAT == TO::category) {
552 if (
auto *already{std::get_if<Expr<TO>>(&x.u)}) {
553 return std::move(*already);
557 }
else if constexpr (TO::category == TypeCategory::Complex) {
558 using Part =
typename TO::Part;
562 }
else if constexpr (FROMCAT == TypeCategory::Complex) {
564 return common::visit(
566 using ZType = ResultType<
decltype(z)>;
567 using Part =
typename ZType::Part;
577template <
typename TO, TypeCategory FROMCAT,
int FROMKIND>
582template <
typename TO>
Expr<TO> ConvertToType(BOZLiteralConstant &&x) {
583 static_assert(IsSpecificIntrinsicType<TO>);
584 if constexpr (TO::category == TypeCategory::Integer ||
585 TO::category == TypeCategory::Unsigned) {
587 Constant<TO>{Scalar<TO>::ConvertUnsigned(std::move(x)).value}};
589 static_assert(TO::category == TypeCategory::Real);
590 using Word =
typename Scalar<TO>::Word;
592 Constant<TO>{Scalar<TO>{Word::ConvertUnsigned(std::move(x)).value}}};
596template <
typename T>
bool IsBOZLiteral(
const Expr<T> &expr) {
597 return std::holds_alternative<BOZLiteralConstant>(expr.u);
601std::optional<Expr<SomeType>> ConvertToType(
603std::optional<Expr<SomeType>> ConvertToType(
606std::optional<Expr<SomeType>> ConvertToType(
610template <TypeCategory TC,
int TK,
typename FROM>
611common::IfNoLvalue<Expr<Type<TC, TK>>, FROM> ConvertTo(
613 return ConvertToType<Type<TC, TK>>(std::move(x));
616template <TypeCategory TC,
typename FROM>
617common::IfNoLvalue<Expr<SomeKind<TC>>, FROM> ConvertTo(
619 return common::visit(
620 [&](
const auto &toKindExpr) {
621 using KindExpr = std::decay_t<
decltype(toKindExpr)>;
622 return AsCategoryExpr(
623 ConvertToType<ResultType<KindExpr>>(std::move(from)));
628template <
typename FROM>
629common::IfNoLvalue<Expr<SomeType>, FROM> ConvertTo(
631 return common::visit(
632 [&](
const auto &toCatExpr) {
633 return AsGenericExpr(ConvertTo(toCatExpr, std::move(from)));
640template <TypeCategory TOCAT,
typename VALUE>
struct ConvertToKindHelper {
641 using Result = std::optional<Expr<SomeKind<TOCAT>>>;
642 using Types = CategoryTypes<TOCAT>;
643 ConvertToKindHelper(
int k, VALUE &&x) : kind{k}, value{std::move(x)} {}
644 template <
typename T> Result Test() {
645 if (kind == T::kind) {
646 return std::make_optional(
647 AsCategoryExpr(ConvertToType<T>(std::move(value))));
655template <TypeCategory TOCAT,
typename VALUE>
656common::IfNoLvalue<Expr<SomeKind<TOCAT>>, VALUE> ConvertToKind(
657 int kind, VALUE &&x) {
658 auto result{common::SearchTypes(
660 CHECK(result.has_value());
667template <
typename A,
int N = 2>
using SameExprs = std::array<Expr<A>, N>;
669 template <
typename A>
using SameExprs = std::array<Expr<A>, N>;
671template <TypeCategory CAT,
int N = 2>
673 common::MapTemplate<SameKindExprsHelper<N>::template SameExprs,
679template <TypeCategory CAT>
680SameKindExprs<CAT, 2> AsSameKindExprs(
682 return common::visit(
683 [&](
auto &&kx,
auto &&ky) -> SameKindExprs<CAT, 2> {
684 using XTy = ResultType<
decltype(kx)>;
685 using YTy = ResultType<
decltype(ky)>;
686 if constexpr (std::is_same_v<XTy, YTy>) {
687 return {SameExprs<XTy>{std::move(kx), std::move(ky)}};
688 }
else if constexpr (XTy::kind < YTy::kind) {
689 return {SameExprs<YTy>{ConvertTo(ky, std::move(kx)), std::move(ky)}};
691 return {SameExprs<XTy>{std::move(kx), ConvertTo(kx, std::move(ky))}};
693#if !__clang__ && 100 * __GNUC__ + __GNUC_MINOR__ == 801
696 CHECK(!
"can't happen");
697 return {SameExprs<XTy>{std::move(kx), std::move(kx)}};
700 std::move(x.u), std::move(y.u));
706using ConvertRealOperandsResult =
707 std::optional<SameKindExprs<TypeCategory::Real, 2>>;
708ConvertRealOperandsResult ConvertRealOperands(parser::ContextualMessages &,
715std::optional<Expr<SomeComplex>> ConstructComplex(parser::ContextualMessages &,
717std::optional<Expr<SomeComplex>> ConstructComplex(parser::ContextualMessages &,
719 int defaultRealKind);
721template <
typename A>
Expr<TypeOf<A>> ScalarConstantToExpr(
const A &x) {
722 using Ty = TypeOf<A>;
724 std::is_same_v<Scalar<Ty>, std::decay_t<A>>,
"TypeOf<> is broken");
730template <
template <
typename>
class OPR,
typename SPECIFIC>
732 static_assert(IsSpecificIntrinsicType<SPECIFIC>);
733 return AsExpr(OPR<SPECIFIC>{std::move(x), std::move(y)});
740template <
template <
typename>
class OPR, TypeCategory CAT>
743 return common::visit(
745 using Ty = ResultType<
decltype(xy[0])>;
746 return AsCategoryExpr(
747 Combine<OPR, Ty>(std::move(xy[0]), std::move(xy[1])));
749 AsSameKindExprs(std::move(x), std::move(y)));
757template <
template <
typename>
class OPR>
758std::optional<Expr<SomeType>> NumericOperation(parser::ContextualMessages &,
761extern template std::optional<Expr<SomeType>> NumericOperation<Power>(
763 int defaultRealKind);
764extern template std::optional<Expr<SomeType>> NumericOperation<Multiply>(
766 int defaultRealKind);
767extern template std::optional<Expr<SomeType>> NumericOperation<Divide>(
769 int defaultRealKind);
770extern template std::optional<Expr<SomeType>> NumericOperation<Add>(
772 int defaultRealKind);
773extern template std::optional<Expr<SomeType>> NumericOperation<Subtract>(
775 int defaultRealKind);
777std::optional<Expr<SomeType>> Negation(
782std::optional<Expr<LogicalResult>> Relate(parser::ContextualMessages &,
790 static_assert(IsSpecificIntrinsicType<T>);
798 return AsExpr(
Not<K>{std::move(x)});
818template <TypeCategory C,
int K>
823template <TypeCategory C,
int K>
825 return AsExpr(Combine<
Add,
Type<C, K>>(std::move(x), std::move(y)));
828template <TypeCategory C,
int K>
833template <TypeCategory C,
int K>
838template <TypeCategory C,
int K>
844 return common::visit(
848template <TypeCategory CAT>
851 return PromoteAndCombine<Add, CAT>(std::move(x), std::move(y));
854template <TypeCategory CAT>
857 return PromoteAndCombine<Subtract, CAT>(std::move(x), std::move(y));
860template <TypeCategory CAT>
863 return PromoteAndCombine<Multiply, CAT>(std::move(x), std::move(y));
866template <TypeCategory CAT>
869 return PromoteAndCombine<Divide, CAT>(std::move(x), std::move(y));
875template <TypeCategory CAT,
template <
typename>
class TEMPLATE,
typename VALUE>
876struct TypeKindVisitor {
877 using Result = std::optional<Expr<SomeType>>;
878 using Types = CategoryTypes<CAT>;
880 TypeKindVisitor(
int k, VALUE &&x) : kind{k}, value{std::move(x)} {}
881 TypeKindVisitor(
int k,
const VALUE &x) : kind{k}, value{x} {}
883 template <
typename T> Result Test() {
884 if (kind == T::kind) {
885 return AsGenericExpr(TEMPLATE<T>{std::move(value)});
897template <TypeCategory CATEGORY,
template <
typename>
typename WRAPPER,
899common::IfNoLvalue<std::optional<Expr<SomeType>>, WRAPPED> WrapperHelper(
900 int kind, WRAPPED &&x) {
901 return common::SearchTypes(
905template <
template <
typename>
typename WRAPPER,
typename WRAPPED>
906common::IfNoLvalue<std::optional<Expr<SomeType>>, WRAPPED> TypedWrapper(
907 const DynamicType &dyType, WRAPPED &&x) {
908 switch (dyType.category()) {
909 SWITCH_COVERS_ALL_CASES
910 case TypeCategory::Integer:
911 return WrapperHelper<TypeCategory::Integer, WRAPPER, WRAPPED>(
912 dyType.kind(), std::move(x));
913 case TypeCategory::Unsigned:
914 return WrapperHelper<TypeCategory::Unsigned, WRAPPER, WRAPPED>(
915 dyType.kind(), std::move(x));
916 case TypeCategory::Real:
917 return WrapperHelper<TypeCategory::Real, WRAPPER, WRAPPED>(
918 dyType.kind(), std::move(x));
919 case TypeCategory::Complex:
920 return WrapperHelper<TypeCategory::Complex, WRAPPER, WRAPPED>(
921 dyType.kind(), std::move(x));
922 case TypeCategory::Character:
923 return WrapperHelper<TypeCategory::Character, WRAPPER, WRAPPED>(
924 dyType.kind(), std::move(x));
925 case TypeCategory::Logical:
926 return WrapperHelper<TypeCategory::Logical, WRAPPER, WRAPPED>(
927 dyType.kind(), std::move(x));
928 case TypeCategory::Derived:
929 return AsGenericExpr(Expr<SomeDerived>{WRAPPER<SomeDerived>{std::move(x)}});
937struct GetLastSymbolHelper
938 :
public AnyTraverse<GetLastSymbolHelper, std::optional<const Symbol *>> {
939 using Result = std::optional<const Symbol *>;
940 using Base = AnyTraverse<GetLastSymbolHelper, Result>;
941 GetLastSymbolHelper() : Base{*
this} {}
942 using Base::operator();
943 Result operator()(
const Symbol &x)
const {
return &x; }
944 Result operator()(
const Component &x)
const {
return &x.GetLastSymbol(); }
945 Result operator()(
const NamedEntity &x)
const {
return &x.GetLastSymbol(); }
947 return x.GetSymbol();
949 template <
typename T> Result operator()(
const Expr<T> &x)
const {
950 if constexpr (common::HasMember<T, AllIntrinsicTypes> ||
951 std::is_same_v<T, SomeDerived>) {
952 if (
const auto *designator{std::get_if<Designator<T>>(&x.u)}) {
953 if (
auto known{(*this)(*designator)}) {
964template <
typename A>
const Symbol *GetLastSymbol(
const A &x) {
975template <
typename A> semantics::Attrs GetAttrs(
const A &x) {
976 if (
const Symbol * symbol{GetLastSymbol(x)}) {
977 return symbol->attrs();
984inline semantics::Attrs GetAttrs<Expr<SomeType>>(
const Expr<SomeType> &x) {
986 if (
const auto *procRef{UnwrapProcedureRef(x)}) {
987 if (
const Symbol * interface{procRef->proc().GetInterfaceSymbol()}) {
988 if (
const auto *details{
989 interface->detailsIf<semantics::SubprogramDetails>()}) {
990 if (details->isFunction() &&
991 details->result().attrs().test(semantics::Attr::POINTER)) {
993 return details->result().attrs();
999 if (
const Symbol * symbol{GetLastSymbol(x)}) {
1000 return symbol->attrs();
1006template <
typename A> semantics::Attrs GetAttrs(
const std::optional<A> &x) {
1008 return GetAttrs(*x);
1015template <
typename A> std::optional<BaseObject> GetBaseObject(
const A &) {
1016 return std::nullopt;
1018template <
typename T>
1019std::optional<BaseObject> GetBaseObject(
const Designator<T> &x) {
1020 return x.GetBaseObject();
1022template <
typename T>
1023std::optional<BaseObject> GetBaseObject(
const Expr<T> &x) {
1024 return common::visit([](
const auto &y) {
return GetBaseObject(y); }, x.u);
1026template <
typename A>
1027std::optional<BaseObject> GetBaseObject(
const std::optional<A> &x) {
1029 return GetBaseObject(*x);
1031 return std::nullopt;
1063struct GetSymbolVectorHelper
1064 :
public Traverse<GetSymbolVectorHelper, SymbolVector> {
1065 using Result = SymbolVector;
1066 using Base = Traverse<GetSymbolVectorHelper, Result>;
1067 using Base::operator();
1068 GetSymbolVectorHelper() : Base{*
this} {}
1069 Result Default() {
return {}; }
1070 Result Combine(Result &&a, Result &&b) {
1071 a.insert(a.end(), b.begin(), b.end());
1072 return std::move(a);
1074 Result operator()(
const Symbol &)
const;
1075 Result operator()(
const Component &)
const;
1076 Result operator()(
const ArrayRef &)
const;
1079template <
typename A> SymbolVector GetSymbolVector(
const A &x) {
1085const Expr<SomeType> *GetVariableSelector(
const Symbol &);
1090const Symbol *GetLastTarget(
const SymbolVector &);
1093template <
typename A> semantics::UnorderedSymbolSet CollectSymbols(
const A &);
1094extern template semantics::UnorderedSymbolSet CollectSymbols(
1095 const Expr<SomeType> &);
1096extern template semantics::UnorderedSymbolSet CollectSymbols(
1097 const Expr<SomeInteger> &);
1098extern template semantics::UnorderedSymbolSet CollectSymbols(
1099 const Expr<SubscriptInteger> &);
1100extern template semantics::UnorderedSymbolSet CollectSymbols(
1101 const ProcedureDesignator &);
1102extern template semantics::UnorderedSymbolSet CollectSymbols(
1103 const Assignment &);
1106template <
typename A>
1107semantics::UnorderedSymbolSet CollectCudaSymbols(
const A &);
1108extern template semantics::UnorderedSymbolSet CollectCudaSymbols(
1109 const Expr<SomeType> &);
1110extern template semantics::UnorderedSymbolSet CollectCudaSymbols(
1111 const Expr<SomeInteger> &);
1112extern template semantics::UnorderedSymbolSet CollectCudaSymbols(
1113 const Expr<SubscriptInteger> &);
1116bool HasVectorSubscript(
const Expr<SomeType> &);
1117bool HasVectorSubscript(
const ActualArgument &);
1120bool IsArraySection(
const Expr<SomeType> &expr);
1123bool HasConstant(
const Expr<SomeType> &);
1126bool HasStructureComponent(
const Expr<SomeType> &expr);
1129bool HasProcedureRef(
const Expr<SomeType> &expr);
1132bool HasVolatileOrAsynchronousSymbol(
const Expr<SomeType> &expr);
1136bool CanBuildSplitSumExpressionTree(
1137 FoldingContext &,
const Expr<SomeType> &lhs,
const Expr<SomeType> &rhs);
1141std::optional<Expr<SomeType>> TryBuildSplitSumExpressionTrees(
1142 const Expr<SomeType> &expr);
1146parser::Message *AttachDeclaration(parser::Message &,
const Symbol &);
1147parser::Message *AttachDeclaration(parser::Message *,
const Symbol &);
1148template <
typename MESSAGES,
typename... A>
1149parser::Message *SayWithDeclaration(
1150 MESSAGES &messages,
const Symbol &symbol, A &&...x) {
1151 return AttachDeclaration(messages.Say(std::forward<A>(x)...), symbol);
1153template <
typename... A>
1155 const Symbol &symbol, common::LanguageFeature feature, A &&...x) {
1156 return AttachDeclaration(
1157 context.Warn(feature, std::forward<A>(x)...), symbol);
1159template <
typename... A>
1161 const Symbol &symbol, common::UsageWarning warning, A &&...x) {
1162 return AttachDeclaration(
1163 context.Warn(warning, std::forward<A>(x)...), symbol);
1168std::optional<std::string> FindImpureCall(
1170std::optional<std::string> FindImpureCall(
1176class UnsafeToCopyVisitor :
public AnyTraverse<UnsafeToCopyVisitor> {
1178 using Base = AnyTraverse<UnsafeToCopyVisitor>;
1179 using Base::operator();
1180 explicit UnsafeToCopyVisitor(
bool admitPureCall)
1181 : Base{*
this}, admitPureCall_{admitPureCall} {}
1182 template <
typename T>
bool operator()(
const FunctionRef<T> &procRef) {
1183 return !admitPureCall_ || !procRef.proc().IsPure();
1185 bool operator()(
const CoarrayRef &) {
return true; }
1188 bool admitPureCall_{
false};
1191template <
typename A>
1192bool IsSafelyCopyable(
const A &x,
bool admitPureCall =
false) {
1199template <
typename T>
1200bool IsExpandableScalar(
const Expr<T> &expr, FoldingContext &context,
1201 const Shape &shape,
bool admitPureCall =
false) {
1202 if (IsSafelyCopyable(expr, admitPureCall)) {
1205 auto extents{AsConstantExtents(context, shape)};
1206 return extents && !HasNegativeExtent(*extents) && GetSize(*extents) == 1;
1213std::optional<parser::MessageFixedText> CheckProcCompatibility(
bool isCall,
1214 const std::optional<characteristics::Procedure> &lhsProcedure,
1217 std::optional<std::string> &warning,
bool ignoreImplicitVsExplicit);
1220class ScalarConstantExpander {
1222 explicit ScalarConstantExpander(ConstantSubscripts &&extents)
1223 : extents_{std::move(extents)} {}
1224 ScalarConstantExpander(
1225 ConstantSubscripts &&extents, std::optional<ConstantSubscripts> &&lbounds)
1226 : extents_{std::move(extents)}, lbounds_{std::move(lbounds)} {}
1227 ScalarConstantExpander(
1228 ConstantSubscripts &&extents, ConstantSubscripts &&lbounds)
1229 : extents_{std::move(extents)}, lbounds_{std::move(lbounds)} {}
1231 template <
typename A> A Expand(A &&x)
const {
1232 return std::move(x);
1235 auto expanded{x.Reshape(std::move(extents_))};
1237 expanded.set_lbounds(std::move(*lbounds_));
1242 return Expand(std::move(x.left()));
1245 return common::visit(
1246 [&](
auto &&x) {
return Expr<T>{Expand(std::move(x))}; },
1251 ConstantSubscripts extents_;
1252 std::optional<ConstantSubscripts> lbounds_;
1258template <
typename T>
1259Constant<T> PackageConstant(std::vector<Scalar<T>> &&elements,
1260 const Constant<T> &reference,
const ConstantSubscripts &shape) {
1261 if constexpr (T::category == TypeCategory::Character) {
1263 reference.LEN(), std::move(elements), ConstantSubscripts{shape}};
1264 }
else if constexpr (T::category == TypeCategory::Derived) {
1265 return Constant<T>{reference.GetType().GetDerivedTypeSpec(),
1266 std::move(elements), ConstantSubscripts{shape}};
1268 return Constant<T>{std::move(elements), ConstantSubscripts{shape}};
1274std::optional<Expr<SomeType>> DataConstantConversionExtension(
1279std::optional<Expr<SomeType>> HollerithToBOZ(
1283class ArrayConstantBoundChanger {
1285 explicit ArrayConstantBoundChanger(ConstantSubscripts &&lbounds)
1286 : lbounds_{std::move(lbounds)} {}
1288 template <
typename A> A ChangeLbounds(A &&x)
const {
1289 return std::move(x);
1292 x.set_lbounds(std::move(lbounds_));
1293 return std::move(x);
1296 return ChangeLbounds(
1297 std::move(x.left()));
1300 return common::visit(
1301 [&](
auto &&x) {
return Expr<T>{ChangeLbounds(std::move(x))}; },
1306 ConstantSubscripts &&lbounds_;
1312template <
typename T>
1313std::optional<bool> AreEquivalentInInterface(
const Expr<T> &,
const Expr<T> &);
1314extern template std::optional<bool> AreEquivalentInInterface<SubscriptInteger>(
1316extern template std::optional<bool> AreEquivalentInInterface<SomeInteger>(
1320 const std::optional<ActualArgument> &,
const std::string &procName,
1321 const std::string &argName);
1328std::vector<SymbolVector> GetSymbolVectors(
const Expr<SomeType> &expr);
1330bool IsCUDADeviceSymbol(
const Symbol &sym);
1331bool IsCUDADeviceOnlySymbol(
const Symbol &sym);
1335bool IsCUDADataAttrSymbol(
const Symbol &sym, common::CUDADataAttr attr);
1337inline bool IsCUDAManagedOrUnifiedSymbol(
const Symbol &sym) {
1338 return IsCUDADataAttrSymbol(sym, common::CUDADataAttr::Managed) ||
1339 IsCUDADataAttrSymbol(sym, common::CUDADataAttr::Unified);
1342inline bool IsCUDAManagedSymbol(
const Symbol &sym) {
1343 return IsCUDADataAttrSymbol(sym, common::CUDADataAttr::Managed);
1346inline bool IsCUDAUnifiedSymbol(
const Symbol &sym) {
1347 return IsCUDADataAttrSymbol(sym, common::CUDADataAttr::Unified);
1350inline bool HasCUDADataAttr(
const Symbol &sym) {
1351 const auto *details{
1352 sym.GetUltimate().detailsIf<semantics::ObjectEntityDetails>()};
1353 return details && details->cudaDataAttr().has_value();
1358semantics::UnorderedSymbolSet ExpandCudaAssociations(
1359 semantics::UnorderedSymbolSet &&symbols);
1366template <
typename A>
1367semantics::UnorderedSymbolSet CollectEffectiveCudaSymbols(
const A &expr) {
1370 semantics::UnorderedSymbolSet result{
1371 ExpandCudaAssociations(CollectCudaSymbols(expr))};
1372 SymbolVector symbols{GetSymbolVector(expr)};
1375 std::reverse(symbols.begin(), symbols.end());
1377 for (
const Symbol &sym : symbols) {
1378 bool isComponent{sym.owner().IsDerivedType()};
1381 }
else if (isComponent && HasCUDADataAttr(sym)) {
1392inline int CountCUDAManagedSymbols(
1393 const semantics::UnorderedSymbolSet &symbols) {
1395 for (
const Symbol &sym : symbols) {
1396 if (IsCUDAManagedSymbol(sym)) {
1405inline int CountCUDANonUnifiedSymbols(
1406 const semantics::UnorderedSymbolSet &symbols) {
1408 for (
const Symbol &sym : symbols) {
1409 if (IsCUDADeviceSymbol(sym) && !IsCUDAUnifiedSymbol(sym)) {
1421inline bool IsNonAllocatableModuleCUDAManagedSymbol(
const Symbol &sym) {
1422 const Symbol &ultimate = sym.GetUltimate();
1423 if (!IsCUDAManagedOrUnifiedSymbol(ultimate))
1425 if (ultimate.attrs().test(semantics::Attr::ALLOCATABLE))
1427 return ultimate.owner().IsModule();
1430template <
typename A>
1431inline bool HasNonAllocatableModuleCUDAManagedSymbols(
const A &expr) {
1432 for (
const Symbol &sym : CollectCudaSymbols(expr))
1433 if (IsNonAllocatableModuleCUDAManagedSymbol(sym))
1440template <
typename A>
inline int GetNbOfCUDADeviceSymbols(
const A &expr) {
1441 semantics::UnorderedSymbolSet symbols;
1442 for (
const Symbol &sym : CollectCudaSymbols(expr)) {
1443 if (IsCUDADeviceSymbol(sym)) {
1444 symbols.insert(sym);
1447 return symbols.size();
1456int GetNbOfUniqueCUDAManagedOrUnifiedSymbols(
const Expr<SomeType> &expr);
1460template <
typename A>
1461inline int GetNbOfCUDAManagedOrUnifiedSymbols(
const A &expr) {
1462 semantics::UnorderedSymbolSet symbols;
1463 for (
const Symbol &sym : CollectCudaSymbols(expr)) {
1464 if (IsCUDAManagedOrUnifiedSymbol(sym)) {
1465 symbols.insert(sym);
1468 return symbols.size();
1473template <
typename A>
inline bool HasCUDADeviceAttrs(
const A &expr) {
1474 return GetNbOfCUDADeviceSymbols(expr) > 0;
1481template <
typename A>
inline bool IsWholeManagedArray(
const A &expr) {
1482 const Symbol *sym{UnwrapWholeSymbolOrComponentDataRef(expr)};
1483 return expr.Rank() > 0 && sym && IsCUDAManagedSymbol(*sym);
1506template <
typename A,
typename B>
1507inline bool IsCUDADataTransfer(
const A &lhs,
const B &rhs) {
1508 semantics::UnorderedSymbolSet lhsSymbols{CollectEffectiveCudaSymbols(lhs)};
1509 semantics::UnorderedSymbolSet rhsSymbols{CollectEffectiveCudaSymbols(rhs)};
1512 bool lhsHasManaged{CountCUDAManagedSymbols(lhsSymbols) > 0};
1513 bool lhsIsHost{CountCUDANonUnifiedSymbols(lhsSymbols) == 0};
1514 int rhsNbManagedSymbols{CountCUDAManagedSymbols(rhsSymbols)};
1515 int rhsNbSymbols{CountCUDANonUnifiedSymbols(rhsSymbols)};
1517 if (HasNonAllocatableModuleCUDAManagedSymbols(lhs))
1522 bool wholeLhs{IsWholeManagedArray(lhs)};
1523 bool wholeRhs{IsWholeManagedArray(rhs)};
1525 if (wholeLhs && rhsNbSymbols == 0 && rhsNbManagedSymbols == 0 &&
1526 (IsVariable(rhs) || IsConstantExpr(rhs))) {
1532 bool lhsIsDeviceOnly{!lhsHasManaged && !lhsIsHost};
1534 bool rhsHasDeviceOnly{rhsNbSymbols > rhsNbManagedSymbols};
1547 if ((IsAllocatableDesignator(lhs) && !lhsIsDeviceOnly && !rhsHasDeviceOnly &&
1548 (lhsHasManaged || rhsNbManagedSymbols >= 1)) ||
1549 (lhsHasManaged && !rhsHasDeviceOnly && !(wholeLhs || wholeRhs)) ||
1550 (lhsIsHost && rhsNbManagedSymbols >= 1 && !rhsHasDeviceOnly &&
1552 (rhsNbManagedSymbols >= 1 && !IsVariable(rhs) && !lhsIsDeviceOnly) ||
1553 (lhsHasManaged && rhsNbSymbols == 0)) {
1556 return !lhsIsHost || rhsNbSymbols > 0;
1569namespace operation {
1571enum class Operator {
1603using OperatorSet = common::EnumSet<Operator, 32>;
1605std::string ToString(Operator op);
1607template <
int Kind> Operator OperationCode(
const LogicalOperation<Kind> &op) {
1608 switch (op.logicalOperator) {
1609 case common::LogicalOperator::And:
1610 return Operator::And;
1611 case common::LogicalOperator::Or:
1612 return Operator::Or;
1613 case common::LogicalOperator::Eqv:
1614 return Operator::Eqv;
1615 case common::LogicalOperator::Neqv:
1616 return Operator::Neqv;
1617 case common::LogicalOperator::Not:
1618 return Operator::Not;
1620 return Operator::Unknown;
1623Operator OperationCode(
const Relational<SomeType> &op);
1625template <
typename T> Operator OperationCode(
const Relational<T> &op) {
1627 case common::RelationalOperator::LT:
1628 return Operator::Lt;
1629 case common::RelationalOperator::LE:
1630 return Operator::Le;
1631 case common::RelationalOperator::EQ:
1632 return Operator::Eq;
1633 case common::RelationalOperator::NE:
1634 return Operator::Ne;
1635 case common::RelationalOperator::GE:
1636 return Operator::Ge;
1637 case common::RelationalOperator::GT:
1638 return Operator::Gt;
1640 return Operator::Unknown;
1643template <
typename T> Operator OperationCode(
const Add<T> &op) {
1644 return Operator::Add;
1647template <
typename T> Operator OperationCode(
const Subtract<T> &op) {
1648 return Operator::Sub;
1651template <
typename T> Operator OperationCode(
const Multiply<T> &op) {
1652 return Operator::Mul;
1655template <
typename T> Operator OperationCode(
const Divide<T> &op) {
1656 return Operator::Div;
1659template <
typename T> Operator OperationCode(
const Power<T> &op) {
1660 return Operator::Pow;
1663template <
typename T> Operator OperationCode(
const RealToIntPower<T> &op) {
1664 return Operator::Pow;
1667template <
typename T, common::TypeCategory C>
1668Operator OperationCode(
const Convert<T, C> &op) {
1669 if constexpr (C == T::category) {
1670 return Operator::Resize;
1672 return Operator::Convert;
1676template <
typename T> Operator OperationCode(
const Extremum<T> &op) {
1677 if (op.ordering == Ordering::Greater) {
1678 return Operator::Max;
1680 return Operator::Min;
1684template <
typename T> Operator OperationCode(
const Constant<T> &x) {
1685 return Operator::Constant;
1688template <
typename T> Operator OperationCode(
const Designator<T> &x) {
1689 return Operator::Identity;
1692template <
typename T> Operator OperationCode(
const T &) {
1693 return Operator::Unknown;
1696Operator OperationCode(
const ProcedureDesignator &proc);
1702std::pair<operation::Operator, std::vector<Expr<SomeType>>>
1707std::pair<operation::Operator, std::vector<Expr<SomeType>>>
1714bool IsVarSubexpressionOf(
1722std::optional<Expr<SomeType>> GetConvertInput(
const Expr<SomeType> &x);
1725std::optional<int> CountDerivedTypeAncestors(
const semantics::Scope &);
1734namespace Fortran::semantics {
1742inline bool IsAlternateEntry(
const Symbol *symbol) {
1745 return symbol && GetMainEntry(symbol) != symbol;
1751bool IsVariableName(
const Symbol &);
1752bool IsPureProcedure(
const Symbol &);
1753bool IsPureProcedure(
const Scope &);
1754bool IsSimpleProcedure(
const Symbol &);
1755bool IsSimpleProcedure(
const Scope &);
1756bool IsExplicitlyImpureProcedure(
const Symbol &);
1757bool IsElementalProcedure(
const Symbol &);
1758bool IsFunction(
const Symbol &);
1759bool IsFunction(
const Scope &);
1760bool IsProcedure(
const Symbol &);
1761bool IsProcedure(
const Scope &);
1762bool IsProcedurePointer(
const Symbol *);
1763bool IsProcedurePointer(
const Symbol &);
1764bool IsObjectPointer(
const Symbol *);
1765bool IsAllocatableOrObjectPointer(
const Symbol *);
1766bool IsAutomatic(
const Symbol &);
1767bool IsSaved(
const Symbol &);
1768bool IsDummy(
const Symbol &);
1770bool IsAssumedRank(
const Symbol &);
1771template <
typename A>
bool IsAssumedRank(
const A &x) {
1772 auto *symbol{UnwrapWholeSymbolDataRef(x)};
1773 return symbol && IsAssumedRank(*symbol);
1776bool IsAssumedShape(
const Symbol &);
1777template <
typename A>
bool IsAssumedShape(
const A &x) {
1778 auto *symbol{UnwrapWholeSymbolDataRef(x)};
1779 return symbol && IsAssumedShape(*symbol);
1782bool IsDeferredShape(
const Symbol &);
1783bool IsFunctionResult(
const Symbol &);
1784bool IsKindTypeParameter(
const Symbol &);
1785bool IsLenTypeParameter(
const Symbol &);
1788bool IsBuiltinDerivedType(
const DerivedTypeSpec *derived,
const char *name);
1789bool IsBuiltinCPtr(
const Symbol &);
1790bool IsFromBuiltinModule(
const Symbol &);
1805inline bool IsAssumedSizeArray(
const Symbol &symbol) {
1807 return (object->isDummy() || symbol.test(Symbol::Flag::CrayPointee)) &&
1808 object->shape().CanBeAssumedSize();
1810 return assoc->IsAssumedSize();
1828const Symbol &ResolveAssociations(
const Symbol &,
bool stopAtTypeGuard =
false);
1829const Symbol &GetAssociationRoot(
const Symbol &,
bool stopAtTypeGuard =
false);
1831const Symbol *FindCommonBlockContaining(
const Symbol &);
1843common::IgnoreTKRSet GetIgnoreTKR(
const Symbol &);
1845std::optional<int> GetDummyArgumentNumber(
const Symbol *);
1847const Symbol *FindAncestorModuleProcedure(
const Symbol *symInSubmodule);
1850const Symbol &GetCrayPointer(
const Symbol &crayPointee);
Definition variable.h:205
Definition variable.h:243
Definition variable.h:357
Definition expression.h:394
Definition constant.h:147
Definition variable.h:381
Definition variable.h:101
Definition expression.h:700
Definition static-data.h:29
Definition variable.h:304
bool HasCUDAImplicitTransfer(const Expr< SomeType > &expr)
Definition tools.cpp:1328
bool HasOnlyCUDAConstntImplicitTransfer(const Expr< SomeType > &expr)
Check if the expression is a mix of host and constant variables.
Definition tools.cpp:1338
Definition expression.h:295
Definition expression.h:256
Definition expression.h:356
Definition expression.h:210
Definition variable.h:288
Definition expression.h:316
Definition expression.h:378
Definition expression.h:309
Definition expression.h:246
Definition expression.h:271
Definition expression.h:228
Definition expression.h:302
Definition characteristics.h:367