Warning: This file is not a C or C++ file. It does not have highlighting.
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/Fortran.h" |
14 | #include "flang/Common/indirection.h" |
15 | #include "flang/Common/restorer.h" |
16 | #include "flang/Common/visit.h" |
17 | #include "flang/Evaluate/characteristics.h" |
18 | #include "flang/Evaluate/check-expression.h" |
19 | #include "flang/Evaluate/expression.h" |
20 | #include "flang/Evaluate/fold.h" |
21 | #include "flang/Evaluate/tools.h" |
22 | #include "flang/Evaluate/type.h" |
23 | #include "flang/Parser/char-block.h" |
24 | #include "flang/Parser/parse-tree-visitor.h" |
25 | #include "flang/Parser/parse-tree.h" |
26 | #include "flang/Parser/tools.h" |
27 | #include <map> |
28 | #include <optional> |
29 | #include <type_traits> |
30 | #include <variant> |
31 | |
32 | using namespace Fortran::parser::literals; |
33 | |
34 | namespace Fortran::parser { |
35 | struct SourceLocationFindingVisitor { |
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 | |
50 | template <typename A> CharBlock FindSourceLocation(const A &x) { |
51 | SourceLocationFindingVisitor visitor; |
52 | Walk(x, visitor); |
53 | return visitor.source; |
54 | } |
55 | } // namespace Fortran::parser |
56 | |
57 | using 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 | |
68 | namespace Fortran::evaluate { |
69 | |
70 | class IntrinsicProcTable; |
71 | |
72 | struct 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 | |
91 | GenericExprWrapper expr_; |
92 | }; |
93 | |
94 | template <typename T> void ResetExpr(const T &x) { |
95 | SetExprHelper{GenericExprWrapper{/* error indicator */}}.Set(x); |
96 | } |
97 | |
98 | template <typename T> void SetExpr(const T &x, Expr<SomeType> &&expr) { |
99 | SetExprHelper{GenericExprWrapper{std::move(expr)}}.Set(x); |
100 | } |
101 | |
102 | class ExpressionAnalyzer { |
103 | public: |
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 | |
127 | template <typename T, typename... A> |
128 | parser::Message *SayAt(const T &parsed, A &&...args) { |
129 | return Say(parser::FindSourceLocation(parsed), std::forward<A>(args)...); |
130 | } |
131 | |
132 | int GetDefaultKind(common::TypeCategory); |
133 | DynamicType GetDefaultKindOfType(common::TypeCategory); |
134 | |
135 | // Return false and emit error if these checks fail: |
136 | bool CheckIntrinsicKind(TypeCategory, std::int64_t kind); |
137 | bool CheckIntrinsicSize(TypeCategory, std::int64_t size); |
138 | |
139 | // Manage a set of active implied DO loops. |
140 | bool AddImpliedDo(parser::CharBlock, int kind); |
141 | void RemoveImpliedDo(parser::CharBlock); |
142 | |
143 | // When the argument is the name of an active implied DO index, returns |
144 | // its INTEGER kind type parameter. |
145 | std::optional<int> IsImpliedDo(parser::CharBlock) const; |
146 | |
147 | common::Restorer<bool> DoNotUseSavedTypedExprs() { |
148 | return common::ScopedSet(useSavedTypedExprs_, false); |
149 | } |
150 | |
151 | Expr<SubscriptInteger> AnalyzeKindSelector(common::TypeCategory category, |
152 | const std::optional<parser::KindSelector> &); |
153 | |
154 | MaybeExpr Analyze(const parser::Expr &); |
155 | MaybeExpr Analyze(const parser::Variable &); |
156 | MaybeExpr Analyze(const parser::Selector &); |
157 | MaybeExpr Analyze(const parser::Designator &); |
158 | MaybeExpr Analyze(const parser::DataStmtValue &); |
159 | MaybeExpr Analyze(const parser::AllocateObject &); |
160 | MaybeExpr Analyze(const parser::PointerObject &); |
161 | |
162 | template <typename A> MaybeExpr Analyze(const common::Indirection<A> &x) { |
163 | return Analyze(x.value()); |
164 | } |
165 | template <typename A> MaybeExpr Analyze(const std::optional<A> &x) { |
166 | if (x) { |
167 | return Analyze(*x); |
168 | } else { |
169 | return std::nullopt; |
170 | } |
171 | } |
172 | |
173 | // Implement constraint-checking wrappers from the Fortran grammar. |
174 | template <typename A> MaybeExpr Analyze(const parser::Scalar<A> &x) { |
175 | auto result{Analyze(x.thing)}; |
176 | if (result) { |
177 | if (int rank{result->Rank()}; rank != 0) { |
178 | SayAt(x, "Must be a scalar value, but is a rank-%d array"_err_en_US, |
179 | rank); |
180 | ResetExpr(x); |
181 | return std::nullopt; |
182 | } |
183 | } |
184 | return result; |
185 | } |
186 | template <typename A> MaybeExpr Analyze(const parser::Constant<A> &x) { |
187 | auto restorer{ |
188 | GetFoldingContext().messages().SetLocation(FindSourceLocation(x))}; |
189 | auto result{Analyze(x.thing)}; |
190 | if (result) { |
191 | *result = Fold(std::move(*result)); |
192 | if (!IsConstantExpr(*result)) { // C886, C887, C713 |
193 | SayAt(x, "Must be a constant value"_err_en_US); |
194 | ResetExpr(x); |
195 | return std::nullopt; |
196 | } else { |
197 | // Save folded expression for later use |
198 | SetExpr(x, common::Clone(*result)); |
199 | } |
200 | } |
201 | return result; |
202 | } |
203 | template <typename A> MaybeExpr Analyze(const parser::Integer<A> &x) { |
204 | auto result{Analyze(x.thing)}; |
205 | if (!EnforceTypeConstraint( |
206 | parser::FindSourceLocation(x), result, TypeCategory::Integer)) { |
207 | ResetExpr(x); |
208 | return std::nullopt; |
209 | } |
210 | return result; |
211 | } |
212 | template <typename A> MaybeExpr Analyze(const parser::Logical<A> &x) { |
213 | auto result{Analyze(x.thing)}; |
214 | if (!EnforceTypeConstraint( |
215 | parser::FindSourceLocation(x), result, TypeCategory::Logical)) { |
216 | ResetExpr(x); |
217 | return std::nullopt; |
218 | } |
219 | return result; |
220 | } |
221 | template <typename A> MaybeExpr Analyze(const parser::DefaultChar<A> &x) { |
222 | auto result{Analyze(x.thing)}; |
223 | if (!EnforceTypeConstraint(parser::FindSourceLocation(x), result, |
224 | TypeCategory::Character, true /* default kind */)) { |
225 | ResetExpr(x); |
226 | return std::nullopt; |
227 | } |
228 | return result; |
229 | } |
230 | |
231 | MaybeExpr Analyze(const parser::Name &); |
232 | MaybeExpr Analyze(const parser::DataRef &dr) { |
233 | return Analyze<parser::DataRef>(dr); |
234 | } |
235 | MaybeExpr Analyze(const parser::StructureComponent &); |
236 | MaybeExpr Analyze(const parser::SignedIntLiteralConstant &); |
237 | MaybeExpr Analyze(const parser::SignedRealLiteralConstant &); |
238 | MaybeExpr Analyze(const parser::SignedComplexLiteralConstant &); |
239 | MaybeExpr Analyze(const parser::StructureConstructor &); |
240 | MaybeExpr Analyze(const parser::InitialDataTarget &); |
241 | MaybeExpr Analyze(const parser::NullInit &); |
242 | MaybeExpr Analyze(const parser::StmtFunctionStmt &); |
243 | |
244 | void Analyze(const parser::CallStmt &); |
245 | const Assignment *Analyze(const parser::AssignmentStmt &); |
246 | const Assignment *Analyze(const parser::PointerAssignmentStmt &); |
247 | |
248 | // Builds a typed Designator from an untyped DataRef |
249 | MaybeExpr Designate(DataRef &&); |
250 | |
251 | protected: |
252 | int IntegerTypeSpecKind(const parser::IntegerTypeSpec &); |
253 | |
254 | private: |
255 | // Allows a whole assumed-size array to appear for the lifetime of |
256 | // the returned value. |
257 | common::Restorer<bool> AllowWholeAssumedSizeArray() { |
258 | return common::ScopedSet(isWholeAssumedSizeArrayOk_, true); |
259 | } |
260 | |
261 | // Allows an Expr to be a null pointer. |
262 | common::Restorer<bool> AllowNullPointer() { |
263 | return common::ScopedSet(isNullPointerOk_, true); |
264 | } |
265 | |
266 | MaybeExpr Analyze(const parser::IntLiteralConstant &, bool negated = false); |
267 | MaybeExpr Analyze(const parser::RealLiteralConstant &); |
268 | MaybeExpr Analyze(const parser::ComplexPart &); |
269 | MaybeExpr Analyze(const parser::ComplexLiteralConstant &); |
270 | MaybeExpr Analyze(const parser::LogicalLiteralConstant &); |
271 | MaybeExpr Analyze(const parser::CharLiteralConstant &); |
272 | MaybeExpr Analyze(const parser::HollerithLiteralConstant &); |
273 | MaybeExpr Analyze(const parser::BOZLiteralConstant &); |
274 | MaybeExpr Analyze(const parser::NamedConstant &); |
275 | MaybeExpr Analyze(const parser::DataStmtConstant &); |
276 | MaybeExpr Analyze(const parser::Substring &); |
277 | MaybeExpr Analyze(const parser::ArrayElement &); |
278 | MaybeExpr Analyze(const parser::CoindexedNamedObject &); |
279 | MaybeExpr Analyze(const parser::CharLiteralConstantSubstring &); |
280 | MaybeExpr Analyze(const parser::SubstringInquiry &); |
281 | MaybeExpr Analyze(const parser::ArrayConstructor &); |
282 | MaybeExpr Analyze(const parser::FunctionReference &, |
283 | std::optional<parser::StructureConstructor> * = nullptr); |
284 | MaybeExpr Analyze(const parser::Expr::Parentheses &); |
285 | MaybeExpr Analyze(const parser::Expr::UnaryPlus &); |
286 | MaybeExpr Analyze(const parser::Expr::Negate &); |
287 | MaybeExpr Analyze(const parser::Expr::NOT &); |
288 | MaybeExpr Analyze(const parser::Expr::PercentLoc &); |
289 | MaybeExpr Analyze(const parser::Expr::DefinedUnary &); |
290 | MaybeExpr Analyze(const parser::Expr::Power &); |
291 | MaybeExpr Analyze(const parser::Expr::Multiply &); |
292 | MaybeExpr Analyze(const parser::Expr::Divide &); |
293 | MaybeExpr Analyze(const parser::Expr::Add &); |
294 | MaybeExpr Analyze(const parser::Expr::Subtract &); |
295 | MaybeExpr Analyze(const parser::Expr::ComplexConstructor &); |
296 | MaybeExpr Analyze(const parser::Expr::Concat &); |
297 | MaybeExpr Analyze(const parser::Expr::LT &); |
298 | MaybeExpr Analyze(const parser::Expr::LE &); |
299 | MaybeExpr Analyze(const parser::Expr::EQ &); |
300 | MaybeExpr Analyze(const parser::Expr::NE &); |
301 | MaybeExpr Analyze(const parser::Expr::GE &); |
302 | MaybeExpr Analyze(const parser::Expr::GT &); |
303 | MaybeExpr Analyze(const parser::Expr::AND &); |
304 | MaybeExpr Analyze(const parser::Expr::OR &); |
305 | MaybeExpr Analyze(const parser::Expr::EQV &); |
306 | MaybeExpr Analyze(const parser::Expr::NEQV &); |
307 | MaybeExpr Analyze(const parser::Expr::DefinedBinary &); |
308 | template <typename A> MaybeExpr Analyze(const A &x) { |
309 | return Analyze(x.u); // default case |
310 | } |
311 | template <typename... As> MaybeExpr Analyze(const std::variant<As...> &u) { |
312 | return common::visit([&](const auto &x) { return Analyze(x); }, u); |
313 | } |
314 | |
315 | // Analysis subroutines |
316 | int AnalyzeKindParam( |
317 | const std::optional<parser::KindParam> &, int defaultKind); |
318 | template <typename PARSED> |
319 | MaybeExpr ExprOrVariable(const PARSED &, parser::CharBlock source); |
320 | template <typename PARSED> |
321 | MaybeExpr IntLiteralConstant(const PARSED &, bool negated = false); |
322 | MaybeExpr AnalyzeString(std::string &&, int kind); |
323 | std::optional<Expr<SubscriptInteger>> AsSubscript(MaybeExpr &&); |
324 | std::optional<Expr<SubscriptInteger>> TripletPart( |
325 | const std::optional<parser::Subscript> &); |
326 | std::optional<Subscript> AnalyzeSectionSubscript( |
327 | const parser::SectionSubscript &); |
328 | std::vector<Subscript> AnalyzeSectionSubscripts( |
329 | const std::list<parser::SectionSubscript> &); |
330 | std::optional<Component> CreateComponent(DataRef &&, const Symbol &, |
331 | const semantics::Scope &, bool C919bAlreadyEnforced = false); |
332 | MaybeExpr CompleteSubscripts(ArrayRef &&); |
333 | MaybeExpr ApplySubscripts(DataRef &&, std::vector<Subscript> &&); |
334 | void CheckConstantSubscripts(ArrayRef &); |
335 | bool CheckRanks(const DataRef &); // Return false if error exists. |
336 | bool CheckPolymorphic(const DataRef &); // ditto |
337 | bool CheckDataRef(const DataRef &); // ditto |
338 | std::optional<Expr<SubscriptInteger>> GetSubstringBound( |
339 | const std::optional<parser::ScalarIntExpr> &); |
340 | MaybeExpr AnalyzeDefinedOp(const parser::Name &, ActualArguments &&); |
341 | MaybeExpr FixMisparsedSubstring(const parser::Designator &); |
342 | |
343 | struct CalleeAndArguments { |
344 | // A non-component function reference may constitute a misparsed |
345 | // structure constructor, in which case its derived type's Symbol |
346 | // will appear here. |
347 | std::variant<ProcedureDesignator, SymbolRef> u; |
348 | ActualArguments arguments; |
349 | }; |
350 | |
351 | std::optional<CalleeAndArguments> AnalyzeProcedureComponentRef( |
352 | const parser::ProcComponentRef &, ActualArguments &&, bool isSubroutine); |
353 | std::optional<characteristics::Procedure> CheckCall( |
354 | parser::CharBlock, const ProcedureDesignator &, ActualArguments &); |
355 | using AdjustActuals = |
356 | std::optional<std::function<bool(const Symbol &, ActualArguments &)>>; |
357 | bool ResolveForward(const Symbol &); |
358 | std::pair<const Symbol *, bool /* failure due ambiguity */> ResolveGeneric( |
359 | const Symbol &, const ActualArguments &, const AdjustActuals &, |
360 | bool isSubroutine, bool mightBeStructureConstructor = false); |
361 | void EmitGenericResolutionError( |
362 | const Symbol &, bool dueToNullActuals, bool isSubroutine); |
363 | const Symbol &AccessSpecific( |
364 | const Symbol &originalGeneric, const Symbol &specific); |
365 | std::optional<CalleeAndArguments> GetCalleeAndArguments(const parser::Name &, |
366 | ActualArguments &&, bool isSubroutine = false, |
367 | bool mightBeStructureConstructor = false); |
368 | std::optional<CalleeAndArguments> GetCalleeAndArguments( |
369 | const parser::ProcedureDesignator &, ActualArguments &&, |
370 | bool isSubroutine, bool mightBeStructureConstructor = false); |
371 | void CheckBadExplicitType(const SpecificCall &, const Symbol &); |
372 | void CheckForBadRecursion(parser::CharBlock, const semantics::Symbol &); |
373 | bool EnforceTypeConstraint(parser::CharBlock, const MaybeExpr &, TypeCategory, |
374 | bool defaultKind = false); |
375 | MaybeExpr MakeFunctionRef( |
376 | parser::CharBlock, ProcedureDesignator &&, ActualArguments &&); |
377 | MaybeExpr MakeFunctionRef(parser::CharBlock intrinsic, ActualArguments &&); |
378 | template <typename T> T Fold(T &&expr) { |
379 | return evaluate::Fold(foldingContext_, std::move(expr)); |
380 | } |
381 | bool CheckIsValidForwardReference(const semantics::DerivedTypeSpec &); |
382 | MaybeExpr AnalyzeComplex(MaybeExpr &&re, MaybeExpr &&im, const char *what); |
383 | std::optional<Chevrons> AnalyzeChevrons(const parser::CallStmt &); |
384 | |
385 | MaybeExpr IterativelyAnalyzeSubexpressions(const parser::Expr &); |
386 | |
387 | semantics::SemanticsContext &context_; |
388 | FoldingContext &foldingContext_{context_.foldingContext()}; |
389 | std::map<parser::CharBlock, int> impliedDos_; // values are INTEGER kinds |
390 | std::map<parser::CharBlock, |
391 | std::pair<parser::CharBlock, evaluate::characteristics::Procedure>> |
392 | implicitInterfaces_; |
393 | bool isWholeAssumedSizeArrayOk_{false}; |
394 | bool isNullPointerOk_{false}; |
395 | bool useSavedTypedExprs_{true}; |
396 | bool inWhereBody_{false}; |
397 | bool inDataStmtObject_{false}; |
398 | bool inDataStmtConstant_{false}; |
399 | bool inStmtFunctionDefinition_{false}; |
400 | bool iterativelyAnalyzingSubexpressions_{false}; |
401 | friend class ArgumentAnalyzer; |
402 | }; |
403 | |
404 | inline bool AreConformable(int leftRank, int rightRank) { |
405 | return leftRank == 0 || rightRank == 0 || leftRank == rightRank; |
406 | } |
407 | |
408 | template <typename L, typename R> |
409 | bool AreConformable(const L &left, const R &right) { |
410 | return AreConformable(left.Rank(), right.Rank()); |
411 | } |
412 | |
413 | template <typename L, typename R> |
414 | void ConformabilityCheck( |
415 | parser::ContextualMessages &context, const L &left, const R &right) { |
416 | if (!AreConformable(left, right)) { |
417 | context.Say("left operand has rank %d, right operand has rank %d"_err_en_US, |
418 | left.Rank(), right.Rank()); |
419 | } |
420 | } |
421 | } // namespace Fortran::evaluate |
422 | |
423 | namespace Fortran::semantics { |
424 | |
425 | // Semantic analysis of one expression, variable, selector, designator, &c. |
426 | template <typename A> |
427 | std::optional<evaluate::Expr<evaluate::SomeType>> AnalyzeExpr( |
428 | SemanticsContext &context, const A &expr) { |
429 | return evaluate::ExpressionAnalyzer{context}.Analyze(expr); |
430 | } |
431 | |
432 | // Semantic analysis of an intrinsic type's KIND parameter expression. |
433 | evaluate::Expr<evaluate::SubscriptInteger> AnalyzeKindSelector( |
434 | SemanticsContext &, common::TypeCategory, |
435 | const std::optional<parser::KindSelector> &); |
436 | |
437 | // Semantic analysis of all expressions in a parse tree, which becomes |
438 | // decorated with typed representations for top-level expressions. |
439 | class ExprChecker { |
440 | public: |
441 | explicit ExprChecker(SemanticsContext &); |
442 | |
443 | template <typename A> bool Pre(const A &) { return true; } |
444 | template <typename A> void Post(const A &) {} |
445 | bool Walk(const parser::Program &); |
446 | |
447 | bool Pre(const parser::Expr &x) { |
448 | exprAnalyzer_.Analyze(x); |
449 | return false; |
450 | } |
451 | bool Pre(const parser::Variable &x) { |
452 | exprAnalyzer_.Analyze(x); |
453 | return false; |
454 | } |
455 | bool Pre(const parser::Selector &x) { |
456 | exprAnalyzer_.Analyze(x); |
457 | return false; |
458 | } |
459 | bool Pre(const parser::DataStmtValue &x) { |
460 | exprAnalyzer_.Analyze(x); |
461 | return false; |
462 | } |
463 | bool Pre(const parser::AllocateObject &x) { |
464 | exprAnalyzer_.Analyze(x); |
465 | return false; |
466 | } |
467 | bool Pre(const parser::PointerObject &x) { |
468 | exprAnalyzer_.Analyze(x); |
469 | return false; |
470 | } |
471 | bool Pre(const parser::DataStmtObject &); |
472 | void Post(const parser::DataStmtObject &); |
473 | bool Pre(const parser::DataImpliedDo &); |
474 | |
475 | bool Pre(const parser::CallStmt &x) { |
476 | exprAnalyzer_.Analyze(x); |
477 | return false; |
478 | } |
479 | bool Pre(const parser::AssignmentStmt &x) { |
480 | exprAnalyzer_.Analyze(x); |
481 | return false; |
482 | } |
483 | bool Pre(const parser::PointerAssignmentStmt &x) { |
484 | exprAnalyzer_.Analyze(x); |
485 | return false; |
486 | } |
487 | |
488 | // Track whether we're in a WHERE statement or construct body |
489 | bool Pre(const parser::WhereStmt &) { |
490 | ++whereDepth_; |
491 | exprAnalyzer_.set_inWhereBody(InWhereBody()); |
492 | return true; |
493 | } |
494 | void Post(const parser::WhereStmt &) { |
495 | --whereDepth_; |
496 | exprAnalyzer_.set_inWhereBody(InWhereBody()); |
497 | } |
498 | bool Pre(const parser::WhereBodyConstruct &) { |
499 | ++whereDepth_; |
500 | exprAnalyzer_.set_inWhereBody(InWhereBody()); |
501 | return true; |
502 | } |
503 | void Post(const parser::WhereBodyConstruct &) { |
504 | --whereDepth_; |
505 | exprAnalyzer_.set_inWhereBody(InWhereBody()); |
506 | } |
507 | |
508 | bool Pre(const parser::ComponentDefStmt &) { |
509 | inComponentDefStmt_ = true; |
510 | return true; |
511 | } |
512 | void Post(const parser::ComponentDefStmt &) { inComponentDefStmt_ = false; } |
513 | bool Pre(const parser::Initialization &x) { |
514 | // Default component initialization expressions (but not DATA-like ones |
515 | // as in DEC STRUCTUREs) were already analyzed in name resolution |
516 | // and PDT instantiation; do not attempt to re-analyze them without |
517 | // type parameters. |
518 | return !inComponentDefStmt_ || |
519 | std::holds_alternative< |
520 | std::list<common::Indirection<parser::DataStmtValue>>>(x.u); |
521 | } |
522 | |
523 | template <typename A> bool Pre(const parser::Scalar<A> &x) { |
524 | exprAnalyzer_.Analyze(x); |
525 | return false; |
526 | } |
527 | template <typename A> bool Pre(const parser::Constant<A> &x) { |
528 | exprAnalyzer_.Analyze(x); |
529 | return false; |
530 | } |
531 | template <typename A> bool Pre(const parser::Integer<A> &x) { |
532 | exprAnalyzer_.Analyze(x); |
533 | return false; |
534 | } |
535 | template <typename A> bool Pre(const parser::Logical<A> &x) { |
536 | exprAnalyzer_.Analyze(x); |
537 | return false; |
538 | } |
539 | template <typename A> bool Pre(const parser::DefaultChar<A> &x) { |
540 | exprAnalyzer_.Analyze(x); |
541 | return false; |
542 | } |
543 | |
544 | private: |
545 | bool InWhereBody() const { return whereDepth_ > 0; } |
546 | |
547 | SemanticsContext &context_; |
548 | evaluate::ExpressionAnalyzer exprAnalyzer_{context_}; |
549 | int whereDepth_{0}; // nesting of WHERE statements & constructs |
550 | bool inComponentDefStmt_{false}; |
551 | }; |
552 | } // namespace Fortran::semantics |
553 | #endif // FORTRAN_SEMANTICS_EXPRESSION_H_ |
554 |
Warning: This file is not a C or C++ file. It does not have highlighting.