FLANG
expression.h
1//===-- include/flang/Semantics/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#ifndef FORTRAN_SEMANTICS_EXPRESSION_H_
10#define FORTRAN_SEMANTICS_EXPRESSION_H_
11
12#include "semantics.h"
13#include "flang/Common/indirection.h"
14#include "flang/Common/restorer.h"
15#include "flang/Common/visit.h"
16#include "flang/Evaluate/characteristics.h"
17#include "flang/Evaluate/check-expression.h"
18#include "flang/Evaluate/expression.h"
19#include "flang/Evaluate/fold.h"
20#include "flang/Evaluate/tools.h"
21#include "flang/Evaluate/type.h"
22#include "flang/Parser/char-block.h"
23#include "flang/Parser/parse-tree-visitor.h"
24#include "flang/Parser/parse-tree.h"
25#include "flang/Parser/tools.h"
26#include "flang/Support/Fortran.h"
27#include <map>
28#include <optional>
29#include <type_traits>
30#include <variant>
31
32using namespace Fortran::parser::literals;
33
34namespace Fortran::parser {
36 template <typename A> bool Pre(const A &x) {
37 if constexpr (HasSource<A>::value) {
38 source.ExtendToCover(x.source);
39 return false;
40 } else {
41 return true;
42 }
43 }
44 template <typename A> void Post(const A &) {}
45 void Post(const CharBlock &at) { source.ExtendToCover(at); }
46
47 CharBlock source;
48};
49
50template <typename A> CharBlock FindSourceLocation(const A &x) {
52 Walk(x, visitor);
53 return visitor.source;
54}
55} // namespace Fortran::parser
56
57using namespace Fortran::parser::literals;
58
59// The expression semantic analysis code has its implementation in
60// namespace Fortran::evaluate, but the exposed API to it is in the
61// namespace Fortran::semantics (below).
62//
63// The ExpressionAnalyzer wraps a SemanticsContext reference
64// and implements constraint checking on expressions using the
65// parse tree node wrappers that mirror the grammar annotations used
66// in the Fortran standard (i.e., scalar-, constant-, &c.).
67
68namespace Fortran::evaluate {
69
70class IntrinsicProcTable;
71
72struct SetExprHelper {
73 explicit SetExprHelper(GenericExprWrapper &&expr) : expr_{std::move(expr)} {}
74 void Set(parser::TypedExpr &x) {
75 x.Reset(new GenericExprWrapper{std::move(expr_)},
76 evaluate::GenericExprWrapper::Deleter);
77 }
78 template <typename T> void Set(const common::Indirection<T> &x) {
79 Set(x.value());
80 }
81 template <typename T> void Set(const T &x) {
82 if constexpr (parser::HasTypedExpr<T>::value) {
83 Set(x.typedExpr);
84 } else if constexpr (ConstraintTrait<T>) {
85 Set(x.thing);
86 } else if constexpr (WrapperTrait<T>) {
87 Set(x.v);
88 }
89 }
90
92};
93
94template <typename T> void ResetExpr(const T &x) {
95 SetExprHelper{GenericExprWrapper{/* error indicator */}}.Set(x);
96}
97
98template <typename T> void SetExpr(const T &x, Expr<SomeType> &&expr) {
99 SetExprHelper{GenericExprWrapper{std::move(expr)}}.Set(x);
100}
101
102class ExpressionAnalyzer {
103public:
104 using MaybeExpr = std::optional<Expr<SomeType>>;
105
106 explicit ExpressionAnalyzer(semantics::SemanticsContext &sc) : context_{sc} {}
107 ExpressionAnalyzer(semantics::SemanticsContext &sc, FoldingContext &fc)
108 : context_{sc}, foldingContext_{fc} {}
109 ExpressionAnalyzer(const ExpressionAnalyzer &) = default;
110
111 semantics::SemanticsContext &context() const { return context_; }
112 bool inWhereBody() const { return inWhereBody_; }
113 void set_inWhereBody(bool yes = true) { inWhereBody_ = yes; }
114 bool inDataStmtObject() const { return inDataStmtObject_; }
115 void set_inDataStmtObject(bool yes = true) { inDataStmtObject_ = yes; }
116
117 FoldingContext &GetFoldingContext() const { return foldingContext_; }
118
119 parser::ContextualMessages &GetContextualMessages() {
120 return foldingContext_.messages();
121 }
122
123 template <typename... A> parser::Message *Say(A &&...args) {
124 return GetContextualMessages().Say(std::forward<A>(args)...);
125 }
126 template <typename FeatureOrUsageWarning, typename... A>
127 parser::Message *Warn(
128 FeatureOrUsageWarning warning, parser::CharBlock at, A &&...args) {
129 return context_.Warn(warning, at, std::forward<A>(args)...);
130 }
131 template <typename FeatureOrUsageWarning, typename... A>
132 parser::Message *Warn(FeatureOrUsageWarning warning, A &&...args) {
133 return Warn(
134 warning, GetContextualMessages().at(), std::forward<A>(args)...);
135 }
136
137 template <typename T, typename... A>
138 parser::Message *SayAt(const T &parsed, A &&...args) {
139 return Say(parser::FindSourceLocation(parsed), std::forward<A>(args)...);
140 }
141
142 int GetDefaultKind(common::TypeCategory);
143 DynamicType GetDefaultKindOfType(common::TypeCategory);
144
145 // Return false and emit error if these checks fail:
146 bool CheckIntrinsicKind(TypeCategory, std::int64_t kind);
147 bool CheckIntrinsicSize(TypeCategory, std::int64_t size);
148
149 // Manage a set of active implied DO loops.
150 bool AddImpliedDo(parser::CharBlock, int kind);
151 void RemoveImpliedDo(parser::CharBlock);
152
153 // When the argument is the name of an active implied DO index, returns
154 // its INTEGER kind type parameter.
155 std::optional<int> IsImpliedDo(parser::CharBlock) const;
156
157 common::Restorer<bool> DoNotUseSavedTypedExprs() {
158 return common::ScopedSet(useSavedTypedExprs_, false);
159 }
160
161 Expr<SubscriptInteger> AnalyzeKindSelector(common::TypeCategory category,
162 const std::optional<parser::KindSelector> &);
163
164 MaybeExpr Analyze(const parser::Expr &);
165 MaybeExpr Analyze(const parser::Variable &);
166 MaybeExpr Analyze(const parser::Selector &);
167 MaybeExpr Analyze(const parser::Designator &);
168 MaybeExpr Analyze(const parser::DataStmtValue &);
169 MaybeExpr Analyze(const parser::AllocateObject &);
170 MaybeExpr Analyze(const parser::PointerObject &);
171
172 template <typename A> MaybeExpr Analyze(const common::Indirection<A> &x) {
173 return Analyze(x.value());
174 }
175 template <typename A> MaybeExpr Analyze(const std::optional<A> &x) {
176 if (x) {
177 return Analyze(*x);
178 } else {
179 return std::nullopt;
180 }
181 }
182
183 // Implement constraint-checking wrappers from the Fortran grammar.
184 template <typename A> MaybeExpr Analyze(const parser::Scalar<A> &x) {
185 auto result{Analyze(x.thing)};
186 if (result) {
187 if (int rank{result->Rank()}; rank != 0) {
188 SayAt(x, "Must be a scalar value, but is a rank-%d array"_err_en_US,
189 rank);
190 ResetExpr(x);
191 return std::nullopt;
192 }
193 }
194 return result;
195 }
196 template <typename A> MaybeExpr Analyze(const parser::Constant<A> &x) {
197 auto restorer{
198 GetFoldingContext().messages().SetLocation(FindSourceLocation(x))};
199 auto result{Analyze(x.thing)};
200 if (result) {
201 *result = Fold(std::move(*result));
202 if (!IsConstantExpr(*result)) { // C886, C887, C713
203 SayAt(x, "Must be a constant value"_err_en_US);
204 ResetExpr(x);
205 return std::nullopt;
206 } else {
207 // Save folded expression for later use
208 SetExpr(x, common::Clone(*result));
209 }
210 }
211 return result;
212 }
213 template <typename A> MaybeExpr Analyze(const parser::Integer<A> &x) {
214 auto result{Analyze(x.thing)};
215 if (!EnforceTypeConstraint(
216 parser::FindSourceLocation(x), result, TypeCategory::Integer)) {
217 ResetExpr(x);
218 return std::nullopt;
219 }
220 return result;
221 }
222 template <typename A> MaybeExpr Analyze(const parser::Logical<A> &x) {
223 auto result{Analyze(x.thing)};
224 if (!EnforceTypeConstraint(
225 parser::FindSourceLocation(x), result, TypeCategory::Logical)) {
226 ResetExpr(x);
227 return std::nullopt;
228 }
229 return result;
230 }
231 template <typename A> MaybeExpr Analyze(const parser::DefaultChar<A> &x) {
232 auto result{Analyze(x.thing)};
233 if (!EnforceTypeConstraint(parser::FindSourceLocation(x), result,
234 TypeCategory::Character, true /* default kind */)) {
235 ResetExpr(x);
236 return std::nullopt;
237 }
238 return result;
239 }
240
241 MaybeExpr Analyze(const parser::Name &);
242 MaybeExpr Analyze(const parser::DataRef &dr) {
243 return Analyze<parser::DataRef>(dr);
244 }
245 MaybeExpr Analyze(const parser::StructureComponent &);
246 MaybeExpr Analyze(const parser::SignedIntLiteralConstant &);
247 MaybeExpr Analyze(const parser::SignedRealLiteralConstant &);
248 MaybeExpr Analyze(const parser::SignedComplexLiteralConstant &);
249 MaybeExpr Analyze(const parser::StructureConstructor &);
250 MaybeExpr Analyze(const parser::InitialDataTarget &);
251 MaybeExpr Analyze(const parser::NullInit &);
252 MaybeExpr Analyze(const parser::StmtFunctionStmt &);
253
254 void Analyze(const parser::CallStmt &);
255 const Assignment *Analyze(const parser::AssignmentStmt &);
256 const Assignment *Analyze(const parser::PointerAssignmentStmt &);
257
258 // Builds a typed Designator from an untyped DataRef
259 MaybeExpr Designate(DataRef &&);
260 void CheckForWholeAssumedSizeArray(parser::CharBlock, const Symbol *);
261
262 // Allows a whole assumed-size array to appear for the lifetime of
263 // the returned value.
264 common::Restorer<bool> AllowWholeAssumedSizeArray(bool yes = true) {
265 return common::ScopedSet(isWholeAssumedSizeArrayOk_, yes);
266 }
267
268protected:
269 int IntegerTypeSpecKind(const parser::IntegerTypeSpec &);
270
271private:
272 // Allows an Expr to be a null pointer.
273 common::Restorer<bool> AllowNullPointer() {
274 return common::ScopedSet(isNullPointerOk_, true);
275 }
276
277 MaybeExpr Analyze(const parser::IntLiteralConstant &, bool negated = false);
278 MaybeExpr Analyze(const parser::UnsignedLiteralConstant &);
279 MaybeExpr Analyze(const parser::RealLiteralConstant &);
280 MaybeExpr Analyze(const parser::ComplexPart &);
281 MaybeExpr Analyze(const parser::ComplexLiteralConstant &);
282 MaybeExpr Analyze(const parser::LogicalLiteralConstant &);
283 MaybeExpr Analyze(const parser::CharLiteralConstant &);
284 MaybeExpr Analyze(const parser::HollerithLiteralConstant &);
285 MaybeExpr Analyze(const parser::BOZLiteralConstant &);
286 MaybeExpr Analyze(const parser::NamedConstant &);
287 MaybeExpr Analyze(const parser::DataStmtConstant &);
288 MaybeExpr Analyze(const parser::Substring &);
289 MaybeExpr Analyze(const parser::ArrayElement &);
290 MaybeExpr Analyze(const parser::CoindexedNamedObject &);
291 MaybeExpr Analyze(const parser::CharLiteralConstantSubstring &);
292 MaybeExpr Analyze(const parser::SubstringInquiry &);
293 MaybeExpr Analyze(const parser::ArrayConstructor &);
294 MaybeExpr Analyze(const parser::FunctionReference &,
295 std::optional<parser::StructureConstructor> * = nullptr);
296 MaybeExpr Analyze(const parser::Expr::Parentheses &);
297 MaybeExpr Analyze(const parser::Expr::UnaryPlus &);
298 MaybeExpr Analyze(const parser::Expr::Negate &);
299 MaybeExpr Analyze(const parser::Expr::NOT &);
300 MaybeExpr Analyze(const parser::Expr::PercentLoc &);
301 MaybeExpr Analyze(const parser::Expr::DefinedUnary &);
302 MaybeExpr Analyze(const parser::Expr::Power &);
303 MaybeExpr Analyze(const parser::Expr::Multiply &);
304 MaybeExpr Analyze(const parser::Expr::Divide &);
305 MaybeExpr Analyze(const parser::Expr::Add &);
306 MaybeExpr Analyze(const parser::Expr::Subtract &);
307 MaybeExpr Analyze(const parser::Expr::ComplexConstructor &);
308 MaybeExpr Analyze(const parser::Expr::Concat &);
309 MaybeExpr Analyze(const parser::Expr::LT &);
310 MaybeExpr Analyze(const parser::Expr::LE &);
311 MaybeExpr Analyze(const parser::Expr::EQ &);
312 MaybeExpr Analyze(const parser::Expr::NE &);
313 MaybeExpr Analyze(const parser::Expr::GE &);
314 MaybeExpr Analyze(const parser::Expr::GT &);
315 MaybeExpr Analyze(const parser::Expr::AND &);
316 MaybeExpr Analyze(const parser::Expr::OR &);
317 MaybeExpr Analyze(const parser::Expr::EQV &);
318 MaybeExpr Analyze(const parser::Expr::NEQV &);
319 MaybeExpr Analyze(const parser::Expr::DefinedBinary &);
320 template <typename A> MaybeExpr Analyze(const A &x) {
321 return Analyze(x.u); // default case
322 }
323 template <typename... As> MaybeExpr Analyze(const std::variant<As...> &u) {
324 return common::visit([&](const auto &x) { return Analyze(x); }, u);
325 }
326
327 // Analysis subroutines
328 int AnalyzeKindParam(
329 const std::optional<parser::KindParam> &, int defaultKind);
330 template <typename PARSED>
331 MaybeExpr ExprOrVariable(const PARSED &, parser::CharBlock source);
332 template <typename TYPES, TypeCategory CAT, typename PARSED>
333 MaybeExpr IntLiteralConstant(const PARSED &, bool isNegated = false);
334 MaybeExpr AnalyzeString(std::string &&, int kind);
335 std::optional<Expr<SubscriptInteger>> AsSubscript(MaybeExpr &&);
336 std::optional<Expr<SubscriptInteger>> TripletPart(
337 const std::optional<parser::Subscript> &);
338 std::optional<Subscript> AnalyzeSectionSubscript(
340 std::vector<Subscript> AnalyzeSectionSubscripts(
341 const std::list<parser::SectionSubscript> &);
342 std::optional<Component> CreateComponent(DataRef &&, const Symbol &,
343 const semantics::Scope &, bool C919bAlreadyEnforced = false);
344 MaybeExpr CompleteSubscripts(ArrayRef &&);
345 MaybeExpr ApplySubscripts(DataRef &&, std::vector<Subscript> &&);
346 bool CheckRanks(const DataRef &); // Return false if error exists.
347 bool CheckPolymorphic(const DataRef &); // ditto
348 bool CheckDataRef(const DataRef &); // ditto
349 std::optional<Expr<SubscriptInteger>> GetSubstringBound(
350 const std::optional<parser::ScalarIntExpr> &);
351 MaybeExpr AnalyzeDefinedOp(
352 const parser::Name &, ActualArguments &&, const Symbol *&);
353 MaybeExpr FixMisparsedSubstring(const parser::Designator &);
354
355 struct CalleeAndArguments {
356 // A non-component function reference may constitute a misparsed
357 // structure constructor, in which case its derived type's Symbol
358 // will appear here.
359 std::variant<ProcedureDesignator, SymbolRef> u;
360 ActualArguments arguments;
361 };
362
363 std::optional<CalleeAndArguments> AnalyzeProcedureComponentRef(
364 const parser::ProcComponentRef &, ActualArguments &&, bool isSubroutine);
365 std::optional<characteristics::Procedure> CheckCall(
366 parser::CharBlock, const ProcedureDesignator &, ActualArguments &);
367 using AdjustActuals =
368 std::optional<std::function<bool(const Symbol &, ActualArguments &)>>;
369 const Symbol *ResolveForward(const Symbol &);
370 struct GenericResolution {
371 const Symbol *specific{nullptr};
372 bool failedDueToAmbiguity{false};
373 SymbolVector tried{};
374 };
375 GenericResolution ResolveGeneric(const Symbol &, const ActualArguments &,
376 const AdjustActuals &, bool isSubroutine, SymbolVector &&tried,
377 bool mightBeStructureConstructor = false);
378 void EmitGenericResolutionError(const Symbol &, bool dueToNullActuals,
379 bool isSubroutine, ActualArguments &, const SymbolVector &);
380 const Symbol &AccessSpecific(
381 const Symbol &originalGeneric, const Symbol &specific);
382 std::optional<CalleeAndArguments> GetCalleeAndArguments(const parser::Name &,
383 ActualArguments &&, bool isSubroutine = false,
384 bool mightBeStructureConstructor = false);
385 std::optional<CalleeAndArguments> GetCalleeAndArguments(
386 const parser::ProcedureDesignator &, ActualArguments &&,
387 bool isSubroutine, bool mightBeStructureConstructor = false);
388 void CheckBadExplicitType(const SpecificCall &, const Symbol &);
389 void CheckForBadRecursion(parser::CharBlock, const semantics::Symbol &);
390 bool EnforceTypeConstraint(parser::CharBlock, const MaybeExpr &, TypeCategory,
391 bool defaultKind = false);
392 MaybeExpr MakeFunctionRef(
393 parser::CharBlock, ProcedureDesignator &&, ActualArguments &&);
394 MaybeExpr MakeFunctionRef(parser::CharBlock intrinsic, ActualArguments &&);
395 template <typename T> T Fold(T &&expr) {
396 return evaluate::Fold(foldingContext_, std::move(expr));
397 }
398 bool CheckIsValidForwardReference(const semantics::DerivedTypeSpec &);
399 MaybeExpr AnalyzeComplex(MaybeExpr &&re, MaybeExpr &&im, const char *what);
400 std::optional<Chevrons> AnalyzeChevrons(const parser::CallStmt &);
401
402 // CheckStructureConstructor() is used for parsed structure constructors
403 // as well as for generic function references.
404 struct ComponentSpec {
405 ComponentSpec() = default;
406 ComponentSpec(ComponentSpec &&) = default;
407 parser::CharBlock source, exprSource;
408 bool hasKeyword{false};
409 const Symbol *keywordSymbol{nullptr};
410 MaybeExpr expr;
411 };
412 MaybeExpr CheckStructureConstructor(parser::CharBlock typeName,
413 const semantics::DerivedTypeSpec &, std::list<ComponentSpec> &&);
414
415 MaybeExpr IterativelyAnalyzeSubexpressions(const parser::Expr &);
416
418 FoldingContext &foldingContext_{context_.foldingContext()};
419 std::map<parser::CharBlock, int> impliedDos_; // values are INTEGER kinds
420 std::map<parser::CharBlock,
421 std::pair<parser::CharBlock, evaluate::characteristics::Procedure>>
422 implicitInterfaces_;
423 bool isWholeAssumedSizeArrayOk_{false};
424 bool isNullPointerOk_{false};
425 bool useSavedTypedExprs_{true};
426 bool inWhereBody_{false};
427 bool inDataStmtObject_{false};
428 bool inDataStmtConstant_{false};
429 bool inStmtFunctionDefinition_{false};
430 bool iterativelyAnalyzingSubexpressions_{false};
431 friend class ArgumentAnalyzer;
432};
433
434inline bool AreConformable(int leftRank, int rightRank) {
435 return leftRank == 0 || rightRank == 0 || leftRank == rightRank;
436}
437
438template <typename L, typename R>
439bool AreConformable(const L &left, const R &right) {
440 return AreConformable(left.Rank(), right.Rank());
441}
442
443template <typename L, typename R>
444void ConformabilityCheck(
445 parser::ContextualMessages &context, const L &left, const R &right) {
446 if (!AreConformable(left, right)) {
447 context.Say("left operand has rank %d, right operand has rank %d"_err_en_US,
448 left.Rank(), right.Rank());
449 }
450}
451} // namespace Fortran::evaluate
452
453namespace Fortran::semantics {
454
455// Semantic analysis of one expression, variable, selector, designator, &c.
456template <typename A>
457std::optional<evaluate::Expr<evaluate::SomeType>> AnalyzeExpr(
458 SemanticsContext &context, const A &expr) {
459 return evaluate::ExpressionAnalyzer{context}.Analyze(expr);
460}
461
462// Semantic analysis of an intrinsic type's KIND parameter expression.
463evaluate::Expr<evaluate::SubscriptInteger> AnalyzeKindSelector(
464 SemanticsContext &, common::TypeCategory,
465 const std::optional<parser::KindSelector> &);
466
467// Semantic analysis of all expressions in a parse tree, which becomes
468// decorated with typed representations for top-level expressions.
469class ExprChecker {
470public:
471 explicit ExprChecker(SemanticsContext &);
472
473 template <typename A> bool Pre(const A &) { return true; }
474 template <typename A> void Post(const A &) {}
475 bool Walk(const parser::Program &);
476
477 bool Pre(const parser::Expr &x) {
478 exprAnalyzer_.Analyze(x);
479 return false;
480 }
481 bool Pre(const parser::Variable &x) {
482 exprAnalyzer_.Analyze(x);
483 return false;
484 }
485 bool Pre(const parser::Selector &x) {
486 exprAnalyzer_.Analyze(x);
487 return false;
488 }
489 bool Pre(const parser::DataStmtValue &x) {
490 exprAnalyzer_.Analyze(x);
491 return false;
492 }
493 bool Pre(const parser::AllocateObject &x) {
494 exprAnalyzer_.Analyze(x);
495 return false;
496 }
497 bool Pre(const parser::PointerObject &x) {
498 exprAnalyzer_.Analyze(x);
499 return false;
500 }
501 bool Pre(const parser::DataStmtObject &);
502 void Post(const parser::DataStmtObject &);
503 bool Pre(const parser::DataImpliedDo &);
504
505 bool Pre(const parser::CallStmt &x) {
506 exprAnalyzer_.Analyze(x);
507 return false;
508 }
509 bool Pre(const parser::AssignmentStmt &x) {
510 exprAnalyzer_.Analyze(x);
511 return false;
512 }
513 bool Pre(const parser::PointerAssignmentStmt &x) {
514 exprAnalyzer_.Analyze(x);
515 return false;
516 }
517
518 // Track whether we're in a WHERE statement or construct body
519 bool Pre(const parser::WhereStmt &) {
520 ++whereDepth_;
521 exprAnalyzer_.set_inWhereBody(InWhereBody());
522 return true;
523 }
524 void Post(const parser::WhereStmt &) {
525 --whereDepth_;
526 exprAnalyzer_.set_inWhereBody(InWhereBody());
527 }
528 bool Pre(const parser::WhereBodyConstruct &) {
529 ++whereDepth_;
530 exprAnalyzer_.set_inWhereBody(InWhereBody());
531 return true;
532 }
533 void Post(const parser::WhereBodyConstruct &) {
534 --whereDepth_;
535 exprAnalyzer_.set_inWhereBody(InWhereBody());
536 }
537
538 bool Pre(const parser::ComponentDefStmt &) {
539 inComponentDefStmt_ = true;
540 return true;
541 }
542 void Post(const parser::ComponentDefStmt &) { inComponentDefStmt_ = false; }
543 bool Pre(const parser::KindSelector &) { return !inComponentDefStmt_; }
544 bool Pre(const parser::Initialization &x) {
545 // Default component initialization expressions (but not DATA-like ones
546 // as in DEC STRUCTUREs) were already analyzed in name resolution
547 // and PDT instantiation; do not attempt to re-analyze them without
548 // type parameters.
549 return !inComponentDefStmt_ ||
550 std::holds_alternative<
551 std::list<common::Indirection<parser::DataStmtValue>>>(x.u);
552 }
553
554 template <typename A> bool Pre(const parser::Scalar<A> &x) {
555 exprAnalyzer_.Analyze(x);
556 return false;
557 }
558 template <typename A> bool Pre(const parser::Constant<A> &x) {
559 exprAnalyzer_.Analyze(x);
560 return false;
561 }
562 template <typename A> bool Pre(const parser::Integer<A> &x) {
563 exprAnalyzer_.Analyze(x);
564 return false;
565 }
566 template <typename A> bool Pre(const parser::Logical<A> &x) {
567 exprAnalyzer_.Analyze(x);
568 return false;
569 }
570 template <typename A> bool Pre(const parser::DefaultChar<A> &x) {
571 exprAnalyzer_.Analyze(x);
572 return false;
573 }
574
575private:
576 bool InWhereBody() const { return whereDepth_ > 0; }
577
578 SemanticsContext &context_;
579 evaluate::ExpressionAnalyzer exprAnalyzer_{context_};
580 int whereDepth_{0}; // nesting of WHERE statements & constructs
581 bool inComponentDefStmt_{false};
582};
583} // namespace Fortran::semantics
584#endif // FORTRAN_SEMANTICS_EXPRESSION_H_
Definition indirection.h:31
Definition restorer.h:24
Definition variable.h:205
Definition expression.h:878
Definition type.h:74
Definition common.h:214
Definition expression.h:102
Definition common.h:216
Definition char-block.h:28
Definition message.h:386
Definition message.h:190
Definition scope.h:58
Definition semantics.h:67
Definition symbol.h:791
Definition call.h:34
Definition check-expression.h:19
Definition variable.h:284
Definition expression.h:896
Definition expression.h:72
Definition intrinsics.h:45
Definition parse-tree.h:1927
Definition parse-tree.h:1915
Definition parse-tree.h:2020
Definition parse-tree.h:3280
Definition parse-tree.h:871
Definition parse-tree.h:1906
Definition parse-tree.h:857
Definition parse-tree.h:849
Definition parse-tree.h:1119
Definition parse-tree.h:302
Definition parse-tree.h:1531
Definition parse-tree.h:1822
Definition parse-tree.h:1490
Definition parse-tree.h:1539
Definition parse-tree.h:1511
Definition parse-tree.h:326
Definition parse-tree.h:1861
Definition parse-tree.h:1768
Definition parse-tree.h:1741
Definition parse-tree.h:1782
Definition parse-tree.h:1747
Definition parse-tree.h:1786
Definition parse-tree.h:1723
Definition parse-tree.h:1738
Definition parse-tree.h:1774
Definition parse-tree.h:1756
Definition parse-tree.h:1762
Definition parse-tree.h:1765
Definition parse-tree.h:1753
Definition parse-tree.h:1750
Definition parse-tree.h:1735
Definition parse-tree.h:1777
Definition parse-tree.h:1759
Definition parse-tree.h:1717
Definition parse-tree.h:1714
Definition parse-tree.h:1771
Definition parse-tree.h:1708
Definition parse-tree.h:1732
Definition parse-tree.h:1744
Definition parse-tree.h:1711
Definition parse-tree.h:1704
Definition parse-tree.h:3268
Definition tools.h:134
Definition tools.h:140
Definition parse-tree.h:1029
Definition parse-tree.h:805
Definition parse-tree.h:310
Definition parse-tree.h:654
Definition parse-tree.h:885
Definition parse-tree.h:318
Definition parse-tree.h:583
Definition parse-tree.h:2044
Definition parse-tree.h:2003
Definition parse-tree.h:1901
Definition parse-tree.h:3235
Definition parse-tree.h:824
Definition parse-tree.h:294
Definition parse-tree.h:1675
Definition parse-tree.h:2155
Definition parse-tree.h:3346
Definition parse-tree.h:1891
Definition parse-tree.h:1229
Definition parse-tree.h:1853
Definition parse-tree.h:1839
Definition parse-tree.h:811
Definition parse-tree.h:1869
Definition parse-tree.h:2070
Definition parse-tree.h:2057