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