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
32using namespace Fortran::parser::literals;
33
34namespace Fortran::parser {
35struct 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
50template <typename A> CharBlock FindSourceLocation(const A &x) {
51 SourceLocationFindingVisitor visitor;
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
91 GenericExprWrapper expr_;
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
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
251protected:
252 int IntegerTypeSpecKind(const parser::IntegerTypeSpec &);
253
254private:
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
404inline bool AreConformable(int leftRank, int rightRank) {
405 return leftRank == 0 || rightRank == 0 || leftRank == rightRank;
406}
407
408template <typename L, typename R>
409bool AreConformable(const L &left, const R &right) {
410 return AreConformable(left.Rank(), right.Rank());
411}
412
413template <typename L, typename R>
414void 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
423namespace Fortran::semantics {
424
425// Semantic analysis of one expression, variable, selector, designator, &c.
426template <typename A>
427std::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.
433evaluate::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.
439class ExprChecker {
440public:
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
544private:
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.

source code of flang/include/flang/Semantics/expression.h