FLANG
check-expression.h
1//===-- include/flang/Evaluate/check-expression.h ---------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// Static expression checking
10
11#ifndef FORTRAN_EVALUATE_CHECK_EXPRESSION_H_
12#define FORTRAN_EVALUATE_CHECK_EXPRESSION_H_
13
14#include "expression.h"
15#include "intrinsics.h"
16#include "type.h"
17#include <optional>
18
19namespace Fortran::parser {
21}
22namespace Fortran::semantics {
23class Scope;
24}
25
26namespace Fortran::evaluate {
27
28// Predicate: true when an expression is a constant expression (in the
29// strict sense of the Fortran standard); it may not (yet) be a hard
30// constant value.
31// The FoldingContext pointer, if not null, prevents a "free" implied
32// DO index from being allowed in a constant expression or initial data
33// target if it is not registered in the FoldingContext. (Array constructor
34// implied DO indices are always allowed when the implied DO is within
35// the expression.)
36template <typename A>
37bool IsConstantExpr(const A &, const FoldingContext * = nullptr);
38extern template bool IsConstantExpr(
39 const Expr<SomeType> &, const FoldingContext *);
40extern template bool IsConstantExpr(
41 const Expr<SubscriptInteger> &, const FoldingContext *);
42extern template bool IsConstantExpr(
43 const StructureConstructor &, const FoldingContext *);
44
45// Predicate: true when an expression is a constant expression (in the
46// strict sense of the Fortran standard) or a dummy argument with
47// INTENT(IN) and no VALUE. This is useful for representing explicit
48// shapes of other dummy arguments.
49template <typename A>
50bool IsScopeInvariantExpr(const A &, const FoldingContext * = nullptr);
51extern template bool IsScopeInvariantExpr(
52 const Expr<SomeType> &, const FoldingContext *);
53extern template bool IsScopeInvariantExpr(
54 const Expr<SubscriptInteger> &, const FoldingContext *);
55
56// Predicate: true when an expression actually is a typed Constant<T>,
57// perhaps with parentheses and wrapping around it. False for all typeless
58// expressions, including BOZ literals.
59template <typename A> bool IsActuallyConstant(const A &);
60extern template bool IsActuallyConstant(const Expr<SomeType> &);
61extern template bool IsActuallyConstant(const Expr<SubscriptInteger> &);
62extern template bool IsActuallyConstant(
63 const std::optional<Expr<SubscriptInteger>> &);
64
65// Checks whether an expression is an object designator with
66// constant addressing and no vector-valued subscript.
67// If a non-null ContextualMessages pointer is passed, an error message
68// will be generated if and only if the result of the function is false.
69bool IsInitialDataTarget(const Expr<SomeType> &,
70 parser::ContextualMessages * = nullptr, const FoldingContext * = nullptr);
71
72bool IsInitialProcedureTarget(const Symbol &);
73bool IsInitialProcedureTarget(const ProcedureDesignator &);
74bool IsInitialProcedureTarget(const Expr<SomeType> &);
75
76// Emit warnings about default REAL literal constants in contexts that
77// will be converted to a higher precision REAL kind than the default.
78void CheckRealWidening(
79 const Expr<SomeType> &, const DynamicType &toType, FoldingContext &);
80void CheckRealWidening(const Expr<SomeType> &,
81 const std::optional<DynamicType> &, FoldingContext &);
82
83// Validate the value of a named constant, the static initial
84// value of a non-pointer non-allocatable non-dummy variable, or the
85// default initializer of a component of a derived type (or instantiation
86// of a derived type). Converts type and expands scalars as necessary.
87std::optional<Expr<SomeType>> NonPointerInitializationExpr(const Symbol &,
88 Expr<SomeType> &&, FoldingContext &,
89 const semantics::Scope *instantiation = nullptr);
90
91// Check whether an expression is a specification expression
92// (10.1.11(2), C1010). Constant expressions are always valid
93// specification expressions.
94
95template <typename A>
96void CheckSpecificationExpr(const A &, const semantics::Scope &,
97 FoldingContext &, bool forElementalFunctionResult);
98extern template void CheckSpecificationExpr(const Expr<SomeType> &x,
99 const semantics::Scope &, FoldingContext &,
100 bool forElementalFunctionResult);
101extern template void CheckSpecificationExpr(const Expr<SubscriptInteger> &x,
102 const semantics::Scope &, FoldingContext &,
103 bool forElementalFunctionResult);
104extern template void CheckSpecificationExpr(
105 const std::optional<Expr<SomeType>> &x, const semantics::Scope &,
106 FoldingContext &, bool forElementalFunctionResult);
107extern template void CheckSpecificationExpr(
108 const std::optional<Expr<SubscriptInteger>> &x, const semantics::Scope &,
109 FoldingContext &, bool forElementalFunctionResult);
110
111// Contiguity & "simple contiguity" (9.5.4)
112// Named constant sections are expressions, and as such their evaluation is
113// considered to be contiguous. This avoids funny situations where
114// IS_CONTIGUOUS(cst(1:10:2)) would fold to true because `cst(1:10:2)` is
115// folded into an array constructor literal, but IS_CONTIGUOUS(cst(i:i+9:2))
116// folds to false because the named constant reference cannot be folded.
117// Note that these IS_CONTIGUOUS usages are not portable (can probably be
118// considered to fall into F2023 8.5.7 (4)), and existing compilers are not
119// consistent here.
120// However, the compiler may very well decide to create a descriptor over
121// `cst(i:i+9:2)` when it can to avoid copies, and as such it needs internally
122// to be able to tell the actual contiguity of that array section over the
123// read-only data.
124template <typename A>
125std::optional<bool> IsContiguous(const A &, FoldingContext &,
126 bool namedConstantSectionsAreContiguous = true,
127 bool firstDimensionStride1 = false);
128extern template std::optional<bool> IsContiguous(const Expr<SomeType> &,
129 FoldingContext &, bool namedConstantSectionsAreContiguous,
130 bool firstDimensionStride1);
131extern template std::optional<bool> IsContiguous(const ActualArgument &,
132 FoldingContext &, bool namedConstantSectionsAreContiguous,
133 bool firstDimensionStride1);
134extern template std::optional<bool> IsContiguous(const ArrayRef &,
135 FoldingContext &, bool namedConstantSectionsAreContiguous,
136 bool firstDimensionStride1);
137extern template std::optional<bool> IsContiguous(const Substring &,
138 FoldingContext &, bool namedConstantSectionsAreContiguous,
139 bool firstDimensionStride1);
140extern template std::optional<bool> IsContiguous(const Component &,
141 FoldingContext &, bool namedConstantSectionsAreContiguous,
142 bool firstDimensionStride1);
143extern template std::optional<bool> IsContiguous(const ComplexPart &,
144 FoldingContext &, bool namedConstantSectionsAreContiguous,
145 bool firstDimensionStride1);
146extern template std::optional<bool> IsContiguous(const CoarrayRef &,
147 FoldingContext &, bool namedConstantSectionsAreContiguous,
148 bool firstDimensionStride1);
149extern template std::optional<bool> IsContiguous(const Symbol &,
150 FoldingContext &, bool namedConstantSectionsAreContiguous,
151 bool firstDimensionStride1);
152static inline std::optional<bool> IsContiguous(const SymbolRef &s,
153 FoldingContext &c, bool namedConstantSectionsAreContiguous = true) {
154 return IsContiguous(s.get(), c, namedConstantSectionsAreContiguous);
155}
156template <typename A>
157bool IsSimplyContiguous(const A &x, FoldingContext &context,
158 bool namedConstantSectionsAreContiguous = true) {
159 return IsContiguous(x, context, namedConstantSectionsAreContiguous)
160 .value_or(false);
161}
162
163template <typename A> bool IsErrorExpr(const A &);
164extern template bool IsErrorExpr(const Expr<SomeType> &);
165
166std::optional<parser::Message> CheckStatementFunction(
167 const Symbol &, const Expr<SomeType> &, FoldingContext &);
168
169// Actual arguments of procedure references may retain designators of named
170// constants (rather than their folded values) so that lowering can associate
171// dummy arguments with the named constant's storage. Intrinsic argument
172// matching, checking, and folding inspect constant values structurally, so
173// such arguments must be folded back to values once a call is known to
174// resolve to an intrinsic procedure.
175bool IsNamedConstantDesignator(const Expr<SomeType> &);
176bool AnyNamedConstantActualArguments(const ActualArguments &);
177void FoldNamedConstantActualArguments(FoldingContext &, ActualArguments &);
178
179std::optional<bool> ActualArgNeedsCopy(const ActualArgument *,
180 const characteristics::DummyArgument *, FoldingContext &, bool forCopyOut);
181
182// Scan expressions and note uses of values of symbols.
183semantics::UnorderedSymbolSet CollectUsedSymbolValues(
184 semantics::SemanticsContext &, const Expr<SomeType> &,
185 bool isDefinition = false);
186semantics::UnorderedSymbolSet CollectUsedSymbolValues(
187 semantics::SemanticsContext &, const ProcedureRef &);
188semantics::UnorderedSymbolSet CollectUsedSymbolValues(
189 semantics::SemanticsContext &, const Assignment &);
190
191} // namespace Fortran::evaluate
192#endif
Definition expression.h:960
Definition common.h:222
Definition common.h:224
Definition call.h:352
Definition message.h:399
Definition symbol.h:918
Definition call.h:34
Definition check-expression.h:19