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