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 & n)712 MaybeExpr ExpressionAnalyzer::Analyze(const parser::NullInit &n) {
713 if (MaybeExpr value{Analyze(n.v)}) {
714 // Subtle: when the NullInit is a DataStmtConstant, it might
715 // be a misparse of a structure constructor without parameters
716 // or components (e.g., T()). Checking the result to ensure
717 // that a "=>" data entity initializer actually resolved to
718 // a null pointer has to be done by the caller.
719 return Fold(std::move(*value));
720 }
721 return std::nullopt;
722 }
723
Analyze(const parser::InitialDataTarget & x)724 MaybeExpr ExpressionAnalyzer::Analyze(const parser::InitialDataTarget &x) {
725 return Analyze(x.value());
726 }
727
Analyze(const parser::DataStmtValue & x)728 MaybeExpr ExpressionAnalyzer::Analyze(const parser::DataStmtValue &x) {
729 if (const auto &repeat{
730 std::get<std::optional<parser::DataStmtRepeat>>(x.t)}) {
731 x.repetitions = -1;
732 if (MaybeExpr expr{Analyze(repeat->u)}) {
733 Expr<SomeType> folded{Fold(std::move(*expr))};
734 if (auto value{ToInt64(folded)}) {
735 if (*value >= 0) { // C882
736 x.repetitions = *value;
737 } else {
738 Say(FindSourceLocation(repeat),
739 "Repeat count (%jd) for data value must not be negative"_err_en_US,
740 *value);
741 }
742 }
743 }
744 }
745 return Analyze(std::get<parser::DataStmtConstant>(x.t));
746 }
747
748 // Substring references
GetSubstringBound(const std::optional<parser::ScalarIntExpr> & bound)749 std::optional<Expr<SubscriptInteger>> ExpressionAnalyzer::GetSubstringBound(
750 const std::optional<parser::ScalarIntExpr> &bound) {
751 if (bound) {
752 if (MaybeExpr expr{Analyze(*bound)}) {
753 if (expr->Rank() > 1) {
754 Say("substring bound expression has rank %d"_err_en_US, expr->Rank());
755 }
756 if (auto *intExpr{std::get_if<Expr<SomeInteger>>(&expr->u)}) {
757 if (auto *ssIntExpr{std::get_if<Expr<SubscriptInteger>>(&intExpr->u)}) {
758 return {std::move(*ssIntExpr)};
759 }
760 return {Expr<SubscriptInteger>{
761 Convert<SubscriptInteger, TypeCategory::Integer>{
762 std::move(*intExpr)}}};
763 } else {
764 Say("substring bound expression is not INTEGER"_err_en_US);
765 }
766 }
767 }
768 return std::nullopt;
769 }
770
Analyze(const parser::Substring & ss)771 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Substring &ss) {
772 if (MaybeExpr baseExpr{Analyze(std::get<parser::DataRef>(ss.t))}) {
773 if (std::optional<DataRef> dataRef{ExtractDataRef(std::move(*baseExpr))}) {
774 if (MaybeExpr newBaseExpr{TopLevelChecks(std::move(*dataRef))}) {
775 if (std::optional<DataRef> checked{
776 ExtractDataRef(std::move(*newBaseExpr))}) {
777 const parser::SubstringRange &range{
778 std::get<parser::SubstringRange>(ss.t)};
779 std::optional<Expr<SubscriptInteger>> first{
780 GetSubstringBound(std::get<0>(range.t))};
781 std::optional<Expr<SubscriptInteger>> last{
782 GetSubstringBound(std::get<1>(range.t))};
783 const Symbol &symbol{checked->GetLastSymbol()};
784 if (std::optional<DynamicType> dynamicType{
785 DynamicType::From(symbol)}) {
786 if (dynamicType->category() == TypeCategory::Character) {
787 return WrapperHelper<TypeCategory::Character, Designator,
788 Substring>(dynamicType->kind(),
789 Substring{std::move(checked.value()), std::move(first),
790 std::move(last)});
791 }
792 }
793 Say("substring may apply only to CHARACTER"_err_en_US);
794 }
795 }
796 }
797 }
798 return std::nullopt;
799 }
800
801 // CHARACTER literal substrings
Analyze(const parser::CharLiteralConstantSubstring & x)802 MaybeExpr ExpressionAnalyzer::Analyze(
803 const parser::CharLiteralConstantSubstring &x) {
804 const parser::SubstringRange &range{std::get<parser::SubstringRange>(x.t)};
805 std::optional<Expr<SubscriptInteger>> lower{
806 GetSubstringBound(std::get<0>(range.t))};
807 std::optional<Expr<SubscriptInteger>> upper{
808 GetSubstringBound(std::get<1>(range.t))};
809 if (MaybeExpr string{Analyze(std::get<parser::CharLiteralConstant>(x.t))}) {
810 if (auto *charExpr{std::get_if<Expr<SomeCharacter>>(&string->u)}) {
811 Expr<SubscriptInteger> length{
812 std::visit([](const auto &ckExpr) { return ckExpr.LEN().value(); },
813 charExpr->u)};
814 if (!lower) {
815 lower = Expr<SubscriptInteger>{1};
816 }
817 if (!upper) {
818 upper = Expr<SubscriptInteger>{
819 static_cast<std::int64_t>(ToInt64(length).value())};
820 }
821 return std::visit(
822 [&](auto &&ckExpr) -> MaybeExpr {
823 using Result = ResultType<decltype(ckExpr)>;
824 auto *cp{std::get_if<Constant<Result>>(&ckExpr.u)};
825 CHECK(DEREF(cp).size() == 1);
826 StaticDataObject::Pointer staticData{StaticDataObject::Create()};
827 staticData->set_alignment(Result::kind)
828 .set_itemBytes(Result::kind)
829 .Push(cp->GetScalarValue().value());
830 Substring substring{std::move(staticData), std::move(lower.value()),
831 std::move(upper.value())};
832 return AsGenericExpr(
833 Expr<Result>{Designator<Result>{std::move(substring)}});
834 },
835 std::move(charExpr->u));
836 }
837 }
838 return std::nullopt;
839 }
840
841 // Subscripted array references
AsSubscript(MaybeExpr && expr)842 std::optional<Expr<SubscriptInteger>> ExpressionAnalyzer::AsSubscript(
843 MaybeExpr &&expr) {
844 if (expr) {
845 if (expr->Rank() > 1) {
846 Say("Subscript expression has rank %d greater than 1"_err_en_US,
847 expr->Rank());
848 }
849 if (auto *intExpr{std::get_if<Expr<SomeInteger>>(&expr->u)}) {
850 if (auto *ssIntExpr{std::get_if<Expr<SubscriptInteger>>(&intExpr->u)}) {
851 return std::move(*ssIntExpr);
852 } else {
853 return Expr<SubscriptInteger>{
854 Convert<SubscriptInteger, TypeCategory::Integer>{
855 std::move(*intExpr)}};
856 }
857 } else {
858 Say("Subscript expression is not INTEGER"_err_en_US);
859 }
860 }
861 return std::nullopt;
862 }
863
TripletPart(const std::optional<parser::Subscript> & s)864 std::optional<Expr<SubscriptInteger>> ExpressionAnalyzer::TripletPart(
865 const std::optional<parser::Subscript> &s) {
866 if (s) {
867 return AsSubscript(Analyze(*s));
868 } else {
869 return std::nullopt;
870 }
871 }
872
AnalyzeSectionSubscript(const parser::SectionSubscript & ss)873 std::optional<Subscript> ExpressionAnalyzer::AnalyzeSectionSubscript(
874 const parser::SectionSubscript &ss) {
875 return std::visit(
876 common::visitors{
877 [&](const parser::SubscriptTriplet &t) -> std::optional<Subscript> {
878 const auto &lower{std::get<0>(t.t)};
879 const auto &upper{std::get<1>(t.t)};
880 const auto &stride{std::get<2>(t.t)};
881 auto result{Triplet{
882 TripletPart(lower), TripletPart(upper), TripletPart(stride)}};
883 if ((lower && !result.lower()) || (upper && !result.upper())) {
884 return std::nullopt;
885 } else {
886 return std::make_optional<Subscript>(result);
887 }
888 },
889 [&](const auto &s) -> std::optional<Subscript> {
890 if (auto subscriptExpr{AsSubscript(Analyze(s))}) {
891 return Subscript{std::move(*subscriptExpr)};
892 } else {
893 return std::nullopt;
894 }
895 },
896 },
897 ss.u);
898 }
899
900 // Empty result means an error occurred
AnalyzeSectionSubscripts(const std::list<parser::SectionSubscript> & sss)901 std::vector<Subscript> ExpressionAnalyzer::AnalyzeSectionSubscripts(
902 const std::list<parser::SectionSubscript> &sss) {
903 bool error{false};
904 std::vector<Subscript> subscripts;
905 for (const auto &s : sss) {
906 if (auto subscript{AnalyzeSectionSubscript(s)}) {
907 subscripts.emplace_back(std::move(*subscript));
908 } else {
909 error = true;
910 }
911 }
912 return !error ? subscripts : std::vector<Subscript>{};
913 }
914
Analyze(const parser::ArrayElement & ae)915 MaybeExpr ExpressionAnalyzer::Analyze(const parser::ArrayElement &ae) {
916 MaybeExpr baseExpr;
917 {
918 auto restorer{AllowWholeAssumedSizeArray()};
919 baseExpr = Analyze(ae.base);
920 }
921 if (baseExpr) {
922 if (ae.subscripts.empty()) {
923 // will be converted to function call later or error reported
924 } else if (baseExpr->Rank() == 0) {
925 if (const Symbol * symbol{GetLastSymbol(*baseExpr)}) {
926 if (!context_.HasError(symbol)) {
927 Say("'%s' is not an array"_err_en_US, symbol->name());
928 context_.SetError(*symbol);
929 }
930 }
931 } else if (std::optional<DataRef> dataRef{
932 ExtractDataRef(std::move(*baseExpr))}) {
933 return ApplySubscripts(
934 std::move(*dataRef), AnalyzeSectionSubscripts(ae.subscripts));
935 } else {
936 Say("Subscripts may be applied only to an object, component, or array constant"_err_en_US);
937 }
938 }
939 // error was reported: analyze subscripts without reporting more errors
940 auto restorer{GetContextualMessages().DiscardMessages()};
941 AnalyzeSectionSubscripts(ae.subscripts);
942 return std::nullopt;
943 }
944
945 // Type parameter inquiries apply to data references, but don't depend
946 // on any trailing (co)subscripts.
IgnoreAnySubscripts(Designator<SomeDerived> && designator)947 static NamedEntity IgnoreAnySubscripts(Designator<SomeDerived> &&designator) {
948 return std::visit(
949 common::visitors{
950 [](SymbolRef &&symbol) { return NamedEntity{symbol}; },
951 [](Component &&component) {
952 return NamedEntity{std::move(component)};
953 },
954 [](ArrayRef &&arrayRef) { return std::move(arrayRef.base()); },
955 [](CoarrayRef &&coarrayRef) {
956 return NamedEntity{coarrayRef.GetLastSymbol()};
957 },
958 },
959 std::move(designator.u));
960 }
961
962 // Components of parent derived types are explicitly represented as such.
CreateComponent(DataRef && base,const Symbol & component,const semantics::Scope & scope)963 static std::optional<Component> CreateComponent(
964 DataRef &&base, const Symbol &component, const semantics::Scope &scope) {
965 if (&component.owner() == &scope) {
966 return Component{std::move(base), component};
967 }
968 if (const semantics::Scope * parentScope{scope.GetDerivedTypeParent()}) {
969 if (const Symbol * parentComponent{parentScope->GetSymbol()}) {
970 return CreateComponent(
971 DataRef{Component{std::move(base), *parentComponent}}, component,
972 *parentScope);
973 }
974 }
975 return std::nullopt;
976 }
977
978 // Derived type component references and type parameter inquiries
Analyze(const parser::StructureComponent & sc)979 MaybeExpr ExpressionAnalyzer::Analyze(const parser::StructureComponent &sc) {
980 MaybeExpr base{Analyze(sc.base)};
981 Symbol *sym{sc.component.symbol};
982 if (!base || !sym || context_.HasError(sym)) {
983 return std::nullopt;
984 }
985 const auto &name{sc.component.source};
986 if (auto *dtExpr{UnwrapExpr<Expr<SomeDerived>>(*base)}) {
987 const auto *dtSpec{GetDerivedTypeSpec(dtExpr->GetType())};
988 if (sym->detailsIf<semantics::TypeParamDetails>()) {
989 if (auto *designator{UnwrapExpr<Designator<SomeDerived>>(*dtExpr)}) {
990 if (std::optional<DynamicType> dyType{DynamicType::From(*sym)}) {
991 if (dyType->category() == TypeCategory::Integer) {
992 auto restorer{GetContextualMessages().SetLocation(name)};
993 return Fold(ConvertToType(*dyType,
994 AsGenericExpr(TypeParamInquiry{
995 IgnoreAnySubscripts(std::move(*designator)), *sym})));
996 }
997 }
998 Say(name, "Type parameter is not INTEGER"_err_en_US);
999 } else {
1000 Say(name,
1001 "A type parameter inquiry must be applied to "
1002 "a designator"_err_en_US);
1003 }
1004 } else if (!dtSpec || !dtSpec->scope()) {
1005 CHECK(context_.AnyFatalError() || !foldingContext_.messages().empty());
1006 return std::nullopt;
1007 } else if (std::optional<DataRef> dataRef{
1008 ExtractDataRef(std::move(*dtExpr))}) {
1009 if (auto component{
1010 CreateComponent(std::move(*dataRef), *sym, *dtSpec->scope())}) {
1011 return Designate(DataRef{std::move(*component)});
1012 } else {
1013 Say(name, "Component is not in scope of derived TYPE(%s)"_err_en_US,
1014 dtSpec->typeSymbol().name());
1015 }
1016 } else {
1017 Say(name,
1018 "Base of component reference must be a data reference"_err_en_US);
1019 }
1020 } else if (auto *details{sym->detailsIf<semantics::MiscDetails>()}) {
1021 // special part-ref: %re, %im, %kind, %len
1022 // Type errors are detected and reported in semantics.
1023 using MiscKind = semantics::MiscDetails::Kind;
1024 MiscKind kind{details->kind()};
1025 if (kind == MiscKind::ComplexPartRe || kind == MiscKind::ComplexPartIm) {
1026 if (auto *zExpr{std::get_if<Expr<SomeComplex>>(&base->u)}) {
1027 if (std::optional<DataRef> dataRef{ExtractDataRef(std::move(*zExpr))}) {
1028 Expr<SomeReal> realExpr{std::visit(
1029 [&](const auto &z) {
1030 using PartType = typename ResultType<decltype(z)>::Part;
1031 auto part{kind == MiscKind::ComplexPartRe
1032 ? ComplexPart::Part::RE
1033 : ComplexPart::Part::IM};
1034 return AsCategoryExpr(Designator<PartType>{
1035 ComplexPart{std::move(*dataRef), part}});
1036 },
1037 zExpr->u)};
1038 return AsGenericExpr(std::move(realExpr));
1039 }
1040 }
1041 } else if (kind == MiscKind::KindParamInquiry ||
1042 kind == MiscKind::LenParamInquiry) {
1043 // Convert x%KIND -> intrinsic KIND(x), x%LEN -> intrinsic LEN(x)
1044 return MakeFunctionRef(
1045 name, ActualArguments{ActualArgument{std::move(*base)}});
1046 } else {
1047 DIE("unexpected MiscDetails::Kind");
1048 }
1049 } else {
1050 Say(name, "derived type required before component reference"_err_en_US);
1051 }
1052 return std::nullopt;
1053 }
1054
Analyze(const parser::CoindexedNamedObject & x)1055 MaybeExpr ExpressionAnalyzer::Analyze(const parser::CoindexedNamedObject &x) {
1056 if (auto maybeDataRef{ExtractDataRef(Analyze(x.base))}) {
1057 DataRef *dataRef{&*maybeDataRef};
1058 std::vector<Subscript> subscripts;
1059 SymbolVector reversed;
1060 if (auto *aRef{std::get_if<ArrayRef>(&dataRef->u)}) {
1061 subscripts = std::move(aRef->subscript());
1062 reversed.push_back(aRef->GetLastSymbol());
1063 if (Component * component{aRef->base().UnwrapComponent()}) {
1064 dataRef = &component->base();
1065 } else {
1066 dataRef = nullptr;
1067 }
1068 }
1069 if (dataRef) {
1070 while (auto *component{std::get_if<Component>(&dataRef->u)}) {
1071 reversed.push_back(component->GetLastSymbol());
1072 dataRef = &component->base();
1073 }
1074 if (auto *baseSym{std::get_if<SymbolRef>(&dataRef->u)}) {
1075 reversed.push_back(*baseSym);
1076 } else {
1077 Say("Base of coindexed named object has subscripts or cosubscripts"_err_en_US);
1078 }
1079 }
1080 std::vector<Expr<SubscriptInteger>> cosubscripts;
1081 bool cosubsOk{true};
1082 for (const auto &cosub :
1083 std::get<std::list<parser::Cosubscript>>(x.imageSelector.t)) {
1084 MaybeExpr coex{Analyze(cosub)};
1085 if (auto *intExpr{UnwrapExpr<Expr<SomeInteger>>(coex)}) {
1086 cosubscripts.push_back(
1087 ConvertToType<SubscriptInteger>(std::move(*intExpr)));
1088 } else {
1089 cosubsOk = false;
1090 }
1091 }
1092 if (cosubsOk && !reversed.empty()) {
1093 int numCosubscripts{static_cast<int>(cosubscripts.size())};
1094 const Symbol &symbol{reversed.front()};
1095 if (numCosubscripts != symbol.Corank()) {
1096 Say("'%s' has corank %d, but coindexed reference has %d cosubscripts"_err_en_US,
1097 symbol.name(), symbol.Corank(), numCosubscripts);
1098 }
1099 }
1100 for (const auto &imageSelSpec :
1101 std::get<std::list<parser::ImageSelectorSpec>>(x.imageSelector.t)) {
1102 std::visit(
1103 common::visitors{
1104 [&](const auto &x) { Analyze(x.v); },
1105 },
1106 imageSelSpec.u);
1107 }
1108 // Reverse the chain of symbols so that the base is first and coarray
1109 // ultimate component is last.
1110 if (cosubsOk) {
1111 return Designate(
1112 DataRef{CoarrayRef{SymbolVector{reversed.crbegin(), reversed.crend()},
1113 std::move(subscripts), std::move(cosubscripts)}});
1114 }
1115 }
1116 return std::nullopt;
1117 }
1118
IntegerTypeSpecKind(const parser::IntegerTypeSpec & spec)1119 int ExpressionAnalyzer::IntegerTypeSpecKind(
1120 const parser::IntegerTypeSpec &spec) {
1121 Expr<SubscriptInteger> value{
1122 AnalyzeKindSelector(TypeCategory::Integer, spec.v)};
1123 if (auto kind{ToInt64(value)}) {
1124 return static_cast<int>(*kind);
1125 }
1126 SayAt(spec, "Constant INTEGER kind value required here"_err_en_US);
1127 return GetDefaultKind(TypeCategory::Integer);
1128 }
1129
1130 // Array constructors
1131
1132 // Inverts a collection of generic ArrayConstructorValues<SomeType> that
1133 // all happen to have the same actual type T into one ArrayConstructor<T>.
1134 template <typename T>
MakeSpecific(ArrayConstructorValues<SomeType> && from)1135 ArrayConstructorValues<T> MakeSpecific(
1136 ArrayConstructorValues<SomeType> &&from) {
1137 ArrayConstructorValues<T> to;
1138 for (ArrayConstructorValue<SomeType> &x : from) {
1139 std::visit(
1140 common::visitors{
1141 [&](common::CopyableIndirection<Expr<SomeType>> &&expr) {
1142 auto *typed{UnwrapExpr<Expr<T>>(expr.value())};
1143 to.Push(std::move(DEREF(typed)));
1144 },
1145 [&](ImpliedDo<SomeType> &&impliedDo) {
1146 to.Push(ImpliedDo<T>{impliedDo.name(),
1147 std::move(impliedDo.lower()), std::move(impliedDo.upper()),
1148 std::move(impliedDo.stride()),
1149 MakeSpecific<T>(std::move(impliedDo.values()))});
1150 },
1151 },
1152 std::move(x.u));
1153 }
1154 return to;
1155 }
1156
1157 class ArrayConstructorContext {
1158 public:
ArrayConstructorContext(ExpressionAnalyzer & c,std::optional<DynamicTypeWithLength> && t)1159 ArrayConstructorContext(
1160 ExpressionAnalyzer &c, std::optional<DynamicTypeWithLength> &&t)
1161 : exprAnalyzer_{c}, type_{std::move(t)} {}
1162
1163 void Add(const parser::AcValue &);
1164 MaybeExpr ToExpr();
1165
1166 // These interfaces allow *this to be used as a type visitor argument to
1167 // common::SearchTypes() to convert the array constructor to a typed
1168 // expression in ToExpr().
1169 using Result = MaybeExpr;
1170 using Types = AllTypes;
Test()1171 template <typename T> Result Test() {
1172 if (type_ && type_->category() == T::category) {
1173 if constexpr (T::category == TypeCategory::Derived) {
1174 if (type_->IsUnlimitedPolymorphic()) {
1175 return std::nullopt;
1176 } else {
1177 return AsMaybeExpr(ArrayConstructor<T>{type_->GetDerivedTypeSpec(),
1178 MakeSpecific<T>(std::move(values_))});
1179 }
1180 } else if (type_->kind() == T::kind) {
1181 if constexpr (T::category == TypeCategory::Character) {
1182 if (auto len{type_->LEN()}) {
1183 return AsMaybeExpr(ArrayConstructor<T>{
1184 *std::move(len), MakeSpecific<T>(std::move(values_))});
1185 }
1186 } else {
1187 return AsMaybeExpr(
1188 ArrayConstructor<T>{MakeSpecific<T>(std::move(values_))});
1189 }
1190 }
1191 }
1192 return std::nullopt;
1193 }
1194
1195 private:
1196 using ImpliedDoIntType = ResultType<ImpliedDoIndex>;
1197
1198 void Push(MaybeExpr &&);
1199 void Add(const parser::AcValue::Triplet &);
1200 void Add(const parser::Expr &);
1201 void Add(const parser::AcImpliedDo &);
1202 void UnrollConstantImpliedDo(const parser::AcImpliedDo &,
1203 parser::CharBlock name, std::int64_t lower, std::int64_t upper,
1204 std::int64_t stride);
1205
1206 template <int KIND, typename A>
GetSpecificIntExpr(const A & x)1207 std::optional<Expr<Type<TypeCategory::Integer, KIND>>> GetSpecificIntExpr(
1208 const A &x) {
1209 if (MaybeExpr y{exprAnalyzer_.Analyze(x)}) {
1210 Expr<SomeInteger> *intExpr{UnwrapExpr<Expr<SomeInteger>>(*y)};
1211 return Fold(exprAnalyzer_.GetFoldingContext(),
1212 ConvertToType<Type<TypeCategory::Integer, KIND>>(
1213 std::move(DEREF(intExpr))));
1214 }
1215 return std::nullopt;
1216 }
1217
1218 // Nested array constructors all reference the same ExpressionAnalyzer,
1219 // which represents the nest of active implied DO loop indices.
1220 ExpressionAnalyzer &exprAnalyzer_;
1221 std::optional<DynamicTypeWithLength> type_;
1222 bool explicitType_{type_.has_value()};
1223 std::optional<std::int64_t> constantLength_;
1224 ArrayConstructorValues<SomeType> values_;
1225 std::uint64_t messageDisplayedSet_{0};
1226 };
1227
Push(MaybeExpr && x)1228 void ArrayConstructorContext::Push(MaybeExpr &&x) {
1229 if (!x) {
1230 return;
1231 }
1232 if (auto dyType{x->GetType()}) {
1233 DynamicTypeWithLength xType{*dyType};
1234 if (Expr<SomeCharacter> * charExpr{UnwrapExpr<Expr<SomeCharacter>>(*x)}) {
1235 CHECK(xType.category() == TypeCategory::Character);
1236 xType.length =
1237 std::visit([](const auto &kc) { return kc.LEN(); }, charExpr->u);
1238 }
1239 if (!type_) {
1240 // If there is no explicit type-spec in an array constructor, the type
1241 // of the array is the declared type of all of the elements, which must
1242 // be well-defined and all match.
1243 // TODO: Possible language extension: use the most general type of
1244 // the values as the type of a numeric constructed array, convert all
1245 // of the other values to that type. Alternative: let the first value
1246 // determine the type, and convert the others to that type.
1247 CHECK(!explicitType_);
1248 type_ = std::move(xType);
1249 constantLength_ = ToInt64(type_->length);
1250 values_.Push(std::move(*x));
1251 } else if (!explicitType_) {
1252 if (static_cast<const DynamicType &>(*type_) ==
1253 static_cast<const DynamicType &>(xType)) {
1254 values_.Push(std::move(*x));
1255 if (auto thisLen{ToInt64(xType.LEN())}) {
1256 if (constantLength_) {
1257 if (exprAnalyzer_.context().warnOnNonstandardUsage() &&
1258 *thisLen != *constantLength_) {
1259 if (!(messageDisplayedSet_ & 1)) {
1260 exprAnalyzer_.Say(
1261 "Character literal in array constructor without explicit "
1262 "type has different length than earlier elements"_en_US);
1263 messageDisplayedSet_ |= 1;
1264 }
1265 }
1266 if (*thisLen > *constantLength_) {
1267 // Language extension: use the longest literal to determine the
1268 // length of the array constructor's character elements, not the
1269 // first, when there is no explicit type.
1270 *constantLength_ = *thisLen;
1271 type_->length = xType.LEN();
1272 }
1273 } else {
1274 constantLength_ = *thisLen;
1275 type_->length = xType.LEN();
1276 }
1277 }
1278 } else {
1279 if (!(messageDisplayedSet_ & 2)) {
1280 exprAnalyzer_.Say(
1281 "Values in array constructor must have the same declared type "
1282 "when no explicit type appears"_err_en_US); // C7110
1283 messageDisplayedSet_ |= 2;
1284 }
1285 }
1286 } else {
1287 if (auto cast{ConvertToType(*type_, std::move(*x))}) {
1288 values_.Push(std::move(*cast));
1289 } else if (!(messageDisplayedSet_ & 4)) {
1290 exprAnalyzer_.Say(
1291 "Value in array constructor of type '%s' could not "
1292 "be converted to the type of the array '%s'"_err_en_US,
1293 x->GetType()->AsFortran(), type_->AsFortran()); // C7111, C7112
1294 messageDisplayedSet_ |= 4;
1295 }
1296 }
1297 }
1298 }
1299
Add(const parser::AcValue & x)1300 void ArrayConstructorContext::Add(const parser::AcValue &x) {
1301 std::visit(
1302 common::visitors{
1303 [&](const parser::AcValue::Triplet &triplet) { Add(triplet); },
1304 [&](const common::Indirection<parser::Expr> &expr) {
1305 Add(expr.value());
1306 },
1307 [&](const common::Indirection<parser::AcImpliedDo> &impliedDo) {
1308 Add(impliedDo.value());
1309 },
1310 },
1311 x.u);
1312 }
1313
1314 // Transforms l:u(:s) into (_,_=l,u(,s)) with an anonymous index '_'
Add(const parser::AcValue::Triplet & triplet)1315 void ArrayConstructorContext::Add(const parser::AcValue::Triplet &triplet) {
1316 std::optional<Expr<ImpliedDoIntType>> lower{
1317 GetSpecificIntExpr<ImpliedDoIntType::kind>(std::get<0>(triplet.t))};
1318 std::optional<Expr<ImpliedDoIntType>> upper{
1319 GetSpecificIntExpr<ImpliedDoIntType::kind>(std::get<1>(triplet.t))};
1320 std::optional<Expr<ImpliedDoIntType>> stride{
1321 GetSpecificIntExpr<ImpliedDoIntType::kind>(std::get<2>(triplet.t))};
1322 if (lower && upper) {
1323 if (!stride) {
1324 stride = Expr<ImpliedDoIntType>{1};
1325 }
1326 if (!type_) {
1327 type_ = DynamicTypeWithLength{ImpliedDoIntType::GetType()};
1328 }
1329 auto v{std::move(values_)};
1330 parser::CharBlock anonymous;
1331 Push(Expr<SomeType>{
1332 Expr<SomeInteger>{Expr<ImpliedDoIntType>{ImpliedDoIndex{anonymous}}}});
1333 std::swap(v, values_);
1334 values_.Push(ImpliedDo<SomeType>{anonymous, std::move(*lower),
1335 std::move(*upper), std::move(*stride), std::move(v)});
1336 }
1337 }
1338
Add(const parser::Expr & expr)1339 void ArrayConstructorContext::Add(const parser::Expr &expr) {
1340 auto restorer{exprAnalyzer_.GetContextualMessages().SetLocation(expr.source)};
1341 if (MaybeExpr v{exprAnalyzer_.Analyze(expr)}) {
1342 if (auto exprType{v->GetType()}) {
1343 if (!(messageDisplayedSet_ & 8) && exprType->IsUnlimitedPolymorphic()) {
1344 exprAnalyzer_.Say("Cannot have an unlimited polymorphic value in an "
1345 "array constructor"_err_en_US); // C7113
1346 messageDisplayedSet_ |= 8;
1347 }
1348 }
1349 Push(std::move(*v));
1350 }
1351 }
1352
Add(const parser::AcImpliedDo & impliedDo)1353 void ArrayConstructorContext::Add(const parser::AcImpliedDo &impliedDo) {
1354 const auto &control{std::get<parser::AcImpliedDoControl>(impliedDo.t)};
1355 const auto &bounds{std::get<parser::AcImpliedDoControl::Bounds>(control.t)};
1356 exprAnalyzer_.Analyze(bounds.name);
1357 parser::CharBlock name{bounds.name.thing.thing.source};
1358 const Symbol *symbol{bounds.name.thing.thing.symbol};
1359 int kind{ImpliedDoIntType::kind};
1360 if (const auto dynamicType{DynamicType::From(symbol)}) {
1361 kind = dynamicType->kind();
1362 }
1363 if (!exprAnalyzer_.AddImpliedDo(name, kind)) {
1364 if (!(messageDisplayedSet_ & 0x20)) {
1365 exprAnalyzer_.SayAt(name,
1366 "Implied DO index is active in surrounding implied DO loop "
1367 "and may not have the same name"_err_en_US); // C7115
1368 messageDisplayedSet_ |= 0x20;
1369 }
1370 return;
1371 }
1372 std::optional<Expr<ImpliedDoIntType>> lower{
1373 GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.lower)};
1374 std::optional<Expr<ImpliedDoIntType>> upper{
1375 GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.upper)};
1376 if (lower && upper) {
1377 std::optional<Expr<ImpliedDoIntType>> stride{
1378 GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.step)};
1379 if (!stride) {
1380 stride = Expr<ImpliedDoIntType>{1};
1381 }
1382 // Check for constant bounds; the loop may require complete unrolling
1383 // of the parse tree if all bounds are constant in order to allow the
1384 // implied DO loop index to qualify as a constant expression.
1385 auto cLower{ToInt64(lower)};
1386 auto cUpper{ToInt64(upper)};
1387 auto cStride{ToInt64(stride)};
1388 if (!(messageDisplayedSet_ & 0x10) && cStride && *cStride == 0) {
1389 exprAnalyzer_.SayAt(bounds.step.value().thing.thing.value().source,
1390 "The stride of an implied DO loop must not be zero"_err_en_US);
1391 messageDisplayedSet_ |= 0x10;
1392 }
1393 bool isConstant{cLower && cUpper && cStride && *cStride != 0};
1394 bool isNonemptyConstant{isConstant &&
1395 ((*cStride > 0 && *cLower <= *cUpper) ||
1396 (*cStride < 0 && *cLower >= *cUpper))};
1397 bool unrollConstantLoop{false};
1398 parser::Messages buffer;
1399 auto saveMessagesDisplayed{messageDisplayedSet_};
1400 {
1401 auto messageRestorer{
1402 exprAnalyzer_.GetContextualMessages().SetMessages(buffer)};
1403 auto v{std::move(values_)};
1404 for (const auto &value :
1405 std::get<std::list<parser::AcValue>>(impliedDo.t)) {
1406 Add(value);
1407 }
1408 std::swap(v, values_);
1409 if (isNonemptyConstant && buffer.AnyFatalError()) {
1410 unrollConstantLoop = true;
1411 } else {
1412 values_.Push(ImpliedDo<SomeType>{name, std::move(*lower),
1413 std::move(*upper), std::move(*stride), std::move(v)});
1414 }
1415 }
1416 if (unrollConstantLoop) {
1417 messageDisplayedSet_ = saveMessagesDisplayed;
1418 UnrollConstantImpliedDo(impliedDo, name, *cLower, *cUpper, *cStride);
1419 } else if (auto *messages{
1420 exprAnalyzer_.GetContextualMessages().messages()}) {
1421 messages->Annex(std::move(buffer));
1422 }
1423 }
1424 exprAnalyzer_.RemoveImpliedDo(name);
1425 }
1426
1427 // Fortran considers an implied DO index of an array constructor to be
1428 // a constant expression if the bounds of the implied DO loop are constant.
1429 // Usually this doesn't matter, but if we emitted spurious messages as a
1430 // result of not using constant values for the index while analyzing the
1431 // items, we need to do it again the "hard" way with multiple iterations over
1432 // the parse tree.
UnrollConstantImpliedDo(const parser::AcImpliedDo & impliedDo,parser::CharBlock name,std::int64_t lower,std::int64_t upper,std::int64_t stride)1433 void ArrayConstructorContext::UnrollConstantImpliedDo(
1434 const parser::AcImpliedDo &impliedDo, parser::CharBlock name,
1435 std::int64_t lower, std::int64_t upper, std::int64_t stride) {
1436 auto &foldingContext{exprAnalyzer_.GetFoldingContext()};
1437 auto restorer{exprAnalyzer_.DoNotUseSavedTypedExprs()};
1438 for (auto &at{foldingContext.StartImpliedDo(name, lower)};
1439 (stride > 0 && at <= upper) || (stride < 0 && at >= upper);
1440 at += stride) {
1441 for (const auto &value :
1442 std::get<std::list<parser::AcValue>>(impliedDo.t)) {
1443 Add(value);
1444 }
1445 }
1446 foldingContext.EndImpliedDo(name);
1447 }
1448
ToExpr()1449 MaybeExpr ArrayConstructorContext::ToExpr() {
1450 return common::SearchTypes(std::move(*this));
1451 }
1452
Analyze(const parser::ArrayConstructor & array)1453 MaybeExpr ExpressionAnalyzer::Analyze(const parser::ArrayConstructor &array) {
1454 const parser::AcSpec &acSpec{array.v};
1455 ArrayConstructorContext acContext{*this, AnalyzeTypeSpec(acSpec.type)};
1456 for (const parser::AcValue &value : acSpec.values) {
1457 acContext.Add(value);
1458 }
1459 return acContext.ToExpr();
1460 }
1461
Analyze(const parser::StructureConstructor & structure)1462 MaybeExpr ExpressionAnalyzer::Analyze(
1463 const parser::StructureConstructor &structure) {
1464 auto &parsedType{std::get<parser::DerivedTypeSpec>(structure.t)};
1465 parser::CharBlock typeName{std::get<parser::Name>(parsedType.t).source};
1466 if (!parsedType.derivedTypeSpec) {
1467 return std::nullopt;
1468 }
1469 const auto &spec{*parsedType.derivedTypeSpec};
1470 const Symbol &typeSymbol{spec.typeSymbol()};
1471 if (!spec.scope() || !typeSymbol.has<semantics::DerivedTypeDetails>()) {
1472 return std::nullopt; // error recovery
1473 }
1474 const auto &typeDetails{typeSymbol.get<semantics::DerivedTypeDetails>()};
1475 const Symbol *parentComponent{typeDetails.GetParentComponent(*spec.scope())};
1476
1477 if (typeSymbol.attrs().test(semantics::Attr::ABSTRACT)) { // C796
1478 AttachDeclaration(Say(typeName,
1479 "ABSTRACT derived type '%s' may not be used in a "
1480 "structure constructor"_err_en_US,
1481 typeName),
1482 typeSymbol); // C7114
1483 }
1484
1485 // This iterator traverses all of the components in the derived type and its
1486 // parents. The symbols for whole parent components appear after their
1487 // own components and before the components of the types that extend them.
1488 // E.g., TYPE :: A; REAL X; END TYPE
1489 // TYPE, EXTENDS(A) :: B; REAL Y; END TYPE
1490 // produces the component list X, A, Y.
1491 // The order is important below because a structure constructor can
1492 // initialize X or A by name, but not both.
1493 auto components{semantics::OrderedComponentIterator{spec}};
1494 auto nextAnonymous{components.begin()};
1495
1496 std::set<parser::CharBlock> unavailable;
1497 bool anyKeyword{false};
1498 StructureConstructor result{spec};
1499 bool checkConflicts{true}; // until we hit one
1500 auto &messages{GetContextualMessages()};
1501
1502 for (const auto &component :
1503 std::get<std::list<parser::ComponentSpec>>(structure.t)) {
1504 const parser::Expr &expr{
1505 std::get<parser::ComponentDataSource>(component.t).v.value()};
1506 parser::CharBlock source{expr.source};
1507 auto restorer{messages.SetLocation(source)};
1508 const Symbol *symbol{nullptr};
1509 MaybeExpr value{Analyze(expr)};
1510 std::optional<DynamicType> valueType{DynamicType::From(value)};
1511 if (const auto &kw{std::get<std::optional<parser::Keyword>>(component.t)}) {
1512 anyKeyword = true;
1513 source = kw->v.source;
1514 symbol = kw->v.symbol;
1515 if (!symbol) {
1516 auto componentIter{std::find_if(components.begin(), components.end(),
1517 [=](const Symbol &symbol) { return symbol.name() == source; })};
1518 if (componentIter != components.end()) {
1519 symbol = &*componentIter;
1520 }
1521 }
1522 if (!symbol) { // C7101
1523 Say(source,
1524 "Keyword '%s=' does not name a component of derived type '%s'"_err_en_US,
1525 source, typeName);
1526 }
1527 } else {
1528 if (anyKeyword) { // C7100
1529 Say(source,
1530 "Value in structure constructor lacks a component name"_err_en_US);
1531 checkConflicts = false; // stem cascade
1532 }
1533 // Here's a regrettably common extension of the standard: anonymous
1534 // initialization of parent components, e.g., T(PT(1)) rather than
1535 // T(1) or T(PT=PT(1)).
1536 if (nextAnonymous == components.begin() && parentComponent &&
1537 valueType == DynamicType::From(*parentComponent) &&
1538 context().IsEnabled(LanguageFeature::AnonymousParents)) {
1539 auto iter{
1540 std::find(components.begin(), components.end(), *parentComponent)};
1541 if (iter != components.end()) {
1542 symbol = parentComponent;
1543 nextAnonymous = ++iter;
1544 if (context().ShouldWarn(LanguageFeature::AnonymousParents)) {
1545 Say(source,
1546 "Whole parent component '%s' in structure "
1547 "constructor should not be anonymous"_en_US,
1548 symbol->name());
1549 }
1550 }
1551 }
1552 while (!symbol && nextAnonymous != components.end()) {
1553 const Symbol &next{*nextAnonymous};
1554 ++nextAnonymous;
1555 if (!next.test(Symbol::Flag::ParentComp)) {
1556 symbol = &next;
1557 }
1558 }
1559 if (!symbol) {
1560 Say(source, "Unexpected value in structure constructor"_err_en_US);
1561 }
1562 }
1563 if (symbol) {
1564 if (const auto *currScope{context_.globalScope().FindScope(source)}) {
1565 if (auto msg{CheckAccessibleComponent(*currScope, *symbol)}) {
1566 Say(source, *msg);
1567 }
1568 }
1569 if (checkConflicts) {
1570 auto componentIter{
1571 std::find(components.begin(), components.end(), *symbol)};
1572 if (unavailable.find(symbol->name()) != unavailable.cend()) {
1573 // C797, C798
1574 Say(source,
1575 "Component '%s' conflicts with another component earlier in "
1576 "this structure constructor"_err_en_US,
1577 symbol->name());
1578 } else if (symbol->test(Symbol::Flag::ParentComp)) {
1579 // Make earlier components unavailable once a whole parent appears.
1580 for (auto it{components.begin()}; it != componentIter; ++it) {
1581 unavailable.insert(it->name());
1582 }
1583 } else {
1584 // Make whole parent components unavailable after any of their
1585 // constituents appear.
1586 for (auto it{componentIter}; it != components.end(); ++it) {
1587 if (it->test(Symbol::Flag::ParentComp)) {
1588 unavailable.insert(it->name());
1589 }
1590 }
1591 }
1592 }
1593 unavailable.insert(symbol->name());
1594 if (value) {
1595 if (symbol->has<semantics::ProcEntityDetails>()) {
1596 CHECK(IsPointer(*symbol));
1597 } else if (symbol->has<semantics::ObjectEntityDetails>()) {
1598 // C1594(4)
1599 const auto &innermost{context_.FindScope(expr.source)};
1600 if (const auto *pureProc{FindPureProcedureContaining(innermost)}) {
1601 if (const Symbol * pointer{FindPointerComponent(*symbol)}) {
1602 if (const Symbol *
1603 object{FindExternallyVisibleObject(*value, *pureProc)}) {
1604 if (auto *msg{Say(expr.source,
1605 "Externally visible object '%s' may not be "
1606 "associated with pointer component '%s' in a "
1607 "pure procedure"_err_en_US,
1608 object->name(), pointer->name())}) {
1609 msg->Attach(object->name(), "Object declaration"_en_US)
1610 .Attach(pointer->name(), "Pointer declaration"_en_US);
1611 }
1612 }
1613 }
1614 }
1615 } else if (symbol->has<semantics::TypeParamDetails>()) {
1616 Say(expr.source,
1617 "Type parameter '%s' may not appear as a component "
1618 "of a structure constructor"_err_en_US,
1619 symbol->name());
1620 continue;
1621 } else {
1622 Say(expr.source,
1623 "Component '%s' is neither a procedure pointer "
1624 "nor a data object"_err_en_US,
1625 symbol->name());
1626 continue;
1627 }
1628 if (IsPointer(*symbol)) {
1629 semantics::CheckPointerAssignment(
1630 GetFoldingContext(), *symbol, *value); // C7104, C7105
1631 result.Add(*symbol, Fold(std::move(*value)));
1632 } else if (MaybeExpr converted{
1633 ConvertToType(*symbol, std::move(*value))}) {
1634 if (auto componentShape{GetShape(GetFoldingContext(), *symbol)}) {
1635 if (auto valueShape{GetShape(GetFoldingContext(), *converted)}) {
1636 if (GetRank(*componentShape) == 0 && GetRank(*valueShape) > 0) {
1637 AttachDeclaration(
1638 Say(expr.source,
1639 "Rank-%d array value is not compatible with scalar component '%s'"_err_en_US,
1640 GetRank(*valueShape), symbol->name()),
1641 *symbol);
1642 } else if (CheckConformance(messages, *componentShape,
1643 *valueShape, "component", "value", false,
1644 true /* can expand scalar value */)) {
1645 if (GetRank(*componentShape) > 0 && GetRank(*valueShape) == 0 &&
1646 !IsExpandableScalar(*converted)) {
1647 AttachDeclaration(
1648 Say(expr.source,
1649 "Scalar value cannot be expanded to shape of array component '%s'"_err_en_US,
1650 symbol->name()),
1651 *symbol);
1652 } else {
1653 result.Add(*symbol, std::move(*converted));
1654 }
1655 }
1656 } else {
1657 Say(expr.source, "Shape of value cannot be determined"_err_en_US);
1658 }
1659 } else {
1660 AttachDeclaration(
1661 Say(expr.source,
1662 "Shape of component '%s' cannot be determined"_err_en_US,
1663 symbol->name()),
1664 *symbol);
1665 }
1666 } else if (IsAllocatable(*symbol) &&
1667 std::holds_alternative<NullPointer>(value->u)) {
1668 // NULL() with no arguments allowed by 7.5.10 para 6 for ALLOCATABLE
1669 } else if (auto symType{DynamicType::From(symbol)}) {
1670 if (valueType) {
1671 AttachDeclaration(
1672 Say(expr.source,
1673 "Value in structure constructor of type %s is "
1674 "incompatible with component '%s' of type %s"_err_en_US,
1675 valueType->AsFortran(), symbol->name(),
1676 symType->AsFortran()),
1677 *symbol);
1678 } else {
1679 AttachDeclaration(
1680 Say(expr.source,
1681 "Value in structure constructor is incompatible with "
1682 " component '%s' of type %s"_err_en_US,
1683 symbol->name(), symType->AsFortran()),
1684 *symbol);
1685 }
1686 }
1687 }
1688 }
1689 }
1690
1691 // Ensure that unmentioned component objects have default initializers.
1692 for (const Symbol &symbol : components) {
1693 if (!symbol.test(Symbol::Flag::ParentComp) &&
1694 unavailable.find(symbol.name()) == unavailable.cend() &&
1695 !IsAllocatable(symbol)) {
1696 if (const auto *details{
1697 symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
1698 if (details->init()) {
1699 result.Add(symbol, common::Clone(*details->init()));
1700 } else { // C799
1701 AttachDeclaration(Say(typeName,
1702 "Structure constructor lacks a value for "
1703 "component '%s'"_err_en_US,
1704 symbol.name()),
1705 symbol);
1706 }
1707 }
1708 }
1709 }
1710
1711 return AsMaybeExpr(Expr<SomeDerived>{std::move(result)});
1712 }
1713
GetPassName(const semantics::Symbol & proc)1714 static std::optional<parser::CharBlock> GetPassName(
1715 const semantics::Symbol &proc) {
1716 return std::visit(
1717 [](const auto &details) {
1718 if constexpr (std::is_base_of_v<semantics::WithPassArg,
1719 std::decay_t<decltype(details)>>) {
1720 return details.passName();
1721 } else {
1722 return std::optional<parser::CharBlock>{};
1723 }
1724 },
1725 proc.details());
1726 }
1727
GetPassIndex(const Symbol & proc)1728 static int GetPassIndex(const Symbol &proc) {
1729 CHECK(!proc.attrs().test(semantics::Attr::NOPASS));
1730 std::optional<parser::CharBlock> passName{GetPassName(proc)};
1731 const auto *interface{semantics::FindInterface(proc)};
1732 if (!passName || !interface) {
1733 return 0; // first argument is passed-object
1734 }
1735 const auto &subp{interface->get<semantics::SubprogramDetails>()};
1736 int index{0};
1737 for (const auto *arg : subp.dummyArgs()) {
1738 if (arg && arg->name() == passName) {
1739 return index;
1740 }
1741 ++index;
1742 }
1743 DIE("PASS argument name not in dummy argument list");
1744 }
1745
1746 // Injects an expression into an actual argument list as the "passed object"
1747 // for a type-bound procedure reference that is not NOPASS. Adds an
1748 // argument keyword if possible, but not when the passed object goes
1749 // before a positional argument.
1750 // e.g., obj%tbp(x) -> tbp(obj,x).
AddPassArg(ActualArguments & actuals,const Expr<SomeDerived> & expr,const Symbol & component,bool isPassedObject=true)1751 static void AddPassArg(ActualArguments &actuals, const Expr<SomeDerived> &expr,
1752 const Symbol &component, bool isPassedObject = true) {
1753 if (component.attrs().test(semantics::Attr::NOPASS)) {
1754 return;
1755 }
1756 int passIndex{GetPassIndex(component)};
1757 auto iter{actuals.begin()};
1758 int at{0};
1759 while (iter < actuals.end() && at < passIndex) {
1760 if (*iter && (*iter)->keyword()) {
1761 iter = actuals.end();
1762 break;
1763 }
1764 ++iter;
1765 ++at;
1766 }
1767 ActualArgument passed{AsGenericExpr(common::Clone(expr))};
1768 passed.set_isPassedObject(isPassedObject);
1769 if (iter == actuals.end()) {
1770 if (auto passName{GetPassName(component)}) {
1771 passed.set_keyword(*passName);
1772 }
1773 }
1774 actuals.emplace(iter, std::move(passed));
1775 }
1776
1777 // Return the compile-time resolution of a procedure binding, if possible.
GetBindingResolution(const std::optional<DynamicType> & baseType,const Symbol & component)1778 static const Symbol *GetBindingResolution(
1779 const std::optional<DynamicType> &baseType, const Symbol &component) {
1780 const auto *binding{component.detailsIf<semantics::ProcBindingDetails>()};
1781 if (!binding) {
1782 return nullptr;
1783 }
1784 if (!component.attrs().test(semantics::Attr::NON_OVERRIDABLE) &&
1785 (!baseType || baseType->IsPolymorphic())) {
1786 return nullptr;
1787 }
1788 return &binding->symbol();
1789 }
1790
AnalyzeProcedureComponentRef(const parser::ProcComponentRef & pcr,ActualArguments && arguments)1791 auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
1792 const parser::ProcComponentRef &pcr, ActualArguments &&arguments)
1793 -> std::optional<CalleeAndArguments> {
1794 const parser::StructureComponent &sc{pcr.v.thing};
1795 if (MaybeExpr base{Analyze(sc.base)}) {
1796 if (const Symbol * sym{sc.component.symbol}) {
1797 if (context_.HasError(sym)) {
1798 return std::nullopt;
1799 }
1800 if (auto *dtExpr{UnwrapExpr<Expr<SomeDerived>>(*base)}) {
1801 if (sym->has<semantics::GenericDetails>()) {
1802 AdjustActuals adjustment{
1803 [&](const Symbol &proc, ActualArguments &actuals) {
1804 if (!proc.attrs().test(semantics::Attr::NOPASS)) {
1805 AddPassArg(actuals, std::move(*dtExpr), proc);
1806 }
1807 return true;
1808 }};
1809 sym = ResolveGeneric(*sym, arguments, adjustment);
1810 if (!sym) {
1811 EmitGenericResolutionError(*sc.component.symbol);
1812 return std::nullopt;
1813 }
1814 }
1815 if (const Symbol *
1816 resolution{GetBindingResolution(dtExpr->GetType(), *sym)}) {
1817 AddPassArg(arguments, std::move(*dtExpr), *sym, false);
1818 return CalleeAndArguments{
1819 ProcedureDesignator{*resolution}, std::move(arguments)};
1820 } else if (std::optional<DataRef> dataRef{
1821 ExtractDataRef(std::move(*dtExpr))}) {
1822 if (sym->attrs().test(semantics::Attr::NOPASS)) {
1823 return CalleeAndArguments{
1824 ProcedureDesignator{Component{std::move(*dataRef), *sym}},
1825 std::move(arguments)};
1826 } else {
1827 AddPassArg(arguments,
1828 Expr<SomeDerived>{Designator<SomeDerived>{std::move(*dataRef)}},
1829 *sym);
1830 return CalleeAndArguments{
1831 ProcedureDesignator{*sym}, std::move(arguments)};
1832 }
1833 }
1834 }
1835 Say(sc.component.source,
1836 "Base of procedure component reference is not a derived-type object"_err_en_US);
1837 }
1838 }
1839 CHECK(!GetContextualMessages().empty());
1840 return std::nullopt;
1841 }
1842
1843 // Can actual be argument associated with dummy?
CheckCompatibleArgument(bool isElemental,const ActualArgument & actual,const characteristics::DummyArgument & dummy)1844 static bool CheckCompatibleArgument(bool isElemental,
1845 const ActualArgument &actual, const characteristics::DummyArgument &dummy) {
1846 return std::visit(
1847 common::visitors{
1848 [&](const characteristics::DummyDataObject &x) {
1849 characteristics::TypeAndShape dummyTypeAndShape{x.type};
1850 if (!isElemental && actual.Rank() != dummyTypeAndShape.Rank()) {
1851 return false;
1852 } else if (auto actualType{actual.GetType()}) {
1853 return dummyTypeAndShape.type().IsTkCompatibleWith(*actualType);
1854 } else {
1855 return false;
1856 }
1857 },
1858 [&](const characteristics::DummyProcedure &) {
1859 const auto *expr{actual.UnwrapExpr()};
1860 return expr && IsProcedurePointer(*expr);
1861 },
1862 [&](const characteristics::AlternateReturn &) {
1863 return actual.isAlternateReturn();
1864 },
1865 },
1866 dummy.u);
1867 }
1868
1869 // Are the actual arguments compatible with the dummy arguments of procedure?
CheckCompatibleArguments(const characteristics::Procedure & procedure,const ActualArguments & actuals)1870 static bool CheckCompatibleArguments(
1871 const characteristics::Procedure &procedure,
1872 const ActualArguments &actuals) {
1873 bool isElemental{procedure.IsElemental()};
1874 const auto &dummies{procedure.dummyArguments};
1875 CHECK(dummies.size() == actuals.size());
1876 for (std::size_t i{0}; i < dummies.size(); ++i) {
1877 const characteristics::DummyArgument &dummy{dummies[i]};
1878 const std::optional<ActualArgument> &actual{actuals[i]};
1879 if (actual && !CheckCompatibleArgument(isElemental, *actual, dummy)) {
1880 return false;
1881 }
1882 }
1883 return true;
1884 }
1885
1886 // Handles a forward reference to a module function from what must
1887 // be a specification expression. Return false if the symbol is
1888 // an invalid forward reference.
ResolveForward(const Symbol & symbol)1889 bool ExpressionAnalyzer::ResolveForward(const Symbol &symbol) {
1890 if (context_.HasError(symbol)) {
1891 return false;
1892 }
1893 if (const auto *details{
1894 symbol.detailsIf<semantics::SubprogramNameDetails>()}) {
1895 if (details->kind() == semantics::SubprogramKind::Module) {
1896 // If this symbol is still a SubprogramNameDetails, we must be
1897 // checking a specification expression in a sibling module
1898 // procedure. Resolve its names now so that its interface
1899 // is known.
1900 semantics::ResolveSpecificationParts(context_, symbol);
1901 if (symbol.has<semantics::SubprogramNameDetails>()) {
1902 // When the symbol hasn't had its details updated, we must have
1903 // already been in the process of resolving the function's
1904 // specification part; but recursive function calls are not
1905 // allowed in specification parts (10.1.11 para 5).
1906 Say("The module function '%s' may not be referenced recursively in a specification expression"_err_en_US,
1907 symbol.name());
1908 context_.SetError(symbol);
1909 return false;
1910 }
1911 } else { // 10.1.11 para 4
1912 Say("The internal function '%s' may not be referenced in a specification expression"_err_en_US,
1913 symbol.name());
1914 context_.SetError(symbol);
1915 return false;
1916 }
1917 }
1918 return true;
1919 }
1920
1921 // Resolve a call to a generic procedure with given actual arguments.
1922 // adjustActuals is called on procedure bindings to handle pass arg.
ResolveGeneric(const Symbol & symbol,const ActualArguments & actuals,const AdjustActuals & adjustActuals,bool mightBeStructureConstructor)1923 const Symbol *ExpressionAnalyzer::ResolveGeneric(const Symbol &symbol,
1924 const ActualArguments &actuals, const AdjustActuals &adjustActuals,
1925 bool mightBeStructureConstructor) {
1926 const Symbol *elemental{nullptr}; // matching elemental specific proc
1927 const auto &details{symbol.GetUltimate().get<semantics::GenericDetails>()};
1928 for (const Symbol &specific : details.specificProcs()) {
1929 if (!ResolveForward(specific)) {
1930 continue;
1931 }
1932 if (std::optional<characteristics::Procedure> procedure{
1933 characteristics::Procedure::Characterize(
1934 ProcedureDesignator{specific}, context_.foldingContext())}) {
1935 ActualArguments localActuals{actuals};
1936 if (specific.has<semantics::ProcBindingDetails>()) {
1937 if (!adjustActuals.value()(specific, localActuals)) {
1938 continue;
1939 }
1940 }
1941 if (semantics::CheckInterfaceForGeneric(
1942 *procedure, localActuals, GetFoldingContext())) {
1943 if (CheckCompatibleArguments(*procedure, localActuals)) {
1944 if (!procedure->IsElemental()) {
1945 return &specific; // takes priority over elemental match
1946 }
1947 elemental = &specific;
1948 }
1949 }
1950 }
1951 }
1952 if (elemental) {
1953 return elemental;
1954 }
1955 // Check parent derived type
1956 if (const auto *parentScope{symbol.owner().GetDerivedTypeParent()}) {
1957 if (const Symbol * extended{parentScope->FindComponent(symbol.name())}) {
1958 if (extended->GetUltimate().has<semantics::GenericDetails>()) {
1959 if (const Symbol *
1960 result{ResolveGeneric(*extended, actuals, adjustActuals, false)}) {
1961 return result;
1962 }
1963 }
1964 }
1965 }
1966 if (mightBeStructureConstructor && details.derivedType()) {
1967 return details.derivedType();
1968 }
1969 return nullptr;
1970 }
1971
EmitGenericResolutionError(const Symbol & symbol)1972 void ExpressionAnalyzer::EmitGenericResolutionError(const Symbol &symbol) {
1973 if (semantics::IsGenericDefinedOp(symbol)) {
1974 Say("No specific procedure of generic operator '%s' matches the actual arguments"_err_en_US,
1975 symbol.name());
1976 } else {
1977 Say("No specific procedure of generic '%s' matches the actual arguments"_err_en_US,
1978 symbol.name());
1979 }
1980 }
1981
GetCalleeAndArguments(const parser::ProcedureDesignator & pd,ActualArguments && arguments,bool isSubroutine,bool mightBeStructureConstructor)1982 auto ExpressionAnalyzer::GetCalleeAndArguments(
1983 const parser::ProcedureDesignator &pd, ActualArguments &&arguments,
1984 bool isSubroutine, bool mightBeStructureConstructor)
1985 -> std::optional<CalleeAndArguments> {
1986 return std::visit(
1987 common::visitors{
1988 [&](const parser::Name &name) {
1989 return GetCalleeAndArguments(name, std::move(arguments),
1990 isSubroutine, mightBeStructureConstructor);
1991 },
1992 [&](const parser::ProcComponentRef &pcr) {
1993 return AnalyzeProcedureComponentRef(pcr, std::move(arguments));
1994 },
1995 },
1996 pd.u);
1997 }
1998
GetCalleeAndArguments(const parser::Name & name,ActualArguments && arguments,bool isSubroutine,bool mightBeStructureConstructor)1999 auto ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name,
2000 ActualArguments &&arguments, bool isSubroutine,
2001 bool mightBeStructureConstructor) -> std::optional<CalleeAndArguments> {
2002 const Symbol *symbol{name.symbol};
2003 if (context_.HasError(symbol)) {
2004 return std::nullopt; // also handles null symbol
2005 }
2006 const Symbol &ultimate{DEREF(symbol).GetUltimate()};
2007 if (ultimate.attrs().test(semantics::Attr::INTRINSIC)) {
2008 if (std::optional<SpecificCall> specificCall{context_.intrinsics().Probe(
2009 CallCharacteristics{ultimate.name().ToString(), isSubroutine},
2010 arguments, GetFoldingContext())}) {
2011 return CalleeAndArguments{
2012 ProcedureDesignator{std::move(specificCall->specificIntrinsic)},
2013 std::move(specificCall->arguments)};
2014 }
2015 } else {
2016 CheckForBadRecursion(name.source, ultimate);
2017 if (ultimate.has<semantics::GenericDetails>()) {
2018 ExpressionAnalyzer::AdjustActuals noAdjustment;
2019 symbol = ResolveGeneric(
2020 *symbol, arguments, noAdjustment, mightBeStructureConstructor);
2021 }
2022 if (symbol) {
2023 if (symbol->GetUltimate().has<semantics::DerivedTypeDetails>()) {
2024 if (mightBeStructureConstructor) {
2025 return CalleeAndArguments{
2026 semantics::SymbolRef{*symbol}, std::move(arguments)};
2027 }
2028 } else {
2029 return CalleeAndArguments{
2030 ProcedureDesignator{*symbol}, std::move(arguments)};
2031 }
2032 } else if (std::optional<SpecificCall> specificCall{
2033 context_.intrinsics().Probe(
2034 CallCharacteristics{
2035 ultimate.name().ToString(), isSubroutine},
2036 arguments, GetFoldingContext())}) {
2037 // Generics can extend intrinsics
2038 return CalleeAndArguments{
2039 ProcedureDesignator{std::move(specificCall->specificIntrinsic)},
2040 std::move(specificCall->arguments)};
2041 } else {
2042 EmitGenericResolutionError(*name.symbol);
2043 }
2044 }
2045 return std::nullopt;
2046 }
2047
CheckForBadRecursion(parser::CharBlock callSite,const semantics::Symbol & proc)2048 void ExpressionAnalyzer::CheckForBadRecursion(
2049 parser::CharBlock callSite, const semantics::Symbol &proc) {
2050 if (const auto *scope{proc.scope()}) {
2051 if (scope->sourceRange().Contains(callSite)) {
2052 parser::Message *msg{nullptr};
2053 if (proc.attrs().test(semantics::Attr::NON_RECURSIVE)) { // 15.6.2.1(3)
2054 msg = Say("NON_RECURSIVE procedure '%s' cannot call itself"_err_en_US,
2055 callSite);
2056 } else if (IsAssumedLengthCharacter(proc) && IsExternal(proc)) {
2057 msg = Say( // 15.6.2.1(3)
2058 "Assumed-length CHARACTER(*) function '%s' cannot call itself"_err_en_US,
2059 callSite);
2060 }
2061 AttachDeclaration(msg, proc);
2062 }
2063 }
2064 }
2065
AssumedTypeDummy(const A & x)2066 template <typename A> static const Symbol *AssumedTypeDummy(const A &x) {
2067 if (const auto *designator{
2068 std::get_if<common::Indirection<parser::Designator>>(&x.u)}) {
2069 if (const auto *dataRef{
2070 std::get_if<parser::DataRef>(&designator->value().u)}) {
2071 if (const auto *name{std::get_if<parser::Name>(&dataRef->u)}) {
2072 if (const Symbol * symbol{name->symbol}) {
2073 if (const auto *type{symbol->GetType()}) {
2074 if (type->category() == semantics::DeclTypeSpec::TypeStar) {
2075 return symbol;
2076 }
2077 }
2078 }
2079 }
2080 }
2081 }
2082 return nullptr;
2083 }
2084
Analyze(const parser::FunctionReference & funcRef,std::optional<parser::StructureConstructor> * structureConstructor)2085 MaybeExpr ExpressionAnalyzer::Analyze(const parser::FunctionReference &funcRef,
2086 std::optional<parser::StructureConstructor> *structureConstructor) {
2087 const parser::Call &call{funcRef.v};
2088 auto restorer{GetContextualMessages().SetLocation(call.source)};
2089 ArgumentAnalyzer analyzer{*this, call.source, true /* isProcedureCall */};
2090 for (const auto &arg : std::get<std::list<parser::ActualArgSpec>>(call.t)) {
2091 analyzer.Analyze(arg, false /* not subroutine call */);
2092 }
2093 if (analyzer.fatalErrors()) {
2094 return std::nullopt;
2095 }
2096 if (std::optional<CalleeAndArguments> callee{
2097 GetCalleeAndArguments(std::get<parser::ProcedureDesignator>(call.t),
2098 analyzer.GetActuals(), false /* not subroutine */,
2099 true /* might be structure constructor */)}) {
2100 if (auto *proc{std::get_if<ProcedureDesignator>(&callee->u)}) {
2101 return MakeFunctionRef(
2102 call.source, std::move(*proc), std::move(callee->arguments));
2103 } else if (structureConstructor) {
2104 // Structure constructor misparsed as function reference?
2105 CHECK(std::holds_alternative<semantics::SymbolRef>(callee->u));
2106 const Symbol &derivedType{*std::get<semantics::SymbolRef>(callee->u)};
2107 const auto &designator{std::get<parser::ProcedureDesignator>(call.t)};
2108 if (const auto *name{std::get_if<parser::Name>(&designator.u)}) {
2109 semantics::Scope &scope{context_.FindScope(name->source)};
2110 semantics::DerivedTypeSpec dtSpec{
2111 name->source, derivedType.GetUltimate()};
2112 if (dtSpec.IsForwardReferenced()) {
2113 Say(call.source,
2114 "Cannot construct value for derived type '%s' "
2115 "before it is defined"_err_en_US,
2116 name->source);
2117 return std::nullopt;
2118 }
2119 const semantics::DeclTypeSpec &type{
2120 semantics::FindOrInstantiateDerivedType(
2121 scope, std::move(dtSpec), context_)};
2122 auto &mutableRef{const_cast<parser::FunctionReference &>(funcRef)};
2123 *structureConstructor =
2124 mutableRef.ConvertToStructureConstructor(type.derivedTypeSpec());
2125 return Analyze(structureConstructor->value());
2126 }
2127 }
2128 }
2129 return std::nullopt;
2130 }
2131
Analyze(const parser::CallStmt & callStmt)2132 void ExpressionAnalyzer::Analyze(const parser::CallStmt &callStmt) {
2133 const parser::Call &call{callStmt.v};
2134 auto restorer{GetContextualMessages().SetLocation(call.source)};
2135 ArgumentAnalyzer analyzer{*this, call.source, true /* isProcedureCall */};
2136 const auto &actualArgList{std::get<std::list<parser::ActualArgSpec>>(call.t)};
2137 for (const auto &arg : actualArgList) {
2138 analyzer.Analyze(arg, true /* is subroutine call */);
2139 }
2140 if (!analyzer.fatalErrors()) {
2141 if (std::optional<CalleeAndArguments> callee{
2142 GetCalleeAndArguments(std::get<parser::ProcedureDesignator>(call.t),
2143 analyzer.GetActuals(), true /* subroutine */)}) {
2144 ProcedureDesignator *proc{std::get_if<ProcedureDesignator>(&callee->u)};
2145 CHECK(proc);
2146 if (CheckCall(call.source, *proc, callee->arguments)) {
2147 bool hasAlternateReturns{
2148 callee->arguments.size() < actualArgList.size()};
2149 callStmt.typedCall.Reset(
2150 new ProcedureRef{std::move(*proc), std::move(callee->arguments),
2151 hasAlternateReturns},
2152 ProcedureRef::Deleter);
2153 }
2154 }
2155 }
2156 }
2157
Analyze(const parser::AssignmentStmt & x)2158 const Assignment *ExpressionAnalyzer::Analyze(const parser::AssignmentStmt &x) {
2159 if (!x.typedAssignment) {
2160 ArgumentAnalyzer analyzer{*this};
2161 analyzer.Analyze(std::get<parser::Variable>(x.t));
2162 analyzer.Analyze(std::get<parser::Expr>(x.t));
2163 if (analyzer.fatalErrors()) {
2164 x.typedAssignment.Reset(
2165 new GenericAssignmentWrapper{}, GenericAssignmentWrapper::Deleter);
2166 } else {
2167 std::optional<ProcedureRef> procRef{analyzer.TryDefinedAssignment()};
2168 Assignment assignment{analyzer.MoveExpr(0), analyzer.MoveExpr(1)};
2169 if (procRef) {
2170 assignment.u = std::move(*procRef);
2171 }
2172 x.typedAssignment.Reset(
2173 new GenericAssignmentWrapper{std::move(assignment)},
2174 GenericAssignmentWrapper::Deleter);
2175 }
2176 }
2177 return common::GetPtrFromOptional(x.typedAssignment->v);
2178 }
2179
Analyze(const parser::PointerAssignmentStmt & x)2180 const Assignment *ExpressionAnalyzer::Analyze(
2181 const parser::PointerAssignmentStmt &x) {
2182 if (!x.typedAssignment) {
2183 MaybeExpr lhs{Analyze(std::get<parser::DataRef>(x.t))};
2184 MaybeExpr rhs{Analyze(std::get<parser::Expr>(x.t))};
2185 if (!lhs || !rhs) {
2186 x.typedAssignment.Reset(
2187 new GenericAssignmentWrapper{}, GenericAssignmentWrapper::Deleter);
2188 } else {
2189 Assignment assignment{std::move(*lhs), std::move(*rhs)};
2190 std::visit(common::visitors{
2191 [&](const std::list<parser::BoundsRemapping> &list) {
2192 Assignment::BoundsRemapping bounds;
2193 for (const auto &elem : list) {
2194 auto lower{AsSubscript(Analyze(std::get<0>(elem.t)))};
2195 auto upper{AsSubscript(Analyze(std::get<1>(elem.t)))};
2196 if (lower && upper) {
2197 bounds.emplace_back(Fold(std::move(*lower)),
2198 Fold(std::move(*upper)));
2199 }
2200 }
2201 assignment.u = std::move(bounds);
2202 },
2203 [&](const std::list<parser::BoundsSpec> &list) {
2204 Assignment::BoundsSpec bounds;
2205 for (const auto &bound : list) {
2206 if (auto lower{AsSubscript(Analyze(bound.v))}) {
2207 bounds.emplace_back(Fold(std::move(*lower)));
2208 }
2209 }
2210 assignment.u = std::move(bounds);
2211 },
2212 },
2213 std::get<parser::PointerAssignmentStmt::Bounds>(x.t).u);
2214 x.typedAssignment.Reset(
2215 new GenericAssignmentWrapper{std::move(assignment)},
2216 GenericAssignmentWrapper::Deleter);
2217 }
2218 }
2219 return common::GetPtrFromOptional(x.typedAssignment->v);
2220 }
2221
IsExternalCalledImplicitly(parser::CharBlock callSite,const ProcedureDesignator & proc)2222 static bool IsExternalCalledImplicitly(
2223 parser::CharBlock callSite, const ProcedureDesignator &proc) {
2224 if (const auto *symbol{proc.GetSymbol()}) {
2225 return symbol->has<semantics::SubprogramDetails>() &&
2226 symbol->owner().IsGlobal() &&
2227 (!symbol->scope() /*ENTRY*/ ||
2228 !symbol->scope()->sourceRange().Contains(callSite));
2229 } else {
2230 return false;
2231 }
2232 }
2233
CheckCall(parser::CharBlock callSite,const ProcedureDesignator & proc,ActualArguments & arguments)2234 std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
2235 parser::CharBlock callSite, const ProcedureDesignator &proc,
2236 ActualArguments &arguments) {
2237 auto chars{characteristics::Procedure::Characterize(
2238 proc, context_.foldingContext())};
2239 if (chars) {
2240 bool treatExternalAsImplicit{IsExternalCalledImplicitly(callSite, proc)};
2241 if (treatExternalAsImplicit && !chars->CanBeCalledViaImplicitInterface()) {
2242 Say(callSite,
2243 "References to the procedure '%s' require an explicit interface"_en_US,
2244 DEREF(proc.GetSymbol()).name());
2245 }
2246 // Checks for ASSOCIATED() are done in intrinsic table processing
2247 bool procIsAssociated{false};
2248 if (const SpecificIntrinsic *
2249 specificIntrinsic{proc.GetSpecificIntrinsic()}) {
2250 if (specificIntrinsic->name == "associated") {
2251 procIsAssociated = true;
2252 }
2253 }
2254 if (!procIsAssociated) {
2255 semantics::CheckArguments(*chars, arguments, GetFoldingContext(),
2256 context_.FindScope(callSite), treatExternalAsImplicit,
2257 proc.GetSpecificIntrinsic());
2258 const Symbol *procSymbol{proc.GetSymbol()};
2259 if (procSymbol && !IsPureProcedure(*procSymbol)) {
2260 if (const semantics::Scope *
2261 pure{semantics::FindPureProcedureContaining(
2262 context_.FindScope(callSite))}) {
2263 Say(callSite,
2264 "Procedure '%s' referenced in pure subprogram '%s' must be pure too"_err_en_US,
2265 procSymbol->name(), DEREF(pure->symbol()).name());
2266 }
2267 }
2268 }
2269 }
2270 return chars;
2271 }
2272
2273 // Unary operations
2274
Analyze(const parser::Expr::Parentheses & x)2275 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Parentheses &x) {
2276 if (MaybeExpr operand{Analyze(x.v.value())}) {
2277 if (const semantics::Symbol * symbol{GetLastSymbol(*operand)}) {
2278 if (const semantics::Symbol * result{FindFunctionResult(*symbol)}) {
2279 if (semantics::IsProcedurePointer(*result)) {
2280 Say("A function reference that returns a procedure "
2281 "pointer may not be parenthesized"_err_en_US); // C1003
2282 }
2283 }
2284 }
2285 return Parenthesize(std::move(*operand));
2286 }
2287 return std::nullopt;
2288 }
2289
NumericUnaryHelper(ExpressionAnalyzer & context,NumericOperator opr,const parser::Expr::IntrinsicUnary & x)2290 static MaybeExpr NumericUnaryHelper(ExpressionAnalyzer &context,
2291 NumericOperator opr, const parser::Expr::IntrinsicUnary &x) {
2292 ArgumentAnalyzer analyzer{context};
2293 analyzer.Analyze(x.v);
2294 if (analyzer.fatalErrors()) {
2295 return std::nullopt;
2296 } else if (analyzer.IsIntrinsicNumeric(opr)) {
2297 if (opr == NumericOperator::Add) {
2298 return analyzer.MoveExpr(0);
2299 } else {
2300 return Negation(context.GetContextualMessages(), analyzer.MoveExpr(0));
2301 }
2302 } else {
2303 return analyzer.TryDefinedOp(AsFortran(opr),
2304 "Operand of unary %s must be numeric; have %s"_err_en_US);
2305 }
2306 }
2307
Analyze(const parser::Expr::UnaryPlus & x)2308 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::UnaryPlus &x) {
2309 return NumericUnaryHelper(*this, NumericOperator::Add, x);
2310 }
2311
Analyze(const parser::Expr::Negate & x)2312 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Negate &x) {
2313 return NumericUnaryHelper(*this, NumericOperator::Subtract, x);
2314 }
2315
Analyze(const parser::Expr::NOT & x)2316 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::NOT &x) {
2317 ArgumentAnalyzer analyzer{*this};
2318 analyzer.Analyze(x.v);
2319 if (analyzer.fatalErrors()) {
2320 return std::nullopt;
2321 } else if (analyzer.IsIntrinsicLogical()) {
2322 return AsGenericExpr(
2323 LogicalNegation(std::get<Expr<SomeLogical>>(analyzer.MoveExpr(0).u)));
2324 } else {
2325 return analyzer.TryDefinedOp(LogicalOperator::Not,
2326 "Operand of %s must be LOGICAL; have %s"_err_en_US);
2327 }
2328 }
2329
Analyze(const parser::Expr::PercentLoc & x)2330 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::PercentLoc &x) {
2331 // Represent %LOC() exactly as if it had been a call to the LOC() extension
2332 // intrinsic function.
2333 // Use the actual source for the name of the call for error reporting.
2334 std::optional<ActualArgument> arg;
2335 if (const Symbol * assumedTypeDummy{AssumedTypeDummy(x.v.value())}) {
2336 arg = ActualArgument{ActualArgument::AssumedType{*assumedTypeDummy}};
2337 } else if (MaybeExpr argExpr{Analyze(x.v.value())}) {
2338 arg = ActualArgument{std::move(*argExpr)};
2339 } else {
2340 return std::nullopt;
2341 }
2342 parser::CharBlock at{GetContextualMessages().at()};
2343 CHECK(at.size() >= 4);
2344 parser::CharBlock loc{at.begin() + 1, 3};
2345 CHECK(loc == "loc");
2346 return MakeFunctionRef(loc, ActualArguments{std::move(*arg)});
2347 }
2348
Analyze(const parser::Expr::DefinedUnary & x)2349 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::DefinedUnary &x) {
2350 const auto &name{std::get<parser::DefinedOpName>(x.t).v};
2351 ArgumentAnalyzer analyzer{*this, name.source};
2352 analyzer.Analyze(std::get<1>(x.t));
2353 return analyzer.TryDefinedOp(name.source.ToString().c_str(),
2354 "No operator %s defined for %s"_err_en_US, true);
2355 }
2356
2357 // Binary (dyadic) operations
2358
2359 template <template <typename> class OPR>
NumericBinaryHelper(ExpressionAnalyzer & context,NumericOperator opr,const parser::Expr::IntrinsicBinary & x)2360 MaybeExpr NumericBinaryHelper(ExpressionAnalyzer &context, NumericOperator opr,
2361 const parser::Expr::IntrinsicBinary &x) {
2362 ArgumentAnalyzer analyzer{context};
2363 analyzer.Analyze(std::get<0>(x.t));
2364 analyzer.Analyze(std::get<1>(x.t));
2365 if (analyzer.fatalErrors()) {
2366 return std::nullopt;
2367 } else if (analyzer.IsIntrinsicNumeric(opr)) {
2368 analyzer.CheckConformance();
2369 return NumericOperation<OPR>(context.GetContextualMessages(),
2370 analyzer.MoveExpr(0), analyzer.MoveExpr(1),
2371 context.GetDefaultKind(TypeCategory::Real));
2372 } else {
2373 return analyzer.TryDefinedOp(AsFortran(opr),
2374 "Operands of %s must be numeric; have %s and %s"_err_en_US);
2375 }
2376 }
2377
Analyze(const parser::Expr::Power & x)2378 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Power &x) {
2379 return NumericBinaryHelper<Power>(*this, NumericOperator::Power, x);
2380 }
2381
Analyze(const parser::Expr::Multiply & x)2382 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Multiply &x) {
2383 return NumericBinaryHelper<Multiply>(*this, NumericOperator::Multiply, x);
2384 }
2385
Analyze(const parser::Expr::Divide & x)2386 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Divide &x) {
2387 return NumericBinaryHelper<Divide>(*this, NumericOperator::Divide, x);
2388 }
2389
Analyze(const parser::Expr::Add & x)2390 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Add &x) {
2391 return NumericBinaryHelper<Add>(*this, NumericOperator::Add, x);
2392 }
2393
Analyze(const parser::Expr::Subtract & x)2394 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Subtract &x) {
2395 return NumericBinaryHelper<Subtract>(*this, NumericOperator::Subtract, x);
2396 }
2397
Analyze(const parser::Expr::ComplexConstructor & x)2398 MaybeExpr ExpressionAnalyzer::Analyze(
2399 const parser::Expr::ComplexConstructor &x) {
2400 auto re{Analyze(std::get<0>(x.t).value())};
2401 auto im{Analyze(std::get<1>(x.t).value())};
2402 if (re && im) {
2403 ConformabilityCheck(GetContextualMessages(), *re, *im);
2404 }
2405 return AsMaybeExpr(ConstructComplex(GetContextualMessages(), std::move(re),
2406 std::move(im), GetDefaultKind(TypeCategory::Real)));
2407 }
2408
Analyze(const parser::Expr::Concat & x)2409 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Concat &x) {
2410 ArgumentAnalyzer analyzer{*this};
2411 analyzer.Analyze(std::get<0>(x.t));
2412 analyzer.Analyze(std::get<1>(x.t));
2413 if (analyzer.fatalErrors()) {
2414 return std::nullopt;
2415 } else if (analyzer.IsIntrinsicConcat()) {
2416 return std::visit(
2417 [&](auto &&x, auto &&y) -> MaybeExpr {
2418 using T = ResultType<decltype(x)>;
2419 if constexpr (std::is_same_v<T, ResultType<decltype(y)>>) {
2420 return AsGenericExpr(Concat<T::kind>{std::move(x), std::move(y)});
2421 } else {
2422 DIE("different types for intrinsic concat");
2423 }
2424 },
2425 std::move(std::get<Expr<SomeCharacter>>(analyzer.MoveExpr(0).u).u),
2426 std::move(std::get<Expr<SomeCharacter>>(analyzer.MoveExpr(1).u).u));
2427 } else {
2428 return analyzer.TryDefinedOp("//",
2429 "Operands of %s must be CHARACTER with the same kind; have %s and %s"_err_en_US);
2430 }
2431 }
2432
2433 // The Name represents a user-defined intrinsic operator.
2434 // If the actuals match one of the specific procedures, return a function ref.
2435 // Otherwise report the error in messages.
AnalyzeDefinedOp(const parser::Name & name,ActualArguments && actuals)2436 MaybeExpr ExpressionAnalyzer::AnalyzeDefinedOp(
2437 const parser::Name &name, ActualArguments &&actuals) {
2438 if (auto callee{GetCalleeAndArguments(name, std::move(actuals))}) {
2439 CHECK(std::holds_alternative<ProcedureDesignator>(callee->u));
2440 return MakeFunctionRef(name.source,
2441 std::move(std::get<ProcedureDesignator>(callee->u)),
2442 std::move(callee->arguments));
2443 } else {
2444 return std::nullopt;
2445 }
2446 }
2447
RelationHelper(ExpressionAnalyzer & context,RelationalOperator opr,const parser::Expr::IntrinsicBinary & x)2448 MaybeExpr RelationHelper(ExpressionAnalyzer &context, RelationalOperator opr,
2449 const parser::Expr::IntrinsicBinary &x) {
2450 ArgumentAnalyzer analyzer{context};
2451 analyzer.Analyze(std::get<0>(x.t));
2452 analyzer.Analyze(std::get<1>(x.t));
2453 if (analyzer.fatalErrors()) {
2454 return std::nullopt;
2455 } else {
2456 if (IsNullPointer(analyzer.GetExpr(0)) ||
2457 IsNullPointer(analyzer.GetExpr(1))) {
2458 context.Say("NULL() not allowed as an operand of a relational "
2459 "operator"_err_en_US);
2460 return std::nullopt;
2461 }
2462 std::optional<DynamicType> leftType{analyzer.GetType(0)};
2463 std::optional<DynamicType> rightType{analyzer.GetType(1)};
2464 analyzer.ConvertBOZ(0, rightType);
2465 analyzer.ConvertBOZ(1, leftType);
2466 if (analyzer.IsIntrinsicRelational(opr)) {
2467 return AsMaybeExpr(Relate(context.GetContextualMessages(), opr,
2468 analyzer.MoveExpr(0), analyzer.MoveExpr(1)));
2469 } else if (leftType && leftType->category() == TypeCategory::Logical &&
2470 rightType && rightType->category() == TypeCategory::Logical) {
2471 context.Say("LOGICAL operands must be compared using .EQV. or "
2472 ".NEQV."_err_en_US);
2473 return std::nullopt;
2474 } else {
2475 return analyzer.TryDefinedOp(opr,
2476 "Operands of %s must have comparable types; have %s and %s"_err_en_US);
2477 }
2478 }
2479 }
2480
Analyze(const parser::Expr::LT & x)2481 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::LT &x) {
2482 return RelationHelper(*this, RelationalOperator::LT, x);
2483 }
2484
Analyze(const parser::Expr::LE & x)2485 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::LE &x) {
2486 return RelationHelper(*this, RelationalOperator::LE, x);
2487 }
2488
Analyze(const parser::Expr::EQ & x)2489 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::EQ &x) {
2490 return RelationHelper(*this, RelationalOperator::EQ, x);
2491 }
2492
Analyze(const parser::Expr::NE & x)2493 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::NE &x) {
2494 return RelationHelper(*this, RelationalOperator::NE, x);
2495 }
2496
Analyze(const parser::Expr::GE & x)2497 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::GE &x) {
2498 return RelationHelper(*this, RelationalOperator::GE, x);
2499 }
2500
Analyze(const parser::Expr::GT & x)2501 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::GT &x) {
2502 return RelationHelper(*this, RelationalOperator::GT, x);
2503 }
2504
LogicalBinaryHelper(ExpressionAnalyzer & context,LogicalOperator opr,const parser::Expr::IntrinsicBinary & x)2505 MaybeExpr LogicalBinaryHelper(ExpressionAnalyzer &context, LogicalOperator opr,
2506 const parser::Expr::IntrinsicBinary &x) {
2507 ArgumentAnalyzer analyzer{context};
2508 analyzer.Analyze(std::get<0>(x.t));
2509 analyzer.Analyze(std::get<1>(x.t));
2510 if (analyzer.fatalErrors()) {
2511 return std::nullopt;
2512 } else if (analyzer.IsIntrinsicLogical()) {
2513 return AsGenericExpr(BinaryLogicalOperation(opr,
2514 std::get<Expr<SomeLogical>>(analyzer.MoveExpr(0).u),
2515 std::get<Expr<SomeLogical>>(analyzer.MoveExpr(1).u)));
2516 } else {
2517 return analyzer.TryDefinedOp(
2518 opr, "Operands of %s must be LOGICAL; have %s and %s"_err_en_US);
2519 }
2520 }
2521
Analyze(const parser::Expr::AND & x)2522 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::AND &x) {
2523 return LogicalBinaryHelper(*this, LogicalOperator::And, x);
2524 }
2525
Analyze(const parser::Expr::OR & x)2526 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::OR &x) {
2527 return LogicalBinaryHelper(*this, LogicalOperator::Or, x);
2528 }
2529
Analyze(const parser::Expr::EQV & x)2530 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::EQV &x) {
2531 return LogicalBinaryHelper(*this, LogicalOperator::Eqv, x);
2532 }
2533
Analyze(const parser::Expr::NEQV & x)2534 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::NEQV &x) {
2535 return LogicalBinaryHelper(*this, LogicalOperator::Neqv, x);
2536 }
2537
Analyze(const parser::Expr::DefinedBinary & x)2538 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::DefinedBinary &x) {
2539 const auto &name{std::get<parser::DefinedOpName>(x.t).v};
2540 ArgumentAnalyzer analyzer{*this, name.source};
2541 analyzer.Analyze(std::get<1>(x.t));
2542 analyzer.Analyze(std::get<2>(x.t));
2543 return analyzer.TryDefinedOp(name.source.ToString().c_str(),
2544 "No operator %s defined for %s and %s"_err_en_US, true);
2545 }
2546
CheckFuncRefToArrayElementRefHasSubscripts(semantics::SemanticsContext & context,const parser::FunctionReference & funcRef)2547 static void CheckFuncRefToArrayElementRefHasSubscripts(
2548 semantics::SemanticsContext &context,
2549 const parser::FunctionReference &funcRef) {
2550 // Emit message if the function reference fix will end up an array element
2551 // reference with no subscripts because it will not be possible to later tell
2552 // the difference in expressions between empty subscript list due to bad
2553 // subscripts error recovery or because the user did not put any.
2554 if (std::get<std::list<parser::ActualArgSpec>>(funcRef.v.t).empty()) {
2555 auto &proc{std::get<parser::ProcedureDesignator>(funcRef.v.t)};
2556 const auto *name{std::get_if<parser::Name>(&proc.u)};
2557 if (!name) {
2558 name = &std::get<parser::ProcComponentRef>(proc.u).v.thing.component;
2559 }
2560 auto &msg{context.Say(funcRef.v.source,
2561 name->symbol && name->symbol->Rank() == 0
2562 ? "'%s' is not a function"_err_en_US
2563 : "Reference to array '%s' with empty subscript list"_err_en_US,
2564 name->source)};
2565 if (name->symbol) {
2566 if (semantics::IsFunctionResultWithSameNameAsFunction(*name->symbol)) {
2567 msg.Attach(name->source,
2568 "A result variable must be declared with RESULT to allow recursive "
2569 "function calls"_en_US);
2570 } else {
2571 AttachDeclaration(&msg, *name->symbol);
2572 }
2573 }
2574 }
2575 }
2576
2577 // Converts, if appropriate, an original misparse of ambiguous syntax like
2578 // A(1) as a function reference into an array reference.
2579 // Misparse structure constructors are detected elsewhere after generic
2580 // function call resolution fails.
2581 template <typename... A>
FixMisparsedFunctionReference(semantics::SemanticsContext & context,const std::variant<A...> & constU)2582 static void FixMisparsedFunctionReference(
2583 semantics::SemanticsContext &context, const std::variant<A...> &constU) {
2584 // The parse tree is updated in situ when resolving an ambiguous parse.
2585 using uType = std::decay_t<decltype(constU)>;
2586 auto &u{const_cast<uType &>(constU)};
2587 if (auto *func{
2588 std::get_if<common::Indirection<parser::FunctionReference>>(&u)}) {
2589 parser::FunctionReference &funcRef{func->value()};
2590 auto &proc{std::get<parser::ProcedureDesignator>(funcRef.v.t)};
2591 if (Symbol *
2592 origSymbol{
2593 std::visit(common::visitors{
2594 [&](parser::Name &name) { return name.symbol; },
2595 [&](parser::ProcComponentRef &pcr) {
2596 return pcr.v.thing.component.symbol;
2597 },
2598 },
2599 proc.u)}) {
2600 Symbol &symbol{origSymbol->GetUltimate()};
2601 if (symbol.has<semantics::ObjectEntityDetails>() ||
2602 symbol.has<semantics::AssocEntityDetails>()) {
2603 // Note that expression in AssocEntityDetails cannot be a procedure
2604 // pointer as per C1105 so this cannot be a function reference.
2605 if constexpr (common::HasMember<common::Indirection<parser::Designator>,
2606 uType>) {
2607 CheckFuncRefToArrayElementRefHasSubscripts(context, funcRef);
2608 u = common::Indirection{funcRef.ConvertToArrayElementRef()};
2609 } else {
2610 DIE("can't fix misparsed function as array reference");
2611 }
2612 }
2613 }
2614 }
2615 }
2616
2617 // Common handling of parse tree node types that retain the
2618 // representation of the analyzed expression.
2619 template <typename PARSED>
ExprOrVariable(const PARSED & x,parser::CharBlock source)2620 MaybeExpr ExpressionAnalyzer::ExprOrVariable(
2621 const PARSED &x, parser::CharBlock source) {
2622 if (useSavedTypedExprs_ && x.typedExpr) {
2623 return x.typedExpr->v;
2624 }
2625 auto restorer{GetContextualMessages().SetLocation(source)};
2626 if constexpr (std::is_same_v<PARSED, parser::Expr> ||
2627 std::is_same_v<PARSED, parser::Variable>) {
2628 FixMisparsedFunctionReference(context_, x.u);
2629 }
2630 if (AssumedTypeDummy(x)) { // C710
2631 Say("TYPE(*) dummy argument may only be used as an actual argument"_err_en_US);
2632 } else if (MaybeExpr result{Analyze(x.u)}) {
2633 SetExpr(x, Fold(std::move(*result)));
2634 return x.typedExpr->v;
2635 }
2636 ResetExpr(x);
2637 if (!context_.AnyFatalError()) {
2638 std::string buf;
2639 llvm::raw_string_ostream dump{buf};
2640 parser::DumpTree(dump, x);
2641 Say("Internal error: Expression analysis failed on: %s"_err_en_US,
2642 dump.str());
2643 }
2644 return std::nullopt;
2645 }
2646
Analyze(const parser::Expr & expr)2647 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr &expr) {
2648 auto restorer{GetContextualMessages().SetLocation(expr.source)};
2649 return ExprOrVariable(expr, expr.source);
2650 }
2651
Analyze(const parser::Variable & variable)2652 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Variable &variable) {
2653 auto restorer{GetContextualMessages().SetLocation(variable.GetSource())};
2654 return ExprOrVariable(variable, variable.GetSource());
2655 }
2656
Analyze(const parser::DataStmtConstant & x)2657 MaybeExpr ExpressionAnalyzer::Analyze(const parser::DataStmtConstant &x) {
2658 auto restorer{GetContextualMessages().SetLocation(x.source)};
2659 return ExprOrVariable(x, x.source);
2660 }
2661
AnalyzeKindSelector(TypeCategory category,const std::optional<parser::KindSelector> & selector)2662 Expr<SubscriptInteger> ExpressionAnalyzer::AnalyzeKindSelector(
2663 TypeCategory category,
2664 const std::optional<parser::KindSelector> &selector) {
2665 int defaultKind{GetDefaultKind(category)};
2666 if (!selector) {
2667 return Expr<SubscriptInteger>{defaultKind};
2668 }
2669 return std::visit(
2670 common::visitors{
2671 [&](const parser::ScalarIntConstantExpr &x) {
2672 if (MaybeExpr kind{Analyze(x)}) {
2673 if (std::optional<std::int64_t> code{ToInt64(*kind)}) {
2674 if (CheckIntrinsicKind(category, *code)) {
2675 return Expr<SubscriptInteger>{*code};
2676 }
2677 } else if (auto *intExpr{UnwrapExpr<Expr<SomeInteger>>(*kind)}) {
2678 return ConvertToType<SubscriptInteger>(std::move(*intExpr));
2679 }
2680 }
2681 return Expr<SubscriptInteger>{defaultKind};
2682 },
2683 [&](const parser::KindSelector::StarSize &x) {
2684 std::intmax_t size = x.v;
2685 if (!CheckIntrinsicSize(category, size)) {
2686 size = defaultKind;
2687 } else if (category == TypeCategory::Complex) {
2688 size /= 2;
2689 }
2690 return Expr<SubscriptInteger>{size};
2691 },
2692 },
2693 selector->u);
2694 }
2695
GetDefaultKind(common::TypeCategory category)2696 int ExpressionAnalyzer::GetDefaultKind(common::TypeCategory category) {
2697 return context_.GetDefaultKind(category);
2698 }
2699
GetDefaultKindOfType(common::TypeCategory category)2700 DynamicType ExpressionAnalyzer::GetDefaultKindOfType(
2701 common::TypeCategory category) {
2702 return {category, GetDefaultKind(category)};
2703 }
2704
CheckIntrinsicKind(TypeCategory category,std::int64_t kind)2705 bool ExpressionAnalyzer::CheckIntrinsicKind(
2706 TypeCategory category, std::int64_t kind) {
2707 if (IsValidKindOfIntrinsicType(category, kind)) { // C712, C714, C715, C727
2708 return true;
2709 } else {
2710 Say("%s(KIND=%jd) is not a supported type"_err_en_US,
2711 ToUpperCase(EnumToString(category)), kind);
2712 return false;
2713 }
2714 }
2715
CheckIntrinsicSize(TypeCategory category,std::int64_t size)2716 bool ExpressionAnalyzer::CheckIntrinsicSize(
2717 TypeCategory category, std::int64_t size) {
2718 if (category == TypeCategory::Complex) {
2719 // COMPLEX*16 == COMPLEX(KIND=8)
2720 if (size % 2 == 0 && IsValidKindOfIntrinsicType(category, size / 2)) {
2721 return true;
2722 }
2723 } else if (IsValidKindOfIntrinsicType(category, size)) {
2724 return true;
2725 }
2726 Say("%s*%jd is not a supported type"_err_en_US,
2727 ToUpperCase(EnumToString(category)), size);
2728 return false;
2729 }
2730
AddImpliedDo(parser::CharBlock name,int kind)2731 bool ExpressionAnalyzer::AddImpliedDo(parser::CharBlock name, int kind) {
2732 return impliedDos_.insert(std::make_pair(name, kind)).second;
2733 }
2734
RemoveImpliedDo(parser::CharBlock name)2735 void ExpressionAnalyzer::RemoveImpliedDo(parser::CharBlock name) {
2736 auto iter{impliedDos_.find(name)};
2737 if (iter != impliedDos_.end()) {
2738 impliedDos_.erase(iter);
2739 }
2740 }
2741
IsImpliedDo(parser::CharBlock name) const2742 std::optional<int> ExpressionAnalyzer::IsImpliedDo(
2743 parser::CharBlock name) const {
2744 auto iter{impliedDos_.find(name)};
2745 if (iter != impliedDos_.cend()) {
2746 return {iter->second};
2747 } else {
2748 return std::nullopt;
2749 }
2750 }
2751
EnforceTypeConstraint(parser::CharBlock at,const MaybeExpr & result,TypeCategory category,bool defaultKind)2752 bool ExpressionAnalyzer::EnforceTypeConstraint(parser::CharBlock at,
2753 const MaybeExpr &result, TypeCategory category, bool defaultKind) {
2754 if (result) {
2755 if (auto type{result->GetType()}) {
2756 if (type->category() != category) { // C885
2757 Say(at, "Must have %s type, but is %s"_err_en_US,
2758 ToUpperCase(EnumToString(category)),
2759 ToUpperCase(type->AsFortran()));
2760 return false;
2761 } else if (defaultKind) {
2762 int kind{context_.GetDefaultKind(category)};
2763 if (type->kind() != kind) {
2764 Say(at, "Must have default kind(%d) of %s type, but is %s"_err_en_US,
2765 kind, ToUpperCase(EnumToString(category)),
2766 ToUpperCase(type->AsFortran()));
2767 return false;
2768 }
2769 }
2770 } else {
2771 Say(at, "Must have %s type, but is typeless"_err_en_US,
2772 ToUpperCase(EnumToString(category)));
2773 return false;
2774 }
2775 }
2776 return true;
2777 }
2778
MakeFunctionRef(parser::CharBlock callSite,ProcedureDesignator && proc,ActualArguments && arguments)2779 MaybeExpr ExpressionAnalyzer::MakeFunctionRef(parser::CharBlock callSite,
2780 ProcedureDesignator &&proc, ActualArguments &&arguments) {
2781 if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&proc.u)}) {
2782 if (intrinsic->name == "null" && arguments.empty()) {
2783 return Expr<SomeType>{NullPointer{}};
2784 }
2785 }
2786 if (const Symbol * symbol{proc.GetSymbol()}) {
2787 if (!ResolveForward(*symbol)) {
2788 return std::nullopt;
2789 }
2790 }
2791 if (auto chars{CheckCall(callSite, proc, arguments)}) {
2792 if (chars->functionResult) {
2793 const auto &result{*chars->functionResult};
2794 if (result.IsProcedurePointer()) {
2795 return Expr<SomeType>{
2796 ProcedureRef{std::move(proc), std::move(arguments)}};
2797 } else {
2798 // Not a procedure pointer, so type and shape are known.
2799 return TypedWrapper<FunctionRef, ProcedureRef>(
2800 DEREF(result.GetTypeAndShape()).type(),
2801 ProcedureRef{std::move(proc), std::move(arguments)});
2802 }
2803 }
2804 }
2805 return std::nullopt;
2806 }
2807
MakeFunctionRef(parser::CharBlock intrinsic,ActualArguments && arguments)2808 MaybeExpr ExpressionAnalyzer::MakeFunctionRef(
2809 parser::CharBlock intrinsic, ActualArguments &&arguments) {
2810 if (std::optional<SpecificCall> specificCall{
2811 context_.intrinsics().Probe(CallCharacteristics{intrinsic.ToString()},
2812 arguments, context_.foldingContext())}) {
2813 return MakeFunctionRef(intrinsic,
2814 ProcedureDesignator{std::move(specificCall->specificIntrinsic)},
2815 std::move(specificCall->arguments));
2816 } else {
2817 return std::nullopt;
2818 }
2819 }
2820
Analyze(const parser::Variable & x)2821 void ArgumentAnalyzer::Analyze(const parser::Variable &x) {
2822 source_.ExtendToCover(x.GetSource());
2823 if (MaybeExpr expr{context_.Analyze(x)}) {
2824 if (!IsConstantExpr(*expr)) {
2825 actuals_.emplace_back(std::move(*expr));
2826 return;
2827 }
2828 const Symbol *symbol{GetLastSymbol(*expr)};
2829 if (!symbol) {
2830 context_.SayAt(x, "Assignment to constant '%s' is not allowed"_err_en_US,
2831 x.GetSource());
2832 } else if (auto *subp{symbol->detailsIf<semantics::SubprogramDetails>()}) {
2833 auto *msg{context_.SayAt(x,
2834 "Assignment to subprogram '%s' is not allowed"_err_en_US,
2835 symbol->name())};
2836 if (subp->isFunction()) {
2837 const auto &result{subp->result().name()};
2838 msg->Attach(result, "Function result is '%s'"_err_en_US, result);
2839 }
2840 } else {
2841 context_.SayAt(x, "Assignment to constant '%s' is not allowed"_err_en_US,
2842 symbol->name());
2843 }
2844 }
2845 fatalErrors_ = true;
2846 }
2847
Analyze(const parser::ActualArgSpec & arg,bool isSubroutine)2848 void ArgumentAnalyzer::Analyze(
2849 const parser::ActualArgSpec &arg, bool isSubroutine) {
2850 // TODO: Actual arguments that are procedures and procedure pointers need to
2851 // be detected and represented (they're not expressions).
2852 // TODO: C1534: Don't allow a "restricted" specific intrinsic to be passed.
2853 std::optional<ActualArgument> actual;
2854 bool isAltReturn{false};
2855 std::visit(common::visitors{
2856 [&](const common::Indirection<parser::Expr> &x) {
2857 // TODO: Distinguish & handle procedure name and
2858 // proc-component-ref
2859 actual = AnalyzeExpr(x.value());
2860 },
2861 [&](const parser::AltReturnSpec &) {
2862 if (!isSubroutine) {
2863 context_.Say(
2864 "alternate return specification may not appear on"
2865 " function reference"_err_en_US);
2866 }
2867 isAltReturn = true;
2868 },
2869 [&](const parser::ActualArg::PercentRef &) {
2870 context_.Say("TODO: %REF() argument"_err_en_US);
2871 },
2872 [&](const parser::ActualArg::PercentVal &) {
2873 context_.Say("TODO: %VAL() argument"_err_en_US);
2874 },
2875 },
2876 std::get<parser::ActualArg>(arg.t).u);
2877 if (actual) {
2878 if (const auto &argKW{std::get<std::optional<parser::Keyword>>(arg.t)}) {
2879 actual->set_keyword(argKW->v.source);
2880 }
2881 actuals_.emplace_back(std::move(*actual));
2882 } else if (!isAltReturn) {
2883 fatalErrors_ = true;
2884 }
2885 }
2886
IsIntrinsicRelational(RelationalOperator opr) const2887 bool ArgumentAnalyzer::IsIntrinsicRelational(RelationalOperator opr) const {
2888 CHECK(actuals_.size() == 2);
2889 return semantics::IsIntrinsicRelational(
2890 opr, *GetType(0), GetRank(0), *GetType(1), GetRank(1));
2891 }
2892
IsIntrinsicNumeric(NumericOperator opr) const2893 bool ArgumentAnalyzer::IsIntrinsicNumeric(NumericOperator opr) const {
2894 std::optional<DynamicType> type0{GetType(0)};
2895 if (actuals_.size() == 1) {
2896 if (IsBOZLiteral(0)) {
2897 return opr == NumericOperator::Add;
2898 } else {
2899 return type0 && semantics::IsIntrinsicNumeric(*type0);
2900 }
2901 } else {
2902 std::optional<DynamicType> type1{GetType(1)};
2903 if (IsBOZLiteral(0) && type1) {
2904 auto cat1{type1->category()};
2905 return cat1 == TypeCategory::Integer || cat1 == TypeCategory::Real;
2906 } else if (IsBOZLiteral(1) && type0) { // Integer/Real opr BOZ
2907 auto cat0{type0->category()};
2908 return cat0 == TypeCategory::Integer || cat0 == TypeCategory::Real;
2909 } else {
2910 return type0 && type1 &&
2911 semantics::IsIntrinsicNumeric(*type0, GetRank(0), *type1, GetRank(1));
2912 }
2913 }
2914 }
2915
IsIntrinsicLogical() const2916 bool ArgumentAnalyzer::IsIntrinsicLogical() const {
2917 if (actuals_.size() == 1) {
2918 return semantics::IsIntrinsicLogical(*GetType(0));
2919 return GetType(0)->category() == TypeCategory::Logical;
2920 } else {
2921 return semantics::IsIntrinsicLogical(
2922 *GetType(0), GetRank(0), *GetType(1), GetRank(1));
2923 }
2924 }
2925
IsIntrinsicConcat() const2926 bool ArgumentAnalyzer::IsIntrinsicConcat() const {
2927 return semantics::IsIntrinsicConcat(
2928 *GetType(0), GetRank(0), *GetType(1), GetRank(1));
2929 }
2930
CheckConformance() const2931 bool ArgumentAnalyzer::CheckConformance() const {
2932 if (actuals_.size() == 2) {
2933 const auto *lhs{actuals_.at(0).value().UnwrapExpr()};
2934 const auto *rhs{actuals_.at(1).value().UnwrapExpr()};
2935 if (lhs && rhs) {
2936 auto &foldingContext{context_.GetFoldingContext()};
2937 auto lhShape{GetShape(foldingContext, *lhs)};
2938 auto rhShape{GetShape(foldingContext, *rhs)};
2939 if (lhShape && rhShape) {
2940 return evaluate::CheckConformance(foldingContext.messages(), *lhShape,
2941 *rhShape, "left operand", "right operand", true,
2942 true /* scalar expansion is allowed */);
2943 }
2944 }
2945 }
2946 return true; // no proven problem
2947 }
2948
TryDefinedOp(const char * opr,parser::MessageFixedText && error,bool isUserOp)2949 MaybeExpr ArgumentAnalyzer::TryDefinedOp(
2950 const char *opr, parser::MessageFixedText &&error, bool isUserOp) {
2951 if (AnyUntypedOperand()) {
2952 context_.Say(
2953 std::move(error), ToUpperCase(opr), TypeAsFortran(0), TypeAsFortran(1));
2954 return std::nullopt;
2955 }
2956 {
2957 auto restorer{context_.GetContextualMessages().DiscardMessages()};
2958 std::string oprNameString{
2959 isUserOp ? std::string{opr} : "operator("s + opr + ')'};
2960 parser::CharBlock oprName{oprNameString};
2961 const auto &scope{context_.context().FindScope(source_)};
2962 if (Symbol * symbol{scope.FindSymbol(oprName)}) {
2963 parser::Name name{symbol->name(), symbol};
2964 if (auto result{context_.AnalyzeDefinedOp(name, GetActuals())}) {
2965 return result;
2966 }
2967 sawDefinedOp_ = symbol;
2968 }
2969 for (std::size_t passIndex{0}; passIndex < actuals_.size(); ++passIndex) {
2970 if (const Symbol * symbol{FindBoundOp(oprName, passIndex)}) {
2971 if (MaybeExpr result{TryBoundOp(*symbol, passIndex)}) {
2972 return result;
2973 }
2974 }
2975 }
2976 }
2977 if (sawDefinedOp_) {
2978 SayNoMatch(ToUpperCase(sawDefinedOp_->name().ToString()));
2979 } else if (actuals_.size() == 1 || AreConformable()) {
2980 context_.Say(
2981 std::move(error), ToUpperCase(opr), TypeAsFortran(0), TypeAsFortran(1));
2982 } else {
2983 context_.Say(
2984 "Operands of %s are not conformable; have rank %d and rank %d"_err_en_US,
2985 ToUpperCase(opr), actuals_[0]->Rank(), actuals_[1]->Rank());
2986 }
2987 return std::nullopt;
2988 }
2989
TryDefinedOp(std::vector<const char * > oprs,parser::MessageFixedText && error)2990 MaybeExpr ArgumentAnalyzer::TryDefinedOp(
2991 std::vector<const char *> oprs, parser::MessageFixedText &&error) {
2992 for (std::size_t i{1}; i < oprs.size(); ++i) {
2993 auto restorer{context_.GetContextualMessages().DiscardMessages()};
2994 if (auto result{TryDefinedOp(oprs[i], std::move(error))}) {
2995 return result;
2996 }
2997 }
2998 return TryDefinedOp(oprs[0], std::move(error));
2999 }
3000
TryBoundOp(const Symbol & symbol,int passIndex)3001 MaybeExpr ArgumentAnalyzer::TryBoundOp(const Symbol &symbol, int passIndex) {
3002 ActualArguments localActuals{actuals_};
3003 const Symbol *proc{GetBindingResolution(GetType(passIndex), symbol)};
3004 if (!proc) {
3005 proc = &symbol;
3006 localActuals.at(passIndex).value().set_isPassedObject();
3007 }
3008 CheckConformance();
3009 return context_.MakeFunctionRef(
3010 source_, ProcedureDesignator{*proc}, std::move(localActuals));
3011 }
3012
TryDefinedAssignment()3013 std::optional<ProcedureRef> ArgumentAnalyzer::TryDefinedAssignment() {
3014 using semantics::Tristate;
3015 const Expr<SomeType> &lhs{GetExpr(0)};
3016 const Expr<SomeType> &rhs{GetExpr(1)};
3017 std::optional<DynamicType> lhsType{lhs.GetType()};
3018 std::optional<DynamicType> rhsType{rhs.GetType()};
3019 int lhsRank{lhs.Rank()};
3020 int rhsRank{rhs.Rank()};
3021 Tristate isDefined{
3022 semantics::IsDefinedAssignment(lhsType, lhsRank, rhsType, rhsRank)};
3023 if (isDefined == Tristate::No) {
3024 if (lhsType && rhsType) {
3025 AddAssignmentConversion(*lhsType, *rhsType);
3026 }
3027 return std::nullopt; // user-defined assignment not allowed for these args
3028 }
3029 auto restorer{context_.GetContextualMessages().SetLocation(source_)};
3030 if (std::optional<ProcedureRef> procRef{GetDefinedAssignmentProc()}) {
3031 context_.CheckCall(source_, procRef->proc(), procRef->arguments());
3032 return std::move(*procRef);
3033 }
3034 if (isDefined == Tristate::Yes) {
3035 if (!lhsType || !rhsType || (lhsRank != rhsRank && rhsRank != 0) ||
3036 !OkLogicalIntegerAssignment(lhsType->category(), rhsType->category())) {
3037 SayNoMatch("ASSIGNMENT(=)", true);
3038 }
3039 }
3040 return std::nullopt;
3041 }
3042
OkLogicalIntegerAssignment(TypeCategory lhs,TypeCategory rhs)3043 bool ArgumentAnalyzer::OkLogicalIntegerAssignment(
3044 TypeCategory lhs, TypeCategory rhs) {
3045 if (!context_.context().languageFeatures().IsEnabled(
3046 common::LanguageFeature::LogicalIntegerAssignment)) {
3047 return false;
3048 }
3049 std::optional<parser::MessageFixedText> msg;
3050 if (lhs == TypeCategory::Integer && rhs == TypeCategory::Logical) {
3051 // allow assignment to LOGICAL from INTEGER as a legacy extension
3052 msg = "nonstandard usage: assignment of LOGICAL to INTEGER"_en_US;
3053 } else if (lhs == TypeCategory::Logical && rhs == TypeCategory::Integer) {
3054 // ... and assignment to LOGICAL from INTEGER
3055 msg = "nonstandard usage: assignment of INTEGER to LOGICAL"_en_US;
3056 } else {
3057 return false;
3058 }
3059 if (context_.context().languageFeatures().ShouldWarn(
3060 common::LanguageFeature::LogicalIntegerAssignment)) {
3061 context_.Say(std::move(*msg));
3062 }
3063 return true;
3064 }
3065
GetDefinedAssignmentProc()3066 std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc() {
3067 auto restorer{context_.GetContextualMessages().DiscardMessages()};
3068 std::string oprNameString{"assignment(=)"};
3069 parser::CharBlock oprName{oprNameString};
3070 const Symbol *proc{nullptr};
3071 const auto &scope{context_.context().FindScope(source_)};
3072 if (const Symbol * symbol{scope.FindSymbol(oprName)}) {
3073 ExpressionAnalyzer::AdjustActuals noAdjustment;
3074 if (const Symbol *
3075 specific{context_.ResolveGeneric(*symbol, actuals_, noAdjustment)}) {
3076 proc = specific;
3077 } else {
3078 context_.EmitGenericResolutionError(*symbol);
3079 }
3080 }
3081 int passedObjectIndex{-1};
3082 for (std::size_t i{0}; i < actuals_.size(); ++i) {
3083 if (const Symbol * specific{FindBoundOp(oprName, i)}) {
3084 if (const Symbol *
3085 resolution{GetBindingResolution(GetType(i), *specific)}) {
3086 proc = resolution;
3087 } else {
3088 proc = specific;
3089 passedObjectIndex = i;
3090 }
3091 }
3092 }
3093 if (!proc) {
3094 return std::nullopt;
3095 }
3096 ActualArguments actualsCopy{actuals_};
3097 if (passedObjectIndex >= 0) {
3098 actualsCopy[passedObjectIndex]->set_isPassedObject();
3099 }
3100 return ProcedureRef{ProcedureDesignator{*proc}, std::move(actualsCopy)};
3101 }
3102
Dump(llvm::raw_ostream & os)3103 void ArgumentAnalyzer::Dump(llvm::raw_ostream &os) {
3104 os << "source_: " << source_.ToString() << " fatalErrors_ = " << fatalErrors_
3105 << '\n';
3106 for (const auto &actual : actuals_) {
3107 if (!actual.has_value()) {
3108 os << "- error\n";
3109 } else if (const Symbol * symbol{actual->GetAssumedTypeDummy()}) {
3110 os << "- assumed type: " << symbol->name().ToString() << '\n';
3111 } else if (const Expr<SomeType> *expr{actual->UnwrapExpr()}) {
3112 expr->AsFortran(os << "- expr: ") << '\n';
3113 } else {
3114 DIE("bad ActualArgument");
3115 }
3116 }
3117 }
3118
AnalyzeExpr(const parser::Expr & expr)3119 std::optional<ActualArgument> ArgumentAnalyzer::AnalyzeExpr(
3120 const parser::Expr &expr) {
3121 source_.ExtendToCover(expr.source);
3122 if (const Symbol * assumedTypeDummy{AssumedTypeDummy(expr)}) {
3123 expr.typedExpr.Reset(new GenericExprWrapper{}, GenericExprWrapper::Deleter);
3124 if (isProcedureCall_) {
3125 return ActualArgument{ActualArgument::AssumedType{*assumedTypeDummy}};
3126 }
3127 context_.SayAt(expr.source,
3128 "TYPE(*) dummy argument may only be used as an actual argument"_err_en_US);
3129 } else if (MaybeExpr argExpr{AnalyzeExprOrWholeAssumedSizeArray(expr)}) {
3130 if (isProcedureCall_ || !IsProcedure(*argExpr)) {
3131 return ActualArgument{std::move(*argExpr)};
3132 }
3133 context_.SayAt(expr.source,
3134 IsFunction(*argExpr) ? "Function call must have argument list"_err_en_US
3135 : "Subroutine name is not allowed here"_err_en_US);
3136 }
3137 return std::nullopt;
3138 }
3139
AnalyzeExprOrWholeAssumedSizeArray(const parser::Expr & expr)3140 MaybeExpr ArgumentAnalyzer::AnalyzeExprOrWholeAssumedSizeArray(
3141 const parser::Expr &expr) {
3142 // If an expression's parse tree is a whole assumed-size array:
3143 // Expr -> Designator -> DataRef -> Name
3144 // treat it as a special case for argument passing and bypass
3145 // the C1002/C1014 constraint checking in expression semantics.
3146 if (const auto *name{parser::Unwrap<parser::Name>(expr)}) {
3147 if (name->symbol && semantics::IsAssumedSizeArray(*name->symbol)) {
3148 auto restorer{context_.AllowWholeAssumedSizeArray()};
3149 return context_.Analyze(expr);
3150 }
3151 }
3152 return context_.Analyze(expr);
3153 }
3154
AreConformable() const3155 bool ArgumentAnalyzer::AreConformable() const {
3156 CHECK(!fatalErrors_ && actuals_.size() == 2);
3157 return evaluate::AreConformable(*actuals_[0], *actuals_[1]);
3158 }
3159
3160 // Look for a type-bound operator in the type of arg number passIndex.
FindBoundOp(parser::CharBlock oprName,int passIndex)3161 const Symbol *ArgumentAnalyzer::FindBoundOp(
3162 parser::CharBlock oprName, int passIndex) {
3163 const auto *type{GetDerivedTypeSpec(GetType(passIndex))};
3164 if (!type || !type->scope()) {
3165 return nullptr;
3166 }
3167 const Symbol *symbol{type->scope()->FindComponent(oprName)};
3168 if (!symbol) {
3169 return nullptr;
3170 }
3171 sawDefinedOp_ = symbol;
3172 ExpressionAnalyzer::AdjustActuals adjustment{
3173 [&](const Symbol &proc, ActualArguments &) {
3174 return passIndex == GetPassIndex(proc);
3175 }};
3176 const Symbol *result{context_.ResolveGeneric(*symbol, actuals_, adjustment)};
3177 if (!result) {
3178 context_.EmitGenericResolutionError(*symbol);
3179 }
3180 return result;
3181 }
3182
3183 // If there is an implicit conversion between intrinsic types, make it explicit
AddAssignmentConversion(const DynamicType & lhsType,const DynamicType & rhsType)3184 void ArgumentAnalyzer::AddAssignmentConversion(
3185 const DynamicType &lhsType, const DynamicType &rhsType) {
3186 if (lhsType.category() == rhsType.category() &&
3187 lhsType.kind() == rhsType.kind()) {
3188 // no conversion necessary
3189 } else if (auto rhsExpr{evaluate::ConvertToType(lhsType, MoveExpr(1))}) {
3190 actuals_[1] = ActualArgument{*rhsExpr};
3191 } else {
3192 actuals_[1] = std::nullopt;
3193 }
3194 }
3195
GetType(std::size_t i) const3196 std::optional<DynamicType> ArgumentAnalyzer::GetType(std::size_t i) const {
3197 return i < actuals_.size() ? actuals_[i].value().GetType() : std::nullopt;
3198 }
GetRank(std::size_t i) const3199 int ArgumentAnalyzer::GetRank(std::size_t i) const {
3200 return i < actuals_.size() ? actuals_[i].value().Rank() : 0;
3201 }
3202
3203 // If the argument at index i is a BOZ literal, convert its type to match the
3204 // otherType. It it's REAL convert to REAL, otherwise convert to INTEGER.
3205 // Note that IBM supports comparing BOZ literals to CHARACTER operands. That
3206 // is not currently supported.
ConvertBOZ(std::size_t i,std::optional<DynamicType> otherType)3207 void ArgumentAnalyzer::ConvertBOZ(
3208 std::size_t i, std::optional<DynamicType> otherType) {
3209 if (IsBOZLiteral(i)) {
3210 Expr<SomeType> &&argExpr{MoveExpr(i)};
3211 auto *boz{std::get_if<BOZLiteralConstant>(&argExpr.u)};
3212 if (otherType && otherType->category() == TypeCategory::Real) {
3213 MaybeExpr realExpr{ConvertToKind<TypeCategory::Real>(
3214 context_.context().GetDefaultKind(TypeCategory::Real),
3215 std::move(*boz))};
3216 actuals_[i] = std::move(*realExpr);
3217 } else {
3218 MaybeExpr intExpr{ConvertToKind<TypeCategory::Integer>(
3219 context_.context().GetDefaultKind(TypeCategory::Integer),
3220 std::move(*boz))};
3221 actuals_[i] = std::move(*intExpr);
3222 }
3223 }
3224 }
3225
3226 // Report error resolving opr when there is a user-defined one available
SayNoMatch(const std::string & opr,bool isAssignment)3227 void ArgumentAnalyzer::SayNoMatch(const std::string &opr, bool isAssignment) {
3228 std::string type0{TypeAsFortran(0)};
3229 auto rank0{actuals_[0]->Rank()};
3230 if (actuals_.size() == 1) {
3231 if (rank0 > 0) {
3232 context_.Say("No intrinsic or user-defined %s matches "
3233 "rank %d array of %s"_err_en_US,
3234 opr, rank0, type0);
3235 } else {
3236 context_.Say("No intrinsic or user-defined %s matches "
3237 "operand type %s"_err_en_US,
3238 opr, type0);
3239 }
3240 } else {
3241 std::string type1{TypeAsFortran(1)};
3242 auto rank1{actuals_[1]->Rank()};
3243 if (rank0 > 0 && rank1 > 0 && rank0 != rank1) {
3244 context_.Say("No intrinsic or user-defined %s matches "
3245 "rank %d array of %s and rank %d array of %s"_err_en_US,
3246 opr, rank0, type0, rank1, type1);
3247 } else if (isAssignment && rank0 != rank1) {
3248 if (rank0 == 0) {
3249 context_.Say("No intrinsic or user-defined %s matches "
3250 "scalar %s and rank %d array of %s"_err_en_US,
3251 opr, type0, rank1, type1);
3252 } else {
3253 context_.Say("No intrinsic or user-defined %s matches "
3254 "rank %d array of %s and scalar %s"_err_en_US,
3255 opr, rank0, type0, type1);
3256 }
3257 } else {
3258 context_.Say("No intrinsic or user-defined %s matches "
3259 "operand types %s and %s"_err_en_US,
3260 opr, type0, type1);
3261 }
3262 }
3263 }
3264
TypeAsFortran(std::size_t i)3265 std::string ArgumentAnalyzer::TypeAsFortran(std::size_t i) {
3266 if (std::optional<DynamicType> type{GetType(i)}) {
3267 return type->category() == TypeCategory::Derived
3268 ? "TYPE("s + type->AsFortran() + ')'
3269 : type->category() == TypeCategory::Character
3270 ? "CHARACTER(KIND="s + std::to_string(type->kind()) + ')'
3271 : ToUpperCase(type->AsFortran());
3272 } else {
3273 return "untyped";
3274 }
3275 }
3276
AnyUntypedOperand()3277 bool ArgumentAnalyzer::AnyUntypedOperand() {
3278 for (const auto &actual : actuals_) {
3279 if (!actual.value().GetType()) {
3280 return true;
3281 }
3282 }
3283 return false;
3284 }
3285
3286 } // namespace Fortran::evaluate
3287
3288 namespace Fortran::semantics {
AnalyzeKindSelector(SemanticsContext & context,common::TypeCategory category,const std::optional<parser::KindSelector> & selector)3289 evaluate::Expr<evaluate::SubscriptInteger> AnalyzeKindSelector(
3290 SemanticsContext &context, common::TypeCategory category,
3291 const std::optional<parser::KindSelector> &selector) {
3292 evaluate::ExpressionAnalyzer analyzer{context};
3293 auto restorer{
3294 analyzer.GetContextualMessages().SetLocation(context.location().value())};
3295 return analyzer.AnalyzeKindSelector(category, selector);
3296 }
3297
AnalyzeCallStmt(SemanticsContext & context,const parser::CallStmt & call)3298 void AnalyzeCallStmt(SemanticsContext &context, const parser::CallStmt &call) {
3299 evaluate::ExpressionAnalyzer{context}.Analyze(call);
3300 }
3301
AnalyzeAssignmentStmt(SemanticsContext & context,const parser::AssignmentStmt & stmt)3302 const evaluate::Assignment *AnalyzeAssignmentStmt(
3303 SemanticsContext &context, const parser::AssignmentStmt &stmt) {
3304 return evaluate::ExpressionAnalyzer{context}.Analyze(stmt);
3305 }
AnalyzePointerAssignmentStmt(SemanticsContext & context,const parser::PointerAssignmentStmt & stmt)3306 const evaluate::Assignment *AnalyzePointerAssignmentStmt(
3307 SemanticsContext &context, const parser::PointerAssignmentStmt &stmt) {
3308 return evaluate::ExpressionAnalyzer{context}.Analyze(stmt);
3309 }
3310
ExprChecker(SemanticsContext & context)3311 ExprChecker::ExprChecker(SemanticsContext &context) : context_{context} {}
3312
Pre(const parser::DataImpliedDo & ido)3313 bool ExprChecker::Pre(const parser::DataImpliedDo &ido) {
3314 parser::Walk(std::get<parser::DataImpliedDo::Bounds>(ido.t), *this);
3315 const auto &bounds{std::get<parser::DataImpliedDo::Bounds>(ido.t)};
3316 auto name{bounds.name.thing.thing};
3317 int kind{evaluate::ResultType<evaluate::ImpliedDoIndex>::kind};
3318 if (const auto dynamicType{evaluate::DynamicType::From(*name.symbol)}) {
3319 if (dynamicType->category() == TypeCategory::Integer) {
3320 kind = dynamicType->kind();
3321 }
3322 }
3323 exprAnalyzer_.AddImpliedDo(name.source, kind);
3324 parser::Walk(std::get<std::list<parser::DataIDoObject>>(ido.t), *this);
3325 exprAnalyzer_.RemoveImpliedDo(name.source);
3326 return false;
3327 }
3328
Walk(const parser::Program & program)3329 bool ExprChecker::Walk(const parser::Program &program) {
3330 parser::Walk(program, *this);
3331 return !context_.AnyFatalError();
3332 }
3333 } // namespace Fortran::semantics
3334