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; }
53 template <
typename T> Result operator()(
const Expr<T> &x)
const {
54 if constexpr (common::HasMember<T, AllIntrinsicTypes> ||
55 std::is_same_v<T, SomeDerived>) {
59 if (
auto known{(*this)(x.u)}) {
64 }
else if constexpr (std::is_same_v<T, SomeType>) {
65 if (std::holds_alternative<ProcedureDesignator>(x.u) ||
66 std::holds_alternative<ProcedureRef>(x.u)) {
77template <
typename A>
bool IsVariable(
const A &x) {
88static inline int GetCorank(
const Symbol &symbol) {
return symbol.Corank(); }
89template <
typename A>
int GetCorank(
const A &) {
return 0; }
90template <
typename T>
int GetCorank(
const Designator<T> &designator) {
91 return designator.Corank();
93template <
typename T>
int GetCorank(
const Expr<T> &expr) {
94 return common::visit([](
const auto &x) {
return GetCorank(x); }, expr.u);
96template <
typename A>
int GetCorank(
const std::optional<A> &x) {
97 return x ? GetCorank(*x) : 0;
99template <
typename A>
int GetCorank(
const A *x) {
100 return x ? GetCorank(*x) : 0;
104template <
typename A>
bool IsCoarray(
const A &x) {
return GetCorank(x) > 0; }
109template <
typename A> common::IfNoLvalue<Expr<ResultType<A>>, A> AsExpr(A &&x) {
113template <typename T, typename U = typename Relational<T>::Result>
122 static_assert(IsSpecificIntrinsicType<T>);
126template <TypeCategory CATEGORY>
132common::IfNoLvalue<Expr<SomeType>, A> AsGenericExpr(A &&x) {
133 if constexpr (common::HasMember<A, TypelessExpression>) {
144std::optional<Expr<SomeType>> AsGenericExpr(
DataRef &&);
145std::optional<Expr<SomeType>> AsGenericExpr(
const Symbol &);
149std::optional<Expr<SomeType>> AsGenericExpr(std::optional<A> &&x) {
151 return AsGenericExpr(std::move(*x));
158common::IfNoLvalue<Expr<SomeKind<ResultType<A>::category>>, A> AsCategoryExpr(
165template <
typename A>
constexpr bool IsNumericCategoryExpr() {
166 if constexpr (common::HasMember<A, TypelessExpression>) {
169 return common::HasMember<ResultType<A>, NumericCategoryTypes>;
176template <
typename A,
typename B>
177auto UnwrapExpr(B &x) -> common::Constify<A, B> * {
178 using Ty = std::decay_t<B>;
179 if constexpr (std::is_same_v<A, Ty>) {
181 }
else if constexpr (std::is_same_v<Ty, ActualArgument>) {
182 if (
auto *expr{x.UnwrapExpr()}) {
183 return UnwrapExpr<A>(*expr);
185 }
else if constexpr (std::is_same_v<Ty, Expr<SomeType>>) {
186 return common::visit([](
auto &x) {
return UnwrapExpr<A>(x); }, x.u);
187 }
else if constexpr (!common::HasMember<A, TypelessExpression>) {
188 if constexpr (std::is_same_v<Ty, Expr<ResultType<A>>> ||
189 std::is_same_v<Ty, Expr<SomeKind<ResultType<A>::category>>>) {
190 return common::visit([](
auto &x) {
return UnwrapExpr<A>(x); }, x.u);
196template <
typename A,
typename B>
197const A *UnwrapExpr(
const std::optional<B> &x) {
199 return UnwrapExpr<A>(*x);
205template <
typename A,
typename B> A *UnwrapExpr(std::optional<B> &x) {
207 return UnwrapExpr<A>(*x);
213template <
typename A,
typename B>
const A *UnwrapExpr(
const B *x) {
215 return UnwrapExpr<A>(*x);
221template <
typename A,
typename B> A *UnwrapExpr(B *x) {
223 return UnwrapExpr<A>(*x);
232template <
typename A,
typename B>
233auto UnwrapConvertedExpr(B &x) -> common::Constify<A, B> * {
234 using Ty = std::decay_t<B>;
235 if constexpr (std::is_same_v<A, Ty>) {
237 }
else if constexpr (std::is_same_v<Ty, ActualArgument>) {
238 if (
auto *expr{x.UnwrapExpr()}) {
239 return UnwrapConvertedExpr<A>(*expr);
241 }
else if constexpr (std::is_same_v<Ty, Expr<SomeType>>) {
242 return common::visit(
243 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.u);
245 using DesiredResult = ResultType<A>;
246 if constexpr (std::is_same_v<Ty, Expr<DesiredResult>> ||
247 std::is_same_v<Ty, Expr<SomeKind<DesiredResult::category>>>) {
248 return common::visit(
249 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.u);
251 using ThisResult = ResultType<B>;
252 if constexpr (std::is_same_v<Ty, Expr<ThisResult>>) {
253 return common::visit(
254 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.u);
255 }
else if constexpr (std::is_same_v<Ty, Parentheses<ThisResult>> ||
256 std::is_same_v<Ty, Convert<ThisResult, DesiredResult::category>>) {
257 return common::visit(
258 [](
auto &x) {
return UnwrapConvertedExpr<A>(x); }, x.left().u);
267template <
typename A>
inline const ProcedureRef *UnwrapProcedureRef(
const A &) {
284 return common::visit(
285 [](
const auto &x) {
return UnwrapProcedureRef(x); }, expr.u);
291template <
typename A>
const Symbol *ExtractBareLenParameter(
const A &expr) {
292 if (
const auto *typeParam{
293 UnwrapConvertedExpr<evaluate::TypeParamInquiry>(expr)}) {
294 if (!typeParam->base()) {
295 const Symbol &symbol{typeParam->parameter()};
296 if (
const auto *tpd{symbol.detailsIf<semantics::TypeParamDetails>()}) {
297 if (tpd->attr() == common::TypeParamAttr::Len) {
311common::IfNoLvalue<std::optional<DataRef>, A> ExtractDataRef(
312 const A &x,
bool intoSubstring,
bool intoComplexPart) {
313 if constexpr (common::HasMember<
decltype(x),
decltype(DataRef::u)>) {
320std::optional<DataRef> ExtractSubstringBase(
const Substring &);
322inline std::optional<DataRef> ExtractDataRef(
const Substring &x,
323 bool intoSubstring =
false,
bool intoComplexPart =
false) {
325 return ExtractSubstringBase(x);
330inline std::optional<DataRef> ExtractDataRef(
const ComplexPart &x,
331 bool intoSubstring =
false,
bool intoComplexPart =
false) {
332 if (intoComplexPart) {
340 bool intoSubstring =
false,
bool intoComplexPart =
false) {
341 return common::visit(
342 [=](
const auto &x) -> std::optional<DataRef> {
343 return ExtractDataRef(x, intoSubstring, intoComplexPart);
348std::optional<DataRef> ExtractDataRef(
const Expr<T> &expr,
349 bool intoSubstring =
false,
bool intoComplexPart =
false) {
350 return common::visit(
352 return ExtractDataRef(x, intoSubstring, intoComplexPart);
357std::optional<DataRef> ExtractDataRef(
const std::optional<A> &x,
358 bool intoSubstring =
false,
bool intoComplexPart =
false) {
360 return ExtractDataRef(*x, intoSubstring, intoComplexPart);
366std::optional<DataRef> ExtractDataRef(
367 A *p,
bool intoSubstring =
false,
bool intoComplexPart =
false) {
369 return ExtractDataRef(std::as_const(*p), intoSubstring, intoComplexPart);
375 bool intoSubstring =
false,
bool intoComplexPart =
false);
379const Symbol *IsArrayElement(
const Expr<T> &expr,
bool intoSubstring =
true,
380 bool skipComponents =
false) {
381 if (
auto dataRef{ExtractDataRef(expr, intoSubstring)}) {
382 for (
const DataRef *ref{&*dataRef}; ref;) {
383 if (
const Component * component{std::get_if<Component>(&ref->u)}) {
384 ref = skipComponents ? &component->base() :
nullptr;
385 }
else if (
const auto *coarrayRef{std::get_if<CoarrayRef>(&ref->u)}) {
386 ref = &coarrayRef->base();
387 }
else if (
const auto *arrayRef{std::get_if<ArrayRef>(&ref->u)}) {
388 return &arrayRef->GetLastSymbol();
398bool isStructureComponent(
const Fortran::evaluate::Expr<T> &expr) {
399 if (
auto dataRef{ExtractDataRef(expr,
false)}) {
400 const Fortran::evaluate::DataRef *ref{&*dataRef};
401 return std::holds_alternative<Fortran::evaluate::Component>(ref->u);
408std::optional<NamedEntity> ExtractNamedEntity(
const A &x) {
409 if (
auto dataRef{ExtractDataRef(x)}) {
410 return common::visit(
412 [](SymbolRef &&symbol) -> std::optional<NamedEntity> {
415 [](
Component &&component) -> std::optional<NamedEntity> {
418 [](
auto &&) {
return std::optional<NamedEntity>{}; },
420 std::move(dataRef->u));
427 template <
typename A> std::optional<CoarrayRef> operator()(
const A &)
const {
430 std::optional<CoarrayRef> operator()(
const CoarrayRef &x)
const {
return x; }
431 template <
typename A>
432 std::optional<CoarrayRef> operator()(
const Expr<A> &expr)
const {
433 return common::visit(*
this, expr.u);
435 std::optional<CoarrayRef> operator()(
const DataRef &dataRef)
const {
436 return common::visit(*
this, dataRef.u);
438 std::optional<CoarrayRef> operator()(
const NamedEntity &named)
const {
439 if (
const Component * component{named.UnwrapComponent()}) {
440 return (*
this)(*component);
446 if (
const auto *component{
447 std::get_if<common::CopyableIndirection<Component>>(&des.u)}) {
448 return (*
this)(component->value());
453 std::optional<CoarrayRef> operator()(
const Component &component)
const {
454 return (*
this)(component.base());
456 std::optional<CoarrayRef> operator()(
const ArrayRef &arrayRef)
const {
457 return (*
this)(arrayRef.base());
461static inline std::optional<CoarrayRef> ExtractCoarrayRef(
const DataRef &x) {
465template <
typename A> std::optional<CoarrayRef> ExtractCoarrayRef(
const A &x) {
466 if (
auto dataRef{ExtractDataRef(x,
true)}) {
467 return ExtractCoarrayRef(*dataRef);
474 template <
typename T>
static std::optional<TARGET> visit(T &&) {
478 static std::optional<TARGET> visit(
const TARGET &t) {
return t; }
480 template <
typename T>
482 return common::visit([](
auto &&s) {
return visit(s); }, e.u);
485 template <
typename T>
static std::optional<TARGET> visit(
const Expr<T> &e) {
486 return common::visit([](
auto &&s) {
return visit(s); }, e.u);
490template <
typename A> std::optional<Substring> ExtractSubstring(
const A &x) {
491 return ExtractFromExprDesignatorHelper<Substring>::visit(x);
495std::optional<ComplexPart> ExtractComplexPart(
const A &x) {
496 return ExtractFromExprDesignatorHelper<ComplexPart>::visit(x);
501const Symbol *UnwrapWholeSymbolDataRef(
const DataRef &);
502const Symbol *UnwrapWholeSymbolDataRef(
const std::optional<DataRef> &);
503template <
typename A>
const Symbol *UnwrapWholeSymbolDataRef(
const A &x) {
504 return UnwrapWholeSymbolDataRef(ExtractDataRef(x));
509const Symbol *UnwrapWholeSymbolOrComponentDataRef(
const DataRef &);
510const Symbol *UnwrapWholeSymbolOrComponentDataRef(
511 const std::optional<DataRef> &);
513const Symbol *UnwrapWholeSymbolOrComponentDataRef(
const A &x) {
514 return UnwrapWholeSymbolOrComponentDataRef(ExtractDataRef(x));
520const Symbol *UnwrapWholeSymbolOrComponentOrCoarrayRef(
const DataRef &);
521const Symbol *UnwrapWholeSymbolOrComponentOrCoarrayRef(
522 const std::optional<DataRef> &);
524const Symbol *UnwrapWholeSymbolOrComponentOrCoarrayRef(
const A &x) {
525 return UnwrapWholeSymbolOrComponentOrCoarrayRef(ExtractDataRef(x));
529template <
typename A>
const Symbol *GetFirstSymbol(
const A &x) {
530 if (
auto dataRef{ExtractDataRef(x,
true)}) {
531 return &dataRef->GetFirstSymbol();
538const Symbol *GetLastPointerSymbol(
const evaluate::DataRef &);
544template <
typename TO, TypeCategory FROMCAT>
546 static_assert(IsSpecificIntrinsicType<TO>);
547 if constexpr (FROMCAT == TO::category) {
548 if (
auto *already{std::get_if<Expr<TO>>(&x.u)}) {
549 return std::move(*already);
553 }
else if constexpr (TO::category == TypeCategory::Complex) {
554 using Part =
typename TO::Part;
558 }
else if constexpr (FROMCAT == TypeCategory::Complex) {
560 return common::visit(
562 using ZType = ResultType<
decltype(z)>;
563 using Part =
typename ZType::Part;
573template <
typename TO, TypeCategory FROMCAT,
int FROMKIND>
578template <
typename TO>
Expr<TO> ConvertToType(BOZLiteralConstant &&x) {
579 static_assert(IsSpecificIntrinsicType<TO>);
580 if constexpr (TO::category == TypeCategory::Integer ||
581 TO::category == TypeCategory::Unsigned) {
583 Constant<TO>{Scalar<TO>::ConvertUnsigned(std::move(x)).value}};
585 static_assert(TO::category == TypeCategory::Real);
586 using Word =
typename Scalar<TO>::Word;
588 Constant<TO>{Scalar<TO>{Word::ConvertUnsigned(std::move(x)).value}}};
592template <
typename T>
bool IsBOZLiteral(
const Expr<T> &expr) {
593 return std::holds_alternative<BOZLiteralConstant>(expr.u);
597std::optional<Expr<SomeType>> ConvertToType(
599std::optional<Expr<SomeType>> ConvertToType(
602std::optional<Expr<SomeType>> ConvertToType(
606template <TypeCategory TC,
int TK,
typename FROM>
607common::IfNoLvalue<Expr<Type<TC, TK>>, FROM> ConvertTo(
609 return ConvertToType<Type<TC, TK>>(std::move(x));
612template <TypeCategory TC,
typename FROM>
613common::IfNoLvalue<Expr<SomeKind<TC>>, FROM> ConvertTo(
615 return common::visit(
616 [&](
const auto &toKindExpr) {
617 using KindExpr = std::decay_t<
decltype(toKindExpr)>;
618 return AsCategoryExpr(
619 ConvertToType<ResultType<KindExpr>>(std::move(from)));
624template <
typename FROM>
625common::IfNoLvalue<Expr<SomeType>, FROM> ConvertTo(
627 return common::visit(
628 [&](
const auto &toCatExpr) {
629 return AsGenericExpr(ConvertTo(toCatExpr, std::move(from)));
636template <TypeCategory TOCAT,
typename VALUE>
struct ConvertToKindHelper {
637 using Result = std::optional<Expr<SomeKind<TOCAT>>>;
638 using Types = CategoryTypes<TOCAT>;
639 ConvertToKindHelper(
int k, VALUE &&x) : kind{k}, value{std::move(x)} {}
640 template <
typename T> Result Test() {
641 if (kind == T::kind) {
642 return std::make_optional(
643 AsCategoryExpr(ConvertToType<T>(std::move(value))));
651template <TypeCategory TOCAT,
typename VALUE>
652common::IfNoLvalue<Expr<SomeKind<TOCAT>>, VALUE> ConvertToKind(
653 int kind, VALUE &&x) {
654 auto result{common::SearchTypes(
656 CHECK(result.has_value());
663template <
typename A,
int N = 2>
using SameExprs = std::array<Expr<A>, N>;
665 template <
typename A>
using SameExprs = std::array<Expr<A>, N>;
667template <TypeCategory CAT,
int N = 2>
669 common::MapTemplate<SameKindExprsHelper<N>::template SameExprs,
675template <TypeCategory CAT>
676SameKindExprs<CAT, 2> AsSameKindExprs(
678 return common::visit(
679 [&](
auto &&kx,
auto &&ky) -> SameKindExprs<CAT, 2> {
680 using XTy = ResultType<
decltype(kx)>;
681 using YTy = ResultType<
decltype(ky)>;
682 if constexpr (std::is_same_v<XTy, YTy>) {
683 return {SameExprs<XTy>{std::move(kx), std::move(ky)}};
684 }
else if constexpr (XTy::kind < YTy::kind) {
685 return {SameExprs<YTy>{ConvertTo(ky, std::move(kx)), std::move(ky)}};
687 return {SameExprs<XTy>{std::move(kx), ConvertTo(kx, std::move(ky))}};
689#if !__clang__ && 100 * __GNUC__ + __GNUC_MINOR__ == 801
692 CHECK(!
"can't happen");
693 return {SameExprs<XTy>{std::move(kx), std::move(kx)}};
696 std::move(x.u), std::move(y.u));
702using ConvertRealOperandsResult =
703 std::optional<SameKindExprs<TypeCategory::Real, 2>>;
704ConvertRealOperandsResult ConvertRealOperands(parser::ContextualMessages &,
711std::optional<Expr<SomeComplex>> ConstructComplex(parser::ContextualMessages &,
713std::optional<Expr<SomeComplex>> ConstructComplex(parser::ContextualMessages &,
715 int defaultRealKind);
717template <
typename A>
Expr<TypeOf<A>> ScalarConstantToExpr(
const A &x) {
718 using Ty = TypeOf<A>;
720 std::is_same_v<Scalar<Ty>, std::decay_t<A>>,
"TypeOf<> is broken");
726template <
template <
typename>
class OPR,
typename SPECIFIC>
728 static_assert(IsSpecificIntrinsicType<SPECIFIC>);
729 return AsExpr(OPR<SPECIFIC>{std::move(x), std::move(y)});
736template <
template <
typename>
class OPR, TypeCategory CAT>
739 return common::visit(
741 using Ty = ResultType<
decltype(xy[0])>;
742 return AsCategoryExpr(
743 Combine<OPR, Ty>(std::move(xy[0]), std::move(xy[1])));
745 AsSameKindExprs(std::move(x), std::move(y)));
753template <
template <
typename>
class OPR>
754std::optional<Expr<SomeType>> NumericOperation(parser::ContextualMessages &,
757extern template std::optional<Expr<SomeType>> NumericOperation<Power>(
759 int defaultRealKind);
760extern template std::optional<Expr<SomeType>> NumericOperation<Multiply>(
762 int defaultRealKind);
763extern template std::optional<Expr<SomeType>> NumericOperation<Divide>(
765 int defaultRealKind);
766extern template std::optional<Expr<SomeType>> NumericOperation<Add>(
768 int defaultRealKind);
769extern template std::optional<Expr<SomeType>> NumericOperation<Subtract>(
771 int defaultRealKind);
773std::optional<Expr<SomeType>> Negation(
778std::optional<Expr<LogicalResult>> Relate(parser::ContextualMessages &,
786 static_assert(IsSpecificIntrinsicType<T>);
794 return AsExpr(
Not<K>{std::move(x)});
814template <TypeCategory C,
int K>
819template <TypeCategory C,
int K>
821 return AsExpr(Combine<
Add,
Type<C, K>>(std::move(x), std::move(y)));
824template <TypeCategory C,
int K>
829template <TypeCategory C,
int K>
834template <TypeCategory C,
int K>
840 return common::visit(
844template <TypeCategory CAT>
847 return PromoteAndCombine<Add, CAT>(std::move(x), std::move(y));
850template <TypeCategory CAT>
853 return PromoteAndCombine<Subtract, CAT>(std::move(x), std::move(y));
856template <TypeCategory CAT>
859 return PromoteAndCombine<Multiply, CAT>(std::move(x), std::move(y));
862template <TypeCategory CAT>
865 return PromoteAndCombine<Divide, CAT>(std::move(x), std::move(y));
871template <TypeCategory CAT,
template <
typename>
class TEMPLATE,
typename VALUE>
872struct TypeKindVisitor {
873 using Result = std::optional<Expr<SomeType>>;
874 using Types = CategoryTypes<CAT>;
876 TypeKindVisitor(
int k, VALUE &&x) : kind{k}, value{std::move(x)} {}
877 TypeKindVisitor(
int k,
const VALUE &x) : kind{k}, value{x} {}
879 template <
typename T> Result Test() {
880 if (kind == T::kind) {
881 return AsGenericExpr(TEMPLATE<T>{std::move(value)});
893template <TypeCategory CATEGORY,
template <
typename>
typename WRAPPER,
895common::IfNoLvalue<std::optional<Expr<SomeType>>, WRAPPED> WrapperHelper(
896 int kind, WRAPPED &&x) {
897 return common::SearchTypes(
901template <
template <
typename>
typename WRAPPER,
typename WRAPPED>
902common::IfNoLvalue<std::optional<Expr<SomeType>>, WRAPPED> TypedWrapper(
903 const DynamicType &dyType, WRAPPED &&x) {
904 switch (dyType.category()) {
905 SWITCH_COVERS_ALL_CASES
906 case TypeCategory::Integer:
907 return WrapperHelper<TypeCategory::Integer, WRAPPER, WRAPPED>(
908 dyType.kind(), std::move(x));
909 case TypeCategory::Unsigned:
910 return WrapperHelper<TypeCategory::Unsigned, WRAPPER, WRAPPED>(
911 dyType.kind(), std::move(x));
912 case TypeCategory::Real:
913 return WrapperHelper<TypeCategory::Real, WRAPPER, WRAPPED>(
914 dyType.kind(), std::move(x));
915 case TypeCategory::Complex:
916 return WrapperHelper<TypeCategory::Complex, WRAPPER, WRAPPED>(
917 dyType.kind(), std::move(x));
918 case TypeCategory::Character:
919 return WrapperHelper<TypeCategory::Character, WRAPPER, WRAPPED>(
920 dyType.kind(), std::move(x));
921 case TypeCategory::Logical:
922 return WrapperHelper<TypeCategory::Logical, WRAPPER, WRAPPED>(
923 dyType.kind(), std::move(x));
924 case TypeCategory::Derived:
925 return AsGenericExpr(Expr<SomeDerived>{WRAPPER<SomeDerived>{std::move(x)}});
933struct GetLastSymbolHelper
934 :
public AnyTraverse<GetLastSymbolHelper, std::optional<const Symbol *>> {
935 using Result = std::optional<const Symbol *>;
936 using Base = AnyTraverse<GetLastSymbolHelper, Result>;
937 GetLastSymbolHelper() : Base{*
this} {}
938 using Base::operator();
939 Result operator()(
const Symbol &x)
const {
return &x; }
940 Result operator()(
const Component &x)
const {
return &x.GetLastSymbol(); }
941 Result operator()(
const NamedEntity &x)
const {
return &x.GetLastSymbol(); }
943 return x.GetSymbol();
945 template <
typename T> Result operator()(
const Expr<T> &x)
const {
946 if constexpr (common::HasMember<T, AllIntrinsicTypes> ||
947 std::is_same_v<T, SomeDerived>) {
948 if (
const auto *designator{std::get_if<Designator<T>>(&x.u)}) {
949 if (
auto known{(*this)(*designator)}) {
960template <
typename A>
const Symbol *GetLastSymbol(
const A &x) {
971template <
typename A> semantics::Attrs GetAttrs(
const A &x) {
972 if (
const Symbol * symbol{GetLastSymbol(x)}) {
973 return symbol->attrs();
980inline semantics::Attrs GetAttrs<Expr<SomeType>>(
const Expr<SomeType> &x) {
982 if (
const auto *procRef{UnwrapProcedureRef(x)}) {
983 if (
const Symbol * interface{procRef->proc().GetInterfaceSymbol()}) {
984 if (
const auto *details{
985 interface->detailsIf<semantics::SubprogramDetails>()}) {
986 if (details->isFunction() &&
987 details->result().attrs().test(semantics::Attr::POINTER)) {
989 return details->result().attrs();
995 if (
const Symbol * symbol{GetLastSymbol(x)}) {
996 return symbol->attrs();
1002template <
typename A> semantics::Attrs GetAttrs(
const std::optional<A> &x) {
1004 return GetAttrs(*x);
1011template <
typename A> std::optional<BaseObject> GetBaseObject(
const A &) {
1012 return std::nullopt;
1014template <
typename T>
1015std::optional<BaseObject> GetBaseObject(
const Designator<T> &x) {
1016 return x.GetBaseObject();
1018template <
typename T>
1019std::optional<BaseObject> GetBaseObject(
const Expr<T> &x) {
1020 return common::visit([](
const auto &y) {
return GetBaseObject(y); }, x.u);
1022template <
typename A>
1023std::optional<BaseObject> GetBaseObject(
const std::optional<A> &x) {
1025 return GetBaseObject(*x);
1027 return std::nullopt;
1059struct GetSymbolVectorHelper
1060 :
public Traverse<GetSymbolVectorHelper, SymbolVector> {
1061 using Result = SymbolVector;
1062 using Base = Traverse<GetSymbolVectorHelper, Result>;
1063 using Base::operator();
1064 GetSymbolVectorHelper() : Base{*
this} {}
1065 Result Default() {
return {}; }
1066 Result Combine(Result &&a, Result &&b) {
1067 a.insert(a.end(), b.begin(), b.end());
1068 return std::move(a);
1070 Result operator()(
const Symbol &)
const;
1071 Result operator()(
const Component &)
const;
1072 Result operator()(
const ArrayRef &)
const;
1075template <
typename A> SymbolVector GetSymbolVector(
const A &x) {
1082const Symbol *GetLastTarget(
const SymbolVector &);
1085template <
typename A> semantics::UnorderedSymbolSet CollectSymbols(
const A &);
1086extern template semantics::UnorderedSymbolSet CollectSymbols(
1087 const Expr<SomeType> &);
1088extern template semantics::UnorderedSymbolSet CollectSymbols(
1089 const Expr<SomeInteger> &);
1090extern template semantics::UnorderedSymbolSet CollectSymbols(
1091 const Expr<SubscriptInteger> &);
1094template <
typename A>
1095semantics::UnorderedSymbolSet CollectCudaSymbols(
const A &);
1096extern template semantics::UnorderedSymbolSet CollectCudaSymbols(
1097 const Expr<SomeType> &);
1098extern template semantics::UnorderedSymbolSet CollectCudaSymbols(
1099 const Expr<SomeInteger> &);
1100extern template semantics::UnorderedSymbolSet CollectCudaSymbols(
1101 const Expr<SubscriptInteger> &);
1104bool HasVectorSubscript(
const Expr<SomeType> &);
1105bool HasVectorSubscript(
const ActualArgument &);
1108bool IsArraySection(
const Expr<SomeType> &expr);
1111bool HasConstant(
const Expr<SomeType> &);
1115parser::Message *AttachDeclaration(parser::Message &,
const Symbol &);
1116parser::Message *AttachDeclaration(parser::Message *,
const Symbol &);
1117template <
typename MESSAGES,
typename... A>
1118parser::Message *SayWithDeclaration(
1119 MESSAGES &messages,
const Symbol &symbol, A &&...x) {
1120 return AttachDeclaration(messages.Say(std::forward<A>(x)...), symbol);
1122template <
typename... A>
1124 const Symbol &symbol, common::LanguageFeature feature, A &&...x) {
1125 return AttachDeclaration(
1126 context.Warn(feature, std::forward<A>(x)...), symbol);
1128template <
typename... A>
1130 const Symbol &symbol, common::UsageWarning warning, A &&...x) {
1131 return AttachDeclaration(
1132 context.Warn(warning, std::forward<A>(x)...), symbol);
1137std::optional<std::string> FindImpureCall(
1139std::optional<std::string> FindImpureCall(
1145class UnsafeToCopyVisitor :
public AnyTraverse<UnsafeToCopyVisitor> {
1147 using Base = AnyTraverse<UnsafeToCopyVisitor>;
1148 using Base::operator();
1149 explicit UnsafeToCopyVisitor(
bool admitPureCall)
1150 : Base{*
this}, admitPureCall_{admitPureCall} {}
1151 template <
typename T>
bool operator()(
const FunctionRef<T> &procRef) {
1152 return !admitPureCall_ || !procRef.proc().IsPure();
1154 bool operator()(
const CoarrayRef &) {
return true; }
1157 bool admitPureCall_{
false};
1160template <
typename A>
1161bool IsSafelyCopyable(
const A &x,
bool admitPureCall =
false) {
1168template <
typename T>
1169bool IsExpandableScalar(
const Expr<T> &expr, FoldingContext &context,
1170 const Shape &shape,
bool admitPureCall =
false) {
1171 if (IsSafelyCopyable(expr, admitPureCall)) {
1174 auto extents{AsConstantExtents(context, shape)};
1175 return extents && !HasNegativeExtent(*extents) && GetSize(*extents) == 1;
1182std::optional<parser::MessageFixedText> CheckProcCompatibility(
bool isCall,
1183 const std::optional<characteristics::Procedure> &lhsProcedure,
1186 std::optional<std::string> &warning,
bool ignoreImplicitVsExplicit);
1189class ScalarConstantExpander {
1191 explicit ScalarConstantExpander(ConstantSubscripts &&extents)
1192 : extents_{std::move(extents)} {}
1193 ScalarConstantExpander(
1194 ConstantSubscripts &&extents, std::optional<ConstantSubscripts> &&lbounds)
1195 : extents_{std::move(extents)}, lbounds_{std::move(lbounds)} {}
1196 ScalarConstantExpander(
1197 ConstantSubscripts &&extents, ConstantSubscripts &&lbounds)
1198 : extents_{std::move(extents)}, lbounds_{std::move(lbounds)} {}
1200 template <
typename A> A Expand(A &&x)
const {
1201 return std::move(x);
1204 auto expanded{x.Reshape(std::move(extents_))};
1206 expanded.set_lbounds(std::move(*lbounds_));
1211 return Expand(std::move(x.left()));
1214 return common::visit(
1215 [&](
auto &&x) {
return Expr<T>{Expand(std::move(x))}; },
1220 ConstantSubscripts extents_;
1221 std::optional<ConstantSubscripts> lbounds_;
1227template <
typename T>
1228Constant<T> PackageConstant(std::vector<Scalar<T>> &&elements,
1229 const Constant<T> &reference,
const ConstantSubscripts &shape) {
1230 if constexpr (T::category == TypeCategory::Character) {
1232 reference.LEN(), std::move(elements), ConstantSubscripts{shape}};
1233 }
else if constexpr (T::category == TypeCategory::Derived) {
1234 return Constant<T>{reference.GetType().GetDerivedTypeSpec(),
1235 std::move(elements), ConstantSubscripts{shape}};
1237 return Constant<T>{std::move(elements), ConstantSubscripts{shape}};
1243std::optional<Expr<SomeType>> DataConstantConversionExtension(
1248std::optional<Expr<SomeType>> HollerithToBOZ(
1252class ArrayConstantBoundChanger {
1254 explicit ArrayConstantBoundChanger(ConstantSubscripts &&lbounds)
1255 : lbounds_{std::move(lbounds)} {}
1257 template <
typename A> A ChangeLbounds(A &&x)
const {
1258 return std::move(x);
1261 x.set_lbounds(std::move(lbounds_));
1262 return std::move(x);
1265 return ChangeLbounds(
1266 std::move(x.left()));
1269 return common::visit(
1270 [&](
auto &&x) {
return Expr<T>{ChangeLbounds(std::move(x))}; },
1275 ConstantSubscripts &&lbounds_;
1281template <
typename T>
1282std::optional<bool> AreEquivalentInInterface(
const Expr<T> &,
const Expr<T> &);
1283extern template std::optional<bool> AreEquivalentInInterface<SubscriptInteger>(
1285extern template std::optional<bool> AreEquivalentInInterface<SomeInteger>(
1289 const std::optional<ActualArgument> &,
const std::string &procName,
1290 const std::string &argName);
1292inline bool IsCUDADeviceSymbol(
const Symbol &sym) {
1293 if (
const auto *details =
1295 if (details->cudaDataAttr() &&
1296 *details->cudaDataAttr() != common::CUDADataAttr::Pinned) {
1303inline bool IsCUDAManagedOrUnifiedSymbol(
const Symbol &sym) {
1304 if (
const auto *details =
1305 sym.GetUltimate().detailsIf<semantics::ObjectEntityDetails>()) {
1306 if (details->cudaDataAttr() &&
1307 (*details->cudaDataAttr() == common::CUDADataAttr::Managed ||
1308 *details->cudaDataAttr() == common::CUDADataAttr::Unified)) {
1317template <
typename A>
inline int GetNbOfCUDADeviceSymbols(
const A &expr) {
1318 semantics::UnorderedSymbolSet symbols;
1319 for (
const Symbol &sym : CollectCudaSymbols(expr)) {
1320 if (IsCUDADeviceSymbol(sym)) {
1321 symbols.insert(sym);
1324 return symbols.size();
1329template <
typename A>
1330inline int GetNbOfCUDAManagedOrUnifiedSymbols(
const A &expr) {
1331 semantics::UnorderedSymbolSet symbols;
1332 for (
const Symbol &sym : CollectCudaSymbols(expr)) {
1333 if (IsCUDAManagedOrUnifiedSymbol(sym)) {
1334 symbols.insert(sym);
1337 return symbols.size();
1342template <
typename A>
inline bool HasCUDADeviceAttrs(
const A &expr) {
1343 return GetNbOfCUDADeviceSymbols(expr) > 0;
1348template <
typename A,
typename B>
1349inline bool IsCUDADataTransfer(
const A &lhs,
const B &rhs) {
1350 int lhsNbManagedSymbols = {GetNbOfCUDAManagedOrUnifiedSymbols(lhs)};
1351 int rhsNbManagedSymbols = {GetNbOfCUDAManagedOrUnifiedSymbols(rhs)};
1352 int rhsNbSymbols{GetNbOfCUDADeviceSymbols(rhs)};
1356 if (lhsNbManagedSymbols == 1 && rhsNbManagedSymbols == 1 &&
1357 rhsNbSymbols == 1) {
1360 return HasCUDADeviceAttrs(lhs) || rhsNbSymbols > 0;
1370namespace operation {
1372enum class Operator {
1403using OperatorSet = common::EnumSet<Operator, 32>;
1405std::string ToString(Operator op);
1407template <
int Kind> Operator OperationCode(
const LogicalOperation<Kind> &op) {
1408 switch (op.logicalOperator) {
1409 case common::LogicalOperator::And:
1410 return Operator::And;
1411 case common::LogicalOperator::Or:
1412 return Operator::Or;
1413 case common::LogicalOperator::Eqv:
1414 return Operator::Eqv;
1415 case common::LogicalOperator::Neqv:
1416 return Operator::Neqv;
1417 case common::LogicalOperator::Not:
1418 return Operator::Not;
1420 return Operator::Unknown;
1423Operator OperationCode(
const Relational<SomeType> &op);
1425template <
typename T> Operator OperationCode(
const Relational<T> &op) {
1427 case common::RelationalOperator::LT:
1428 return Operator::Lt;
1429 case common::RelationalOperator::LE:
1430 return Operator::Le;
1431 case common::RelationalOperator::EQ:
1432 return Operator::Eq;
1433 case common::RelationalOperator::NE:
1434 return Operator::Ne;
1435 case common::RelationalOperator::GE:
1436 return Operator::Ge;
1437 case common::RelationalOperator::GT:
1438 return Operator::Gt;
1440 return Operator::Unknown;
1443template <
typename T> Operator OperationCode(
const Add<T> &op) {
1444 return Operator::Add;
1447template <
typename T> Operator OperationCode(
const Subtract<T> &op) {
1448 return Operator::Sub;
1451template <
typename T> Operator OperationCode(
const Multiply<T> &op) {
1452 return Operator::Mul;
1455template <
typename T> Operator OperationCode(
const Divide<T> &op) {
1456 return Operator::Div;
1459template <
typename T> Operator OperationCode(
const Power<T> &op) {
1460 return Operator::Pow;
1463template <
typename T> Operator OperationCode(
const RealToIntPower<T> &op) {
1464 return Operator::Pow;
1467template <
typename T, common::TypeCategory C>
1468Operator OperationCode(
const Convert<T, C> &op) {
1469 if constexpr (C == T::category) {
1470 return Operator::Resize;
1472 return Operator::Convert;
1476template <
typename T> Operator OperationCode(
const Extremum<T> &op) {
1477 if (op.ordering == Ordering::Greater) {
1478 return Operator::Max;
1480 return Operator::Min;
1484template <
typename T> Operator OperationCode(
const Constant<T> &x) {
1485 return Operator::Constant;
1488template <
typename T> Operator OperationCode(
const Designator<T> &x) {
1489 return Operator::Identity;
1492template <
typename T> Operator OperationCode(
const T &) {
1493 return Operator::Unknown;
1496Operator OperationCode(
const ProcedureDesignator &proc);
1502std::pair<operation::Operator, std::vector<Expr<SomeType>>>
1507std::pair<operation::Operator, std::vector<Expr<SomeType>>>
1514bool IsVarSubexpressionOf(
1522std::optional<Expr<SomeType>> GetConvertInput(
const Expr<SomeType> &x);
1525std::optional<int> CountDerivedTypeAncestors(
const semantics::Scope &);
1529namespace Fortran::semantics {
1537inline bool IsAlternateEntry(
const Symbol *symbol) {
1540 return symbol && GetMainEntry(symbol) != symbol;
1546bool IsVariableName(
const Symbol &);
1547bool IsPureProcedure(
const Symbol &);
1548bool IsPureProcedure(
const Scope &);
1549bool IsExplicitlyImpureProcedure(
const Symbol &);
1550bool IsElementalProcedure(
const Symbol &);
1551bool IsFunction(
const Symbol &);
1552bool IsFunction(
const Scope &);
1553bool IsProcedure(
const Symbol &);
1554bool IsProcedure(
const Scope &);
1555bool IsProcedurePointer(
const Symbol *);
1556bool IsProcedurePointer(
const Symbol &);
1557bool IsObjectPointer(
const Symbol *);
1558bool IsAllocatableOrObjectPointer(
const Symbol *);
1559bool IsAutomatic(
const Symbol &);
1560bool IsSaved(
const Symbol &);
1561bool IsDummy(
const Symbol &);
1563bool IsAssumedRank(
const Symbol &);
1564template <
typename A>
bool IsAssumedRank(
const A &x) {
1565 auto *symbol{UnwrapWholeSymbolDataRef(x)};
1566 return symbol && IsAssumedRank(*symbol);
1569bool IsAssumedShape(
const Symbol &);
1570template <
typename A>
bool IsAssumedShape(
const A &x) {
1571 auto *symbol{UnwrapWholeSymbolDataRef(x)};
1572 return symbol && IsAssumedShape(*symbol);
1575bool IsDeferredShape(
const Symbol &);
1576bool IsFunctionResult(
const Symbol &);
1577bool IsKindTypeParameter(
const Symbol &);
1578bool IsLenTypeParameter(
const Symbol &);
1581bool IsBuiltinDerivedType(
const DerivedTypeSpec *derived,
const char *name);
1582bool IsBuiltinCPtr(
const Symbol &);
1583bool IsFromBuiltinModule(
const Symbol &);
1598inline bool IsAssumedSizeArray(
const Symbol &symbol) {
1600 return (object->isDummy() || symbol.test(Symbol::Flag::CrayPointee)) &&
1601 object->shape().CanBeAssumedSize();
1603 return assoc->IsAssumedSize();
1621const Symbol &ResolveAssociations(
const Symbol &,
bool stopAtTypeGuard =
false);
1622const Symbol &GetAssociationRoot(
const Symbol &,
bool stopAtTypeGuard =
false);
1624const Symbol *FindCommonBlockContaining(
const Symbol &);
1636common::IgnoreTKRSet GetIgnoreTKR(
const Symbol &);
1638std::optional<int> GetDummyArgumentNumber(
const Symbol *);
1640const Symbol *FindAncestorModuleProcedure(
const Symbol *symInSubmodule);
Definition variable.h:205
Definition variable.h:243
Definition variable.h:353
Definition constant.h:147
Definition variable.h:377
Definition variable.h:101
Definition expression.h:656
Definition static-data.h:29
Definition variable.h:300
bool HasCUDAImplicitTransfer(const Expr< SomeType > &expr)
Definition tools.cpp:1126
Definition expression.h:296
Definition expression.h:257
Definition expression.h:357
Definition expression.h:211
Definition variable.h:284
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