1 //===-- lib/Semantics/expression.cpp --------------------------------------===//
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 #include "flang/Semantics/expression.h"
10 #include "check-call.h"
11 #include "pointer-assignment.h"
12 #include "resolve-names.h"
13 #include "flang/Common/idioms.h"
14 #include "flang/Evaluate/common.h"
15 #include "flang/Evaluate/fold.h"
16 #include "flang/Evaluate/tools.h"
17 #include "flang/Parser/characters.h"
18 #include "flang/Parser/dump-parse-tree.h"
19 #include "flang/Parser/parse-tree-visitor.h"
20 #include "flang/Parser/parse-tree.h"
21 #include "flang/Semantics/scope.h"
22 #include "flang/Semantics/semantics.h"
23 #include "flang/Semantics/symbol.h"
24 #include "flang/Semantics/tools.h"
25 #include "llvm/Support/raw_ostream.h"
26 #include <algorithm>
27 #include <functional>
28 #include <optional>
29 #include <set>
30
31 // Typedef for optional generic expressions (ubiquitous in this file)
32 using MaybeExpr =
33 std::optional<Fortran::evaluate::Expr<Fortran::evaluate::SomeType>>;
34
35 // Much of the code that implements semantic analysis of expressions is
36 // tightly coupled with their typed representations in lib/Evaluate,
37 // and appears here in namespace Fortran::evaluate for convenience.
38 namespace Fortran::evaluate {
39
40 using common::LanguageFeature;
41 using common::NumericOperator;
42 using common::TypeCategory;
43
ToUpperCase(const std::string & str)44 static inline std::string ToUpperCase(const std::string &str) {
45 return parser::ToUpperCaseLetters(str);
46 }
47
48 struct DynamicTypeWithLength : public DynamicType {
DynamicTypeWithLengthFortran::evaluate::DynamicTypeWithLength49 explicit DynamicTypeWithLength(const DynamicType &t) : DynamicType{t} {}
50 std::optional<Expr<SubscriptInteger>> LEN() const;
51 std::optional<Expr<SubscriptInteger>> length;
52 };
53
LEN() const54 std::optional<Expr<SubscriptInteger>> DynamicTypeWithLength::LEN() const {
55 if (length) {
56 return length;
57 }
58 if (auto *lengthParam{charLength()}) {
59 if (const auto &len{lengthParam->GetExplicit()}) {
60 return ConvertToType<SubscriptInteger>(common::Clone(*len));
61 }
62 }
63 return std::nullopt; // assumed or deferred length
64 }
65
AnalyzeTypeSpec(const std::optional<parser::TypeSpec> & spec)66 static std::optional<DynamicTypeWithLength> AnalyzeTypeSpec(
67 const std::optional<parser::TypeSpec> &spec) {
68 if (spec) {
69 if (const semantics::DeclTypeSpec * typeSpec{spec->declTypeSpec}) {
70 // Name resolution sets TypeSpec::declTypeSpec only when it's valid
71 // (viz., an intrinsic type with valid known kind or a non-polymorphic
72 // & non-ABSTRACT derived type).
73 if (const semantics::IntrinsicTypeSpec *
74 intrinsic{typeSpec->AsIntrinsic()}) {
75 TypeCategory category{intrinsic->category()};
76 if (auto optKind{ToInt64(intrinsic->kind())}) {
77 int kind{static_cast<int>(*optKind)};
78 if (category == TypeCategory::Character) {
79 const semantics::CharacterTypeSpec &cts{
80 typeSpec->characterTypeSpec()};
81 const semantics::ParamValue &len{cts.length()};
82 // N.B. CHARACTER(LEN=*) is allowed in type-specs in ALLOCATE() &
83 // type guards, but not in array constructors.
84 return DynamicTypeWithLength{DynamicType{kind, len}};
85 } else {
86 return DynamicTypeWithLength{DynamicType{category, kind}};
87 }
88 }
89 } else if (const semantics::DerivedTypeSpec *
90 derived{typeSpec->AsDerived()}) {
91 return DynamicTypeWithLength{DynamicType{*derived}};
92 }
93 }
94 }
95 return std::nullopt;
96 }
97
98 class ArgumentAnalyzer {
99 public:
ArgumentAnalyzer(ExpressionAnalyzer & context)100 explicit ArgumentAnalyzer(ExpressionAnalyzer &context)
101 : context_{context}, source_{context.GetContextualMessages().at()},
102 isProcedureCall_{false} {}
ArgumentAnalyzer(ExpressionAnalyzer & context,parser::CharBlock source,bool isProcedureCall=false)103 ArgumentAnalyzer(ExpressionAnalyzer &context, parser::CharBlock source,
104 bool isProcedureCall = false)
105 : context_{context}, source_{source}, isProcedureCall_{isProcedureCall} {}
fatalErrors() const106 bool fatalErrors() const { return fatalErrors_; }
GetActuals()107 ActualArguments &&GetActuals() {
108 CHECK(!fatalErrors_);
109 return std::move(actuals_);
110 }
GetExpr(std::size_t i) const111 const Expr<SomeType> &GetExpr(std::size_t i) const {
112 return DEREF(actuals_.at(i).value().UnwrapExpr());
113 }
MoveExpr(std::size_t i)114 Expr<SomeType> &&MoveExpr(std::size_t i) {
115 return std::move(DEREF(actuals_.at(i).value().UnwrapExpr()));
116 }
Analyze(const common::Indirection<parser::Expr> & x)117 void Analyze(const common::Indirection<parser::Expr> &x) {
118 Analyze(x.value());
119 }
Analyze(const parser::Expr & x)120 void Analyze(const parser::Expr &x) {
121 actuals_.emplace_back(AnalyzeExpr(x));
122 fatalErrors_ |= !actuals_.back();
123 }
124 void Analyze(const parser::Variable &);
125 void Analyze(const parser::ActualArgSpec &, bool isSubroutine);
126 void ConvertBOZ(std::size_t i, std::optional<DynamicType> otherType);
127
128 bool IsIntrinsicRelational(RelationalOperator) const;
129 bool IsIntrinsicLogical() const;
130 bool IsIntrinsicNumeric(NumericOperator) const;
131 bool IsIntrinsicConcat() const;
132
133 bool CheckConformance() const;
134
135 // Find and return a user-defined operator or report an error.
136 // The provided message is used if there is no such operator.
137 MaybeExpr TryDefinedOp(
138 const char *, parser::MessageFixedText &&, bool isUserOp = false);
139 template <typename E>
TryDefinedOp(E opr,parser::MessageFixedText && msg)140 MaybeExpr TryDefinedOp(E opr, parser::MessageFixedText &&msg) {
141 return TryDefinedOp(
142 context_.context().languageFeatures().GetNames(opr), std::move(msg));
143 }
144 // Find and return a user-defined assignment
145 std::optional<ProcedureRef> TryDefinedAssignment();
146 std::optional<ProcedureRef> GetDefinedAssignmentProc();
147 std::optional<DynamicType> GetType(std::size_t) const;
148 void Dump(llvm::raw_ostream &);
149
150 private:
151 MaybeExpr TryDefinedOp(
152 std::vector<const char *>, parser::MessageFixedText &&);
153 MaybeExpr TryBoundOp(const Symbol &, int passIndex);
154 std::optional<ActualArgument> AnalyzeExpr(const parser::Expr &);
155 MaybeExpr AnalyzeExprOrWholeAssumedSizeArray(const parser::Expr &);
156 bool AreConformable() const;
157 const Symbol *FindBoundOp(parser::CharBlock, int passIndex);
158 void AddAssignmentConversion(
159 const DynamicType &lhsType, const DynamicType &rhsType);
160 bool OkLogicalIntegerAssignment(TypeCategory lhs, TypeCategory rhs);
161 int GetRank(std::size_t) const;
IsBOZLiteral(std::size_t i) const162 bool IsBOZLiteral(std::size_t i) const {
163 return std::holds_alternative<BOZLiteralConstant>(GetExpr(i).u);
164 }
165 void SayNoMatch(const std::string &, bool isAssignment = false);
166 std::string TypeAsFortran(std::size_t);
167 bool AnyUntypedOperand();
168
169 ExpressionAnalyzer &context_;
170 ActualArguments actuals_;
171 parser::CharBlock source_;
172 bool fatalErrors_{false};
173 const bool isProcedureCall_; // false for user-defined op or assignment
174 const Symbol *sawDefinedOp_{nullptr};
175 };
176
177 // Wraps a data reference in a typed Designator<>, and a procedure
178 // or procedure pointer reference in a ProcedureDesignator.
Designate(DataRef && ref)179 MaybeExpr ExpressionAnalyzer::Designate(DataRef &&ref) {
180 const Symbol &symbol{ref.GetLastSymbol().GetUltimate()};
181 if (semantics::IsProcedure(symbol)) {
182 if (auto *component{std::get_if<Component>(&ref.u)}) {
183 return Expr<SomeType>{ProcedureDesignator{std::move(*component)}};
184 } else if (!std::holds_alternative<SymbolRef>(ref.u)) {
185 DIE("unexpected alternative in DataRef");
186 } else if (!symbol.attrs().test(semantics::Attr::INTRINSIC)) {
187 return Expr<SomeType>{ProcedureDesignator{symbol}};
188 } else if (auto interface{context_.intrinsics().IsSpecificIntrinsicFunction(
189 symbol.name().ToString())}) {
190 SpecificIntrinsic intrinsic{
191 symbol.name().ToString(), std::move(*interface)};
192 intrinsic.isRestrictedSpecific = interface->isRestrictedSpecific;
193 return Expr<SomeType>{ProcedureDesignator{std::move(intrinsic)}};
194 } else {
195 Say("'%s' is not a specific intrinsic procedure"_err_en_US,
196 symbol.name());
197 return std::nullopt;
198 }
199 } else if (auto dyType{DynamicType::From(symbol)}) {
200 return TypedWrapper<Designator, DataRef>(*dyType, std::move(ref));
201 }
202 return std::nullopt;
203 }
204
205 // Some subscript semantic checks must be deferred until all of the
206 // subscripts are in hand.
CompleteSubscripts(ArrayRef && ref)207 MaybeExpr ExpressionAnalyzer::CompleteSubscripts(ArrayRef &&ref) {
208 const Symbol &symbol{ref.GetLastSymbol().GetUltimate()};
209 int symbolRank{symbol.Rank()};
210 int subscripts{static_cast<int>(ref.size())};
211 if (subscripts == 0) {
212 return std::nullopt; // error recovery
213 } else if (subscripts != symbolRank) {
214 if (symbolRank != 0) {
215 Say("Reference to rank-%d object '%s' has %d subscripts"_err_en_US,
216 symbolRank, symbol.name(), subscripts);
217 }
218 return std::nullopt;
219 } else if (Component * component{ref.base().UnwrapComponent()}) {
220 int baseRank{component->base().Rank()};
221 if (baseRank > 0) {
222 int subscriptRank{0};
223 for (const auto &expr : ref.subscript()) {
224 subscriptRank += expr.Rank();
225 }
226 if (subscriptRank > 0) {
227 Say("Subscripts of component '%s' of rank-%d derived type "
228 "array have rank %d but must all be scalar"_err_en_US,
229 symbol.name(), baseRank, subscriptRank);
230 return std::nullopt;
231 }
232 }
233 } else if (const auto *object{
234 symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
235 // C928 & C1002
236 if (Triplet * last{std::get_if<Triplet>(&ref.subscript().back().u)}) {
237 if (!last->upper() && object->IsAssumedSize()) {
238 Say("Assumed-size array '%s' must have explicit final "
239 "subscript upper bound value"_err_en_US,
240 symbol.name());
241 return std::nullopt;
242 }
243 }
244 } else {
245 // Shouldn't get here from Analyze(ArrayElement) without a valid base,
246 // which, if not an object, must be a construct entity from
247 // SELECT TYPE/RANK or ASSOCIATE.
248 CHECK(symbol.has<semantics::AssocEntityDetails>());
249 }
250 return Designate(DataRef{std::move(ref)});
251 }
252
253 // Applies subscripts to a data reference.
ApplySubscripts(DataRef && dataRef,std::vector<Subscript> && subscripts)254 MaybeExpr ExpressionAnalyzer::ApplySubscripts(
255 DataRef &&dataRef, std::vector<Subscript> &&subscripts) {
256 if (subscripts.empty()) {
257 return std::nullopt; // error recovery
258 }
259 return std::visit(
260 common::visitors{
261 [&](SymbolRef &&symbol) {
262 return CompleteSubscripts(ArrayRef{symbol, std::move(subscripts)});
263 },
264 [&](Component &&c) {
265 return CompleteSubscripts(
266 ArrayRef{std::move(c), std::move(subscripts)});
267 },
268 [&](auto &&) -> MaybeExpr {
269 DIE("bad base for ArrayRef");
270 return std::nullopt;
271 },
272 },
273 std::move(dataRef.u));
274 }
275
276 // Top-level checks for data references.
TopLevelChecks(DataRef && dataRef)277 MaybeExpr ExpressionAnalyzer::TopLevelChecks(DataRef &&dataRef) {
278 if (Component * component{std::get_if<Component>(&dataRef.u)}) {
279 const Symbol &symbol{component->GetLastSymbol()};
280 int componentRank{symbol.Rank()};
281 if (componentRank > 0) {
282 int baseRank{component->base().Rank()};
283 if (baseRank > 0) {
284 Say("Reference to whole rank-%d component '%%%s' of "
285 "rank-%d array of derived type is not allowed"_err_en_US,
286 componentRank, symbol.name(), baseRank);
287 }
288 }
289 }
290 return Designate(std::move(dataRef));
291 }
292
293 // Parse tree correction after a substring S(j:k) was misparsed as an
294 // array section. N.B. Fortran substrings have to have a range, not a
295 // single index.
FixMisparsedSubstring(const parser::Designator & d)296 static void FixMisparsedSubstring(const parser::Designator &d) {
297 auto &mutate{const_cast<parser::Designator &>(d)};
298 if (auto *dataRef{std::get_if<parser::DataRef>(&mutate.u)}) {
299 if (auto *ae{std::get_if<common::Indirection<parser::ArrayElement>>(
300 &dataRef->u)}) {
301 parser::ArrayElement &arrElement{ae->value()};
302 if (!arrElement.subscripts.empty()) {
303 auto iter{arrElement.subscripts.begin()};
304 if (auto *triplet{std::get_if<parser::SubscriptTriplet>(&iter->u)}) {
305 if (!std::get<2>(triplet->t) /* no stride */ &&
306 ++iter == arrElement.subscripts.end() /* one subscript */) {
307 if (Symbol *
308 symbol{std::visit(
309 common::visitors{
310 [](parser::Name &n) { return n.symbol; },
311 [](common::Indirection<parser::StructureComponent>
312 &sc) { return sc.value().component.symbol; },
313 [](auto &) -> Symbol * { return nullptr; },
314 },
315 arrElement.base.u)}) {
316 const Symbol &ultimate{symbol->GetUltimate()};
317 if (const semantics::DeclTypeSpec * type{ultimate.GetType()}) {
318 if (!ultimate.IsObjectArray() &&
319 type->category() == semantics::DeclTypeSpec::Character) {
320 // The ambiguous S(j:k) was parsed as an array section
321 // reference, but it's now clear that it's a substring.
322 // Fix the parse tree in situ.
323 mutate.u = arrElement.ConvertToSubstring();
324 }
325 }
326 }
327 }
328 }
329 }
330 }
331 }
332 }
333
Analyze(const parser::Designator & d)334 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Designator &d) {
335 auto restorer{GetContextualMessages().SetLocation(d.source)};
336 FixMisparsedSubstring(d);
337 // These checks have to be deferred to these "top level" data-refs where
338 // we can be sure that there are no following subscripts (yet).
339 // Substrings have already been run through TopLevelChecks() and
340 // won't be returned by ExtractDataRef().
341 if (MaybeExpr result{Analyze(d.u)}) {
342 if (std::optional<DataRef> dataRef{ExtractDataRef(std::move(result))}) {
343 return TopLevelChecks(std::move(*dataRef));
344 }
345 return result;
346 }
347 return std::nullopt;
348 }
349
350 // A utility subroutine to repackage optional expressions of various levels
351 // of type specificity as fully general MaybeExpr values.
AsMaybeExpr(A && x)352 template <typename A> common::IfNoLvalue<MaybeExpr, A> AsMaybeExpr(A &&x) {
353 return AsGenericExpr(std::move(x));
354 }
AsMaybeExpr(std::optional<A> && x)355 template <typename A> MaybeExpr AsMaybeExpr(std::optional<A> &&x) {
356 if (x) {
357 return AsMaybeExpr(std::move(*x));
358 }
359 return std::nullopt;
360 }
361
362 // Type kind parameter values for literal constants.
AnalyzeKindParam(const std::optional<parser::KindParam> & kindParam,int defaultKind)363 int ExpressionAnalyzer::AnalyzeKindParam(
364 const std::optional<parser::KindParam> &kindParam, int defaultKind) {
365 if (!kindParam) {
366 return defaultKind;
367 }
368 return std::visit(
369 common::visitors{
370 [](std::uint64_t k) { return static_cast<int>(k); },
371 [&](const parser::Scalar<
372 parser::Integer<parser::Constant<parser::Name>>> &n) {
373 if (MaybeExpr ie{Analyze(n)}) {
374 if (std::optional<std::int64_t> i64{ToInt64(*ie)}) {
375 int iv = *i64;
376 if (iv == *i64) {
377 return iv;
378 }
379 }
380 }
381 return defaultKind;
382 },
383 },
384 kindParam->u);
385 }
386
387 // Common handling of parser::IntLiteralConstant and SignedIntLiteralConstant
388 struct IntTypeVisitor {
389 using Result = MaybeExpr;
390 using Types = IntegerTypes;
TestFortran::evaluate::IntTypeVisitor391 template <typename T> Result Test() {
392 if (T::kind >= kind) {
393 const char *p{digits.begin()};
394 auto value{T::Scalar::Read(p, 10, true /*signed*/)};
395 if (!value.overflow) {
396 if (T::kind > kind) {
397 if (!isDefaultKind ||
398 !analyzer.context().IsEnabled(LanguageFeature::BigIntLiterals)) {
399 return std::nullopt;
400 } else if (analyzer.context().ShouldWarn(
401 LanguageFeature::BigIntLiterals)) {
402 analyzer.Say(digits,
403 "Integer literal is too large for default INTEGER(KIND=%d); "
404 "assuming INTEGER(KIND=%d)"_en_US,
405 kind, T::kind);
406 }
407 }
408 return Expr<SomeType>{
409 Expr<SomeInteger>{Expr<T>{Constant<T>{std::move(value.value)}}}};
410 }
411 }
412 return std::nullopt;
413 }
414 ExpressionAnalyzer &analyzer;
415 parser::CharBlock digits;
416 int kind;
417 bool isDefaultKind;
418 };
419
420 template <typename PARSED>
IntLiteralConstant(const PARSED & x)421 MaybeExpr ExpressionAnalyzer::IntLiteralConstant(const PARSED &x) {
422 const auto &kindParam{std::get<std::optional<parser::KindParam>>(x.t)};
423 bool isDefaultKind{!kindParam};
424 int kind{AnalyzeKindParam(kindParam, GetDefaultKind(TypeCategory::Integer))};
425 if (CheckIntrinsicKind(TypeCategory::Integer, kind)) {
426 auto digits{std::get<parser::CharBlock>(x.t)};
427 if (MaybeExpr result{common::SearchTypes(
428 IntTypeVisitor{*this, digits, kind, isDefaultKind})}) {
429 return result;
430 } else if (isDefaultKind) {
431 Say(digits,
432 "Integer literal is too large for any allowable "
433 "kind of INTEGER"_err_en_US);
434 } else {
435 Say(digits, "Integer literal is too large for INTEGER(KIND=%d)"_err_en_US,
436 kind);
437 }
438 }
439 return std::nullopt;
440 }
441
Analyze(const parser::IntLiteralConstant & x)442 MaybeExpr ExpressionAnalyzer::Analyze(const parser::IntLiteralConstant &x) {
443 auto restorer{
444 GetContextualMessages().SetLocation(std::get<parser::CharBlock>(x.t))};
445 return IntLiteralConstant(x);
446 }
447
Analyze(const parser::SignedIntLiteralConstant & x)448 MaybeExpr ExpressionAnalyzer::Analyze(
449 const parser::SignedIntLiteralConstant &x) {
450 auto restorer{GetContextualMessages().SetLocation(x.source)};
451 return IntLiteralConstant(x);
452 }
453
454 template <typename TYPE>
ReadRealLiteral(parser::CharBlock source,FoldingContext & context)455 Constant<TYPE> ReadRealLiteral(
456 parser::CharBlock source, FoldingContext &context) {
457 const char *p{source.begin()};
458 auto valWithFlags{Scalar<TYPE>::Read(p, context.rounding())};
459 CHECK(p == source.end());
460 RealFlagWarnings(context, valWithFlags.flags, "conversion of REAL literal");
461 auto value{valWithFlags.value};
462 if (context.flushSubnormalsToZero()) {
463 value = value.FlushSubnormalToZero();
464 }
465 return {value};
466 }
467
468 struct RealTypeVisitor {
469 using Result = std::optional<Expr<SomeReal>>;
470 using Types = RealTypes;
471
RealTypeVisitorFortran::evaluate::RealTypeVisitor472 RealTypeVisitor(int k, parser::CharBlock lit, FoldingContext &ctx)
473 : kind{k}, literal{lit}, context{ctx} {}
474
TestFortran::evaluate::RealTypeVisitor475 template <typename T> Result Test() {
476 if (kind == T::kind) {
477 return {AsCategoryExpr(ReadRealLiteral<T>(literal, context))};
478 }
479 return std::nullopt;
480 }
481
482 int kind;
483 parser::CharBlock literal;
484 FoldingContext &context;
485 };
486
487 // Reads a real literal constant and encodes it with the right kind.
Analyze(const parser::RealLiteralConstant & x)488 MaybeExpr ExpressionAnalyzer::Analyze(const parser::RealLiteralConstant &x) {
489 // Use a local message context around the real literal for better
490 // provenance on any messages.
491 auto restorer{GetContextualMessages().SetLocation(x.real.source)};
492 // If a kind parameter appears, it defines the kind of the literal and the
493 // letter used in an exponent part must be 'E' (e.g., the 'E' in
494 // "6.02214E+23"). In the absence of an explicit kind parameter, any
495 // exponent letter determines the kind. Otherwise, defaults apply.
496 auto &defaults{context_.defaultKinds()};
497 int defaultKind{defaults.GetDefaultKind(TypeCategory::Real)};
498 const char *end{x.real.source.end()};
499 char expoLetter{' '};
500 std::optional<int> letterKind;
501 for (const char *p{x.real.source.begin()}; p < end; ++p) {
502 if (parser::IsLetter(*p)) {
503 expoLetter = *p;
504 switch (expoLetter) {
505 case 'e':
506 letterKind = defaults.GetDefaultKind(TypeCategory::Real);
507 break;
508 case 'd':
509 letterKind = defaults.doublePrecisionKind();
510 break;
511 case 'q':
512 letterKind = defaults.quadPrecisionKind();
513 break;
514 default:
515 Say("Unknown exponent letter '%c'"_err_en_US, expoLetter);
516 }
517 break;
518 }
519 }
520 if (letterKind) {
521 defaultKind = *letterKind;
522 }
523 // C716 requires 'E' as an exponent, but this is more useful
524 auto kind{AnalyzeKindParam(x.kind, defaultKind)};
525 if (letterKind && kind != *letterKind && expoLetter != 'e') {
526 Say("Explicit kind parameter on real constant disagrees with "
527 "exponent letter '%c'"_en_US,
528 expoLetter);
529 }
530 auto result{common::SearchTypes(
531 RealTypeVisitor{kind, x.real.source, GetFoldingContext()})};
532 if (!result) { // C717
533 Say("Unsupported REAL(KIND=%d)"_err_en_US, kind);
534 }
535 return AsMaybeExpr(std::move(result));
536 }
537
Analyze(const parser::SignedRealLiteralConstant & x)538 MaybeExpr ExpressionAnalyzer::Analyze(
539 const parser::SignedRealLiteralConstant &x) {
540 if (auto result{Analyze(std::get<parser::RealLiteralConstant>(x.t))}) {
541 auto &realExpr{std::get<Expr<SomeReal>>(result->u)};
542 if (auto sign{std::get<std::optional<parser::Sign>>(x.t)}) {
543 if (sign == parser::Sign::Negative) {
544 return AsGenericExpr(-std::move(realExpr));
545 }
546 }
547 return result;
548 }
549 return std::nullopt;
550 }
551
Analyze(const parser::SignedComplexLiteralConstant & x)552 MaybeExpr ExpressionAnalyzer::Analyze(
553 const parser::SignedComplexLiteralConstant &x) {
554 auto result{Analyze(std::get<parser::ComplexLiteralConstant>(x.t))};
555 if (!result) {
556 return std::nullopt;
557 } else if (std::get<parser::Sign>(x.t) == parser::Sign::Negative) {
558 return AsGenericExpr(-std::move(std::get<Expr<SomeComplex>>(result->u)));
559 } else {
560 return result;
561 }
562 }
563
Analyze(const parser::ComplexPart & x)564 MaybeExpr ExpressionAnalyzer::Analyze(const parser::ComplexPart &x) {
565 return Analyze(x.u);
566 }
567
Analyze(const parser::ComplexLiteralConstant & z)568 MaybeExpr ExpressionAnalyzer::Analyze(const parser::ComplexLiteralConstant &z) {
569 return AsMaybeExpr(
570 ConstructComplex(GetContextualMessages(), Analyze(std::get<0>(z.t)),
571 Analyze(std::get<1>(z.t)), GetDefaultKind(TypeCategory::Real)));
572 }
573
574 // CHARACTER literal processing.
AnalyzeString(std::string && string,int kind)575 MaybeExpr ExpressionAnalyzer::AnalyzeString(std::string &&string, int kind) {
576 if (!CheckIntrinsicKind(TypeCategory::Character, kind)) {
577 return std::nullopt;
578 }
579 switch (kind) {
580 case 1:
581 return AsGenericExpr(Constant<Type<TypeCategory::Character, 1>>{
582 parser::DecodeString<std::string, parser::Encoding::LATIN_1>(
583 string, true)});
584 case 2:
585 return AsGenericExpr(Constant<Type<TypeCategory::Character, 2>>{
586 parser::DecodeString<std::u16string, parser::Encoding::UTF_8>(
587 string, true)});
588 case 4:
589 return AsGenericExpr(Constant<Type<TypeCategory::Character, 4>>{
590 parser::DecodeString<std::u32string, parser::Encoding::UTF_8>(
591 string, true)});
592 default:
593 CRASH_NO_CASE;
594 }
595 }
596
Analyze(const parser::CharLiteralConstant & x)597 MaybeExpr ExpressionAnalyzer::Analyze(const parser::CharLiteralConstant &x) {
598 int kind{
599 AnalyzeKindParam(std::get<std::optional<parser::KindParam>>(x.t), 1)};
600 auto value{std::get<std::string>(x.t)};
601 return AnalyzeString(std::move(value), kind);
602 }
603
Analyze(const parser::HollerithLiteralConstant & x)604 MaybeExpr ExpressionAnalyzer::Analyze(
605 const parser::HollerithLiteralConstant &x) {
606 int kind{GetDefaultKind(TypeCategory::Character)};
607 auto value{x.v};
608 return AnalyzeString(std::move(value), kind);
609 }
610
611 // .TRUE. and .FALSE. of various kinds
Analyze(const parser::LogicalLiteralConstant & x)612 MaybeExpr ExpressionAnalyzer::Analyze(const parser::LogicalLiteralConstant &x) {
613 auto kind{AnalyzeKindParam(std::get<std::optional<parser::KindParam>>(x.t),
614 GetDefaultKind(TypeCategory::Logical))};
615 bool value{std::get<bool>(x.t)};
616 auto result{common::SearchTypes(
617 TypeKindVisitor<TypeCategory::Logical, Constant, bool>{
618 kind, std::move(value)})};
619 if (!result) {
620 Say("unsupported LOGICAL(KIND=%d)"_err_en_US, kind); // C728
621 }
622 return result;
623 }
624
625 // BOZ typeless literals
Analyze(const parser::BOZLiteralConstant & x)626 MaybeExpr ExpressionAnalyzer::Analyze(const parser::BOZLiteralConstant &x) {
627 const char *p{x.v.c_str()};
628 std::uint64_t base{16};
629 switch (*p++) {
630 case 'b':
631 base = 2;
632 break;
633 case 'o':
634 base = 8;
635 break;
636 case 'z':
637 break;
638 case 'x':
639 break;
640 default:
641 CRASH_NO_CASE;
642 }
643 CHECK(*p == '"');
644 ++p;
645 auto value{BOZLiteralConstant::Read(p, base, false /*unsigned*/)};
646 if (*p != '"') {
647 Say("Invalid digit ('%c') in BOZ literal '%s'"_err_en_US, *p,
648 x.v); // C7107, C7108
649 return std::nullopt;
650 }
651 if (value.overflow) {
652 Say("BOZ literal '%s' too large"_err_en_US, x.v);
653 return std::nullopt;
654 }
655 return AsGenericExpr(std::move(value.value));
656 }
657
658 // Names and named constants
Analyze(const parser::Name & n)659 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Name &n) {
660 auto restorer{GetContextualMessages().SetLocation(n.source)};
661 if (std::optional<int> kind{IsImpliedDo(n.source)}) {
662 return AsMaybeExpr(ConvertToKind<TypeCategory::Integer>(
663 *kind, AsExpr(ImpliedDoIndex{n.source})));
664 } else if (context_.HasError(n)) {
665 return std::nullopt;
666 } else if (!n.symbol) {
667 SayAt(n, "Internal error: unresolved name '%s'"_err_en_US, n.source);
668 return std::nullopt;
669 } else {
670 const Symbol &ultimate{n.symbol->GetUltimate()};
671 if (ultimate.has<semantics::TypeParamDetails>()) {
672 // A bare reference to a derived type parameter (within a parameterized
673 // derived type definition)
674 return Fold(ConvertToType(
675 ultimate, AsGenericExpr(TypeParamInquiry{std::nullopt, ultimate})));
676 } else {
677 if (n.symbol->attrs().test(semantics::Attr::VOLATILE)) {
678 if (const semantics::Scope *
679 pure{semantics::FindPureProcedureContaining(
680 context_.FindScope(n.source))}) {
681 SayAt(n,
682 "VOLATILE variable '%s' may not be referenced in pure subprogram '%s'"_err_en_US,
683 n.source, DEREF(pure->symbol()).name());
684 n.symbol->attrs().reset(semantics::Attr::VOLATILE);
685 }
686 }
687 if (!isWholeAssumedSizeArrayOk_ &&
688 semantics::IsAssumedSizeArray(*n.symbol)) { // C1002, C1014, C1231
689 AttachDeclaration(
690 SayAt(n,
691 "Whole assumed-size array '%s' may not appear here without subscripts"_err_en_US,
692 n.source),
693 *n.symbol);
694 }
695 return Designate(DataRef{*n.symbol});
696 }
697 }
698 }
699
Analyze(const parser::NamedConstant & n)700 MaybeExpr ExpressionAnalyzer::Analyze(const parser::NamedConstant &n) {
701 auto restorer{GetContextualMessages().SetLocation(n.v.source)};
702 if (MaybeExpr value{Analyze(n.v)}) {
703 Expr<SomeType> folded{Fold(std::move(*value))};
704 if (IsConstantExpr(folded)) {
705 return folded;
706 }
707 Say(n.v.source, "must be a constant"_err_en_US); // C718
708 }
709 return std::nullopt;
710 }
711
Analyze(const parser::NullInit & x)712 MaybeExpr ExpressionAnalyzer::Analyze(const parser::NullInit &x) {
713 return Expr<SomeType>{NullPointer{}};
714 }
715
Analyze(const parser::InitialDataTarget & x)716 MaybeExpr ExpressionAnalyzer::Analyze(const parser::InitialDataTarget &x) {
717 return Analyze(x.value());
718 }
719
Analyze(const parser::DataStmtValue & x)720 MaybeExpr ExpressionAnalyzer::Analyze(const parser::DataStmtValue &x) {
721 if (const auto &repeat{
722 std::get<std::optional<parser::DataStmtRepeat>>(x.t)}) {
723 x.repetitions = -1;
724 if (MaybeExpr expr{Analyze(repeat->u)}) {
725 Expr<SomeType> folded{Fold(std::move(*expr))};
726 if (auto value{ToInt64(folded)}) {
727 if (*value >= 0) { // C882
728 x.repetitions = *value;
729 } else {
730 Say(FindSourceLocation(repeat),
731 "Repeat count (%jd) for data value must not be negative"_err_en_US,
732 *value);
733 }
734 }
735 }
736 }
737 return Analyze(std::get<parser::DataStmtConstant>(x.t));
738 }
739
740 // Substring references
GetSubstringBound(const std::optional<parser::ScalarIntExpr> & bound)741 std::optional<Expr<SubscriptInteger>> ExpressionAnalyzer::GetSubstringBound(
742 const std::optional<parser::ScalarIntExpr> &bound) {
743 if (bound) {
744 if (MaybeExpr expr{Analyze(*bound)}) {
745 if (expr->Rank() > 1) {
746 Say("substring bound expression has rank %d"_err_en_US, expr->Rank());
747 }
748 if (auto *intExpr{std::get_if<Expr<SomeInteger>>(&expr->u)}) {
749 if (auto *ssIntExpr{std::get_if<Expr<SubscriptInteger>>(&intExpr->u)}) {
750 return {std::move(*ssIntExpr)};
751 }
752 return {Expr<SubscriptInteger>{
753 Convert<SubscriptInteger, TypeCategory::Integer>{
754 std::move(*intExpr)}}};
755 } else {
756 Say("substring bound expression is not INTEGER"_err_en_US);
757 }
758 }
759 }
760 return std::nullopt;
761 }
762
Analyze(const parser::Substring & ss)763 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Substring &ss) {
764 if (MaybeExpr baseExpr{Analyze(std::get<parser::DataRef>(ss.t))}) {
765 if (std::optional<DataRef> dataRef{ExtractDataRef(std::move(*baseExpr))}) {
766 if (MaybeExpr newBaseExpr{TopLevelChecks(std::move(*dataRef))}) {
767 if (std::optional<DataRef> checked{
768 ExtractDataRef(std::move(*newBaseExpr))}) {
769 const parser::SubstringRange &range{
770 std::get<parser::SubstringRange>(ss.t)};
771 std::optional<Expr<SubscriptInteger>> first{
772 GetSubstringBound(std::get<0>(range.t))};
773 std::optional<Expr<SubscriptInteger>> last{
774 GetSubstringBound(std::get<1>(range.t))};
775 const Symbol &symbol{checked->GetLastSymbol()};
776 if (std::optional<DynamicType> dynamicType{
777 DynamicType::From(symbol)}) {
778 if (dynamicType->category() == TypeCategory::Character) {
779 return WrapperHelper<TypeCategory::Character, Designator,
780 Substring>(dynamicType->kind(),
781 Substring{std::move(checked.value()), std::move(first),
782 std::move(last)});
783 }
784 }
785 Say("substring may apply only to CHARACTER"_err_en_US);
786 }
787 }
788 }
789 }
790 return std::nullopt;
791 }
792
793 // CHARACTER literal substrings
Analyze(const parser::CharLiteralConstantSubstring & x)794 MaybeExpr ExpressionAnalyzer::Analyze(
795 const parser::CharLiteralConstantSubstring &x) {
796 const parser::SubstringRange &range{std::get<parser::SubstringRange>(x.t)};
797 std::optional<Expr<SubscriptInteger>> lower{
798 GetSubstringBound(std::get<0>(range.t))};
799 std::optional<Expr<SubscriptInteger>> upper{
800 GetSubstringBound(std::get<1>(range.t))};
801 if (MaybeExpr string{Analyze(std::get<parser::CharLiteralConstant>(x.t))}) {
802 if (auto *charExpr{std::get_if<Expr<SomeCharacter>>(&string->u)}) {
803 Expr<SubscriptInteger> length{
804 std::visit([](const auto &ckExpr) { return ckExpr.LEN().value(); },
805 charExpr->u)};
806 if (!lower) {
807 lower = Expr<SubscriptInteger>{1};
808 }
809 if (!upper) {
810 upper = Expr<SubscriptInteger>{
811 static_cast<std::int64_t>(ToInt64(length).value())};
812 }
813 return std::visit(
814 [&](auto &&ckExpr) -> MaybeExpr {
815 using Result = ResultType<decltype(ckExpr)>;
816 auto *cp{std::get_if<Constant<Result>>(&ckExpr.u)};
817 CHECK(DEREF(cp).size() == 1);
818 StaticDataObject::Pointer staticData{StaticDataObject::Create()};
819 staticData->set_alignment(Result::kind)
820 .set_itemBytes(Result::kind)
821 .Push(cp->GetScalarValue().value());
822 Substring substring{std::move(staticData), std::move(lower.value()),
823 std::move(upper.value())};
824 return AsGenericExpr(
825 Expr<Result>{Designator<Result>{std::move(substring)}});
826 },
827 std::move(charExpr->u));
828 }
829 }
830 return std::nullopt;
831 }
832
833 // Subscripted array references
AsSubscript(MaybeExpr && expr)834 std::optional<Expr<SubscriptInteger>> ExpressionAnalyzer::AsSubscript(
835 MaybeExpr &&expr) {
836 if (expr) {
837 if (expr->Rank() > 1) {
838 Say("Subscript expression has rank %d greater than 1"_err_en_US,
839 expr->Rank());
840 }
841 if (auto *intExpr{std::get_if<Expr<SomeInteger>>(&expr->u)}) {
842 if (auto *ssIntExpr{std::get_if<Expr<SubscriptInteger>>(&intExpr->u)}) {
843 return std::move(*ssIntExpr);
844 } else {
845 return Expr<SubscriptInteger>{
846 Convert<SubscriptInteger, TypeCategory::Integer>{
847 std::move(*intExpr)}};
848 }
849 } else {
850 Say("Subscript expression is not INTEGER"_err_en_US);
851 }
852 }
853 return std::nullopt;
854 }
855
TripletPart(const std::optional<parser::Subscript> & s)856 std::optional<Expr<SubscriptInteger>> ExpressionAnalyzer::TripletPart(
857 const std::optional<parser::Subscript> &s) {
858 if (s) {
859 return AsSubscript(Analyze(*s));
860 } else {
861 return std::nullopt;
862 }
863 }
864
AnalyzeSectionSubscript(const parser::SectionSubscript & ss)865 std::optional<Subscript> ExpressionAnalyzer::AnalyzeSectionSubscript(
866 const parser::SectionSubscript &ss) {
867 return std::visit(
868 common::visitors{
869 [&](const parser::SubscriptTriplet &t) -> std::optional<Subscript> {
870 const auto &lower{std::get<0>(t.t)};
871 const auto &upper{std::get<1>(t.t)};
872 const auto &stride{std::get<2>(t.t)};
873 auto result{Triplet{
874 TripletPart(lower), TripletPart(upper), TripletPart(stride)}};
875 if ((lower && !result.lower()) || (upper && !result.upper())) {
876 return std::nullopt;
877 } else {
878 return std::make_optional<Subscript>(result);
879 }
880 },
881 [&](const auto &s) -> std::optional<Subscript> {
882 if (auto subscriptExpr{AsSubscript(Analyze(s))}) {
883 return Subscript{std::move(*subscriptExpr)};
884 } else {
885 return std::nullopt;
886 }
887 },
888 },
889 ss.u);
890 }
891
892 // Empty result means an error occurred
AnalyzeSectionSubscripts(const std::list<parser::SectionSubscript> & sss)893 std::vector<Subscript> ExpressionAnalyzer::AnalyzeSectionSubscripts(
894 const std::list<parser::SectionSubscript> &sss) {
895 bool error{false};
896 std::vector<Subscript> subscripts;
897 for (const auto &s : sss) {
898 if (auto subscript{AnalyzeSectionSubscript(s)}) {
899 subscripts.emplace_back(std::move(*subscript));
900 } else {
901 error = true;
902 }
903 }
904 return !error ? subscripts : std::vector<Subscript>{};
905 }
906
Analyze(const parser::ArrayElement & ae)907 MaybeExpr ExpressionAnalyzer::Analyze(const parser::ArrayElement &ae) {
908 MaybeExpr baseExpr;
909 {
910 auto restorer{AllowWholeAssumedSizeArray()};
911 baseExpr = Analyze(ae.base);
912 }
913 if (baseExpr) {
914 if (ae.subscripts.empty()) {
915 // will be converted to function call later or error reported
916 } else if (baseExpr->Rank() == 0) {
917 if (const Symbol * symbol{GetLastSymbol(*baseExpr)}) {
918 if (!context_.HasError(symbol)) {
919 Say("'%s' is not an array"_err_en_US, symbol->name());
920 context_.SetError(*symbol);
921 }
922 }
923 } else if (std::optional<DataRef> dataRef{
924 ExtractDataRef(std::move(*baseExpr))}) {
925 return ApplySubscripts(
926 std::move(*dataRef), AnalyzeSectionSubscripts(ae.subscripts));
927 } else {
928 Say("Subscripts may be applied only to an object, component, or array constant"_err_en_US);
929 }
930 }
931 // error was reported: analyze subscripts without reporting more errors
932 auto restorer{GetContextualMessages().DiscardMessages()};
933 AnalyzeSectionSubscripts(ae.subscripts);
934 return std::nullopt;
935 }
936
937 // Type parameter inquiries apply to data references, but don't depend
938 // on any trailing (co)subscripts.
IgnoreAnySubscripts(Designator<SomeDerived> && designator)939 static NamedEntity IgnoreAnySubscripts(Designator<SomeDerived> &&designator) {
940 return std::visit(
941 common::visitors{
942 [](SymbolRef &&symbol) { return NamedEntity{symbol}; },
943 [](Component &&component) {
944 return NamedEntity{std::move(component)};
945 },
946 [](ArrayRef &&arrayRef) { return std::move(arrayRef.base()); },
947 [](CoarrayRef &&coarrayRef) {
948 return NamedEntity{coarrayRef.GetLastSymbol()};
949 },
950 },
951 std::move(designator.u));
952 }
953
954 // Components of parent derived types are explicitly represented as such.
CreateComponent(DataRef && base,const Symbol & component,const semantics::Scope & scope)955 static std::optional<Component> CreateComponent(
956 DataRef &&base, const Symbol &component, const semantics::Scope &scope) {
957 if (&component.owner() == &scope) {
958 return Component{std::move(base), component};
959 }
960 if (const semantics::Scope * parentScope{scope.GetDerivedTypeParent()}) {
961 if (const Symbol * parentComponent{parentScope->GetSymbol()}) {
962 return CreateComponent(
963 DataRef{Component{std::move(base), *parentComponent}}, component,
964 *parentScope);
965 }
966 }
967 return std::nullopt;
968 }
969
970 // Derived type component references and type parameter inquiries
Analyze(const parser::StructureComponent & sc)971 MaybeExpr ExpressionAnalyzer::Analyze(const parser::StructureComponent &sc) {
972 MaybeExpr base{Analyze(sc.base)};
973 Symbol *sym{sc.component.symbol};
974 if (!base || !sym || context_.HasError(sym)) {
975 return std::nullopt;
976 }
977 const auto &name{sc.component.source};
978 if (auto *dtExpr{UnwrapExpr<Expr<SomeDerived>>(*base)}) {
979 const auto *dtSpec{GetDerivedTypeSpec(dtExpr->GetType())};
980 if (sym->detailsIf<semantics::TypeParamDetails>()) {
981 if (auto *designator{UnwrapExpr<Designator<SomeDerived>>(*dtExpr)}) {
982 if (std::optional<DynamicType> dyType{DynamicType::From(*sym)}) {
983 if (dyType->category() == TypeCategory::Integer) {
984 auto restorer{GetContextualMessages().SetLocation(name)};
985 return Fold(ConvertToType(*dyType,
986 AsGenericExpr(TypeParamInquiry{
987 IgnoreAnySubscripts(std::move(*designator)), *sym})));
988 }
989 }
990 Say(name, "Type parameter is not INTEGER"_err_en_US);
991 } else {
992 Say(name,
993 "A type parameter inquiry must be applied to "
994 "a designator"_err_en_US);
995 }
996 } else if (!dtSpec || !dtSpec->scope()) {
997 CHECK(context_.AnyFatalError() || !foldingContext_.messages().empty());
998 return std::nullopt;
999 } else if (std::optional<DataRef> dataRef{
1000 ExtractDataRef(std::move(*dtExpr))}) {
1001 if (auto component{
1002 CreateComponent(std::move(*dataRef), *sym, *dtSpec->scope())}) {
1003 return Designate(DataRef{std::move(*component)});
1004 } else {
1005 Say(name, "Component is not in scope of derived TYPE(%s)"_err_en_US,
1006 dtSpec->typeSymbol().name());
1007 }
1008 } else {
1009 Say(name,
1010 "Base of component reference must be a data reference"_err_en_US);
1011 }
1012 } else if (auto *details{sym->detailsIf<semantics::MiscDetails>()}) {
1013 // special part-ref: %re, %im, %kind, %len
1014 // Type errors are detected and reported in semantics.
1015 using MiscKind = semantics::MiscDetails::Kind;
1016 MiscKind kind{details->kind()};
1017 if (kind == MiscKind::ComplexPartRe || kind == MiscKind::ComplexPartIm) {
1018 if (auto *zExpr{std::get_if<Expr<SomeComplex>>(&base->u)}) {
1019 if (std::optional<DataRef> dataRef{ExtractDataRef(std::move(*zExpr))}) {
1020 Expr<SomeReal> realExpr{std::visit(
1021 [&](const auto &z) {
1022 using PartType = typename ResultType<decltype(z)>::Part;
1023 auto part{kind == MiscKind::ComplexPartRe
1024 ? ComplexPart::Part::RE
1025 : ComplexPart::Part::IM};
1026 return AsCategoryExpr(Designator<PartType>{
1027 ComplexPart{std::move(*dataRef), part}});
1028 },
1029 zExpr->u)};
1030 return AsGenericExpr(std::move(realExpr));
1031 }
1032 }
1033 } else if (kind == MiscKind::KindParamInquiry ||
1034 kind == MiscKind::LenParamInquiry) {
1035 // Convert x%KIND -> intrinsic KIND(x), x%LEN -> intrinsic LEN(x)
1036 return MakeFunctionRef(
1037 name, ActualArguments{ActualArgument{std::move(*base)}});
1038 } else {
1039 DIE("unexpected MiscDetails::Kind");
1040 }
1041 } else {
1042 Say(name, "derived type required before component reference"_err_en_US);
1043 }
1044 return std::nullopt;
1045 }
1046
Analyze(const parser::CoindexedNamedObject & x)1047 MaybeExpr ExpressionAnalyzer::Analyze(const parser::CoindexedNamedObject &x) {
1048 if (auto maybeDataRef{ExtractDataRef(Analyze(x.base))}) {
1049 DataRef *dataRef{&*maybeDataRef};
1050 std::vector<Subscript> subscripts;
1051 SymbolVector reversed;
1052 if (auto *aRef{std::get_if<ArrayRef>(&dataRef->u)}) {
1053 subscripts = std::move(aRef->subscript());
1054 reversed.push_back(aRef->GetLastSymbol());
1055 if (Component * component{aRef->base().UnwrapComponent()}) {
1056 dataRef = &component->base();
1057 } else {
1058 dataRef = nullptr;
1059 }
1060 }
1061 if (dataRef) {
1062 while (auto *component{std::get_if<Component>(&dataRef->u)}) {
1063 reversed.push_back(component->GetLastSymbol());
1064 dataRef = &component->base();
1065 }
1066 if (auto *baseSym{std::get_if<SymbolRef>(&dataRef->u)}) {
1067 reversed.push_back(*baseSym);
1068 } else {
1069 Say("Base of coindexed named object has subscripts or cosubscripts"_err_en_US);
1070 }
1071 }
1072 std::vector<Expr<SubscriptInteger>> cosubscripts;
1073 bool cosubsOk{true};
1074 for (const auto &cosub :
1075 std::get<std::list<parser::Cosubscript>>(x.imageSelector.t)) {
1076 MaybeExpr coex{Analyze(cosub)};
1077 if (auto *intExpr{UnwrapExpr<Expr<SomeInteger>>(coex)}) {
1078 cosubscripts.push_back(
1079 ConvertToType<SubscriptInteger>(std::move(*intExpr)));
1080 } else {
1081 cosubsOk = false;
1082 }
1083 }
1084 if (cosubsOk && !reversed.empty()) {
1085 int numCosubscripts{static_cast<int>(cosubscripts.size())};
1086 const Symbol &symbol{reversed.front()};
1087 if (numCosubscripts != symbol.Corank()) {
1088 Say("'%s' has corank %d, but coindexed reference has %d cosubscripts"_err_en_US,
1089 symbol.name(), symbol.Corank(), numCosubscripts);
1090 }
1091 }
1092 for (const auto &imageSelSpec :
1093 std::get<std::list<parser::ImageSelectorSpec>>(x.imageSelector.t)) {
1094 std::visit(
1095 common::visitors{
1096 [&](const auto &x) { Analyze(x.v); },
1097 },
1098 imageSelSpec.u);
1099 }
1100 // Reverse the chain of symbols so that the base is first and coarray
1101 // ultimate component is last.
1102 if (cosubsOk) {
1103 return Designate(
1104 DataRef{CoarrayRef{SymbolVector{reversed.crbegin(), reversed.crend()},
1105 std::move(subscripts), std::move(cosubscripts)}});
1106 }
1107 }
1108 return std::nullopt;
1109 }
1110
IntegerTypeSpecKind(const parser::IntegerTypeSpec & spec)1111 int ExpressionAnalyzer::IntegerTypeSpecKind(
1112 const parser::IntegerTypeSpec &spec) {
1113 Expr<SubscriptInteger> value{
1114 AnalyzeKindSelector(TypeCategory::Integer, spec.v)};
1115 if (auto kind{ToInt64(value)}) {
1116 return static_cast<int>(*kind);
1117 }
1118 SayAt(spec, "Constant INTEGER kind value required here"_err_en_US);
1119 return GetDefaultKind(TypeCategory::Integer);
1120 }
1121
1122 // Array constructors
1123
1124 // Inverts a collection of generic ArrayConstructorValues<SomeType> that
1125 // all happen to have the same actual type T into one ArrayConstructor<T>.
1126 template <typename T>
MakeSpecific(ArrayConstructorValues<SomeType> && from)1127 ArrayConstructorValues<T> MakeSpecific(
1128 ArrayConstructorValues<SomeType> &&from) {
1129 ArrayConstructorValues<T> to;
1130 for (ArrayConstructorValue<SomeType> &x : from) {
1131 std::visit(
1132 common::visitors{
1133 [&](common::CopyableIndirection<Expr<SomeType>> &&expr) {
1134 auto *typed{UnwrapExpr<Expr<T>>(expr.value())};
1135 to.Push(std::move(DEREF(typed)));
1136 },
1137 [&](ImpliedDo<SomeType> &&impliedDo) {
1138 to.Push(ImpliedDo<T>{impliedDo.name(),
1139 std::move(impliedDo.lower()), std::move(impliedDo.upper()),
1140 std::move(impliedDo.stride()),
1141 MakeSpecific<T>(std::move(impliedDo.values()))});
1142 },
1143 },
1144 std::move(x.u));
1145 }
1146 return to;
1147 }
1148
1149 class ArrayConstructorContext {
1150 public:
ArrayConstructorContext(ExpressionAnalyzer & c,std::optional<DynamicTypeWithLength> && t)1151 ArrayConstructorContext(
1152 ExpressionAnalyzer &c, std::optional<DynamicTypeWithLength> &&t)
1153 : exprAnalyzer_{c}, type_{std::move(t)} {}
1154
1155 void Add(const parser::AcValue &);
1156 MaybeExpr ToExpr();
1157
1158 // These interfaces allow *this to be used as a type visitor argument to
1159 // common::SearchTypes() to convert the array constructor to a typed
1160 // expression in ToExpr().
1161 using Result = MaybeExpr;
1162 using Types = AllTypes;
Test()1163 template <typename T> Result Test() {
1164 if (type_ && type_->category() == T::category) {
1165 if constexpr (T::category == TypeCategory::Derived) {
1166 if (type_->IsUnlimitedPolymorphic()) {
1167 return std::nullopt;
1168 } else {
1169 return AsMaybeExpr(ArrayConstructor<T>{type_->GetDerivedTypeSpec(),
1170 MakeSpecific<T>(std::move(values_))});
1171 }
1172 } else if (type_->kind() == T::kind) {
1173 if constexpr (T::category == TypeCategory::Character) {
1174 if (auto len{type_->LEN()}) {
1175 return AsMaybeExpr(ArrayConstructor<T>{
1176 *std::move(len), MakeSpecific<T>(std::move(values_))});
1177 }
1178 } else {
1179 return AsMaybeExpr(
1180 ArrayConstructor<T>{MakeSpecific<T>(std::move(values_))});
1181 }
1182 }
1183 }
1184 return std::nullopt;
1185 }
1186
1187 private:
1188 using ImpliedDoIntType = ResultType<ImpliedDoIndex>;
1189
1190 void Push(MaybeExpr &&);
1191 void Add(const parser::AcValue::Triplet &);
1192 void Add(const parser::Expr &);
1193 void Add(const parser::AcImpliedDo &);
1194 void UnrollConstantImpliedDo(const parser::AcImpliedDo &,
1195 parser::CharBlock name, std::int64_t lower, std::int64_t upper,
1196 std::int64_t stride);
1197
1198 template <int KIND, typename A>
GetSpecificIntExpr(const A & x)1199 std::optional<Expr<Type<TypeCategory::Integer, KIND>>> GetSpecificIntExpr(
1200 const A &x) {
1201 if (MaybeExpr y{exprAnalyzer_.Analyze(x)}) {
1202 Expr<SomeInteger> *intExpr{UnwrapExpr<Expr<SomeInteger>>(*y)};
1203 return Fold(exprAnalyzer_.GetFoldingContext(),
1204 ConvertToType<Type<TypeCategory::Integer, KIND>>(
1205 std::move(DEREF(intExpr))));
1206 }
1207 return std::nullopt;
1208 }
1209
1210 // Nested array constructors all reference the same ExpressionAnalyzer,
1211 // which represents the nest of active implied DO loop indices.
1212 ExpressionAnalyzer &exprAnalyzer_;
1213 std::optional<DynamicTypeWithLength> type_;
1214 bool explicitType_{type_.has_value()};
1215 std::optional<std::int64_t> constantLength_;
1216 ArrayConstructorValues<SomeType> values_;
1217 std::uint64_t messageDisplayedSet_{0};
1218 };
1219
Push(MaybeExpr && x)1220 void ArrayConstructorContext::Push(MaybeExpr &&x) {
1221 if (!x) {
1222 return;
1223 }
1224 if (auto dyType{x->GetType()}) {
1225 DynamicTypeWithLength xType{*dyType};
1226 if (Expr<SomeCharacter> * charExpr{UnwrapExpr<Expr<SomeCharacter>>(*x)}) {
1227 CHECK(xType.category() == TypeCategory::Character);
1228 xType.length =
1229 std::visit([](const auto &kc) { return kc.LEN(); }, charExpr->u);
1230 }
1231 if (!type_) {
1232 // If there is no explicit type-spec in an array constructor, the type
1233 // of the array is the declared type of all of the elements, which must
1234 // be well-defined and all match.
1235 // TODO: Possible language extension: use the most general type of
1236 // the values as the type of a numeric constructed array, convert all
1237 // of the other values to that type. Alternative: let the first value
1238 // determine the type, and convert the others to that type.
1239 CHECK(!explicitType_);
1240 type_ = std::move(xType);
1241 constantLength_ = ToInt64(type_->length);
1242 values_.Push(std::move(*x));
1243 } else if (!explicitType_) {
1244 if (static_cast<const DynamicType &>(*type_) ==
1245 static_cast<const DynamicType &>(xType)) {
1246 values_.Push(std::move(*x));
1247 if (auto thisLen{ToInt64(xType.LEN())}) {
1248 if (constantLength_) {
1249 if (exprAnalyzer_.context().warnOnNonstandardUsage() &&
1250 *thisLen != *constantLength_) {
1251 if (!(messageDisplayedSet_ & 1)) {
1252 exprAnalyzer_.Say(
1253 "Character literal in array constructor without explicit "
1254 "type has different length than earlier elements"_en_US);
1255 messageDisplayedSet_ |= 1;
1256 }
1257 }
1258 if (*thisLen > *constantLength_) {
1259 // Language extension: use the longest literal to determine the
1260 // length of the array constructor's character elements, not the
1261 // first, when there is no explicit type.
1262 *constantLength_ = *thisLen;
1263 type_->length = xType.LEN();
1264 }
1265 } else {
1266 constantLength_ = *thisLen;
1267 type_->length = xType.LEN();
1268 }
1269 }
1270 } else {
1271 if (!(messageDisplayedSet_ & 2)) {
1272 exprAnalyzer_.Say(
1273 "Values in array constructor must have the same declared type "
1274 "when no explicit type appears"_err_en_US); // C7110
1275 messageDisplayedSet_ |= 2;
1276 }
1277 }
1278 } else {
1279 if (auto cast{ConvertToType(*type_, std::move(*x))}) {
1280 values_.Push(std::move(*cast));
1281 } else if (!(messageDisplayedSet_ & 4)) {
1282 exprAnalyzer_.Say(
1283 "Value in array constructor of type '%s' could not "
1284 "be converted to the type of the array '%s'"_err_en_US,
1285 x->GetType()->AsFortran(), type_->AsFortran()); // C7111, C7112
1286 messageDisplayedSet_ |= 4;
1287 }
1288 }
1289 }
1290 }
1291
Add(const parser::AcValue & x)1292 void ArrayConstructorContext::Add(const parser::AcValue &x) {
1293 std::visit(
1294 common::visitors{
1295 [&](const parser::AcValue::Triplet &triplet) { Add(triplet); },
1296 [&](const common::Indirection<parser::Expr> &expr) {
1297 Add(expr.value());
1298 },
1299 [&](const common::Indirection<parser::AcImpliedDo> &impliedDo) {
1300 Add(impliedDo.value());
1301 },
1302 },
1303 x.u);
1304 }
1305
1306 // Transforms l:u(:s) into (_,_=l,u(,s)) with an anonymous index '_'
Add(const parser::AcValue::Triplet & triplet)1307 void ArrayConstructorContext::Add(const parser::AcValue::Triplet &triplet) {
1308 std::optional<Expr<ImpliedDoIntType>> lower{
1309 GetSpecificIntExpr<ImpliedDoIntType::kind>(std::get<0>(triplet.t))};
1310 std::optional<Expr<ImpliedDoIntType>> upper{
1311 GetSpecificIntExpr<ImpliedDoIntType::kind>(std::get<1>(triplet.t))};
1312 std::optional<Expr<ImpliedDoIntType>> stride{
1313 GetSpecificIntExpr<ImpliedDoIntType::kind>(std::get<2>(triplet.t))};
1314 if (lower && upper) {
1315 if (!stride) {
1316 stride = Expr<ImpliedDoIntType>{1};
1317 }
1318 if (!type_) {
1319 type_ = DynamicTypeWithLength{ImpliedDoIntType::GetType()};
1320 }
1321 auto v{std::move(values_)};
1322 parser::CharBlock anonymous;
1323 Push(Expr<SomeType>{
1324 Expr<SomeInteger>{Expr<ImpliedDoIntType>{ImpliedDoIndex{anonymous}}}});
1325 std::swap(v, values_);
1326 values_.Push(ImpliedDo<SomeType>{anonymous, std::move(*lower),
1327 std::move(*upper), std::move(*stride), std::move(v)});
1328 }
1329 }
1330
Add(const parser::Expr & expr)1331 void ArrayConstructorContext::Add(const parser::Expr &expr) {
1332 auto restorer{exprAnalyzer_.GetContextualMessages().SetLocation(expr.source)};
1333 if (MaybeExpr v{exprAnalyzer_.Analyze(expr)}) {
1334 if (auto exprType{v->GetType()}) {
1335 if (!(messageDisplayedSet_ & 8) && exprType->IsUnlimitedPolymorphic()) {
1336 exprAnalyzer_.Say("Cannot have an unlimited polymorphic value in an "
1337 "array constructor"_err_en_US); // C7113
1338 messageDisplayedSet_ |= 8;
1339 }
1340 }
1341 Push(std::move(*v));
1342 }
1343 }
1344
Add(const parser::AcImpliedDo & impliedDo)1345 void ArrayConstructorContext::Add(const parser::AcImpliedDo &impliedDo) {
1346 const auto &control{std::get<parser::AcImpliedDoControl>(impliedDo.t)};
1347 const auto &bounds{std::get<parser::AcImpliedDoControl::Bounds>(control.t)};
1348 exprAnalyzer_.Analyze(bounds.name);
1349 parser::CharBlock name{bounds.name.thing.thing.source};
1350 const Symbol *symbol{bounds.name.thing.thing.symbol};
1351 int kind{ImpliedDoIntType::kind};
1352 if (const auto dynamicType{DynamicType::From(symbol)}) {
1353 kind = dynamicType->kind();
1354 }
1355 if (!exprAnalyzer_.AddImpliedDo(name, kind)) {
1356 if (!(messageDisplayedSet_ & 0x20)) {
1357 exprAnalyzer_.SayAt(name,
1358 "Implied DO index is active in surrounding implied DO loop "
1359 "and may not have the same name"_err_en_US); // C7115
1360 messageDisplayedSet_ |= 0x20;
1361 }
1362 return;
1363 }
1364 std::optional<Expr<ImpliedDoIntType>> lower{
1365 GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.lower)};
1366 std::optional<Expr<ImpliedDoIntType>> upper{
1367 GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.upper)};
1368 if (lower && upper) {
1369 std::optional<Expr<ImpliedDoIntType>> stride{
1370 GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.step)};
1371 if (!stride) {
1372 stride = Expr<ImpliedDoIntType>{1};
1373 }
1374 // Check for constant bounds; the loop may require complete unrolling
1375 // of the parse tree if all bounds are constant in order to allow the
1376 // implied DO loop index to qualify as a constant expression.
1377 auto cLower{ToInt64(lower)};
1378 auto cUpper{ToInt64(upper)};
1379 auto cStride{ToInt64(stride)};
1380 if (!(messageDisplayedSet_ & 0x10) && cStride && *cStride == 0) {
1381 exprAnalyzer_.SayAt(bounds.step.value().thing.thing.value().source,
1382 "The stride of an implied DO loop must not be zero"_err_en_US);
1383 messageDisplayedSet_ |= 0x10;
1384 }
1385 bool isConstant{cLower && cUpper && cStride && *cStride != 0};
1386 bool isNonemptyConstant{isConstant &&
1387 ((*cStride > 0 && *cLower <= *cUpper) ||
1388 (*cStride < 0 && *cLower >= *cUpper))};
1389 bool unrollConstantLoop{false};
1390 parser::Messages buffer;
1391 auto saveMessagesDisplayed{messageDisplayedSet_};
1392 {
1393 auto messageRestorer{
1394 exprAnalyzer_.GetContextualMessages().SetMessages(buffer)};
1395 auto v{std::move(values_)};
1396 for (const auto &value :
1397 std::get<std::list<parser::AcValue>>(impliedDo.t)) {
1398 Add(value);
1399 }
1400 std::swap(v, values_);
1401 if (isNonemptyConstant && buffer.AnyFatalError()) {
1402 unrollConstantLoop = true;
1403 } else {
1404 values_.Push(ImpliedDo<SomeType>{name, std::move(*lower),
1405 std::move(*upper), std::move(*stride), std::move(v)});
1406 }
1407 }
1408 if (unrollConstantLoop) {
1409 messageDisplayedSet_ = saveMessagesDisplayed;
1410 UnrollConstantImpliedDo(impliedDo, name, *cLower, *cUpper, *cStride);
1411 } else if (auto *messages{
1412 exprAnalyzer_.GetContextualMessages().messages()}) {
1413 messages->Annex(std::move(buffer));
1414 }
1415 }
1416 exprAnalyzer_.RemoveImpliedDo(name);
1417 }
1418
1419 // Fortran considers an implied DO index of an array constructor to be
1420 // a constant expression if the bounds of the implied DO loop are constant.
1421 // Usually this doesn't matter, but if we emitted spurious messages as a
1422 // result of not using constant values for the index while analyzing the
1423 // items, we need to do it again the "hard" way with multiple iterations over
1424 // the parse tree.
UnrollConstantImpliedDo(const parser::AcImpliedDo & impliedDo,parser::CharBlock name,std::int64_t lower,std::int64_t upper,std::int64_t stride)1425 void ArrayConstructorContext::UnrollConstantImpliedDo(
1426 const parser::AcImpliedDo &impliedDo, parser::CharBlock name,
1427 std::int64_t lower, std::int64_t upper, std::int64_t stride) {
1428 auto &foldingContext{exprAnalyzer_.GetFoldingContext()};
1429 auto restorer{exprAnalyzer_.DoNotUseSavedTypedExprs()};
1430 for (auto &at{foldingContext.StartImpliedDo(name, lower)};
1431 (stride > 0 && at <= upper) || (stride < 0 && at >= upper);
1432 at += stride) {
1433 for (const auto &value :
1434 std::get<std::list<parser::AcValue>>(impliedDo.t)) {
1435 Add(value);
1436 }
1437 }
1438 foldingContext.EndImpliedDo(name);
1439 }
1440
ToExpr()1441 MaybeExpr ArrayConstructorContext::ToExpr() {
1442 return common::SearchTypes(std::move(*this));
1443 }
1444
Analyze(const parser::ArrayConstructor & array)1445 MaybeExpr ExpressionAnalyzer::Analyze(const parser::ArrayConstructor &array) {
1446 const parser::AcSpec &acSpec{array.v};
1447 ArrayConstructorContext acContext{*this, AnalyzeTypeSpec(acSpec.type)};
1448 for (const parser::AcValue &value : acSpec.values) {
1449 acContext.Add(value);
1450 }
1451 return acContext.ToExpr();
1452 }
1453
Analyze(const parser::StructureConstructor & structure)1454 MaybeExpr ExpressionAnalyzer::Analyze(
1455 const parser::StructureConstructor &structure) {
1456 auto &parsedType{std::get<parser::DerivedTypeSpec>(structure.t)};
1457 parser::CharBlock typeName{std::get<parser::Name>(parsedType.t).source};
1458 if (!parsedType.derivedTypeSpec) {
1459 return std::nullopt;
1460 }
1461 const auto &spec{*parsedType.derivedTypeSpec};
1462 const Symbol &typeSymbol{spec.typeSymbol()};
1463 if (!spec.scope() || !typeSymbol.has<semantics::DerivedTypeDetails>()) {
1464 return std::nullopt; // error recovery
1465 }
1466 const auto &typeDetails{typeSymbol.get<semantics::DerivedTypeDetails>()};
1467 const Symbol *parentComponent{typeDetails.GetParentComponent(*spec.scope())};
1468
1469 if (typeSymbol.attrs().test(semantics::Attr::ABSTRACT)) { // C796
1470 AttachDeclaration(Say(typeName,
1471 "ABSTRACT derived type '%s' may not be used in a "
1472 "structure constructor"_err_en_US,
1473 typeName),
1474 typeSymbol); // C7114
1475 }
1476
1477 // This iterator traverses all of the components in the derived type and its
1478 // parents. The symbols for whole parent components appear after their
1479 // own components and before the components of the types that extend them.
1480 // E.g., TYPE :: A; REAL X; END TYPE
1481 // TYPE, EXTENDS(A) :: B; REAL Y; END TYPE
1482 // produces the component list X, A, Y.
1483 // The order is important below because a structure constructor can
1484 // initialize X or A by name, but not both.
1485 auto components{semantics::OrderedComponentIterator{spec}};
1486 auto nextAnonymous{components.begin()};
1487
1488 std::set<parser::CharBlock> unavailable;
1489 bool anyKeyword{false};
1490 StructureConstructor result{spec};
1491 bool checkConflicts{true}; // until we hit one
1492 auto &messages{GetContextualMessages()};
1493
1494 for (const auto &component :
1495 std::get<std::list<parser::ComponentSpec>>(structure.t)) {
1496 const parser::Expr &expr{
1497 std::get<parser::ComponentDataSource>(component.t).v.value()};
1498 parser::CharBlock source{expr.source};
1499 auto restorer{messages.SetLocation(source)};
1500 const Symbol *symbol{nullptr};
1501 MaybeExpr value{Analyze(expr)};
1502 std::optional<DynamicType> valueType{DynamicType::From(value)};
1503 if (const auto &kw{std::get<std::optional<parser::Keyword>>(component.t)}) {
1504 anyKeyword = true;
1505 source = kw->v.source;
1506 symbol = kw->v.symbol;
1507 if (!symbol) {
1508 auto componentIter{std::find_if(components.begin(), components.end(),
1509 [=](const Symbol &symbol) { return symbol.name() == source; })};
1510 if (componentIter != components.end()) {
1511 symbol = &*componentIter;
1512 }
1513 }
1514 if (!symbol) { // C7101
1515 Say(source,
1516 "Keyword '%s=' does not name a component of derived type '%s'"_err_en_US,
1517 source, typeName);
1518 }
1519 } else {
1520 if (anyKeyword) { // C7100
1521 Say(source,
1522 "Value in structure constructor lacks a component name"_err_en_US);
1523 checkConflicts = false; // stem cascade
1524 }
1525 // Here's a regrettably common extension of the standard: anonymous
1526 // initialization of parent components, e.g., T(PT(1)) rather than
1527 // T(1) or T(PT=PT(1)).
1528 if (nextAnonymous == components.begin() && parentComponent &&
1529 valueType == DynamicType::From(*parentComponent) &&
1530 context().IsEnabled(LanguageFeature::AnonymousParents)) {
1531 auto iter{
1532 std::find(components.begin(), components.end(), *parentComponent)};
1533 if (iter != components.end()) {
1534 symbol = parentComponent;
1535 nextAnonymous = ++iter;
1536 if (context().ShouldWarn(LanguageFeature::AnonymousParents)) {
1537 Say(source,
1538 "Whole parent component '%s' in structure "
1539 "constructor should not be anonymous"_en_US,
1540 symbol->name());
1541 }
1542 }
1543 }
1544 while (!symbol && nextAnonymous != components.end()) {
1545 const Symbol &next{*nextAnonymous};
1546 ++nextAnonymous;
1547 if (!next.test(Symbol::Flag::ParentComp)) {
1548 symbol = &next;
1549 }
1550 }
1551 if (!symbol) {
1552 Say(source, "Unexpected value in structure constructor"_err_en_US);
1553 }
1554 }
1555 if (symbol) {
1556 if (const auto *currScope{context_.globalScope().FindScope(source)}) {
1557 if (auto msg{CheckAccessibleComponent(*currScope, *symbol)}) {
1558 Say(source, *msg);
1559 }
1560 }
1561 if (checkConflicts) {
1562 auto componentIter{
1563 std::find(components.begin(), components.end(), *symbol)};
1564 if (unavailable.find(symbol->name()) != unavailable.cend()) {
1565 // C797, C798
1566 Say(source,
1567 "Component '%s' conflicts with another component earlier in "
1568 "this structure constructor"_err_en_US,
1569 symbol->name());
1570 } else if (symbol->test(Symbol::Flag::ParentComp)) {
1571 // Make earlier components unavailable once a whole parent appears.
1572 for (auto it{components.begin()}; it != componentIter; ++it) {
1573 unavailable.insert(it->name());
1574 }
1575 } else {
1576 // Make whole parent components unavailable after any of their
1577 // constituents appear.
1578 for (auto it{componentIter}; it != components.end(); ++it) {
1579 if (it->test(Symbol::Flag::ParentComp)) {
1580 unavailable.insert(it->name());
1581 }
1582 }
1583 }
1584 }
1585 unavailable.insert(symbol->name());
1586 if (value) {
1587 if (symbol->has<semantics::ProcEntityDetails>()) {
1588 CHECK(IsPointer(*symbol));
1589 } else if (symbol->has<semantics::ObjectEntityDetails>()) {
1590 // C1594(4)
1591 const auto &innermost{context_.FindScope(expr.source)};
1592 if (const auto *pureProc{FindPureProcedureContaining(innermost)}) {
1593 if (const Symbol * pointer{FindPointerComponent(*symbol)}) {
1594 if (const Symbol *
1595 object{FindExternallyVisibleObject(*value, *pureProc)}) {
1596 if (auto *msg{Say(expr.source,
1597 "Externally visible object '%s' may not be "
1598 "associated with pointer component '%s' in a "
1599 "pure procedure"_err_en_US,
1600 object->name(), pointer->name())}) {
1601 msg->Attach(object->name(), "Object declaration"_en_US)
1602 .Attach(pointer->name(), "Pointer declaration"_en_US);
1603 }
1604 }
1605 }
1606 }
1607 } else if (symbol->has<semantics::TypeParamDetails>()) {
1608 Say(expr.source,
1609 "Type parameter '%s' may not appear as a component "
1610 "of a structure constructor"_err_en_US,
1611 symbol->name());
1612 continue;
1613 } else {
1614 Say(expr.source,
1615 "Component '%s' is neither a procedure pointer "
1616 "nor a data object"_err_en_US,
1617 symbol->name());
1618 continue;
1619 }
1620 if (IsPointer(*symbol)) {
1621 semantics::CheckPointerAssignment(
1622 GetFoldingContext(), *symbol, *value); // C7104, C7105
1623 result.Add(*symbol, Fold(std::move(*value)));
1624 } else if (MaybeExpr converted{
1625 ConvertToType(*symbol, std::move(*value))}) {
1626 if (auto componentShape{GetShape(GetFoldingContext(), *symbol)}) {
1627 if (auto valueShape{GetShape(GetFoldingContext(), *converted)}) {
1628 if (GetRank(*componentShape) == 0 && GetRank(*valueShape) > 0) {
1629 AttachDeclaration(
1630 Say(expr.source,
1631 "Rank-%d array value is not compatible with scalar component '%s'"_err_en_US,
1632 GetRank(*valueShape), symbol->name()),
1633 *symbol);
1634 } else if (CheckConformance(messages, *componentShape,
1635 *valueShape, "component", "value")) {
1636 if (GetRank(*componentShape) > 0 && GetRank(*valueShape) == 0 &&
1637 !IsExpandableScalar(*converted)) {
1638 AttachDeclaration(
1639 Say(expr.source,
1640 "Scalar value cannot be expanded to shape of array component '%s'"_err_en_US,
1641 symbol->name()),
1642 *symbol);
1643 } else {
1644 result.Add(*symbol, std::move(*converted));
1645 }
1646 }
1647 } else {
1648 Say(expr.source, "Shape of value cannot be determined"_err_en_US);
1649 }
1650 } else {
1651 AttachDeclaration(
1652 Say(expr.source,
1653 "Shape of component '%s' cannot be determined"_err_en_US,
1654 symbol->name()),
1655 *symbol);
1656 }
1657 } else if (IsAllocatable(*symbol) &&
1658 std::holds_alternative<NullPointer>(value->u)) {
1659 // NULL() with no arguments allowed by 7.5.10 para 6 for ALLOCATABLE
1660 } else if (auto symType{DynamicType::From(symbol)}) {
1661 if (valueType) {
1662 AttachDeclaration(
1663 Say(expr.source,
1664 "Value in structure constructor of type %s is "
1665 "incompatible with component '%s' of type %s"_err_en_US,
1666 valueType->AsFortran(), symbol->name(),
1667 symType->AsFortran()),
1668 *symbol);
1669 } else {
1670 AttachDeclaration(
1671 Say(expr.source,
1672 "Value in structure constructor is incompatible with "
1673 " component '%s' of type %s"_err_en_US,
1674 symbol->name(), symType->AsFortran()),
1675 *symbol);
1676 }
1677 }
1678 }
1679 }
1680 }
1681
1682 // Ensure that unmentioned component objects have default initializers.
1683 for (const Symbol &symbol : components) {
1684 if (!symbol.test(Symbol::Flag::ParentComp) &&
1685 unavailable.find(symbol.name()) == unavailable.cend() &&
1686 !IsAllocatable(symbol)) {
1687 if (const auto *details{
1688 symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
1689 if (details->init()) {
1690 result.Add(symbol, common::Clone(*details->init()));
1691 } else { // C799
1692 AttachDeclaration(Say(typeName,
1693 "Structure constructor lacks a value for "
1694 "component '%s'"_err_en_US,
1695 symbol.name()),
1696 symbol);
1697 }
1698 }
1699 }
1700 }
1701
1702 return AsMaybeExpr(Expr<SomeDerived>{std::move(result)});
1703 }
1704
GetPassName(const semantics::Symbol & proc)1705 static std::optional<parser::CharBlock> GetPassName(
1706 const semantics::Symbol &proc) {
1707 return std::visit(
1708 [](const auto &details) {
1709 if constexpr (std::is_base_of_v<semantics::WithPassArg,
1710 std::decay_t<decltype(details)>>) {
1711 return details.passName();
1712 } else {
1713 return std::optional<parser::CharBlock>{};
1714 }
1715 },
1716 proc.details());
1717 }
1718
GetPassIndex(const Symbol & proc)1719 static int GetPassIndex(const Symbol &proc) {
1720 CHECK(!proc.attrs().test(semantics::Attr::NOPASS));
1721 std::optional<parser::CharBlock> passName{GetPassName(proc)};
1722 const auto *interface{semantics::FindInterface(proc)};
1723 if (!passName || !interface) {
1724 return 0; // first argument is passed-object
1725 }
1726 const auto &subp{interface->get<semantics::SubprogramDetails>()};
1727 int index{0};
1728 for (const auto *arg : subp.dummyArgs()) {
1729 if (arg && arg->name() == passName) {
1730 return index;
1731 }
1732 ++index;
1733 }
1734 DIE("PASS argument name not in dummy argument list");
1735 }
1736
1737 // Injects an expression into an actual argument list as the "passed object"
1738 // for a type-bound procedure reference that is not NOPASS. Adds an
1739 // argument keyword if possible, but not when the passed object goes
1740 // before a positional argument.
1741 // e.g., obj%tbp(x) -> tbp(obj,x).
AddPassArg(ActualArguments & actuals,const Expr<SomeDerived> & expr,const Symbol & component,bool isPassedObject=true)1742 static void AddPassArg(ActualArguments &actuals, const Expr<SomeDerived> &expr,
1743 const Symbol &component, bool isPassedObject = true) {
1744 if (component.attrs().test(semantics::Attr::NOPASS)) {
1745 return;
1746 }
1747 int passIndex{GetPassIndex(component)};
1748 auto iter{actuals.begin()};
1749 int at{0};
1750 while (iter < actuals.end() && at < passIndex) {
1751 if (*iter && (*iter)->keyword()) {
1752 iter = actuals.end();
1753 break;
1754 }
1755 ++iter;
1756 ++at;
1757 }
1758 ActualArgument passed{AsGenericExpr(common::Clone(expr))};
1759 passed.set_isPassedObject(isPassedObject);
1760 if (iter == actuals.end()) {
1761 if (auto passName{GetPassName(component)}) {
1762 passed.set_keyword(*passName);
1763 }
1764 }
1765 actuals.emplace(iter, std::move(passed));
1766 }
1767
1768 // Return the compile-time resolution of a procedure binding, if possible.
GetBindingResolution(const std::optional<DynamicType> & baseType,const Symbol & component)1769 static const Symbol *GetBindingResolution(
1770 const std::optional<DynamicType> &baseType, const Symbol &component) {
1771 const auto *binding{component.detailsIf<semantics::ProcBindingDetails>()};
1772 if (!binding) {
1773 return nullptr;
1774 }
1775 if (!component.attrs().test(semantics::Attr::NON_OVERRIDABLE) &&
1776 (!baseType || baseType->IsPolymorphic())) {
1777 return nullptr;
1778 }
1779 return &binding->symbol();
1780 }
1781
AnalyzeProcedureComponentRef(const parser::ProcComponentRef & pcr,ActualArguments && arguments)1782 auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
1783 const parser::ProcComponentRef &pcr, ActualArguments &&arguments)
1784 -> std::optional<CalleeAndArguments> {
1785 const parser::StructureComponent &sc{pcr.v.thing};
1786 if (MaybeExpr base{Analyze(sc.base)}) {
1787 if (const Symbol * sym{sc.component.symbol}) {
1788 if (context_.HasError(sym)) {
1789 return std::nullopt;
1790 }
1791 if (auto *dtExpr{UnwrapExpr<Expr<SomeDerived>>(*base)}) {
1792 if (sym->has<semantics::GenericDetails>()) {
1793 AdjustActuals adjustment{
1794 [&](const Symbol &proc, ActualArguments &actuals) {
1795 if (!proc.attrs().test(semantics::Attr::NOPASS)) {
1796 AddPassArg(actuals, std::move(*dtExpr), proc);
1797 }
1798 return true;
1799 }};
1800 sym = ResolveGeneric(*sym, arguments, adjustment);
1801 if (!sym) {
1802 EmitGenericResolutionError(*sc.component.symbol);
1803 return std::nullopt;
1804 }
1805 }
1806 if (const Symbol *
1807 resolution{GetBindingResolution(dtExpr->GetType(), *sym)}) {
1808 AddPassArg(arguments, std::move(*dtExpr), *sym, false);
1809 return CalleeAndArguments{
1810 ProcedureDesignator{*resolution}, std::move(arguments)};
1811 } else if (std::optional<DataRef> dataRef{
1812 ExtractDataRef(std::move(*dtExpr))}) {
1813 if (sym->attrs().test(semantics::Attr::NOPASS)) {
1814 return CalleeAndArguments{
1815 ProcedureDesignator{Component{std::move(*dataRef), *sym}},
1816 std::move(arguments)};
1817 } else {
1818 AddPassArg(arguments,
1819 Expr<SomeDerived>{Designator<SomeDerived>{std::move(*dataRef)}},
1820 *sym);
1821 return CalleeAndArguments{
1822 ProcedureDesignator{*sym}, std::move(arguments)};
1823 }
1824 }
1825 }
1826 Say(sc.component.source,
1827 "Base of procedure component reference is not a derived-type object"_err_en_US);
1828 }
1829 }
1830 CHECK(!GetContextualMessages().empty());
1831 return std::nullopt;
1832 }
1833
1834 // Can actual be argument associated with dummy?
CheckCompatibleArgument(bool isElemental,const ActualArgument & actual,const characteristics::DummyArgument & dummy)1835 static bool CheckCompatibleArgument(bool isElemental,
1836 const ActualArgument &actual, const characteristics::DummyArgument &dummy) {
1837 return std::visit(
1838 common::visitors{
1839 [&](const characteristics::DummyDataObject &x) {
1840 characteristics::TypeAndShape dummyTypeAndShape{x.type};
1841 if (!isElemental && actual.Rank() != dummyTypeAndShape.Rank()) {
1842 return false;
1843 } else if (auto actualType{actual.GetType()}) {
1844 return dummyTypeAndShape.type().IsTkCompatibleWith(*actualType);
1845 } else {
1846 return false;
1847 }
1848 },
1849 [&](const characteristics::DummyProcedure &) {
1850 const auto *expr{actual.UnwrapExpr()};
1851 return expr && IsProcedurePointer(*expr);
1852 },
1853 [&](const characteristics::AlternateReturn &) {
1854 return actual.isAlternateReturn();
1855 },
1856 },
1857 dummy.u);
1858 }
1859
1860 // Are the actual arguments compatible with the dummy arguments of procedure?
CheckCompatibleArguments(const characteristics::Procedure & procedure,const ActualArguments & actuals)1861 static bool CheckCompatibleArguments(
1862 const characteristics::Procedure &procedure,
1863 const ActualArguments &actuals) {
1864 bool isElemental{procedure.IsElemental()};
1865 const auto &dummies{procedure.dummyArguments};
1866 CHECK(dummies.size() == actuals.size());
1867 for (std::size_t i{0}; i < dummies.size(); ++i) {
1868 const characteristics::DummyArgument &dummy{dummies[i]};
1869 const std::optional<ActualArgument> &actual{actuals[i]};
1870 if (actual && !CheckCompatibleArgument(isElemental, *actual, dummy)) {
1871 return false;
1872 }
1873 }
1874 return true;
1875 }
1876
1877 // Handles a forward reference to a module function from what must
1878 // be a specification expression. Return false if the symbol is
1879 // an invalid forward reference.
ResolveForward(const Symbol & symbol)1880 bool ExpressionAnalyzer::ResolveForward(const Symbol &symbol) {
1881 if (context_.HasError(symbol)) {
1882 return false;
1883 }
1884 if (const auto *details{
1885 symbol.detailsIf<semantics::SubprogramNameDetails>()}) {
1886 if (details->kind() == semantics::SubprogramKind::Module) {
1887 // If this symbol is still a SubprogramNameDetails, we must be
1888 // checking a specification expression in a sibling module
1889 // procedure. Resolve its names now so that its interface
1890 // is known.
1891 semantics::ResolveSpecificationParts(context_, symbol);
1892 if (symbol.has<semantics::SubprogramNameDetails>()) {
1893 // When the symbol hasn't had its details updated, we must have
1894 // already been in the process of resolving the function's
1895 // specification part; but recursive function calls are not
1896 // allowed in specification parts (10.1.11 para 5).
1897 Say("The module function '%s' may not be referenced recursively in a specification expression"_err_en_US,
1898 symbol.name());
1899 context_.SetError(symbol);
1900 return false;
1901 }
1902 } else { // 10.1.11 para 4
1903 Say("The internal function '%s' may not be referenced in a specification expression"_err_en_US,
1904 symbol.name());
1905 context_.SetError(symbol);
1906 return false;
1907 }
1908 }
1909 return true;
1910 }
1911
1912 // Resolve a call to a generic procedure with given actual arguments.
1913 // adjustActuals is called on procedure bindings to handle pass arg.
ResolveGeneric(const Symbol & symbol,const ActualArguments & actuals,const AdjustActuals & adjustActuals,bool mightBeStructureConstructor)1914 const Symbol *ExpressionAnalyzer::ResolveGeneric(const Symbol &symbol,
1915 const ActualArguments &actuals, const AdjustActuals &adjustActuals,
1916 bool mightBeStructureConstructor) {
1917 const Symbol *elemental{nullptr}; // matching elemental specific proc
1918 const auto &details{symbol.GetUltimate().get<semantics::GenericDetails>()};
1919 for (const Symbol &specific : details.specificProcs()) {
1920 if (!ResolveForward(specific)) {
1921 continue;
1922 }
1923 if (std::optional<characteristics::Procedure> procedure{
1924 characteristics::Procedure::Characterize(
1925 ProcedureDesignator{specific}, context_.intrinsics())}) {
1926 ActualArguments localActuals{actuals};
1927 if (specific.has<semantics::ProcBindingDetails>()) {
1928 if (!adjustActuals.value()(specific, localActuals)) {
1929 continue;
1930 }
1931 }
1932 if (semantics::CheckInterfaceForGeneric(
1933 *procedure, localActuals, GetFoldingContext())) {
1934 if (CheckCompatibleArguments(*procedure, localActuals)) {
1935 if (!procedure->IsElemental()) {
1936 return &specific; // takes priority over elemental match
1937 }
1938 elemental = &specific;
1939 }
1940 }
1941 }
1942 }
1943 if (elemental) {
1944 return elemental;
1945 }
1946 // Check parent derived type
1947 if (const auto *parentScope{symbol.owner().GetDerivedTypeParent()}) {
1948 if (const Symbol * extended{parentScope->FindComponent(symbol.name())}) {
1949 if (extended->GetUltimate().has<semantics::GenericDetails>()) {
1950 if (const Symbol *
1951 result{ResolveGeneric(*extended, actuals, adjustActuals, false)}) {
1952 return result;
1953 }
1954 }
1955 }
1956 }
1957 if (mightBeStructureConstructor && details.derivedType()) {
1958 return details.derivedType();
1959 }
1960 return nullptr;
1961 }
1962
EmitGenericResolutionError(const Symbol & symbol)1963 void ExpressionAnalyzer::EmitGenericResolutionError(const Symbol &symbol) {
1964 if (semantics::IsGenericDefinedOp(symbol)) {
1965 Say("No specific procedure of generic operator '%s' matches the actual arguments"_err_en_US,
1966 symbol.name());
1967 } else {
1968 Say("No specific procedure of generic '%s' matches the actual arguments"_err_en_US,
1969 symbol.name());
1970 }
1971 }
1972
GetCalleeAndArguments(const parser::ProcedureDesignator & pd,ActualArguments && arguments,bool isSubroutine,bool mightBeStructureConstructor)1973 auto ExpressionAnalyzer::GetCalleeAndArguments(
1974 const parser::ProcedureDesignator &pd, ActualArguments &&arguments,
1975 bool isSubroutine, bool mightBeStructureConstructor)
1976 -> std::optional<CalleeAndArguments> {
1977 return std::visit(
1978 common::visitors{
1979 [&](const parser::Name &name) {
1980 return GetCalleeAndArguments(name, std::move(arguments),
1981 isSubroutine, mightBeStructureConstructor);
1982 },
1983 [&](const parser::ProcComponentRef &pcr) {
1984 return AnalyzeProcedureComponentRef(pcr, std::move(arguments));
1985 },
1986 },
1987 pd.u);
1988 }
1989
GetCalleeAndArguments(const parser::Name & name,ActualArguments && arguments,bool isSubroutine,bool mightBeStructureConstructor)1990 auto ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name,
1991 ActualArguments &&arguments, bool isSubroutine,
1992 bool mightBeStructureConstructor) -> std::optional<CalleeAndArguments> {
1993 const Symbol *symbol{name.symbol};
1994 if (context_.HasError(symbol)) {
1995 return std::nullopt; // also handles null symbol
1996 }
1997 const Symbol &ultimate{DEREF(symbol).GetUltimate()};
1998 if (ultimate.attrs().test(semantics::Attr::INTRINSIC)) {
1999 if (std::optional<SpecificCall> specificCall{context_.intrinsics().Probe(
2000 CallCharacteristics{ultimate.name().ToString(), isSubroutine},
2001 arguments, GetFoldingContext())}) {
2002 return CalleeAndArguments{
2003 ProcedureDesignator{std::move(specificCall->specificIntrinsic)},
2004 std::move(specificCall->arguments)};
2005 }
2006 } else {
2007 CheckForBadRecursion(name.source, ultimate);
2008 if (ultimate.has<semantics::GenericDetails>()) {
2009 ExpressionAnalyzer::AdjustActuals noAdjustment;
2010 symbol = ResolveGeneric(
2011 *symbol, arguments, noAdjustment, mightBeStructureConstructor);
2012 }
2013 if (symbol) {
2014 if (symbol->GetUltimate().has<semantics::DerivedTypeDetails>()) {
2015 if (mightBeStructureConstructor) {
2016 return CalleeAndArguments{
2017 semantics::SymbolRef{*symbol}, std::move(arguments)};
2018 }
2019 } else {
2020 return CalleeAndArguments{
2021 ProcedureDesignator{*symbol}, std::move(arguments)};
2022 }
2023 } else if (std::optional<SpecificCall> specificCall{
2024 context_.intrinsics().Probe(
2025 CallCharacteristics{
2026 ultimate.name().ToString(), isSubroutine},
2027 arguments, GetFoldingContext())}) {
2028 // Generics can extend intrinsics
2029 return CalleeAndArguments{
2030 ProcedureDesignator{std::move(specificCall->specificIntrinsic)},
2031 std::move(specificCall->arguments)};
2032 } else {
2033 EmitGenericResolutionError(*name.symbol);
2034 }
2035 }
2036 return std::nullopt;
2037 }
2038
CheckForBadRecursion(parser::CharBlock callSite,const semantics::Symbol & proc)2039 void ExpressionAnalyzer::CheckForBadRecursion(
2040 parser::CharBlock callSite, const semantics::Symbol &proc) {
2041 if (const auto *scope{proc.scope()}) {
2042 if (scope->sourceRange().Contains(callSite)) {
2043 parser::Message *msg{nullptr};
2044 if (proc.attrs().test(semantics::Attr::NON_RECURSIVE)) { // 15.6.2.1(3)
2045 msg = Say("NON_RECURSIVE procedure '%s' cannot call itself"_err_en_US,
2046 callSite);
2047 } else if (IsAssumedLengthCharacter(proc) && IsExternal(proc)) {
2048 msg = Say( // 15.6.2.1(3)
2049 "Assumed-length CHARACTER(*) function '%s' cannot call itself"_err_en_US,
2050 callSite);
2051 }
2052 AttachDeclaration(msg, proc);
2053 }
2054 }
2055 }
2056
AssumedTypeDummy(const A & x)2057 template <typename A> static const Symbol *AssumedTypeDummy(const A &x) {
2058 if (const auto *designator{
2059 std::get_if<common::Indirection<parser::Designator>>(&x.u)}) {
2060 if (const auto *dataRef{
2061 std::get_if<parser::DataRef>(&designator->value().u)}) {
2062 if (const auto *name{std::get_if<parser::Name>(&dataRef->u)}) {
2063 if (const Symbol * symbol{name->symbol}) {
2064 if (const auto *type{symbol->GetType()}) {
2065 if (type->category() == semantics::DeclTypeSpec::TypeStar) {
2066 return symbol;
2067 }
2068 }
2069 }
2070 }
2071 }
2072 }
2073 return nullptr;
2074 }
2075
Analyze(const parser::FunctionReference & funcRef,std::optional<parser::StructureConstructor> * structureConstructor)2076 MaybeExpr ExpressionAnalyzer::Analyze(const parser::FunctionReference &funcRef,
2077 std::optional<parser::StructureConstructor> *structureConstructor) {
2078 const parser::Call &call{funcRef.v};
2079 auto restorer{GetContextualMessages().SetLocation(call.source)};
2080 ArgumentAnalyzer analyzer{*this, call.source, true /* isProcedureCall */};
2081 for (const auto &arg : std::get<std::list<parser::ActualArgSpec>>(call.t)) {
2082 analyzer.Analyze(arg, false /* not subroutine call */);
2083 }
2084 if (analyzer.fatalErrors()) {
2085 return std::nullopt;
2086 }
2087 if (std::optional<CalleeAndArguments> callee{
2088 GetCalleeAndArguments(std::get<parser::ProcedureDesignator>(call.t),
2089 analyzer.GetActuals(), false /* not subroutine */,
2090 true /* might be structure constructor */)}) {
2091 if (auto *proc{std::get_if<ProcedureDesignator>(&callee->u)}) {
2092 return MakeFunctionRef(
2093 call.source, std::move(*proc), std::move(callee->arguments));
2094 } else if (structureConstructor) {
2095 // Structure constructor misparsed as function reference?
2096 CHECK(std::holds_alternative<semantics::SymbolRef>(callee->u));
2097 const Symbol &derivedType{*std::get<semantics::SymbolRef>(callee->u)};
2098 const auto &designator{std::get<parser::ProcedureDesignator>(call.t)};
2099 if (const auto *name{std::get_if<parser::Name>(&designator.u)}) {
2100 semantics::Scope &scope{context_.FindScope(name->source)};
2101 semantics::DerivedTypeSpec dtSpec{
2102 name->source, derivedType.GetUltimate()};
2103 if (dtSpec.IsForwardReferenced()) {
2104 Say(call.source,
2105 "Cannot construct value for derived type '%s' "
2106 "before it is defined"_err_en_US,
2107 name->source);
2108 return std::nullopt;
2109 }
2110 const semantics::DeclTypeSpec &type{
2111 semantics::FindOrInstantiateDerivedType(
2112 scope, std::move(dtSpec), context_)};
2113 auto &mutableRef{const_cast<parser::FunctionReference &>(funcRef)};
2114 *structureConstructor =
2115 mutableRef.ConvertToStructureConstructor(type.derivedTypeSpec());
2116 return Analyze(structureConstructor->value());
2117 }
2118 }
2119 }
2120 return std::nullopt;
2121 }
2122
Analyze(const parser::CallStmt & callStmt)2123 void ExpressionAnalyzer::Analyze(const parser::CallStmt &callStmt) {
2124 const parser::Call &call{callStmt.v};
2125 auto restorer{GetContextualMessages().SetLocation(call.source)};
2126 ArgumentAnalyzer analyzer{*this, call.source, true /* isProcedureCall */};
2127 const auto &actualArgList{std::get<std::list<parser::ActualArgSpec>>(call.t)};
2128 for (const auto &arg : actualArgList) {
2129 analyzer.Analyze(arg, true /* is subroutine call */);
2130 }
2131 if (!analyzer.fatalErrors()) {
2132 if (std::optional<CalleeAndArguments> callee{
2133 GetCalleeAndArguments(std::get<parser::ProcedureDesignator>(call.t),
2134 analyzer.GetActuals(), true /* subroutine */)}) {
2135 ProcedureDesignator *proc{std::get_if<ProcedureDesignator>(&callee->u)};
2136 CHECK(proc);
2137 if (CheckCall(call.source, *proc, callee->arguments)) {
2138 bool hasAlternateReturns{
2139 callee->arguments.size() < actualArgList.size()};
2140 callStmt.typedCall.Reset(
2141 new ProcedureRef{std::move(*proc), std::move(callee->arguments),
2142 hasAlternateReturns},
2143 ProcedureRef::Deleter);
2144 }
2145 }
2146 }
2147 }
2148
Analyze(const parser::AssignmentStmt & x)2149 const Assignment *ExpressionAnalyzer::Analyze(const parser::AssignmentStmt &x) {
2150 if (!x.typedAssignment) {
2151 ArgumentAnalyzer analyzer{*this};
2152 analyzer.Analyze(std::get<parser::Variable>(x.t));
2153 analyzer.Analyze(std::get<parser::Expr>(x.t));
2154 if (analyzer.fatalErrors()) {
2155 x.typedAssignment.Reset(
2156 new GenericAssignmentWrapper{}, GenericAssignmentWrapper::Deleter);
2157 } else {
2158 std::optional<ProcedureRef> procRef{analyzer.TryDefinedAssignment()};
2159 Assignment assignment{analyzer.MoveExpr(0), analyzer.MoveExpr(1)};
2160 if (procRef) {
2161 assignment.u = std::move(*procRef);
2162 }
2163 x.typedAssignment.Reset(
2164 new GenericAssignmentWrapper{std::move(assignment)},
2165 GenericAssignmentWrapper::Deleter);
2166 }
2167 }
2168 return common::GetPtrFromOptional(x.typedAssignment->v);
2169 }
2170
Analyze(const parser::PointerAssignmentStmt & x)2171 const Assignment *ExpressionAnalyzer::Analyze(
2172 const parser::PointerAssignmentStmt &x) {
2173 if (!x.typedAssignment) {
2174 MaybeExpr lhs{Analyze(std::get<parser::DataRef>(x.t))};
2175 MaybeExpr rhs{Analyze(std::get<parser::Expr>(x.t))};
2176 if (!lhs || !rhs) {
2177 x.typedAssignment.Reset(
2178 new GenericAssignmentWrapper{}, GenericAssignmentWrapper::Deleter);
2179 } else {
2180 Assignment assignment{std::move(*lhs), std::move(*rhs)};
2181 std::visit(common::visitors{
2182 [&](const std::list<parser::BoundsRemapping> &list) {
2183 Assignment::BoundsRemapping bounds;
2184 for (const auto &elem : list) {
2185 auto lower{AsSubscript(Analyze(std::get<0>(elem.t)))};
2186 auto upper{AsSubscript(Analyze(std::get<1>(elem.t)))};
2187 if (lower && upper) {
2188 bounds.emplace_back(Fold(std::move(*lower)),
2189 Fold(std::move(*upper)));
2190 }
2191 }
2192 assignment.u = std::move(bounds);
2193 },
2194 [&](const std::list<parser::BoundsSpec> &list) {
2195 Assignment::BoundsSpec bounds;
2196 for (const auto &bound : list) {
2197 if (auto lower{AsSubscript(Analyze(bound.v))}) {
2198 bounds.emplace_back(Fold(std::move(*lower)));
2199 }
2200 }
2201 assignment.u = std::move(bounds);
2202 },
2203 },
2204 std::get<parser::PointerAssignmentStmt::Bounds>(x.t).u);
2205 x.typedAssignment.Reset(
2206 new GenericAssignmentWrapper{std::move(assignment)},
2207 GenericAssignmentWrapper::Deleter);
2208 }
2209 }
2210 return common::GetPtrFromOptional(x.typedAssignment->v);
2211 }
2212
IsExternalCalledImplicitly(parser::CharBlock callSite,const ProcedureDesignator & proc)2213 static bool IsExternalCalledImplicitly(
2214 parser::CharBlock callSite, const ProcedureDesignator &proc) {
2215 if (const auto *symbol{proc.GetSymbol()}) {
2216 return symbol->has<semantics::SubprogramDetails>() &&
2217 symbol->owner().IsGlobal() &&
2218 (!symbol->scope() /*ENTRY*/ ||
2219 !symbol->scope()->sourceRange().Contains(callSite));
2220 } else {
2221 return false;
2222 }
2223 }
2224
CheckCall(parser::CharBlock callSite,const ProcedureDesignator & proc,ActualArguments & arguments)2225 std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
2226 parser::CharBlock callSite, const ProcedureDesignator &proc,
2227 ActualArguments &arguments) {
2228 auto chars{
2229 characteristics::Procedure::Characterize(proc, context_.intrinsics())};
2230 if (chars) {
2231 bool treatExternalAsImplicit{IsExternalCalledImplicitly(callSite, proc)};
2232 if (treatExternalAsImplicit && !chars->CanBeCalledViaImplicitInterface()) {
2233 Say(callSite,
2234 "References to the procedure '%s' require an explicit interface"_en_US,
2235 DEREF(proc.GetSymbol()).name());
2236 }
2237 // Checks for ASSOCIATED() are done in intrinsic table processing
2238 bool procIsAssociated{false};
2239 if (const SpecificIntrinsic *
2240 specificIntrinsic{proc.GetSpecificIntrinsic()}) {
2241 if (specificIntrinsic->name == "associated") {
2242 procIsAssociated = true;
2243 }
2244 }
2245 if (!procIsAssociated) {
2246 semantics::CheckArguments(*chars, arguments, GetFoldingContext(),
2247 context_.FindScope(callSite), treatExternalAsImplicit,
2248 proc.GetSpecificIntrinsic());
2249 const Symbol *procSymbol{proc.GetSymbol()};
2250 if (procSymbol && !IsPureProcedure(*procSymbol)) {
2251 if (const semantics::Scope *
2252 pure{semantics::FindPureProcedureContaining(
2253 context_.FindScope(callSite))}) {
2254 Say(callSite,
2255 "Procedure '%s' referenced in pure subprogram '%s' must be pure too"_err_en_US,
2256 procSymbol->name(), DEREF(pure->symbol()).name());
2257 }
2258 }
2259 }
2260 }
2261 return chars;
2262 }
2263
2264 // Unary operations
2265
Analyze(const parser::Expr::Parentheses & x)2266 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Parentheses &x) {
2267 if (MaybeExpr operand{Analyze(x.v.value())}) {
2268 if (const semantics::Symbol * symbol{GetLastSymbol(*operand)}) {
2269 if (const semantics::Symbol * result{FindFunctionResult(*symbol)}) {
2270 if (semantics::IsProcedurePointer(*result)) {
2271 Say("A function reference that returns a procedure "
2272 "pointer may not be parenthesized"_err_en_US); // C1003
2273 }
2274 }
2275 }
2276 return Parenthesize(std::move(*operand));
2277 }
2278 return std::nullopt;
2279 }
2280
NumericUnaryHelper(ExpressionAnalyzer & context,NumericOperator opr,const parser::Expr::IntrinsicUnary & x)2281 static MaybeExpr NumericUnaryHelper(ExpressionAnalyzer &context,
2282 NumericOperator opr, const parser::Expr::IntrinsicUnary &x) {
2283 ArgumentAnalyzer analyzer{context};
2284 analyzer.Analyze(x.v);
2285 if (analyzer.fatalErrors()) {
2286 return std::nullopt;
2287 } else if (analyzer.IsIntrinsicNumeric(opr)) {
2288 if (opr == NumericOperator::Add) {
2289 return analyzer.MoveExpr(0);
2290 } else {
2291 return Negation(context.GetContextualMessages(), analyzer.MoveExpr(0));
2292 }
2293 } else {
2294 return analyzer.TryDefinedOp(AsFortran(opr),
2295 "Operand of unary %s must be numeric; have %s"_err_en_US);
2296 }
2297 }
2298
Analyze(const parser::Expr::UnaryPlus & x)2299 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::UnaryPlus &x) {
2300 return NumericUnaryHelper(*this, NumericOperator::Add, x);
2301 }
2302
Analyze(const parser::Expr::Negate & x)2303 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Negate &x) {
2304 return NumericUnaryHelper(*this, NumericOperator::Subtract, x);
2305 }
2306
Analyze(const parser::Expr::NOT & x)2307 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::NOT &x) {
2308 ArgumentAnalyzer analyzer{*this};
2309 analyzer.Analyze(x.v);
2310 if (analyzer.fatalErrors()) {
2311 return std::nullopt;
2312 } else if (analyzer.IsIntrinsicLogical()) {
2313 return AsGenericExpr(
2314 LogicalNegation(std::get<Expr<SomeLogical>>(analyzer.MoveExpr(0).u)));
2315 } else {
2316 return analyzer.TryDefinedOp(LogicalOperator::Not,
2317 "Operand of %s must be LOGICAL; have %s"_err_en_US);
2318 }
2319 }
2320
Analyze(const parser::Expr::PercentLoc & x)2321 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::PercentLoc &x) {
2322 // Represent %LOC() exactly as if it had been a call to the LOC() extension
2323 // intrinsic function.
2324 // Use the actual source for the name of the call for error reporting.
2325 std::optional<ActualArgument> arg;
2326 if (const Symbol * assumedTypeDummy{AssumedTypeDummy(x.v.value())}) {
2327 arg = ActualArgument{ActualArgument::AssumedType{*assumedTypeDummy}};
2328 } else if (MaybeExpr argExpr{Analyze(x.v.value())}) {
2329 arg = ActualArgument{std::move(*argExpr)};
2330 } else {
2331 return std::nullopt;
2332 }
2333 parser::CharBlock at{GetContextualMessages().at()};
2334 CHECK(at.size() >= 4);
2335 parser::CharBlock loc{at.begin() + 1, 3};
2336 CHECK(loc == "loc");
2337 return MakeFunctionRef(loc, ActualArguments{std::move(*arg)});
2338 }
2339
Analyze(const parser::Expr::DefinedUnary & x)2340 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::DefinedUnary &x) {
2341 const auto &name{std::get<parser::DefinedOpName>(x.t).v};
2342 ArgumentAnalyzer analyzer{*this, name.source};
2343 analyzer.Analyze(std::get<1>(x.t));
2344 return analyzer.TryDefinedOp(name.source.ToString().c_str(),
2345 "No operator %s defined for %s"_err_en_US, true);
2346 }
2347
2348 // Binary (dyadic) operations
2349
2350 template <template <typename> class OPR>
NumericBinaryHelper(ExpressionAnalyzer & context,NumericOperator opr,const parser::Expr::IntrinsicBinary & x)2351 MaybeExpr NumericBinaryHelper(ExpressionAnalyzer &context, NumericOperator opr,
2352 const parser::Expr::IntrinsicBinary &x) {
2353 ArgumentAnalyzer analyzer{context};
2354 analyzer.Analyze(std::get<0>(x.t));
2355 analyzer.Analyze(std::get<1>(x.t));
2356 if (analyzer.fatalErrors()) {
2357 return std::nullopt;
2358 } else if (analyzer.IsIntrinsicNumeric(opr)) {
2359 analyzer.CheckConformance();
2360 return NumericOperation<OPR>(context.GetContextualMessages(),
2361 analyzer.MoveExpr(0), analyzer.MoveExpr(1),
2362 context.GetDefaultKind(TypeCategory::Real));
2363 } else {
2364 return analyzer.TryDefinedOp(AsFortran(opr),
2365 "Operands of %s must be numeric; have %s and %s"_err_en_US);
2366 }
2367 }
2368
Analyze(const parser::Expr::Power & x)2369 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Power &x) {
2370 return NumericBinaryHelper<Power>(*this, NumericOperator::Power, x);
2371 }
2372
Analyze(const parser::Expr::Multiply & x)2373 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Multiply &x) {
2374 return NumericBinaryHelper<Multiply>(*this, NumericOperator::Multiply, x);
2375 }
2376
Analyze(const parser::Expr::Divide & x)2377 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Divide &x) {
2378 return NumericBinaryHelper<Divide>(*this, NumericOperator::Divide, x);
2379 }
2380
Analyze(const parser::Expr::Add & x)2381 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Add &x) {
2382 return NumericBinaryHelper<Add>(*this, NumericOperator::Add, x);
2383 }
2384
Analyze(const parser::Expr::Subtract & x)2385 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Subtract &x) {
2386 return NumericBinaryHelper<Subtract>(*this, NumericOperator::Subtract, x);
2387 }
2388
Analyze(const parser::Expr::ComplexConstructor & x)2389 MaybeExpr ExpressionAnalyzer::Analyze(
2390 const parser::Expr::ComplexConstructor &x) {
2391 auto re{Analyze(std::get<0>(x.t).value())};
2392 auto im{Analyze(std::get<1>(x.t).value())};
2393 if (re && im) {
2394 ConformabilityCheck(GetContextualMessages(), *re, *im);
2395 }
2396 return AsMaybeExpr(ConstructComplex(GetContextualMessages(), std::move(re),
2397 std::move(im), GetDefaultKind(TypeCategory::Real)));
2398 }
2399
Analyze(const parser::Expr::Concat & x)2400 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Concat &x) {
2401 ArgumentAnalyzer analyzer{*this};
2402 analyzer.Analyze(std::get<0>(x.t));
2403 analyzer.Analyze(std::get<1>(x.t));
2404 if (analyzer.fatalErrors()) {
2405 return std::nullopt;
2406 } else if (analyzer.IsIntrinsicConcat()) {
2407 return std::visit(
2408 [&](auto &&x, auto &&y) -> MaybeExpr {
2409 using T = ResultType<decltype(x)>;
2410 if constexpr (std::is_same_v<T, ResultType<decltype(y)>>) {
2411 return AsGenericExpr(Concat<T::kind>{std::move(x), std::move(y)});
2412 } else {
2413 DIE("different types for intrinsic concat");
2414 }
2415 },
2416 std::move(std::get<Expr<SomeCharacter>>(analyzer.MoveExpr(0).u).u),
2417 std::move(std::get<Expr<SomeCharacter>>(analyzer.MoveExpr(1).u).u));
2418 } else {
2419 return analyzer.TryDefinedOp("//",
2420 "Operands of %s must be CHARACTER with the same kind; have %s and %s"_err_en_US);
2421 }
2422 }
2423
2424 // The Name represents a user-defined intrinsic operator.
2425 // If the actuals match one of the specific procedures, return a function ref.
2426 // Otherwise report the error in messages.
AnalyzeDefinedOp(const parser::Name & name,ActualArguments && actuals)2427 MaybeExpr ExpressionAnalyzer::AnalyzeDefinedOp(
2428 const parser::Name &name, ActualArguments &&actuals) {
2429 if (auto callee{GetCalleeAndArguments(name, std::move(actuals))}) {
2430 CHECK(std::holds_alternative<ProcedureDesignator>(callee->u));
2431 return MakeFunctionRef(name.source,
2432 std::move(std::get<ProcedureDesignator>(callee->u)),
2433 std::move(callee->arguments));
2434 } else {
2435 return std::nullopt;
2436 }
2437 }
2438
RelationHelper(ExpressionAnalyzer & context,RelationalOperator opr,const parser::Expr::IntrinsicBinary & x)2439 MaybeExpr RelationHelper(ExpressionAnalyzer &context, RelationalOperator opr,
2440 const parser::Expr::IntrinsicBinary &x) {
2441 ArgumentAnalyzer analyzer{context};
2442 analyzer.Analyze(std::get<0>(x.t));
2443 analyzer.Analyze(std::get<1>(x.t));
2444 if (analyzer.fatalErrors()) {
2445 return std::nullopt;
2446 } else {
2447 if (IsNullPointer(analyzer.GetExpr(0)) ||
2448 IsNullPointer(analyzer.GetExpr(1))) {
2449 context.Say("NULL() not allowed as an operand of a relational "
2450 "operator"_err_en_US);
2451 return std::nullopt;
2452 }
2453 analyzer.ConvertBOZ(0, analyzer.GetType(1));
2454 analyzer.ConvertBOZ(1, analyzer.GetType(0));
2455 if (analyzer.IsIntrinsicRelational(opr)) {
2456 return AsMaybeExpr(Relate(context.GetContextualMessages(), opr,
2457 analyzer.MoveExpr(0), analyzer.MoveExpr(1)));
2458 } else {
2459 return analyzer.TryDefinedOp(opr,
2460 "Operands of %s must have comparable types; have %s and %s"_err_en_US);
2461 }
2462 }
2463 }
2464
Analyze(const parser::Expr::LT & x)2465 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::LT &x) {
2466 return RelationHelper(*this, RelationalOperator::LT, x);
2467 }
2468
Analyze(const parser::Expr::LE & x)2469 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::LE &x) {
2470 return RelationHelper(*this, RelationalOperator::LE, x);
2471 }
2472
Analyze(const parser::Expr::EQ & x)2473 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::EQ &x) {
2474 return RelationHelper(*this, RelationalOperator::EQ, x);
2475 }
2476
Analyze(const parser::Expr::NE & x)2477 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::NE &x) {
2478 return RelationHelper(*this, RelationalOperator::NE, x);
2479 }
2480
Analyze(const parser::Expr::GE & x)2481 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::GE &x) {
2482 return RelationHelper(*this, RelationalOperator::GE, x);
2483 }
2484
Analyze(const parser::Expr::GT & x)2485 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::GT &x) {
2486 return RelationHelper(*this, RelationalOperator::GT, x);
2487 }
2488
LogicalBinaryHelper(ExpressionAnalyzer & context,LogicalOperator opr,const parser::Expr::IntrinsicBinary & x)2489 MaybeExpr LogicalBinaryHelper(ExpressionAnalyzer &context, LogicalOperator opr,
2490 const parser::Expr::IntrinsicBinary &x) {
2491 ArgumentAnalyzer analyzer{context};
2492 analyzer.Analyze(std::get<0>(x.t));
2493 analyzer.Analyze(std::get<1>(x.t));
2494 if (analyzer.fatalErrors()) {
2495 return std::nullopt;
2496 } else if (analyzer.IsIntrinsicLogical()) {
2497 return AsGenericExpr(BinaryLogicalOperation(opr,
2498 std::get<Expr<SomeLogical>>(analyzer.MoveExpr(0).u),
2499 std::get<Expr<SomeLogical>>(analyzer.MoveExpr(1).u)));
2500 } else {
2501 return analyzer.TryDefinedOp(
2502 opr, "Operands of %s must be LOGICAL; have %s and %s"_err_en_US);
2503 }
2504 }
2505
Analyze(const parser::Expr::AND & x)2506 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::AND &x) {
2507 return LogicalBinaryHelper(*this, LogicalOperator::And, x);
2508 }
2509
Analyze(const parser::Expr::OR & x)2510 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::OR &x) {
2511 return LogicalBinaryHelper(*this, LogicalOperator::Or, x);
2512 }
2513
Analyze(const parser::Expr::EQV & x)2514 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::EQV &x) {
2515 return LogicalBinaryHelper(*this, LogicalOperator::Eqv, x);
2516 }
2517
Analyze(const parser::Expr::NEQV & x)2518 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::NEQV &x) {
2519 return LogicalBinaryHelper(*this, LogicalOperator::Neqv, x);
2520 }
2521
Analyze(const parser::Expr::DefinedBinary & x)2522 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::DefinedBinary &x) {
2523 const auto &name{std::get<parser::DefinedOpName>(x.t).v};
2524 ArgumentAnalyzer analyzer{*this, name.source};
2525 analyzer.Analyze(std::get<1>(x.t));
2526 analyzer.Analyze(std::get<2>(x.t));
2527 return analyzer.TryDefinedOp(name.source.ToString().c_str(),
2528 "No operator %s defined for %s and %s"_err_en_US, true);
2529 }
2530
CheckFuncRefToArrayElementRefHasSubscripts(semantics::SemanticsContext & context,const parser::FunctionReference & funcRef)2531 static void CheckFuncRefToArrayElementRefHasSubscripts(
2532 semantics::SemanticsContext &context,
2533 const parser::FunctionReference &funcRef) {
2534 // Emit message if the function reference fix will end up an array element
2535 // reference with no subscripts because it will not be possible to later tell
2536 // the difference in expressions between empty subscript list due to bad
2537 // subscripts error recovery or because the user did not put any.
2538 if (std::get<std::list<parser::ActualArgSpec>>(funcRef.v.t).empty()) {
2539 auto &proc{std::get<parser::ProcedureDesignator>(funcRef.v.t)};
2540 const auto *name{std::get_if<parser::Name>(&proc.u)};
2541 if (!name) {
2542 name = &std::get<parser::ProcComponentRef>(proc.u).v.thing.component;
2543 }
2544 auto &msg{context.Say(funcRef.v.source,
2545 name->symbol && name->symbol->Rank() == 0
2546 ? "'%s' is not a function"_err_en_US
2547 : "Reference to array '%s' with empty subscript list"_err_en_US,
2548 name->source)};
2549 if (name->symbol) {
2550 if (semantics::IsFunctionResultWithSameNameAsFunction(*name->symbol)) {
2551 msg.Attach(name->source,
2552 "A result variable must be declared with RESULT to allow recursive "
2553 "function calls"_en_US);
2554 } else {
2555 AttachDeclaration(&msg, *name->symbol);
2556 }
2557 }
2558 }
2559 }
2560
2561 // Converts, if appropriate, an original misparse of ambiguous syntax like
2562 // A(1) as a function reference into an array reference.
2563 // Misparse structure constructors are detected elsewhere after generic
2564 // function call resolution fails.
2565 template <typename... A>
FixMisparsedFunctionReference(semantics::SemanticsContext & context,const std::variant<A...> & constU)2566 static void FixMisparsedFunctionReference(
2567 semantics::SemanticsContext &context, const std::variant<A...> &constU) {
2568 // The parse tree is updated in situ when resolving an ambiguous parse.
2569 using uType = std::decay_t<decltype(constU)>;
2570 auto &u{const_cast<uType &>(constU)};
2571 if (auto *func{
2572 std::get_if<common::Indirection<parser::FunctionReference>>(&u)}) {
2573 parser::FunctionReference &funcRef{func->value()};
2574 auto &proc{std::get<parser::ProcedureDesignator>(funcRef.v.t)};
2575 if (Symbol *
2576 origSymbol{
2577 std::visit(common::visitors{
2578 [&](parser::Name &name) { return name.symbol; },
2579 [&](parser::ProcComponentRef &pcr) {
2580 return pcr.v.thing.component.symbol;
2581 },
2582 },
2583 proc.u)}) {
2584 Symbol &symbol{origSymbol->GetUltimate()};
2585 if (symbol.has<semantics::ObjectEntityDetails>() ||
2586 symbol.has<semantics::AssocEntityDetails>()) {
2587 // Note that expression in AssocEntityDetails cannot be a procedure
2588 // pointer as per C1105 so this cannot be a function reference.
2589 if constexpr (common::HasMember<common::Indirection<parser::Designator>,
2590 uType>) {
2591 CheckFuncRefToArrayElementRefHasSubscripts(context, funcRef);
2592 u = common::Indirection{funcRef.ConvertToArrayElementRef()};
2593 } else {
2594 DIE("can't fix misparsed function as array reference");
2595 }
2596 }
2597 }
2598 }
2599 }
2600
2601 // Common handling of parse tree node types that retain the
2602 // representation of the analyzed expression.
2603 template <typename PARSED>
ExprOrVariable(const PARSED & x,parser::CharBlock source)2604 MaybeExpr ExpressionAnalyzer::ExprOrVariable(
2605 const PARSED &x, parser::CharBlock source) {
2606 if (useSavedTypedExprs_ && x.typedExpr) {
2607 return x.typedExpr->v;
2608 }
2609 auto restorer{GetContextualMessages().SetLocation(source)};
2610 if constexpr (std::is_same_v<PARSED, parser::Expr> ||
2611 std::is_same_v<PARSED, parser::Variable>) {
2612 FixMisparsedFunctionReference(context_, x.u);
2613 }
2614 if (AssumedTypeDummy(x)) { // C710
2615 Say("TYPE(*) dummy argument may only be used as an actual argument"_err_en_US);
2616 } else if (MaybeExpr result{Analyze(x.u)}) {
2617 SetExpr(x, Fold(std::move(*result)));
2618 return x.typedExpr->v;
2619 }
2620 ResetExpr(x);
2621 if (!context_.AnyFatalError()) {
2622 std::string buf;
2623 llvm::raw_string_ostream dump{buf};
2624 parser::DumpTree(dump, x);
2625 Say("Internal error: Expression analysis failed on: %s"_err_en_US,
2626 dump.str());
2627 }
2628 return std::nullopt;
2629 }
2630
Analyze(const parser::Expr & expr)2631 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr &expr) {
2632 auto restorer{GetContextualMessages().SetLocation(expr.source)};
2633 return ExprOrVariable(expr, expr.source);
2634 }
2635
Analyze(const parser::Variable & variable)2636 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Variable &variable) {
2637 auto restorer{GetContextualMessages().SetLocation(variable.GetSource())};
2638 return ExprOrVariable(variable, variable.GetSource());
2639 }
2640
Analyze(const parser::DataStmtConstant & x)2641 MaybeExpr ExpressionAnalyzer::Analyze(const parser::DataStmtConstant &x) {
2642 auto restorer{GetContextualMessages().SetLocation(x.source)};
2643 return ExprOrVariable(x, x.source);
2644 }
2645
AnalyzeKindSelector(TypeCategory category,const std::optional<parser::KindSelector> & selector)2646 Expr<SubscriptInteger> ExpressionAnalyzer::AnalyzeKindSelector(
2647 TypeCategory category,
2648 const std::optional<parser::KindSelector> &selector) {
2649 int defaultKind{GetDefaultKind(category)};
2650 if (!selector) {
2651 return Expr<SubscriptInteger>{defaultKind};
2652 }
2653 return std::visit(
2654 common::visitors{
2655 [&](const parser::ScalarIntConstantExpr &x) {
2656 if (MaybeExpr kind{Analyze(x)}) {
2657 if (std::optional<std::int64_t> code{ToInt64(*kind)}) {
2658 if (CheckIntrinsicKind(category, *code)) {
2659 return Expr<SubscriptInteger>{*code};
2660 }
2661 } else if (auto *intExpr{UnwrapExpr<Expr<SomeInteger>>(*kind)}) {
2662 return ConvertToType<SubscriptInteger>(std::move(*intExpr));
2663 }
2664 }
2665 return Expr<SubscriptInteger>{defaultKind};
2666 },
2667 [&](const parser::KindSelector::StarSize &x) {
2668 std::intmax_t size = x.v;
2669 if (!CheckIntrinsicSize(category, size)) {
2670 size = defaultKind;
2671 } else if (category == TypeCategory::Complex) {
2672 size /= 2;
2673 }
2674 return Expr<SubscriptInteger>{size};
2675 },
2676 },
2677 selector->u);
2678 }
2679
GetDefaultKind(common::TypeCategory category)2680 int ExpressionAnalyzer::GetDefaultKind(common::TypeCategory category) {
2681 return context_.GetDefaultKind(category);
2682 }
2683
GetDefaultKindOfType(common::TypeCategory category)2684 DynamicType ExpressionAnalyzer::GetDefaultKindOfType(
2685 common::TypeCategory category) {
2686 return {category, GetDefaultKind(category)};
2687 }
2688
CheckIntrinsicKind(TypeCategory category,std::int64_t kind)2689 bool ExpressionAnalyzer::CheckIntrinsicKind(
2690 TypeCategory category, std::int64_t kind) {
2691 if (IsValidKindOfIntrinsicType(category, kind)) { // C712, C714, C715, C727
2692 return true;
2693 } else {
2694 Say("%s(KIND=%jd) is not a supported type"_err_en_US,
2695 ToUpperCase(EnumToString(category)), kind);
2696 return false;
2697 }
2698 }
2699
CheckIntrinsicSize(TypeCategory category,std::int64_t size)2700 bool ExpressionAnalyzer::CheckIntrinsicSize(
2701 TypeCategory category, std::int64_t size) {
2702 if (category == TypeCategory::Complex) {
2703 // COMPLEX*16 == COMPLEX(KIND=8)
2704 if (size % 2 == 0 && IsValidKindOfIntrinsicType(category, size / 2)) {
2705 return true;
2706 }
2707 } else if (IsValidKindOfIntrinsicType(category, size)) {
2708 return true;
2709 }
2710 Say("%s*%jd is not a supported type"_err_en_US,
2711 ToUpperCase(EnumToString(category)), size);
2712 return false;
2713 }
2714
AddImpliedDo(parser::CharBlock name,int kind)2715 bool ExpressionAnalyzer::AddImpliedDo(parser::CharBlock name, int kind) {
2716 return impliedDos_.insert(std::make_pair(name, kind)).second;
2717 }
2718
RemoveImpliedDo(parser::CharBlock name)2719 void ExpressionAnalyzer::RemoveImpliedDo(parser::CharBlock name) {
2720 auto iter{impliedDos_.find(name)};
2721 if (iter != impliedDos_.end()) {
2722 impliedDos_.erase(iter);
2723 }
2724 }
2725
IsImpliedDo(parser::CharBlock name) const2726 std::optional<int> ExpressionAnalyzer::IsImpliedDo(
2727 parser::CharBlock name) const {
2728 auto iter{impliedDos_.find(name)};
2729 if (iter != impliedDos_.cend()) {
2730 return {iter->second};
2731 } else {
2732 return std::nullopt;
2733 }
2734 }
2735
EnforceTypeConstraint(parser::CharBlock at,const MaybeExpr & result,TypeCategory category,bool defaultKind)2736 bool ExpressionAnalyzer::EnforceTypeConstraint(parser::CharBlock at,
2737 const MaybeExpr &result, TypeCategory category, bool defaultKind) {
2738 if (result) {
2739 if (auto type{result->GetType()}) {
2740 if (type->category() != category) { // C885
2741 Say(at, "Must have %s type, but is %s"_err_en_US,
2742 ToUpperCase(EnumToString(category)),
2743 ToUpperCase(type->AsFortran()));
2744 return false;
2745 } else if (defaultKind) {
2746 int kind{context_.GetDefaultKind(category)};
2747 if (type->kind() != kind) {
2748 Say(at, "Must have default kind(%d) of %s type, but is %s"_err_en_US,
2749 kind, ToUpperCase(EnumToString(category)),
2750 ToUpperCase(type->AsFortran()));
2751 return false;
2752 }
2753 }
2754 } else {
2755 Say(at, "Must have %s type, but is typeless"_err_en_US,
2756 ToUpperCase(EnumToString(category)));
2757 return false;
2758 }
2759 }
2760 return true;
2761 }
2762
MakeFunctionRef(parser::CharBlock callSite,ProcedureDesignator && proc,ActualArguments && arguments)2763 MaybeExpr ExpressionAnalyzer::MakeFunctionRef(parser::CharBlock callSite,
2764 ProcedureDesignator &&proc, ActualArguments &&arguments) {
2765 if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&proc.u)}) {
2766 if (intrinsic->name == "null" && arguments.empty()) {
2767 return Expr<SomeType>{NullPointer{}};
2768 }
2769 }
2770 if (const Symbol * symbol{proc.GetSymbol()}) {
2771 if (!ResolveForward(*symbol)) {
2772 return std::nullopt;
2773 }
2774 }
2775 if (auto chars{CheckCall(callSite, proc, arguments)}) {
2776 if (chars->functionResult) {
2777 const auto &result{*chars->functionResult};
2778 if (result.IsProcedurePointer()) {
2779 return Expr<SomeType>{
2780 ProcedureRef{std::move(proc), std::move(arguments)}};
2781 } else {
2782 // Not a procedure pointer, so type and shape are known.
2783 return TypedWrapper<FunctionRef, ProcedureRef>(
2784 DEREF(result.GetTypeAndShape()).type(),
2785 ProcedureRef{std::move(proc), std::move(arguments)});
2786 }
2787 }
2788 }
2789 return std::nullopt;
2790 }
2791
MakeFunctionRef(parser::CharBlock intrinsic,ActualArguments && arguments)2792 MaybeExpr ExpressionAnalyzer::MakeFunctionRef(
2793 parser::CharBlock intrinsic, ActualArguments &&arguments) {
2794 if (std::optional<SpecificCall> specificCall{
2795 context_.intrinsics().Probe(CallCharacteristics{intrinsic.ToString()},
2796 arguments, context_.foldingContext())}) {
2797 return MakeFunctionRef(intrinsic,
2798 ProcedureDesignator{std::move(specificCall->specificIntrinsic)},
2799 std::move(specificCall->arguments));
2800 } else {
2801 return std::nullopt;
2802 }
2803 }
2804
Analyze(const parser::Variable & x)2805 void ArgumentAnalyzer::Analyze(const parser::Variable &x) {
2806 source_.ExtendToCover(x.GetSource());
2807 if (MaybeExpr expr{context_.Analyze(x)}) {
2808 if (!IsConstantExpr(*expr)) {
2809 actuals_.emplace_back(std::move(*expr));
2810 return;
2811 }
2812 const Symbol *symbol{GetLastSymbol(*expr)};
2813 if (!symbol) {
2814 context_.SayAt(x, "Assignment to constant '%s' is not allowed"_err_en_US,
2815 x.GetSource());
2816 } else if (auto *subp{symbol->detailsIf<semantics::SubprogramDetails>()}) {
2817 auto *msg{context_.SayAt(x,
2818 "Assignment to subprogram '%s' is not allowed"_err_en_US,
2819 symbol->name())};
2820 if (subp->isFunction()) {
2821 const auto &result{subp->result().name()};
2822 msg->Attach(result, "Function result is '%s'"_err_en_US, result);
2823 }
2824 } else {
2825 context_.SayAt(x, "Assignment to constant '%s' is not allowed"_err_en_US,
2826 symbol->name());
2827 }
2828 }
2829 fatalErrors_ = true;
2830 }
2831
Analyze(const parser::ActualArgSpec & arg,bool isSubroutine)2832 void ArgumentAnalyzer::Analyze(
2833 const parser::ActualArgSpec &arg, bool isSubroutine) {
2834 // TODO: Actual arguments that are procedures and procedure pointers need to
2835 // be detected and represented (they're not expressions).
2836 // TODO: C1534: Don't allow a "restricted" specific intrinsic to be passed.
2837 std::optional<ActualArgument> actual;
2838 bool isAltReturn{false};
2839 std::visit(common::visitors{
2840 [&](const common::Indirection<parser::Expr> &x) {
2841 // TODO: Distinguish & handle procedure name and
2842 // proc-component-ref
2843 actual = AnalyzeExpr(x.value());
2844 },
2845 [&](const parser::AltReturnSpec &) {
2846 if (!isSubroutine) {
2847 context_.Say(
2848 "alternate return specification may not appear on"
2849 " function reference"_err_en_US);
2850 }
2851 isAltReturn = true;
2852 },
2853 [&](const parser::ActualArg::PercentRef &) {
2854 context_.Say("TODO: %REF() argument"_err_en_US);
2855 },
2856 [&](const parser::ActualArg::PercentVal &) {
2857 context_.Say("TODO: %VAL() argument"_err_en_US);
2858 },
2859 },
2860 std::get<parser::ActualArg>(arg.t).u);
2861 if (actual) {
2862 if (const auto &argKW{std::get<std::optional<parser::Keyword>>(arg.t)}) {
2863 actual->set_keyword(argKW->v.source);
2864 }
2865 actuals_.emplace_back(std::move(*actual));
2866 } else if (!isAltReturn) {
2867 fatalErrors_ = true;
2868 }
2869 }
2870
IsIntrinsicRelational(RelationalOperator opr) const2871 bool ArgumentAnalyzer::IsIntrinsicRelational(RelationalOperator opr) const {
2872 CHECK(actuals_.size() == 2);
2873 return semantics::IsIntrinsicRelational(
2874 opr, *GetType(0), GetRank(0), *GetType(1), GetRank(1));
2875 }
2876
IsIntrinsicNumeric(NumericOperator opr) const2877 bool ArgumentAnalyzer::IsIntrinsicNumeric(NumericOperator opr) const {
2878 std::optional<DynamicType> type0{GetType(0)};
2879 if (actuals_.size() == 1) {
2880 if (IsBOZLiteral(0)) {
2881 return opr == NumericOperator::Add;
2882 } else {
2883 return type0 && semantics::IsIntrinsicNumeric(*type0);
2884 }
2885 } else {
2886 std::optional<DynamicType> type1{GetType(1)};
2887 if (IsBOZLiteral(0) && type1) {
2888 auto cat1{type1->category()};
2889 return cat1 == TypeCategory::Integer || cat1 == TypeCategory::Real;
2890 } else if (IsBOZLiteral(1) && type0) { // Integer/Real opr BOZ
2891 auto cat0{type0->category()};
2892 return cat0 == TypeCategory::Integer || cat0 == TypeCategory::Real;
2893 } else {
2894 return type0 && type1 &&
2895 semantics::IsIntrinsicNumeric(*type0, GetRank(0), *type1, GetRank(1));
2896 }
2897 }
2898 }
2899
IsIntrinsicLogical() const2900 bool ArgumentAnalyzer::IsIntrinsicLogical() const {
2901 if (actuals_.size() == 1) {
2902 return semantics::IsIntrinsicLogical(*GetType(0));
2903 return GetType(0)->category() == TypeCategory::Logical;
2904 } else {
2905 return semantics::IsIntrinsicLogical(
2906 *GetType(0), GetRank(0), *GetType(1), GetRank(1));
2907 }
2908 }
2909
IsIntrinsicConcat() const2910 bool ArgumentAnalyzer::IsIntrinsicConcat() const {
2911 return semantics::IsIntrinsicConcat(
2912 *GetType(0), GetRank(0), *GetType(1), GetRank(1));
2913 }
2914
CheckConformance() const2915 bool ArgumentAnalyzer::CheckConformance() const {
2916 if (actuals_.size() == 2) {
2917 const auto *lhs{actuals_.at(0).value().UnwrapExpr()};
2918 const auto *rhs{actuals_.at(1).value().UnwrapExpr()};
2919 if (lhs && rhs) {
2920 auto &foldingContext{context_.GetFoldingContext()};
2921 auto lhShape{GetShape(foldingContext, *lhs)};
2922 auto rhShape{GetShape(foldingContext, *rhs)};
2923 if (lhShape && rhShape) {
2924 return evaluate::CheckConformance(foldingContext.messages(), *lhShape,
2925 *rhShape, "left operand", "right operand");
2926 }
2927 }
2928 }
2929 return true; // no proven problem
2930 }
2931
TryDefinedOp(const char * opr,parser::MessageFixedText && error,bool isUserOp)2932 MaybeExpr ArgumentAnalyzer::TryDefinedOp(
2933 const char *opr, parser::MessageFixedText &&error, bool isUserOp) {
2934 if (AnyUntypedOperand()) {
2935 context_.Say(
2936 std::move(error), ToUpperCase(opr), TypeAsFortran(0), TypeAsFortran(1));
2937 return std::nullopt;
2938 }
2939 {
2940 auto restorer{context_.GetContextualMessages().DiscardMessages()};
2941 std::string oprNameString{
2942 isUserOp ? std::string{opr} : "operator("s + opr + ')'};
2943 parser::CharBlock oprName{oprNameString};
2944 const auto &scope{context_.context().FindScope(source_)};
2945 if (Symbol * symbol{scope.FindSymbol(oprName)}) {
2946 parser::Name name{symbol->name(), symbol};
2947 if (auto result{context_.AnalyzeDefinedOp(name, GetActuals())}) {
2948 return result;
2949 }
2950 sawDefinedOp_ = symbol;
2951 }
2952 for (std::size_t passIndex{0}; passIndex < actuals_.size(); ++passIndex) {
2953 if (const Symbol * symbol{FindBoundOp(oprName, passIndex)}) {
2954 if (MaybeExpr result{TryBoundOp(*symbol, passIndex)}) {
2955 return result;
2956 }
2957 }
2958 }
2959 }
2960 if (sawDefinedOp_) {
2961 SayNoMatch(ToUpperCase(sawDefinedOp_->name().ToString()));
2962 } else if (actuals_.size() == 1 || AreConformable()) {
2963 context_.Say(
2964 std::move(error), ToUpperCase(opr), TypeAsFortran(0), TypeAsFortran(1));
2965 } else {
2966 context_.Say(
2967 "Operands of %s are not conformable; have rank %d and rank %d"_err_en_US,
2968 ToUpperCase(opr), actuals_[0]->Rank(), actuals_[1]->Rank());
2969 }
2970 return std::nullopt;
2971 }
2972
TryDefinedOp(std::vector<const char * > oprs,parser::MessageFixedText && error)2973 MaybeExpr ArgumentAnalyzer::TryDefinedOp(
2974 std::vector<const char *> oprs, parser::MessageFixedText &&error) {
2975 for (std::size_t i{1}; i < oprs.size(); ++i) {
2976 auto restorer{context_.GetContextualMessages().DiscardMessages()};
2977 if (auto result{TryDefinedOp(oprs[i], std::move(error))}) {
2978 return result;
2979 }
2980 }
2981 return TryDefinedOp(oprs[0], std::move(error));
2982 }
2983
TryBoundOp(const Symbol & symbol,int passIndex)2984 MaybeExpr ArgumentAnalyzer::TryBoundOp(const Symbol &symbol, int passIndex) {
2985 ActualArguments localActuals{actuals_};
2986 const Symbol *proc{GetBindingResolution(GetType(passIndex), symbol)};
2987 if (!proc) {
2988 proc = &symbol;
2989 localActuals.at(passIndex).value().set_isPassedObject();
2990 }
2991 CheckConformance();
2992 return context_.MakeFunctionRef(
2993 source_, ProcedureDesignator{*proc}, std::move(localActuals));
2994 }
2995
TryDefinedAssignment()2996 std::optional<ProcedureRef> ArgumentAnalyzer::TryDefinedAssignment() {
2997 using semantics::Tristate;
2998 const Expr<SomeType> &lhs{GetExpr(0)};
2999 const Expr<SomeType> &rhs{GetExpr(1)};
3000 std::optional<DynamicType> lhsType{lhs.GetType()};
3001 std::optional<DynamicType> rhsType{rhs.GetType()};
3002 int lhsRank{lhs.Rank()};
3003 int rhsRank{rhs.Rank()};
3004 Tristate isDefined{
3005 semantics::IsDefinedAssignment(lhsType, lhsRank, rhsType, rhsRank)};
3006 if (isDefined == Tristate::No) {
3007 if (lhsType && rhsType) {
3008 AddAssignmentConversion(*lhsType, *rhsType);
3009 }
3010 return std::nullopt; // user-defined assignment not allowed for these args
3011 }
3012 auto restorer{context_.GetContextualMessages().SetLocation(source_)};
3013 if (std::optional<ProcedureRef> procRef{GetDefinedAssignmentProc()}) {
3014 context_.CheckCall(source_, procRef->proc(), procRef->arguments());
3015 return std::move(*procRef);
3016 }
3017 if (isDefined == Tristate::Yes) {
3018 if (!lhsType || !rhsType || (lhsRank != rhsRank && rhsRank != 0) ||
3019 !OkLogicalIntegerAssignment(lhsType->category(), rhsType->category())) {
3020 SayNoMatch("ASSIGNMENT(=)", true);
3021 }
3022 }
3023 return std::nullopt;
3024 }
3025
OkLogicalIntegerAssignment(TypeCategory lhs,TypeCategory rhs)3026 bool ArgumentAnalyzer::OkLogicalIntegerAssignment(
3027 TypeCategory lhs, TypeCategory rhs) {
3028 if (!context_.context().languageFeatures().IsEnabled(
3029 common::LanguageFeature::LogicalIntegerAssignment)) {
3030 return false;
3031 }
3032 std::optional<parser::MessageFixedText> msg;
3033 if (lhs == TypeCategory::Integer && rhs == TypeCategory::Logical) {
3034 // allow assignment to LOGICAL from INTEGER as a legacy extension
3035 msg = "nonstandard usage: assignment of LOGICAL to INTEGER"_en_US;
3036 } else if (lhs == TypeCategory::Logical && rhs == TypeCategory::Integer) {
3037 // ... and assignment to LOGICAL from INTEGER
3038 msg = "nonstandard usage: assignment of INTEGER to LOGICAL"_en_US;
3039 } else {
3040 return false;
3041 }
3042 if (context_.context().languageFeatures().ShouldWarn(
3043 common::LanguageFeature::LogicalIntegerAssignment)) {
3044 context_.Say(std::move(*msg));
3045 }
3046 return true;
3047 }
3048
GetDefinedAssignmentProc()3049 std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc() {
3050 auto restorer{context_.GetContextualMessages().DiscardMessages()};
3051 std::string oprNameString{"assignment(=)"};
3052 parser::CharBlock oprName{oprNameString};
3053 const Symbol *proc{nullptr};
3054 const auto &scope{context_.context().FindScope(source_)};
3055 if (const Symbol * symbol{scope.FindSymbol(oprName)}) {
3056 ExpressionAnalyzer::AdjustActuals noAdjustment;
3057 if (const Symbol *
3058 specific{context_.ResolveGeneric(*symbol, actuals_, noAdjustment)}) {
3059 proc = specific;
3060 } else {
3061 context_.EmitGenericResolutionError(*symbol);
3062 }
3063 }
3064 int passedObjectIndex{-1};
3065 for (std::size_t i{0}; i < actuals_.size(); ++i) {
3066 if (const Symbol * specific{FindBoundOp(oprName, i)}) {
3067 if (const Symbol *
3068 resolution{GetBindingResolution(GetType(i), *specific)}) {
3069 proc = resolution;
3070 } else {
3071 proc = specific;
3072 passedObjectIndex = i;
3073 }
3074 }
3075 }
3076 if (!proc) {
3077 return std::nullopt;
3078 }
3079 ActualArguments actualsCopy{actuals_};
3080 if (passedObjectIndex >= 0) {
3081 actualsCopy[passedObjectIndex]->set_isPassedObject();
3082 }
3083 return ProcedureRef{ProcedureDesignator{*proc}, std::move(actualsCopy)};
3084 }
3085
Dump(llvm::raw_ostream & os)3086 void ArgumentAnalyzer::Dump(llvm::raw_ostream &os) {
3087 os << "source_: " << source_.ToString() << " fatalErrors_ = " << fatalErrors_
3088 << '\n';
3089 for (const auto &actual : actuals_) {
3090 if (!actual.has_value()) {
3091 os << "- error\n";
3092 } else if (const Symbol * symbol{actual->GetAssumedTypeDummy()}) {
3093 os << "- assumed type: " << symbol->name().ToString() << '\n';
3094 } else if (const Expr<SomeType> *expr{actual->UnwrapExpr()}) {
3095 expr->AsFortran(os << "- expr: ") << '\n';
3096 } else {
3097 DIE("bad ActualArgument");
3098 }
3099 }
3100 }
3101
AnalyzeExpr(const parser::Expr & expr)3102 std::optional<ActualArgument> ArgumentAnalyzer::AnalyzeExpr(
3103 const parser::Expr &expr) {
3104 source_.ExtendToCover(expr.source);
3105 if (const Symbol * assumedTypeDummy{AssumedTypeDummy(expr)}) {
3106 expr.typedExpr.Reset(new GenericExprWrapper{}, GenericExprWrapper::Deleter);
3107 if (isProcedureCall_) {
3108 return ActualArgument{ActualArgument::AssumedType{*assumedTypeDummy}};
3109 }
3110 context_.SayAt(expr.source,
3111 "TYPE(*) dummy argument may only be used as an actual argument"_err_en_US);
3112 } else if (MaybeExpr argExpr{AnalyzeExprOrWholeAssumedSizeArray(expr)}) {
3113 if (isProcedureCall_ || !IsProcedure(*argExpr)) {
3114 return ActualArgument{std::move(*argExpr)};
3115 }
3116 context_.SayAt(expr.source,
3117 IsFunction(*argExpr) ? "Function call must have argument list"_err_en_US
3118 : "Subroutine name is not allowed here"_err_en_US);
3119 }
3120 return std::nullopt;
3121 }
3122
AnalyzeExprOrWholeAssumedSizeArray(const parser::Expr & expr)3123 MaybeExpr ArgumentAnalyzer::AnalyzeExprOrWholeAssumedSizeArray(
3124 const parser::Expr &expr) {
3125 // If an expression's parse tree is a whole assumed-size array:
3126 // Expr -> Designator -> DataRef -> Name
3127 // treat it as a special case for argument passing and bypass
3128 // the C1002/C1014 constraint checking in expression semantics.
3129 if (const auto *name{parser::Unwrap<parser::Name>(expr)}) {
3130 if (name->symbol && semantics::IsAssumedSizeArray(*name->symbol)) {
3131 auto restorer{context_.AllowWholeAssumedSizeArray()};
3132 return context_.Analyze(expr);
3133 }
3134 }
3135 return context_.Analyze(expr);
3136 }
3137
AreConformable() const3138 bool ArgumentAnalyzer::AreConformable() const {
3139 CHECK(!fatalErrors_ && actuals_.size() == 2);
3140 return evaluate::AreConformable(*actuals_[0], *actuals_[1]);
3141 }
3142
3143 // Look for a type-bound operator in the type of arg number passIndex.
FindBoundOp(parser::CharBlock oprName,int passIndex)3144 const Symbol *ArgumentAnalyzer::FindBoundOp(
3145 parser::CharBlock oprName, int passIndex) {
3146 const auto *type{GetDerivedTypeSpec(GetType(passIndex))};
3147 if (!type || !type->scope()) {
3148 return nullptr;
3149 }
3150 const Symbol *symbol{type->scope()->FindComponent(oprName)};
3151 if (!symbol) {
3152 return nullptr;
3153 }
3154 sawDefinedOp_ = symbol;
3155 ExpressionAnalyzer::AdjustActuals adjustment{
3156 [&](const Symbol &proc, ActualArguments &) {
3157 return passIndex == GetPassIndex(proc);
3158 }};
3159 const Symbol *result{context_.ResolveGeneric(*symbol, actuals_, adjustment)};
3160 if (!result) {
3161 context_.EmitGenericResolutionError(*symbol);
3162 }
3163 return result;
3164 }
3165
3166 // If there is an implicit conversion between intrinsic types, make it explicit
AddAssignmentConversion(const DynamicType & lhsType,const DynamicType & rhsType)3167 void ArgumentAnalyzer::AddAssignmentConversion(
3168 const DynamicType &lhsType, const DynamicType &rhsType) {
3169 if (lhsType.category() == rhsType.category() &&
3170 lhsType.kind() == rhsType.kind()) {
3171 // no conversion necessary
3172 } else if (auto rhsExpr{evaluate::ConvertToType(lhsType, MoveExpr(1))}) {
3173 actuals_[1] = ActualArgument{*rhsExpr};
3174 } else {
3175 actuals_[1] = std::nullopt;
3176 }
3177 }
3178
GetType(std::size_t i) const3179 std::optional<DynamicType> ArgumentAnalyzer::GetType(std::size_t i) const {
3180 return i < actuals_.size() ? actuals_[i].value().GetType() : std::nullopt;
3181 }
GetRank(std::size_t i) const3182 int ArgumentAnalyzer::GetRank(std::size_t i) const {
3183 return i < actuals_.size() ? actuals_[i].value().Rank() : 0;
3184 }
3185
3186 // If the argument at index i is a BOZ literal, convert its type to match the
3187 // otherType. It it's REAL convert to REAL, otherwise convert to INTEGER.
3188 // Note that IBM supports comparing BOZ literals to CHARACTER operands. That
3189 // is not currently supported.
ConvertBOZ(std::size_t i,std::optional<DynamicType> otherType)3190 void ArgumentAnalyzer::ConvertBOZ(
3191 std::size_t i, std::optional<DynamicType> otherType) {
3192 if (IsBOZLiteral(i)) {
3193 Expr<SomeType> &&argExpr{MoveExpr(i)};
3194 auto *boz{std::get_if<BOZLiteralConstant>(&argExpr.u)};
3195 if (otherType && otherType->category() == TypeCategory::Real) {
3196 MaybeExpr realExpr{ConvertToKind<TypeCategory::Real>(
3197 context_.context().GetDefaultKind(TypeCategory::Real),
3198 std::move(*boz))};
3199 actuals_[i] = std::move(*realExpr);
3200 } else {
3201 MaybeExpr intExpr{ConvertToKind<TypeCategory::Integer>(
3202 context_.context().GetDefaultKind(TypeCategory::Integer),
3203 std::move(*boz))};
3204 actuals_[i] = std::move(*intExpr);
3205 }
3206 }
3207 }
3208
3209 // Report error resolving opr when there is a user-defined one available
SayNoMatch(const std::string & opr,bool isAssignment)3210 void ArgumentAnalyzer::SayNoMatch(const std::string &opr, bool isAssignment) {
3211 std::string type0{TypeAsFortran(0)};
3212 auto rank0{actuals_[0]->Rank()};
3213 if (actuals_.size() == 1) {
3214 if (rank0 > 0) {
3215 context_.Say("No intrinsic or user-defined %s matches "
3216 "rank %d array of %s"_err_en_US,
3217 opr, rank0, type0);
3218 } else {
3219 context_.Say("No intrinsic or user-defined %s matches "
3220 "operand type %s"_err_en_US,
3221 opr, type0);
3222 }
3223 } else {
3224 std::string type1{TypeAsFortran(1)};
3225 auto rank1{actuals_[1]->Rank()};
3226 if (rank0 > 0 && rank1 > 0 && rank0 != rank1) {
3227 context_.Say("No intrinsic or user-defined %s matches "
3228 "rank %d array of %s and rank %d array of %s"_err_en_US,
3229 opr, rank0, type0, rank1, type1);
3230 } else if (isAssignment && rank0 != rank1) {
3231 if (rank0 == 0) {
3232 context_.Say("No intrinsic or user-defined %s matches "
3233 "scalar %s and rank %d array of %s"_err_en_US,
3234 opr, type0, rank1, type1);
3235 } else {
3236 context_.Say("No intrinsic or user-defined %s matches "
3237 "rank %d array of %s and scalar %s"_err_en_US,
3238 opr, rank0, type0, type1);
3239 }
3240 } else {
3241 context_.Say("No intrinsic or user-defined %s matches "
3242 "operand types %s and %s"_err_en_US,
3243 opr, type0, type1);
3244 }
3245 }
3246 }
3247
TypeAsFortran(std::size_t i)3248 std::string ArgumentAnalyzer::TypeAsFortran(std::size_t i) {
3249 if (std::optional<DynamicType> type{GetType(i)}) {
3250 return type->category() == TypeCategory::Derived
3251 ? "TYPE("s + type->AsFortran() + ')'
3252 : type->category() == TypeCategory::Character
3253 ? "CHARACTER(KIND="s + std::to_string(type->kind()) + ')'
3254 : ToUpperCase(type->AsFortran());
3255 } else {
3256 return "untyped";
3257 }
3258 }
3259
AnyUntypedOperand()3260 bool ArgumentAnalyzer::AnyUntypedOperand() {
3261 for (const auto &actual : actuals_) {
3262 if (!actual.value().GetType()) {
3263 return true;
3264 }
3265 }
3266 return false;
3267 }
3268
3269 } // namespace Fortran::evaluate
3270
3271 namespace Fortran::semantics {
AnalyzeKindSelector(SemanticsContext & context,common::TypeCategory category,const std::optional<parser::KindSelector> & selector)3272 evaluate::Expr<evaluate::SubscriptInteger> AnalyzeKindSelector(
3273 SemanticsContext &context, common::TypeCategory category,
3274 const std::optional<parser::KindSelector> &selector) {
3275 evaluate::ExpressionAnalyzer analyzer{context};
3276 auto restorer{
3277 analyzer.GetContextualMessages().SetLocation(context.location().value())};
3278 return analyzer.AnalyzeKindSelector(category, selector);
3279 }
3280
AnalyzeCallStmt(SemanticsContext & context,const parser::CallStmt & call)3281 void AnalyzeCallStmt(SemanticsContext &context, const parser::CallStmt &call) {
3282 evaluate::ExpressionAnalyzer{context}.Analyze(call);
3283 }
3284
AnalyzeAssignmentStmt(SemanticsContext & context,const parser::AssignmentStmt & stmt)3285 const evaluate::Assignment *AnalyzeAssignmentStmt(
3286 SemanticsContext &context, const parser::AssignmentStmt &stmt) {
3287 return evaluate::ExpressionAnalyzer{context}.Analyze(stmt);
3288 }
AnalyzePointerAssignmentStmt(SemanticsContext & context,const parser::PointerAssignmentStmt & stmt)3289 const evaluate::Assignment *AnalyzePointerAssignmentStmt(
3290 SemanticsContext &context, const parser::PointerAssignmentStmt &stmt) {
3291 return evaluate::ExpressionAnalyzer{context}.Analyze(stmt);
3292 }
3293
ExprChecker(SemanticsContext & context)3294 ExprChecker::ExprChecker(SemanticsContext &context) : context_{context} {}
3295
Pre(const parser::DataImpliedDo & ido)3296 bool ExprChecker::Pre(const parser::DataImpliedDo &ido) {
3297 parser::Walk(std::get<parser::DataImpliedDo::Bounds>(ido.t), *this);
3298 const auto &bounds{std::get<parser::DataImpliedDo::Bounds>(ido.t)};
3299 auto name{bounds.name.thing.thing};
3300 int kind{evaluate::ResultType<evaluate::ImpliedDoIndex>::kind};
3301 if (const auto dynamicType{evaluate::DynamicType::From(*name.symbol)}) {
3302 if (dynamicType->category() == TypeCategory::Integer) {
3303 kind = dynamicType->kind();
3304 }
3305 }
3306 exprAnalyzer_.AddImpliedDo(name.source, kind);
3307 parser::Walk(std::get<std::list<parser::DataIDoObject>>(ido.t), *this);
3308 exprAnalyzer_.RemoveImpliedDo(name.source);
3309 return false;
3310 }
3311
Walk(const parser::Program & program)3312 bool ExprChecker::Walk(const parser::Program &program) {
3313 parser::Walk(program, *this);
3314 return !context_.AnyFatalError();
3315 }
3316 } // namespace Fortran::semantics
3317