xref: /llvm-project/flang/lib/Semantics/expression.cpp (revision 3a8a52f4a52e0c301a5f3d6acce684c7fd4a6d57)
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-utils.h"
13 #include "resolve-names.h"
14 #include "flang/Common/Fortran.h"
15 #include "flang/Common/idioms.h"
16 #include "flang/Evaluate/common.h"
17 #include "flang/Evaluate/fold.h"
18 #include "flang/Evaluate/tools.h"
19 #include "flang/Parser/characters.h"
20 #include "flang/Parser/dump-parse-tree.h"
21 #include "flang/Parser/parse-tree-visitor.h"
22 #include "flang/Parser/parse-tree.h"
23 #include "flang/Semantics/scope.h"
24 #include "flang/Semantics/semantics.h"
25 #include "flang/Semantics/symbol.h"
26 #include "flang/Semantics/tools.h"
27 #include "llvm/Support/raw_ostream.h"
28 #include <algorithm>
29 #include <functional>
30 #include <optional>
31 #include <set>
32 #include <vector>
33 
34 // Typedef for optional generic expressions (ubiquitous in this file)
35 using MaybeExpr =
36     std::optional<Fortran::evaluate::Expr<Fortran::evaluate::SomeType>>;
37 
38 // Much of the code that implements semantic analysis of expressions is
39 // tightly coupled with their typed representations in lib/Evaluate,
40 // and appears here in namespace Fortran::evaluate for convenience.
41 namespace Fortran::evaluate {
42 
43 using common::LanguageFeature;
44 using common::NumericOperator;
45 using common::TypeCategory;
46 
47 static inline std::string ToUpperCase(std::string_view str) {
48   return parser::ToUpperCaseLetters(str);
49 }
50 
51 struct DynamicTypeWithLength : public DynamicType {
52   explicit DynamicTypeWithLength(const DynamicType &t) : DynamicType{t} {}
53   std::optional<Expr<SubscriptInteger>> LEN() const;
54   std::optional<Expr<SubscriptInteger>> length;
55 };
56 
57 std::optional<Expr<SubscriptInteger>> DynamicTypeWithLength::LEN() const {
58   if (length) {
59     return length;
60   } else {
61     return GetCharLength();
62   }
63 }
64 
65 static std::optional<DynamicTypeWithLength> AnalyzeTypeSpec(
66     const std::optional<parser::TypeSpec> &spec, FoldingContext &context) {
67   if (spec) {
68     if (const semantics::DeclTypeSpec *typeSpec{spec->declTypeSpec}) {
69       // Name resolution sets TypeSpec::declTypeSpec only when it's valid
70       // (viz., an intrinsic type with valid known kind or a non-polymorphic
71       // & non-ABSTRACT derived type).
72       if (const semantics::IntrinsicTypeSpec *intrinsic{
73               typeSpec->AsIntrinsic()}) {
74         TypeCategory category{intrinsic->category()};
75         if (auto optKind{ToInt64(intrinsic->kind())}) {
76           int kind{static_cast<int>(*optKind)};
77           if (category == TypeCategory::Character) {
78             const semantics::CharacterTypeSpec &cts{
79                 typeSpec->characterTypeSpec()};
80             const semantics::ParamValue &len{cts.length()};
81             // N.B. CHARACTER(LEN=*) is allowed in type-specs in ALLOCATE() &
82             // type guards, but not in array constructors.
83             DynamicTypeWithLength type{DynamicType{kind, len}};
84             if (auto lenExpr{type.LEN()}) {
85               type.length = Fold(context,
86                   AsExpr(Extremum<SubscriptInteger>{Ordering::Greater,
87                       Expr<SubscriptInteger>{0}, std::move(*lenExpr)}));
88             }
89             return type;
90           } else {
91             return DynamicTypeWithLength{DynamicType{category, kind}};
92           }
93         }
94       } else if (const semantics::DerivedTypeSpec *derived{
95                      typeSpec->AsDerived()}) {
96         return DynamicTypeWithLength{DynamicType{*derived}};
97       }
98     }
99   }
100   return std::nullopt;
101 }
102 
103 // Utilities to set a source location, if we have one, on an actual argument,
104 // when it is statically present.
105 static void SetArgSourceLocation(ActualArgument &x, parser::CharBlock at) {
106   x.set_sourceLocation(at);
107 }
108 static void SetArgSourceLocation(
109     std::optional<ActualArgument> &x, parser::CharBlock at) {
110   if (x) {
111     x->set_sourceLocation(at);
112   }
113 }
114 static void SetArgSourceLocation(
115     std::optional<ActualArgument> &x, std::optional<parser::CharBlock> at) {
116   if (x && at) {
117     x->set_sourceLocation(*at);
118   }
119 }
120 
121 class ArgumentAnalyzer {
122 public:
123   explicit ArgumentAnalyzer(ExpressionAnalyzer &context)
124       : context_{context}, source_{context.GetContextualMessages().at()},
125         isProcedureCall_{false} {}
126   ArgumentAnalyzer(ExpressionAnalyzer &context, parser::CharBlock source,
127       bool isProcedureCall = false)
128       : context_{context}, source_{source}, isProcedureCall_{isProcedureCall} {}
129   bool fatalErrors() const { return fatalErrors_; }
130   ActualArguments &&GetActuals() {
131     CHECK(!fatalErrors_);
132     return std::move(actuals_);
133   }
134   const Expr<SomeType> &GetExpr(std::size_t i) const {
135     return DEREF(actuals_.at(i).value().UnwrapExpr());
136   }
137   Expr<SomeType> &&MoveExpr(std::size_t i) {
138     return std::move(DEREF(actuals_.at(i).value().UnwrapExpr()));
139   }
140   void Analyze(const common::Indirection<parser::Expr> &x) {
141     Analyze(x.value());
142   }
143   void Analyze(const parser::Expr &x) {
144     actuals_.emplace_back(AnalyzeExpr(x));
145     SetArgSourceLocation(actuals_.back(), x.source);
146     fatalErrors_ |= !actuals_.back();
147   }
148   void Analyze(const parser::Variable &);
149   void Analyze(const parser::ActualArgSpec &, bool isSubroutine);
150   void ConvertBOZ(std::optional<DynamicType> *thisType, std::size_t,
151       std::optional<DynamicType> otherType);
152 
153   bool IsIntrinsicRelational(
154       RelationalOperator, const DynamicType &, const DynamicType &) const;
155   bool IsIntrinsicLogical() const;
156   bool IsIntrinsicNumeric(NumericOperator) const;
157   bool IsIntrinsicConcat() const;
158 
159   bool CheckConformance();
160   bool CheckAssignmentConformance();
161   bool CheckForNullPointer(const char *where = "as an operand here");
162   bool CheckForAssumedRank(const char *where = "as an operand here");
163 
164   // Find and return a user-defined operator or report an error.
165   // The provided message is used if there is no such operator.
166   // If a definedOpSymbolPtr is provided, the caller must check
167   // for its accessibility.
168   MaybeExpr TryDefinedOp(
169       const char *, parser::MessageFixedText, bool isUserOp = false);
170   template <typename E>
171   MaybeExpr TryDefinedOp(E opr, parser::MessageFixedText msg) {
172     return TryDefinedOp(
173         context_.context().languageFeatures().GetNames(opr), msg);
174   }
175   // Find and return a user-defined assignment
176   std::optional<ProcedureRef> TryDefinedAssignment();
177   std::optional<ProcedureRef> GetDefinedAssignmentProc();
178   std::optional<DynamicType> GetType(std::size_t) const;
179   void Dump(llvm::raw_ostream &);
180 
181 private:
182   MaybeExpr TryDefinedOp(
183       const std::vector<const char *> &, parser::MessageFixedText);
184   MaybeExpr TryBoundOp(const Symbol &, int passIndex);
185   std::optional<ActualArgument> AnalyzeExpr(const parser::Expr &);
186   std::optional<ActualArgument> AnalyzeVariable(const parser::Variable &);
187   MaybeExpr AnalyzeExprOrWholeAssumedSizeArray(const parser::Expr &);
188   bool AreConformable() const;
189   const Symbol *FindBoundOp(parser::CharBlock, int passIndex,
190       const Symbol *&generic, bool isSubroutine);
191   void AddAssignmentConversion(
192       const DynamicType &lhsType, const DynamicType &rhsType);
193   bool OkLogicalIntegerAssignment(TypeCategory lhs, TypeCategory rhs);
194   int GetRank(std::size_t) const;
195   bool IsBOZLiteral(std::size_t i) const {
196     return evaluate::IsBOZLiteral(GetExpr(i));
197   }
198   void SayNoMatch(const std::string &, bool isAssignment = false);
199   std::string TypeAsFortran(std::size_t);
200   bool AnyUntypedOrMissingOperand();
201 
202   ExpressionAnalyzer &context_;
203   ActualArguments actuals_;
204   parser::CharBlock source_;
205   bool fatalErrors_{false};
206   const bool isProcedureCall_; // false for user-defined op or assignment
207 };
208 
209 // Wraps a data reference in a typed Designator<>, and a procedure
210 // or procedure pointer reference in a ProcedureDesignator.
211 MaybeExpr ExpressionAnalyzer::Designate(DataRef &&ref) {
212   const Symbol &last{ref.GetLastSymbol()};
213   const Symbol &specific{BypassGeneric(last)};
214   const Symbol &symbol{specific.GetUltimate()};
215   if (semantics::IsProcedure(symbol)) {
216     if (symbol.attrs().test(semantics::Attr::ABSTRACT)) {
217       Say("Abstract procedure interface '%s' may not be used as a designator"_err_en_US,
218           last.name());
219     }
220     if (auto *component{std::get_if<Component>(&ref.u)}) {
221       if (!CheckDataRef(ref)) {
222         return std::nullopt;
223       }
224       return Expr<SomeType>{ProcedureDesignator{std::move(*component)}};
225     } else if (!std::holds_alternative<SymbolRef>(ref.u)) {
226       DIE("unexpected alternative in DataRef");
227     } else if (!symbol.attrs().test(semantics::Attr::INTRINSIC)) {
228       if (symbol.has<semantics::GenericDetails>()) {
229         Say("'%s' is not a specific procedure"_err_en_US, last.name());
230       } else if (IsProcedurePointer(specific)) {
231         // For procedure pointers, retain associations so that data accesses
232         // from client modules will work.
233         return Expr<SomeType>{ProcedureDesignator{specific}};
234       } else {
235         return Expr<SomeType>{ProcedureDesignator{symbol}};
236       }
237     } else if (auto interface{context_.intrinsics().IsSpecificIntrinsicFunction(
238                    symbol.name().ToString())};
239                interface && !interface->isRestrictedSpecific) {
240       SpecificIntrinsic intrinsic{
241           symbol.name().ToString(), std::move(*interface)};
242       intrinsic.isRestrictedSpecific = interface->isRestrictedSpecific;
243       return Expr<SomeType>{ProcedureDesignator{std::move(intrinsic)}};
244     } else {
245       Say("'%s' is not an unrestricted specific intrinsic procedure"_err_en_US,
246           last.name());
247     }
248     return std::nullopt;
249   } else if (MaybeExpr result{AsGenericExpr(std::move(ref))}) {
250     return result;
251   } else if (semantics::HadUseError(
252                  context_, GetContextualMessages().at(), &symbol)) {
253     return std::nullopt;
254   } else {
255     if (!context_.HasError(last) && !context_.HasError(symbol)) {
256       AttachDeclaration(
257           Say("'%s' is not an object that can appear in an expression"_err_en_US,
258               last.name()),
259           symbol);
260       context_.SetError(last);
261     }
262     return std::nullopt;
263   }
264 }
265 
266 // Some subscript semantic checks must be deferred until all of the
267 // subscripts are in hand.
268 MaybeExpr ExpressionAnalyzer::CompleteSubscripts(ArrayRef &&ref) {
269   const Symbol &symbol{ref.GetLastSymbol().GetUltimate()};
270   int symbolRank{symbol.Rank()};
271   int subscripts{static_cast<int>(ref.size())};
272   if (subscripts == 0) {
273     return std::nullopt; // error recovery
274   } else if (subscripts != symbolRank) {
275     if (symbolRank != 0) {
276       Say("Reference to rank-%d object '%s' has %d subscripts"_err_en_US,
277           symbolRank, symbol.name(), subscripts);
278     }
279     return std::nullopt;
280   } else if (symbol.has<semantics::ObjectEntityDetails>() ||
281       symbol.has<semantics::AssocEntityDetails>()) {
282     // C928 & C1002
283     if (Triplet *last{std::get_if<Triplet>(&ref.subscript().back().u)}) {
284       if (!last->upper() && IsAssumedSizeArray(symbol)) {
285         Say("Assumed-size array '%s' must have explicit final "
286             "subscript upper bound value"_err_en_US,
287             symbol.name());
288         return std::nullopt;
289       }
290     }
291   } else {
292     // Shouldn't get here from Analyze(ArrayElement) without a valid base,
293     // which, if not an object, must be a construct entity from
294     // SELECT TYPE/RANK or ASSOCIATE.
295     CHECK(symbol.has<semantics::AssocEntityDetails>());
296   }
297   if (!semantics::IsNamedConstant(symbol) && !inDataStmtObject_) {
298     // Subscripts of named constants are checked in folding.
299     // Subscripts of DATA statement objects are checked in data statement
300     // conversion to initializers.
301     CheckSubscripts(ref);
302   }
303   return Designate(DataRef{std::move(ref)});
304 }
305 
306 // Applies subscripts to a data reference.
307 MaybeExpr ExpressionAnalyzer::ApplySubscripts(
308     DataRef &&dataRef, std::vector<Subscript> &&subscripts) {
309   if (subscripts.empty()) {
310     return std::nullopt; // error recovery
311   }
312   return common::visit(
313       common::visitors{
314           [&](SymbolRef &&symbol) {
315             return CompleteSubscripts(ArrayRef{symbol, std::move(subscripts)});
316           },
317           [&](Component &&c) {
318             return CompleteSubscripts(
319                 ArrayRef{std::move(c), std::move(subscripts)});
320           },
321           [&](auto &&) -> MaybeExpr {
322             DIE("bad base for ArrayRef");
323             return std::nullopt;
324           },
325       },
326       std::move(dataRef.u));
327 }
328 
329 void ExpressionAnalyzer::CheckSubscripts(ArrayRef &ref) {
330   // Fold subscript expressions and check for an empty triplet.
331   const Symbol &arraySymbol{ref.base().GetLastSymbol()};
332   Shape lb{GetLBOUNDs(foldingContext_, NamedEntity{arraySymbol})};
333   CHECK(lb.size() >= ref.subscript().size());
334   Shape ub{GetUBOUNDs(foldingContext_, NamedEntity{arraySymbol})};
335   CHECK(ub.size() >= ref.subscript().size());
336   bool anyPossiblyEmptyDim{false};
337   int dim{0};
338   for (Subscript &ss : ref.subscript()) {
339     if (Triplet * triplet{std::get_if<Triplet>(&ss.u)}) {
340       auto expr{Fold(triplet->stride())};
341       auto stride{ToInt64(expr)};
342       triplet->set_stride(std::move(expr));
343       std::optional<ConstantSubscript> lower, upper;
344       if (auto expr{triplet->lower()}) {
345         *expr = Fold(std::move(*expr));
346         lower = ToInt64(*expr);
347         triplet->set_lower(std::move(*expr));
348       } else {
349         lower = ToInt64(lb[dim]);
350       }
351       if (auto expr{triplet->upper()}) {
352         *expr = Fold(std::move(*expr));
353         upper = ToInt64(*expr);
354         triplet->set_upper(std::move(*expr));
355       } else {
356         upper = ToInt64(ub[dim]);
357       }
358       if (stride) {
359         if (*stride == 0) {
360           Say("Stride of triplet must not be zero"_err_en_US);
361           return;
362         }
363         if (lower && upper) {
364           if (*stride > 0) {
365             anyPossiblyEmptyDim |= *lower > *upper;
366           } else {
367             anyPossiblyEmptyDim |= *lower < *upper;
368           }
369         } else {
370           anyPossiblyEmptyDim = true;
371         }
372       } else { // non-constant stride
373         if (lower && upper && *lower == *upper) {
374           // stride is not relevant
375         } else {
376           anyPossiblyEmptyDim = true;
377         }
378       }
379     } else { // not triplet
380       auto &expr{std::get<IndirectSubscriptIntegerExpr>(ss.u).value()};
381       expr = Fold(std::move(expr));
382       anyPossiblyEmptyDim |= expr.Rank() > 0; // vector subscript
383     }
384     ++dim;
385   }
386   if (anyPossiblyEmptyDim) {
387     return;
388   }
389   dim = 0;
390   for (Subscript &ss : ref.subscript()) {
391     auto dimLB{ToInt64(lb[dim])};
392     auto dimUB{ToInt64(ub[dim])};
393     if (dimUB && dimLB && *dimUB < *dimLB) {
394       AttachDeclaration(
395           Warn(common::UsageWarning::SubscriptedEmptyArray,
396               "Empty array dimension %d should not be subscripted as an element or non-empty array section"_err_en_US,
397               dim + 1),
398           arraySymbol);
399       break;
400     }
401     std::optional<ConstantSubscript> val[2];
402     int vals{0};
403     if (auto *triplet{std::get_if<Triplet>(&ss.u)}) {
404       auto stride{ToInt64(triplet->stride())};
405       std::optional<ConstantSubscript> lower, upper;
406       if (const auto *lowerExpr{triplet->GetLower()}) {
407         lower = ToInt64(*lowerExpr);
408       } else if (lb[dim]) {
409         lower = ToInt64(*lb[dim]);
410       }
411       if (const auto *upperExpr{triplet->GetUpper()}) {
412         upper = ToInt64(*upperExpr);
413       } else if (ub[dim]) {
414         upper = ToInt64(*ub[dim]);
415       }
416       if (lower) {
417         val[vals++] = *lower;
418         if (upper && *upper != lower && (stride && *stride != 0)) {
419           // Normalize upper bound for non-unit stride
420           // 1:10:2 -> 1:9:2, 10:1:-2 -> 10:2:-2
421           val[vals++] = *lower + *stride * ((*upper - *lower) / *stride);
422         }
423       }
424     } else {
425       val[vals++] =
426           ToInt64(std::get<IndirectSubscriptIntegerExpr>(ss.u).value());
427     }
428     for (int j{0}; j < vals; ++j) {
429       if (val[j]) {
430         std::optional<parser::MessageFixedText> msg;
431         std::optional<ConstantSubscript> bound;
432         if (dimLB && *val[j] < *dimLB) {
433           msg =
434               "Subscript %jd is less than lower bound %jd for dimension %d of array"_err_en_US;
435           bound = *dimLB;
436         } else if (dimUB && *val[j] > *dimUB) {
437           msg =
438               "Subscript %jd is greater than upper bound %jd for dimension %d of array"_err_en_US;
439           bound = *dimUB;
440           if (dim + 1 == arraySymbol.Rank() && IsDummy(arraySymbol) &&
441               *bound == 1) {
442             // Old-school overindexing of a dummy array isn't fatal when
443             // it's on the last dimension and the extent is 1.
444             msg->set_severity(parser::Severity::Warning);
445           }
446         }
447         if (msg) {
448           AttachDeclaration(
449               Say(std::move(*msg), static_cast<std::intmax_t>(*val[j]),
450                   static_cast<std::intmax_t>(bound.value()), dim + 1),
451               arraySymbol);
452         }
453       }
454     }
455     ++dim;
456   }
457 }
458 
459 // C919a - only one part-ref of a data-ref may have rank > 0
460 bool ExpressionAnalyzer::CheckRanks(const DataRef &dataRef) {
461   return common::visit(
462       common::visitors{
463           [this](const Component &component) {
464             const Symbol &symbol{component.GetLastSymbol()};
465             if (int componentRank{symbol.Rank()}; componentRank > 0) {
466               if (int baseRank{component.base().Rank()}; baseRank > 0) {
467                 Say("Reference to whole rank-%d component '%s' of rank-%d array of derived type is not allowed"_err_en_US,
468                     componentRank, symbol.name(), baseRank);
469                 return false;
470               }
471             } else {
472               return CheckRanks(component.base());
473             }
474             return true;
475           },
476           [this](const ArrayRef &arrayRef) {
477             if (const auto *component{arrayRef.base().UnwrapComponent()}) {
478               int subscriptRank{0};
479               for (const Subscript &subscript : arrayRef.subscript()) {
480                 subscriptRank += subscript.Rank();
481               }
482               if (subscriptRank > 0) {
483                 if (int componentBaseRank{component->base().Rank()};
484                     componentBaseRank > 0) {
485                   Say("Subscripts of component '%s' of rank-%d derived type array have rank %d but must all be scalar"_err_en_US,
486                       component->GetLastSymbol().name(), componentBaseRank,
487                       subscriptRank);
488                   return false;
489                 }
490               } else {
491                 return CheckRanks(component->base());
492               }
493             }
494             return true;
495           },
496           [](const SymbolRef &) { return true; },
497           [](const CoarrayRef &) { return true; },
498       },
499       dataRef.u);
500 }
501 
502 // C911 - if the last name in a data-ref has an abstract derived type,
503 // it must also be polymorphic.
504 bool ExpressionAnalyzer::CheckPolymorphic(const DataRef &dataRef) {
505   if (auto type{DynamicType::From(dataRef.GetLastSymbol())}) {
506     if (type->category() == TypeCategory::Derived && !type->IsPolymorphic()) {
507       const Symbol &typeSymbol{
508           type->GetDerivedTypeSpec().typeSymbol().GetUltimate()};
509       if (typeSymbol.attrs().test(semantics::Attr::ABSTRACT)) {
510         AttachDeclaration(
511             Say("Reference to object with abstract derived type '%s' must be polymorphic"_err_en_US,
512                 typeSymbol.name()),
513             typeSymbol);
514         return false;
515       }
516     }
517   }
518   return true;
519 }
520 
521 bool ExpressionAnalyzer::CheckDataRef(const DataRef &dataRef) {
522   // Always check both, don't short-circuit
523   bool ranksOk{CheckRanks(dataRef)};
524   bool polyOk{CheckPolymorphic(dataRef)};
525   return ranksOk && polyOk;
526 }
527 
528 // Parse tree correction after a substring S(j:k) was misparsed as an
529 // array section.  Fortran substrings must have a range, not a
530 // single index.
531 static std::optional<parser::Substring> FixMisparsedSubstringDataRef(
532     parser::DataRef &dataRef) {
533   if (auto *ae{
534           std::get_if<common::Indirection<parser::ArrayElement>>(&dataRef.u)}) {
535     // ...%a(j:k) and "a" is a character scalar
536     parser::ArrayElement &arrElement{ae->value()};
537     if (arrElement.subscripts.size() == 1) {
538       if (auto *triplet{std::get_if<parser::SubscriptTriplet>(
539               &arrElement.subscripts.front().u)}) {
540         if (!std::get<2 /*stride*/>(triplet->t).has_value()) {
541           if (const Symbol *symbol{
542                   parser::GetLastName(arrElement.base).symbol}) {
543             const Symbol &ultimate{symbol->GetUltimate()};
544             if (const semantics::DeclTypeSpec *type{ultimate.GetType()}) {
545               if (ultimate.Rank() == 0 &&
546                   type->category() == semantics::DeclTypeSpec::Character) {
547                 // The ambiguous S(j:k) was parsed as an array section
548                 // reference, but it's now clear that it's a substring.
549                 // Fix the parse tree in situ.
550                 return arrElement.ConvertToSubstring();
551               }
552             }
553           }
554         }
555       }
556     }
557   }
558   return std::nullopt;
559 }
560 
561 // When a designator is a misparsed type-param-inquiry of a misparsed
562 // substring -- it looks like a structure component reference of an array
563 // slice -- fix the substring and then convert to an intrinsic function
564 // call to KIND() or LEN().  And when the designator is a misparsed
565 // substring, convert it into a substring reference in place.
566 MaybeExpr ExpressionAnalyzer::FixMisparsedSubstring(
567     const parser::Designator &d) {
568   auto &mutate{const_cast<parser::Designator &>(d)};
569   if (auto *dataRef{std::get_if<parser::DataRef>(&mutate.u)}) {
570     if (auto *sc{std::get_if<common::Indirection<parser::StructureComponent>>(
571             &dataRef->u)}) {
572       parser::StructureComponent &structComponent{sc->value()};
573       parser::CharBlock which{structComponent.component.source};
574       if (which == "kind" || which == "len") {
575         if (auto substring{
576                 FixMisparsedSubstringDataRef(structComponent.base)}) {
577           // ...%a(j:k)%kind or %len and "a" is a character scalar
578           mutate.u = std::move(*substring);
579           if (MaybeExpr substringExpr{Analyze(d)}) {
580             return MakeFunctionRef(which,
581                 ActualArguments{ActualArgument{std::move(*substringExpr)}});
582           }
583         }
584       }
585     } else if (auto substring{FixMisparsedSubstringDataRef(*dataRef)}) {
586       mutate.u = std::move(*substring);
587     }
588   }
589   return std::nullopt;
590 }
591 
592 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Designator &d) {
593   auto restorer{GetContextualMessages().SetLocation(d.source)};
594   if (auto substringInquiry{FixMisparsedSubstring(d)}) {
595     return substringInquiry;
596   }
597   // These checks have to be deferred to these "top level" data-refs where
598   // we can be sure that there are no following subscripts (yet).
599   MaybeExpr result{Analyze(d.u)};
600   if (result) {
601     std::optional<DataRef> dataRef{ExtractDataRef(std::move(result))};
602     if (!dataRef) {
603       dataRef = ExtractDataRef(std::move(result), /*intoSubstring=*/true);
604     }
605     if (!dataRef) {
606       dataRef = ExtractDataRef(std::move(result),
607           /*intoSubstring=*/false, /*intoComplexPart=*/true);
608     }
609     if (dataRef && !CheckDataRef(*dataRef)) {
610       result.reset();
611     }
612   }
613   return result;
614 }
615 
616 // A utility subroutine to repackage optional expressions of various levels
617 // of type specificity as fully general MaybeExpr values.
618 template <typename A> common::IfNoLvalue<MaybeExpr, A> AsMaybeExpr(A &&x) {
619   return AsGenericExpr(std::move(x));
620 }
621 template <typename A> MaybeExpr AsMaybeExpr(std::optional<A> &&x) {
622   if (x) {
623     return AsMaybeExpr(std::move(*x));
624   }
625   return std::nullopt;
626 }
627 
628 // Type kind parameter values for literal constants.
629 int ExpressionAnalyzer::AnalyzeKindParam(
630     const std::optional<parser::KindParam> &kindParam, int defaultKind) {
631   if (!kindParam) {
632     return defaultKind;
633   }
634   std::int64_t kind{common::visit(
635       common::visitors{
636           [](std::uint64_t k) { return static_cast<std::int64_t>(k); },
637           [&](const parser::Scalar<
638               parser::Integer<parser::Constant<parser::Name>>> &n) {
639             if (MaybeExpr ie{Analyze(n)}) {
640               return ToInt64(*ie).value_or(defaultKind);
641             }
642             return static_cast<std::int64_t>(defaultKind);
643           },
644       },
645       kindParam->u)};
646   if (kind != static_cast<int>(kind)) {
647     Say("Unsupported type kind value (%jd)"_err_en_US,
648         static_cast<std::intmax_t>(kind));
649     kind = defaultKind;
650   }
651   return static_cast<int>(kind);
652 }
653 
654 // Common handling of parser::IntLiteralConstant, SignedIntLiteralConstant,
655 // and UnsignedLiteralConstant
656 template <typename TYPES, TypeCategory CAT> struct IntTypeVisitor {
657   using Result = MaybeExpr;
658   using Types = TYPES;
659   template <typename T> Result Test() {
660     if (T::kind >= kind) {
661       const char *p{digits.begin()};
662       using Int = typename T::Scalar;
663       typename Int::ValueWithOverflow num{0, false};
664       const char *typeName{
665           CAT == TypeCategory::Integer ? "INTEGER" : "UNSIGNED"};
666       if (isNegated) {
667         auto unsignedNum{Int::Read(p, 10, false /*unsigned*/)};
668         num.value = unsignedNum.value.Negate().value;
669         num.overflow = unsignedNum.overflow ||
670             (CAT == TypeCategory::Integer && num.value > Int{0});
671         if (!num.overflow && num.value.Negate().overflow) {
672           analyzer.Warn(LanguageFeature::BigIntLiterals, digits,
673               "negated maximum INTEGER(KIND=%d) literal"_port_en_US, T::kind);
674         }
675       } else {
676         num = Int::Read(p, 10, /*isSigned=*/CAT == TypeCategory::Integer);
677       }
678       if (num.overflow) {
679         if constexpr (CAT == TypeCategory::Unsigned) {
680           analyzer.Warn(common::UsageWarning::UnsignedLiteralTruncation,
681               "Unsigned literal too large for UNSIGNED(KIND=%d); truncated"_warn_en_US,
682               kind);
683           return Expr<SomeType>{
684               Expr<SomeKind<CAT>>{Expr<T>{Constant<T>{std::move(num.value)}}}};
685         }
686       } else {
687         if (T::kind > kind) {
688           if (!isDefaultKind ||
689               !analyzer.context().IsEnabled(LanguageFeature::BigIntLiterals)) {
690             return std::nullopt;
691           } else {
692             analyzer.Warn(LanguageFeature::BigIntLiterals, digits,
693                 "Integer literal is too large for default %s(KIND=%d); "
694                 "assuming %s(KIND=%d)"_port_en_US,
695                 typeName, kind, typeName, T::kind);
696           }
697         }
698         return Expr<SomeType>{
699             Expr<SomeKind<CAT>>{Expr<T>{Constant<T>{std::move(num.value)}}}};
700       }
701     }
702     return std::nullopt;
703   }
704   ExpressionAnalyzer &analyzer;
705   parser::CharBlock digits;
706   std::int64_t kind;
707   bool isDefaultKind;
708   bool isNegated;
709 };
710 
711 template <typename TYPES, TypeCategory CAT, typename PARSED>
712 MaybeExpr ExpressionAnalyzer::IntLiteralConstant(
713     const PARSED &x, bool isNegated) {
714   const auto &kindParam{std::get<std::optional<parser::KindParam>>(x.t)};
715   bool isDefaultKind{!kindParam};
716   int kind{AnalyzeKindParam(kindParam, GetDefaultKind(CAT))};
717   const char *typeName{CAT == TypeCategory::Integer ? "INTEGER" : "UNSIGNED"};
718   if (CheckIntrinsicKind(CAT, kind)) {
719     auto digits{std::get<parser::CharBlock>(x.t)};
720     if (MaybeExpr result{common::SearchTypes(IntTypeVisitor<TYPES, CAT>{
721             *this, digits, kind, isDefaultKind, isNegated})}) {
722       return result;
723     } else if (isDefaultKind) {
724       Say(digits,
725           "Integer literal is too large for any allowable kind of %s"_err_en_US,
726           typeName);
727     } else {
728       Say(digits, "Integer literal is too large for %s(KIND=%d)"_err_en_US,
729           typeName, kind);
730     }
731   }
732   return std::nullopt;
733 }
734 
735 MaybeExpr ExpressionAnalyzer::Analyze(
736     const parser::IntLiteralConstant &x, bool isNegated) {
737   auto restorer{
738       GetContextualMessages().SetLocation(std::get<parser::CharBlock>(x.t))};
739   return IntLiteralConstant<IntegerTypes, TypeCategory::Integer>(x, isNegated);
740 }
741 
742 MaybeExpr ExpressionAnalyzer::Analyze(
743     const parser::SignedIntLiteralConstant &x) {
744   auto restorer{GetContextualMessages().SetLocation(x.source)};
745   return IntLiteralConstant<IntegerTypes, TypeCategory::Integer>(x);
746 }
747 
748 MaybeExpr ExpressionAnalyzer::Analyze(
749     const parser::UnsignedLiteralConstant &x) {
750   parser::CharBlock at{std::get<parser::CharBlock>(x.t)};
751   auto restorer{GetContextualMessages().SetLocation(at)};
752   if (!context().IsEnabled(common::LanguageFeature::Unsigned) &&
753       !context().AnyFatalError()) {
754     context().Say(
755         at, "-funsigned is required to enable UNSIGNED constants"_err_en_US);
756   }
757   return IntLiteralConstant<UnsignedTypes, TypeCategory::Unsigned>(x);
758 }
759 
760 template <typename TYPE>
761 Constant<TYPE> ReadRealLiteral(
762     parser::CharBlock source, FoldingContext &context) {
763   const char *p{source.begin()};
764   auto valWithFlags{
765       Scalar<TYPE>::Read(p, context.targetCharacteristics().roundingMode())};
766   CHECK(p == source.end());
767   RealFlagWarnings(context, valWithFlags.flags, "conversion of REAL literal");
768   auto value{valWithFlags.value};
769   if (context.targetCharacteristics().areSubnormalsFlushedToZero()) {
770     value = value.FlushSubnormalToZero();
771   }
772   return {value};
773 }
774 
775 struct RealTypeVisitor {
776   using Result = std::optional<Expr<SomeReal>>;
777   using Types = RealTypes;
778 
779   RealTypeVisitor(int k, parser::CharBlock lit, FoldingContext &ctx)
780       : kind{k}, literal{lit}, context{ctx} {}
781 
782   template <typename T> Result Test() {
783     if (kind == T::kind) {
784       return {AsCategoryExpr(ReadRealLiteral<T>(literal, context))};
785     }
786     return std::nullopt;
787   }
788 
789   int kind;
790   parser::CharBlock literal;
791   FoldingContext &context;
792 };
793 
794 // Reads a real literal constant and encodes it with the right kind.
795 MaybeExpr ExpressionAnalyzer::Analyze(const parser::RealLiteralConstant &x) {
796   // Use a local message context around the real literal for better
797   // provenance on any messages.
798   auto restorer{GetContextualMessages().SetLocation(x.real.source)};
799   // If a kind parameter appears, it defines the kind of the literal and the
800   // letter used in an exponent part must be 'E' (e.g., the 'E' in
801   // "6.02214E+23").  In the absence of an explicit kind parameter, any
802   // exponent letter determines the kind.  Otherwise, defaults apply.
803   auto &defaults{context_.defaultKinds()};
804   int defaultKind{defaults.GetDefaultKind(TypeCategory::Real)};
805   const char *end{x.real.source.end()};
806   char expoLetter{' '};
807   std::optional<int> letterKind;
808   for (const char *p{x.real.source.begin()}; p < end; ++p) {
809     if (parser::IsLetter(*p)) {
810       expoLetter = *p;
811       switch (expoLetter) {
812       case 'e':
813         letterKind = defaults.GetDefaultKind(TypeCategory::Real);
814         break;
815       case 'd':
816         letterKind = defaults.doublePrecisionKind();
817         break;
818       case 'q':
819         letterKind = defaults.quadPrecisionKind();
820         break;
821       default:
822         Say("Unknown exponent letter '%c'"_err_en_US, expoLetter);
823       }
824       break;
825     }
826   }
827   if (letterKind) {
828     defaultKind = *letterKind;
829   }
830   // C716 requires 'E' as an exponent.
831   // Extension: allow exponent-letter matching the kind-param.
832   auto kind{AnalyzeKindParam(x.kind, defaultKind)};
833   if (letterKind && expoLetter != 'e') {
834     if (kind != *letterKind) {
835       Warn(common::LanguageFeature::ExponentMatchingKindParam,
836           "Explicit kind parameter on real constant disagrees with exponent letter '%c'"_warn_en_US,
837           expoLetter);
838     } else if (x.kind) {
839       Warn(common::LanguageFeature::ExponentMatchingKindParam,
840           "Explicit kind parameter together with non-'E' exponent letter is not standard"_port_en_US);
841     }
842   }
843   auto result{common::SearchTypes(
844       RealTypeVisitor{kind, x.real.source, GetFoldingContext()})};
845   if (!result) { // C717
846     Say("Unsupported REAL(KIND=%d)"_err_en_US, kind);
847   }
848   return AsMaybeExpr(std::move(result));
849 }
850 
851 MaybeExpr ExpressionAnalyzer::Analyze(
852     const parser::SignedRealLiteralConstant &x) {
853   if (auto result{Analyze(std::get<parser::RealLiteralConstant>(x.t))}) {
854     auto &realExpr{std::get<Expr<SomeReal>>(result->u)};
855     if (auto sign{std::get<std::optional<parser::Sign>>(x.t)}) {
856       if (sign == parser::Sign::Negative) {
857         return AsGenericExpr(-std::move(realExpr));
858       }
859     }
860     return result;
861   }
862   return std::nullopt;
863 }
864 
865 MaybeExpr ExpressionAnalyzer::Analyze(
866     const parser::SignedComplexLiteralConstant &x) {
867   auto result{Analyze(std::get<parser::ComplexLiteralConstant>(x.t))};
868   if (!result) {
869     return std::nullopt;
870   } else if (std::get<parser::Sign>(x.t) == parser::Sign::Negative) {
871     return AsGenericExpr(-std::move(std::get<Expr<SomeComplex>>(result->u)));
872   } else {
873     return result;
874   }
875 }
876 
877 MaybeExpr ExpressionAnalyzer::Analyze(const parser::ComplexPart &x) {
878   return Analyze(x.u);
879 }
880 
881 MaybeExpr ExpressionAnalyzer::Analyze(const parser::ComplexLiteralConstant &z) {
882   return AnalyzeComplex(Analyze(std::get<0>(z.t)), Analyze(std::get<1>(z.t)),
883       "complex literal constant");
884 }
885 
886 // CHARACTER literal processing.
887 MaybeExpr ExpressionAnalyzer::AnalyzeString(std::string &&string, int kind) {
888   if (!CheckIntrinsicKind(TypeCategory::Character, kind)) {
889     return std::nullopt;
890   }
891   switch (kind) {
892   case 1:
893     return AsGenericExpr(Constant<Type<TypeCategory::Character, 1>>{
894         parser::DecodeString<std::string, parser::Encoding::LATIN_1>(
895             string, true)});
896   case 2:
897     return AsGenericExpr(Constant<Type<TypeCategory::Character, 2>>{
898         parser::DecodeString<std::u16string, parser::Encoding::UTF_8>(
899             string, true)});
900   case 4:
901     return AsGenericExpr(Constant<Type<TypeCategory::Character, 4>>{
902         parser::DecodeString<std::u32string, parser::Encoding::UTF_8>(
903             string, true)});
904   default:
905     CRASH_NO_CASE;
906   }
907 }
908 
909 MaybeExpr ExpressionAnalyzer::Analyze(const parser::CharLiteralConstant &x) {
910   int kind{
911       AnalyzeKindParam(std::get<std::optional<parser::KindParam>>(x.t), 1)};
912   auto value{std::get<std::string>(x.t)};
913   return AnalyzeString(std::move(value), kind);
914 }
915 
916 MaybeExpr ExpressionAnalyzer::Analyze(
917     const parser::HollerithLiteralConstant &x) {
918   int kind{GetDefaultKind(TypeCategory::Character)};
919   auto result{AnalyzeString(std::string{x.v}, kind)};
920   if (auto *constant{UnwrapConstantValue<Ascii>(result)}) {
921     constant->set_wasHollerith(true);
922   }
923   return result;
924 }
925 
926 // .TRUE. and .FALSE. of various kinds
927 MaybeExpr ExpressionAnalyzer::Analyze(const parser::LogicalLiteralConstant &x) {
928   auto kind{AnalyzeKindParam(std::get<std::optional<parser::KindParam>>(x.t),
929       GetDefaultKind(TypeCategory::Logical))};
930   bool value{std::get<bool>(x.t)};
931   auto result{common::SearchTypes(
932       TypeKindVisitor<TypeCategory::Logical, Constant, bool>{
933           kind, std::move(value)})};
934   if (!result) {
935     Say("unsupported LOGICAL(KIND=%d)"_err_en_US, kind); // C728
936   }
937   return result;
938 }
939 
940 // BOZ typeless literals
941 MaybeExpr ExpressionAnalyzer::Analyze(const parser::BOZLiteralConstant &x) {
942   const char *p{x.v.c_str()};
943   std::uint64_t base{16};
944   switch (*p++) {
945   case 'b':
946     base = 2;
947     break;
948   case 'o':
949     base = 8;
950     break;
951   case 'z':
952     break;
953   case 'x':
954     break;
955   default:
956     CRASH_NO_CASE;
957   }
958   CHECK(*p == '"');
959   ++p;
960   auto value{BOZLiteralConstant::Read(p, base, false /*unsigned*/)};
961   if (*p != '"') {
962     Say("Invalid digit ('%c') in BOZ literal '%s'"_err_en_US, *p,
963         x.v); // C7107, C7108
964     return std::nullopt;
965   }
966   if (value.overflow) {
967     Say("BOZ literal '%s' too large"_err_en_US, x.v);
968     return std::nullopt;
969   }
970   return AsGenericExpr(std::move(value.value));
971 }
972 
973 // Names and named constants
974 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Name &n) {
975   auto restorer{GetContextualMessages().SetLocation(n.source)};
976   if (std::optional<int> kind{IsImpliedDo(n.source)}) {
977     return AsMaybeExpr(ConvertToKind<TypeCategory::Integer>(
978         *kind, AsExpr(ImpliedDoIndex{n.source})));
979   }
980   if (context_.HasError(n.symbol)) { // includes case of no symbol
981     return std::nullopt;
982   } else {
983     const Symbol &ultimate{n.symbol->GetUltimate()};
984     if (ultimate.has<semantics::TypeParamDetails>()) {
985       // A bare reference to a derived type parameter within a parameterized
986       // derived type definition.
987       auto dyType{DynamicType::From(ultimate)};
988       if (!dyType) {
989         // When the integer kind of this type parameter is not known now,
990         // it's either an error or because it depends on earlier-declared kind
991         // type parameters.  So assume that it's a subscript integer for now
992         // while processing other specification expressions in the PDT
993         // definition; the right kind value will be used later in each of its
994         // instantiations.
995         int kind{SubscriptInteger::kind};
996         if (const auto *typeSpec{ultimate.GetType()}) {
997           if (const semantics::IntrinsicTypeSpec *
998               intrinType{typeSpec->AsIntrinsic()}) {
999             if (auto k{ToInt64(Fold(semantics::KindExpr{intrinType->kind()}))};
1000                 k && IsValidKindOfIntrinsicType(TypeCategory::Integer, *k)) {
1001               kind = *k;
1002             }
1003           }
1004         }
1005         dyType = DynamicType{TypeCategory::Integer, kind};
1006       }
1007       return Fold(ConvertToType(
1008           *dyType, AsGenericExpr(TypeParamInquiry{std::nullopt, ultimate})));
1009     } else {
1010       if (n.symbol->attrs().test(semantics::Attr::VOLATILE)) {
1011         if (const semantics::Scope *pure{semantics::FindPureProcedureContaining(
1012                 context_.FindScope(n.source))}) {
1013           SayAt(n,
1014               "VOLATILE variable '%s' may not be referenced in pure subprogram '%s'"_err_en_US,
1015               n.source, DEREF(pure->symbol()).name());
1016           n.symbol->attrs().reset(semantics::Attr::VOLATILE);
1017         }
1018       }
1019       if (!isWholeAssumedSizeArrayOk_ &&
1020           semantics::IsAssumedSizeArray(
1021               ResolveAssociations(*n.symbol))) { // C1002, C1014, C1231
1022         AttachDeclaration(
1023             SayAt(n,
1024                 "Whole assumed-size array '%s' may not appear here without subscripts"_err_en_US,
1025                 n.source),
1026             *n.symbol);
1027       }
1028       return Designate(DataRef{*n.symbol});
1029     }
1030   }
1031 }
1032 
1033 MaybeExpr ExpressionAnalyzer::Analyze(const parser::NamedConstant &n) {
1034   auto restorer{GetContextualMessages().SetLocation(n.v.source)};
1035   if (MaybeExpr value{Analyze(n.v)}) {
1036     Expr<SomeType> folded{Fold(std::move(*value))};
1037     if (IsConstantExpr(folded)) {
1038       return folded;
1039     }
1040     Say(n.v.source, "must be a constant"_err_en_US); // C718
1041   }
1042   return std::nullopt;
1043 }
1044 
1045 MaybeExpr ExpressionAnalyzer::Analyze(const parser::NullInit &n) {
1046   auto restorer{AllowNullPointer()};
1047   if (MaybeExpr value{Analyze(n.v.value())}) {
1048     // Subtle: when the NullInit is a DataStmtConstant, it might
1049     // be a misparse of a structure constructor without parameters
1050     // or components (e.g., T()).  Checking the result to ensure
1051     // that a "=>" data entity initializer actually resolved to
1052     // a null pointer has to be done by the caller.
1053     return Fold(std::move(*value));
1054   }
1055   return std::nullopt;
1056 }
1057 
1058 MaybeExpr ExpressionAnalyzer::Analyze(
1059     const parser::StmtFunctionStmt &stmtFunc) {
1060   inStmtFunctionDefinition_ = true;
1061   return Analyze(std::get<parser::Scalar<parser::Expr>>(stmtFunc.t));
1062 }
1063 
1064 MaybeExpr ExpressionAnalyzer::Analyze(const parser::InitialDataTarget &x) {
1065   return Analyze(x.value());
1066 }
1067 
1068 MaybeExpr ExpressionAnalyzer::Analyze(const parser::DataStmtValue &x) {
1069   if (const auto &repeat{
1070           std::get<std::optional<parser::DataStmtRepeat>>(x.t)}) {
1071     x.repetitions = -1;
1072     if (MaybeExpr expr{Analyze(repeat->u)}) {
1073       Expr<SomeType> folded{Fold(std::move(*expr))};
1074       if (auto value{ToInt64(folded)}) {
1075         if (*value >= 0) { // C882
1076           x.repetitions = *value;
1077         } else {
1078           Say(FindSourceLocation(repeat),
1079               "Repeat count (%jd) for data value must not be negative"_err_en_US,
1080               *value);
1081         }
1082       }
1083     }
1084   }
1085   return Analyze(std::get<parser::DataStmtConstant>(x.t));
1086 }
1087 
1088 // Substring references
1089 std::optional<Expr<SubscriptInteger>> ExpressionAnalyzer::GetSubstringBound(
1090     const std::optional<parser::ScalarIntExpr> &bound) {
1091   if (bound) {
1092     if (MaybeExpr expr{Analyze(*bound)}) {
1093       if (expr->Rank() > 1) {
1094         Say("substring bound expression has rank %d"_err_en_US, expr->Rank());
1095       }
1096       if (auto *intExpr{std::get_if<Expr<SomeInteger>>(&expr->u)}) {
1097         if (auto *ssIntExpr{std::get_if<Expr<SubscriptInteger>>(&intExpr->u)}) {
1098           return {std::move(*ssIntExpr)};
1099         }
1100         return {Expr<SubscriptInteger>{
1101             Convert<SubscriptInteger, TypeCategory::Integer>{
1102                 std::move(*intExpr)}}};
1103       } else {
1104         Say("substring bound expression is not INTEGER"_err_en_US);
1105       }
1106     }
1107   }
1108   return std::nullopt;
1109 }
1110 
1111 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Substring &ss) {
1112   if (MaybeExpr baseExpr{Analyze(std::get<parser::DataRef>(ss.t))}) {
1113     if (std::optional<DataRef> dataRef{ExtractDataRef(std::move(*baseExpr))}) {
1114       if (MaybeExpr newBaseExpr{Designate(std::move(*dataRef))}) {
1115         if (std::optional<DataRef> checked{
1116                 ExtractDataRef(std::move(*newBaseExpr))}) {
1117           const parser::SubstringRange &range{
1118               std::get<parser::SubstringRange>(ss.t)};
1119           std::optional<Expr<SubscriptInteger>> first{
1120               Fold(GetSubstringBound(std::get<0>(range.t)))};
1121           std::optional<Expr<SubscriptInteger>> last{
1122               Fold(GetSubstringBound(std::get<1>(range.t)))};
1123           const Symbol &symbol{checked->GetLastSymbol()};
1124           if (std::optional<DynamicType> dynamicType{
1125                   DynamicType::From(symbol)}) {
1126             if (dynamicType->category() == TypeCategory::Character) {
1127               auto lbValue{ToInt64(first)};
1128               if (!lbValue) {
1129                 lbValue = 1;
1130               }
1131               auto ubValue{ToInt64(last)};
1132               auto len{dynamicType->knownLength()};
1133               if (!ubValue) {
1134                 ubValue = len;
1135               }
1136               if (lbValue && ubValue && *lbValue > *ubValue) {
1137                 // valid, substring is empty
1138               } else if (lbValue && *lbValue < 1 && (ubValue || !last)) {
1139                 Say("Substring must begin at 1 or later, not %jd"_err_en_US,
1140                     static_cast<std::intmax_t>(*lbValue));
1141                 return std::nullopt;
1142               } else if (ubValue && len && *ubValue > *len &&
1143                   (lbValue || !first)) {
1144                 Say("Substring must end at %zd or earlier, not %jd"_err_en_US,
1145                     static_cast<std::intmax_t>(*len),
1146                     static_cast<std::intmax_t>(*ubValue));
1147                 return std::nullopt;
1148               }
1149               return WrapperHelper<TypeCategory::Character, Designator,
1150                   Substring>(dynamicType->kind(),
1151                   Substring{std::move(checked.value()), std::move(first),
1152                       std::move(last)});
1153             }
1154           }
1155           Say("substring may apply only to CHARACTER"_err_en_US);
1156         }
1157       }
1158     }
1159   }
1160   return std::nullopt;
1161 }
1162 
1163 // CHARACTER literal substrings
1164 MaybeExpr ExpressionAnalyzer::Analyze(
1165     const parser::CharLiteralConstantSubstring &x) {
1166   const parser::SubstringRange &range{std::get<parser::SubstringRange>(x.t)};
1167   std::optional<Expr<SubscriptInteger>> lower{
1168       GetSubstringBound(std::get<0>(range.t))};
1169   std::optional<Expr<SubscriptInteger>> upper{
1170       GetSubstringBound(std::get<1>(range.t))};
1171   if (MaybeExpr string{Analyze(std::get<parser::CharLiteralConstant>(x.t))}) {
1172     if (auto *charExpr{std::get_if<Expr<SomeCharacter>>(&string->u)}) {
1173       Expr<SubscriptInteger> length{
1174           common::visit([](const auto &ckExpr) { return ckExpr.LEN().value(); },
1175               charExpr->u)};
1176       if (!lower) {
1177         lower = Expr<SubscriptInteger>{1};
1178       }
1179       if (!upper) {
1180         upper = Expr<SubscriptInteger>{
1181             static_cast<std::int64_t>(ToInt64(length).value())};
1182       }
1183       return common::visit(
1184           [&](auto &&ckExpr) -> MaybeExpr {
1185             using Result = ResultType<decltype(ckExpr)>;
1186             auto *cp{std::get_if<Constant<Result>>(&ckExpr.u)};
1187             CHECK(DEREF(cp).size() == 1);
1188             StaticDataObject::Pointer staticData{StaticDataObject::Create()};
1189             staticData->set_alignment(Result::kind)
1190                 .set_itemBytes(Result::kind)
1191                 .Push(cp->GetScalarValue().value(),
1192                     foldingContext_.targetCharacteristics().isBigEndian());
1193             Substring substring{std::move(staticData), std::move(lower.value()),
1194                 std::move(upper.value())};
1195             return AsGenericExpr(
1196                 Expr<Result>{Designator<Result>{std::move(substring)}});
1197           },
1198           std::move(charExpr->u));
1199     }
1200   }
1201   return std::nullopt;
1202 }
1203 
1204 // substring%KIND/LEN
1205 MaybeExpr ExpressionAnalyzer::Analyze(const parser::SubstringInquiry &x) {
1206   if (MaybeExpr substring{Analyze(x.v)}) {
1207     CHECK(x.source.size() >= 8);
1208     int nameLen{x.source.end()[-1] == 'n' ? 3 /*LEN*/ : 4 /*KIND*/};
1209     parser::CharBlock name{
1210         x.source.end() - nameLen, static_cast<std::size_t>(nameLen)};
1211     CHECK(name == "len" || name == "kind");
1212     return MakeFunctionRef(
1213         name, ActualArguments{ActualArgument{std::move(*substring)}});
1214   } else {
1215     return std::nullopt;
1216   }
1217 }
1218 
1219 // Subscripted array references
1220 std::optional<Expr<SubscriptInteger>> ExpressionAnalyzer::AsSubscript(
1221     MaybeExpr &&expr) {
1222   if (expr) {
1223     if (expr->Rank() > 1) {
1224       Say("Subscript expression has rank %d greater than 1"_err_en_US,
1225           expr->Rank());
1226     }
1227     if (auto *intExpr{std::get_if<Expr<SomeInteger>>(&expr->u)}) {
1228       if (auto *ssIntExpr{std::get_if<Expr<SubscriptInteger>>(&intExpr->u)}) {
1229         return std::move(*ssIntExpr);
1230       } else {
1231         return Expr<SubscriptInteger>{
1232             Convert<SubscriptInteger, TypeCategory::Integer>{
1233                 std::move(*intExpr)}};
1234       }
1235     } else {
1236       Say("Subscript expression is not INTEGER"_err_en_US);
1237     }
1238   }
1239   return std::nullopt;
1240 }
1241 
1242 std::optional<Expr<SubscriptInteger>> ExpressionAnalyzer::TripletPart(
1243     const std::optional<parser::Subscript> &s) {
1244   if (s) {
1245     return AsSubscript(Analyze(*s));
1246   } else {
1247     return std::nullopt;
1248   }
1249 }
1250 
1251 std::optional<Subscript> ExpressionAnalyzer::AnalyzeSectionSubscript(
1252     const parser::SectionSubscript &ss) {
1253   return common::visit(
1254       common::visitors{
1255           [&](const parser::SubscriptTriplet &t) -> std::optional<Subscript> {
1256             const auto &lower{std::get<0>(t.t)};
1257             const auto &upper{std::get<1>(t.t)};
1258             const auto &stride{std::get<2>(t.t)};
1259             auto result{Triplet{
1260                 TripletPart(lower), TripletPart(upper), TripletPart(stride)}};
1261             if ((lower && !result.lower()) || (upper && !result.upper())) {
1262               return std::nullopt;
1263             } else {
1264               return std::make_optional<Subscript>(result);
1265             }
1266           },
1267           [&](const auto &s) -> std::optional<Subscript> {
1268             if (auto subscriptExpr{AsSubscript(Analyze(s))}) {
1269               return Subscript{std::move(*subscriptExpr)};
1270             } else {
1271               return std::nullopt;
1272             }
1273           },
1274       },
1275       ss.u);
1276 }
1277 
1278 // Empty result means an error occurred
1279 std::vector<Subscript> ExpressionAnalyzer::AnalyzeSectionSubscripts(
1280     const std::list<parser::SectionSubscript> &sss) {
1281   bool error{false};
1282   std::vector<Subscript> subscripts;
1283   for (const auto &s : sss) {
1284     if (auto subscript{AnalyzeSectionSubscript(s)}) {
1285       subscripts.emplace_back(std::move(*subscript));
1286     } else {
1287       error = true;
1288     }
1289   }
1290   return !error ? subscripts : std::vector<Subscript>{};
1291 }
1292 
1293 MaybeExpr ExpressionAnalyzer::Analyze(const parser::ArrayElement &ae) {
1294   MaybeExpr baseExpr;
1295   {
1296     auto restorer{AllowWholeAssumedSizeArray()};
1297     baseExpr = Analyze(ae.base);
1298   }
1299   if (baseExpr) {
1300     if (ae.subscripts.empty()) {
1301       // will be converted to function call later or error reported
1302     } else if (baseExpr->Rank() == 0) {
1303       if (const Symbol *symbol{GetLastSymbol(*baseExpr)}) {
1304         if (!context_.HasError(symbol)) {
1305           if (inDataStmtConstant_) {
1306             // Better error for NULL(X) with a MOLD= argument
1307             Say("'%s' must be an array or structure constructor if used with non-empty parentheses as a DATA statement constant"_err_en_US,
1308                 symbol->name());
1309           } else {
1310             Say("'%s' is not an array"_err_en_US, symbol->name());
1311           }
1312           context_.SetError(*symbol);
1313         }
1314       }
1315     } else if (std::optional<DataRef> dataRef{
1316                    ExtractDataRef(std::move(*baseExpr))}) {
1317       return ApplySubscripts(
1318           std::move(*dataRef), AnalyzeSectionSubscripts(ae.subscripts));
1319     } else {
1320       Say("Subscripts may be applied only to an object, component, or array constant"_err_en_US);
1321     }
1322   }
1323   // error was reported: analyze subscripts without reporting more errors
1324   auto restorer{GetContextualMessages().DiscardMessages()};
1325   AnalyzeSectionSubscripts(ae.subscripts);
1326   return std::nullopt;
1327 }
1328 
1329 // Type parameter inquiries apply to data references, but don't depend
1330 // on any trailing (co)subscripts.
1331 static NamedEntity IgnoreAnySubscripts(Designator<SomeDerived> &&designator) {
1332   return common::visit(
1333       common::visitors{
1334           [](SymbolRef &&symbol) { return NamedEntity{symbol}; },
1335           [](Component &&component) {
1336             return NamedEntity{std::move(component)};
1337           },
1338           [](ArrayRef &&arrayRef) { return std::move(arrayRef.base()); },
1339           [](CoarrayRef &&coarrayRef) {
1340             return NamedEntity{coarrayRef.GetLastSymbol()};
1341           },
1342       },
1343       std::move(designator.u));
1344 }
1345 
1346 // Components, but not bindings, of parent derived types are explicitly
1347 // represented as such.
1348 std::optional<Component> ExpressionAnalyzer::CreateComponent(DataRef &&base,
1349     const Symbol &component, const semantics::Scope &scope,
1350     bool C919bAlreadyEnforced) {
1351   if (!C919bAlreadyEnforced && IsAllocatableOrPointer(component) &&
1352       base.Rank() > 0) { // C919b
1353     Say("An allocatable or pointer component reference must be applied to a scalar base"_err_en_US);
1354   }
1355   if (&component.owner() == &scope ||
1356       component.has<semantics::ProcBindingDetails>()) {
1357     return Component{std::move(base), component};
1358   }
1359   if (const Symbol *typeSymbol{scope.GetSymbol()}) {
1360     if (const Symbol *parentComponent{typeSymbol->GetParentComponent(&scope)}) {
1361       if (const auto *object{
1362               parentComponent->detailsIf<semantics::ObjectEntityDetails>()}) {
1363         if (const auto *parentType{object->type()}) {
1364           if (const semantics::Scope *parentScope{
1365                   parentType->derivedTypeSpec().scope()}) {
1366             return CreateComponent(
1367                 DataRef{Component{std::move(base), *parentComponent}},
1368                 component, *parentScope, C919bAlreadyEnforced);
1369           }
1370         }
1371       }
1372     }
1373   }
1374   return std::nullopt;
1375 }
1376 
1377 // Derived type component references and type parameter inquiries
1378 MaybeExpr ExpressionAnalyzer::Analyze(const parser::StructureComponent &sc) {
1379   Symbol *sym{sc.component.symbol};
1380   if (context_.HasError(sym)) {
1381     return std::nullopt;
1382   }
1383   const auto *misc{sym->detailsIf<semantics::MiscDetails>()};
1384   bool isTypeParamInquiry{sym->has<semantics::TypeParamDetails>() ||
1385       (misc &&
1386           (misc->kind() == semantics::MiscDetails::Kind::KindParamInquiry ||
1387               misc->kind() == semantics::MiscDetails::Kind::LenParamInquiry))};
1388   MaybeExpr base;
1389   if (isTypeParamInquiry) {
1390     auto restorer{AllowWholeAssumedSizeArray()};
1391     base = Analyze(sc.base);
1392   } else {
1393     base = Analyze(sc.base);
1394   }
1395   if (!base) {
1396     return std::nullopt;
1397   }
1398   const auto &name{sc.component.source};
1399   if (auto *dtExpr{UnwrapExpr<Expr<SomeDerived>>(*base)}) {
1400     const auto *dtSpec{GetDerivedTypeSpec(dtExpr->GetType())};
1401     if (isTypeParamInquiry) {
1402       if (auto *designator{UnwrapExpr<Designator<SomeDerived>>(*dtExpr)}) {
1403         if (std::optional<DynamicType> dyType{DynamicType::From(*sym)}) {
1404           if (dyType->category() == TypeCategory::Integer) {
1405             auto restorer{GetContextualMessages().SetLocation(name)};
1406             return Fold(ConvertToType(*dyType,
1407                 AsGenericExpr(TypeParamInquiry{
1408                     IgnoreAnySubscripts(std::move(*designator)), *sym})));
1409           }
1410         }
1411         Say(name, "Type parameter is not INTEGER"_err_en_US);
1412       } else {
1413         Say(name,
1414             "A type parameter inquiry must be applied to a designator"_err_en_US);
1415       }
1416     } else if (!dtSpec || !dtSpec->scope()) {
1417       CHECK(context_.AnyFatalError() || !foldingContext_.messages().empty());
1418       return std::nullopt;
1419     } else if (std::optional<DataRef> dataRef{
1420                    ExtractDataRef(std::move(*dtExpr))}) {
1421       auto restorer{GetContextualMessages().SetLocation(name)};
1422       if (auto component{
1423               CreateComponent(std::move(*dataRef), *sym, *dtSpec->scope())}) {
1424         return Designate(DataRef{std::move(*component)});
1425       } else {
1426         Say(name, "Component is not in scope of derived TYPE(%s)"_err_en_US,
1427             dtSpec->typeSymbol().name());
1428       }
1429     } else {
1430       Say(name,
1431           "Base of component reference must be a data reference"_err_en_US);
1432     }
1433   } else if (auto *details{sym->detailsIf<semantics::MiscDetails>()}) {
1434     // special part-ref: %re, %im, %kind, %len
1435     // Type errors on the base of %re/%im/%len are detected and
1436     // reported in name resolution.
1437     using MiscKind = semantics::MiscDetails::Kind;
1438     MiscKind kind{details->kind()};
1439     if (kind == MiscKind::ComplexPartRe || kind == MiscKind::ComplexPartIm) {
1440       if (auto *zExpr{std::get_if<Expr<SomeComplex>>(&base->u)}) {
1441         if (std::optional<DataRef> dataRef{ExtractDataRef(*zExpr)}) {
1442           // Represent %RE/%IM as a designator
1443           Expr<SomeReal> realExpr{common::visit(
1444               [&](const auto &z) {
1445                 using PartType = typename ResultType<decltype(z)>::Part;
1446                 auto part{kind == MiscKind::ComplexPartRe
1447                         ? ComplexPart::Part::RE
1448                         : ComplexPart::Part::IM};
1449                 return AsCategoryExpr(Designator<PartType>{
1450                     ComplexPart{std::move(*dataRef), part}});
1451               },
1452               zExpr->u)};
1453           return AsGenericExpr(std::move(realExpr));
1454         }
1455       }
1456     } else if (isTypeParamInquiry) { // %kind or %len
1457       ActualArgument arg{std::move(*base)};
1458       SetArgSourceLocation(arg, name);
1459       return MakeFunctionRef(name, ActualArguments{std::move(arg)});
1460     } else {
1461       DIE("unexpected MiscDetails::Kind");
1462     }
1463   } else {
1464     Say(name, "derived type required before component reference"_err_en_US);
1465   }
1466   return std::nullopt;
1467 }
1468 
1469 MaybeExpr ExpressionAnalyzer::Analyze(const parser::CoindexedNamedObject &x) {
1470   if (auto maybeDataRef{ExtractDataRef(Analyze(x.base))}) {
1471     DataRef *dataRef{&*maybeDataRef};
1472     std::vector<Subscript> subscripts;
1473     SymbolVector reversed;
1474     if (auto *aRef{std::get_if<ArrayRef>(&dataRef->u)}) {
1475       subscripts = std::move(aRef->subscript());
1476       reversed.push_back(aRef->GetLastSymbol());
1477       if (Component *component{aRef->base().UnwrapComponent()}) {
1478         dataRef = &component->base();
1479       } else {
1480         dataRef = nullptr;
1481       }
1482     }
1483     if (dataRef) {
1484       while (auto *component{std::get_if<Component>(&dataRef->u)}) {
1485         reversed.push_back(component->GetLastSymbol());
1486         dataRef = &component->base();
1487       }
1488       if (auto *baseSym{std::get_if<SymbolRef>(&dataRef->u)}) {
1489         reversed.push_back(*baseSym);
1490       } else {
1491         Say("Base of coindexed named object has subscripts or cosubscripts"_err_en_US);
1492       }
1493     }
1494     std::vector<Expr<SubscriptInteger>> cosubscripts;
1495     bool cosubsOk{true};
1496     for (const auto &cosub :
1497         std::get<std::list<parser::Cosubscript>>(x.imageSelector.t)) {
1498       MaybeExpr coex{Analyze(cosub)};
1499       if (auto *intExpr{UnwrapExpr<Expr<SomeInteger>>(coex)}) {
1500         cosubscripts.push_back(
1501             ConvertToType<SubscriptInteger>(std::move(*intExpr)));
1502       } else {
1503         cosubsOk = false;
1504       }
1505     }
1506     if (cosubsOk && !reversed.empty()) {
1507       int numCosubscripts{static_cast<int>(cosubscripts.size())};
1508       const Symbol &symbol{reversed.front()};
1509       if (numCosubscripts != GetCorank(symbol)) {
1510         Say("'%s' has corank %d, but coindexed reference has %d cosubscripts"_err_en_US,
1511             symbol.name(), GetCorank(symbol), numCosubscripts);
1512       }
1513     }
1514     for (const auto &imageSelSpec :
1515         std::get<std::list<parser::ImageSelectorSpec>>(x.imageSelector.t)) {
1516       common::visit(
1517           common::visitors{
1518               [&](const auto &x) { Analyze(x.v); },
1519           },
1520           imageSelSpec.u);
1521     }
1522     // Reverse the chain of symbols so that the base is first and coarray
1523     // ultimate component is last.
1524     if (cosubsOk) {
1525       return Designate(
1526           DataRef{CoarrayRef{SymbolVector{reversed.crbegin(), reversed.crend()},
1527               std::move(subscripts), std::move(cosubscripts)}});
1528     }
1529   }
1530   return std::nullopt;
1531 }
1532 
1533 int ExpressionAnalyzer::IntegerTypeSpecKind(
1534     const parser::IntegerTypeSpec &spec) {
1535   Expr<SubscriptInteger> value{
1536       AnalyzeKindSelector(TypeCategory::Integer, spec.v)};
1537   if (auto kind{ToInt64(value)}) {
1538     return static_cast<int>(*kind);
1539   }
1540   SayAt(spec, "Constant INTEGER kind value required here"_err_en_US);
1541   return GetDefaultKind(TypeCategory::Integer);
1542 }
1543 
1544 // Array constructors
1545 
1546 // Inverts a collection of generic ArrayConstructorValues<SomeType> that
1547 // all happen to have the same actual type T into one ArrayConstructor<T>.
1548 template <typename T>
1549 ArrayConstructorValues<T> MakeSpecific(
1550     ArrayConstructorValues<SomeType> &&from) {
1551   ArrayConstructorValues<T> to;
1552   for (ArrayConstructorValue<SomeType> &x : from) {
1553     common::visit(
1554         common::visitors{
1555             [&](common::CopyableIndirection<Expr<SomeType>> &&expr) {
1556               auto *typed{UnwrapExpr<Expr<T>>(expr.value())};
1557               to.Push(std::move(DEREF(typed)));
1558             },
1559             [&](ImpliedDo<SomeType> &&impliedDo) {
1560               to.Push(ImpliedDo<T>{impliedDo.name(),
1561                   std::move(impliedDo.lower()), std::move(impliedDo.upper()),
1562                   std::move(impliedDo.stride()),
1563                   MakeSpecific<T>(std::move(impliedDo.values()))});
1564             },
1565         },
1566         std::move(x.u));
1567   }
1568   return to;
1569 }
1570 
1571 class ArrayConstructorContext {
1572 public:
1573   ArrayConstructorContext(
1574       ExpressionAnalyzer &c, std::optional<DynamicTypeWithLength> &&t)
1575       : exprAnalyzer_{c}, type_{std::move(t)} {}
1576 
1577   void Add(const parser::AcValue &);
1578   MaybeExpr ToExpr();
1579 
1580   // These interfaces allow *this to be used as a type visitor argument to
1581   // common::SearchTypes() to convert the array constructor to a typed
1582   // expression in ToExpr().
1583   using Result = MaybeExpr;
1584   using Types = AllTypes;
1585   template <typename T> Result Test() {
1586     if (type_ && type_->category() == T::category) {
1587       if constexpr (T::category == TypeCategory::Derived) {
1588         if (!type_->IsUnlimitedPolymorphic()) {
1589           return AsMaybeExpr(ArrayConstructor<T>{type_->GetDerivedTypeSpec(),
1590               MakeSpecific<T>(std::move(values_))});
1591         }
1592       } else if (type_->kind() == T::kind) {
1593         ArrayConstructor<T> result{MakeSpecific<T>(std::move(values_))};
1594         if constexpr (T::category == TypeCategory::Character) {
1595           if (auto len{LengthIfGood()}) {
1596             // The ac-do-variables may be treated as constant expressions,
1597             // if some conditions on ac-implied-do-control hold (10.1.12 (12)).
1598             // At the same time, they may be treated as constant expressions
1599             // only in the context of the ac-implied-do, but setting
1600             // the character length here may result in complete elimination
1601             // of the ac-implied-do. For example:
1602             //   character(10) :: c
1603             //   ... len([(c(i:i), integer(8)::i = 1,4)])
1604             // would be evaulated into:
1605             //   ... int(max(0_8,i-i+1_8),kind=4)
1606             // with a dangling reference to the ac-do-variable.
1607             // Prevent this by checking for the ac-do-variable references
1608             // in the 'len' expression.
1609             result.set_LEN(std::move(*len));
1610           }
1611         }
1612         return AsMaybeExpr(std::move(result));
1613       }
1614     }
1615     return std::nullopt;
1616   }
1617 
1618 private:
1619   using ImpliedDoIntType = ResultType<ImpliedDoIndex>;
1620 
1621   std::optional<Expr<SubscriptInteger>> LengthIfGood() const {
1622     if (type_) {
1623       auto len{type_->LEN()};
1624       if (explicitType_ ||
1625           (len && IsConstantExpr(*len) && !ContainsAnyImpliedDoIndex(*len))) {
1626         return len;
1627       }
1628     }
1629     return std::nullopt;
1630   }
1631   bool NeedLength() const {
1632     return type_ && type_->category() == TypeCategory::Character &&
1633         !LengthIfGood();
1634   }
1635   void Push(MaybeExpr &&);
1636   void Add(const parser::AcValue::Triplet &);
1637   void Add(const parser::Expr &);
1638   void Add(const parser::AcImpliedDo &);
1639   void UnrollConstantImpliedDo(const parser::AcImpliedDo &,
1640       parser::CharBlock name, std::int64_t lower, std::int64_t upper,
1641       std::int64_t stride);
1642 
1643   template <int KIND>
1644   std::optional<Expr<Type<TypeCategory::Integer, KIND>>> ToSpecificInt(
1645       MaybeExpr &&y) {
1646     if (y) {
1647       Expr<SomeInteger> *intExpr{UnwrapExpr<Expr<SomeInteger>>(*y)};
1648       return Fold(exprAnalyzer_.GetFoldingContext(),
1649           ConvertToType<Type<TypeCategory::Integer, KIND>>(
1650               std::move(DEREF(intExpr))));
1651     } else {
1652       return std::nullopt;
1653     }
1654   }
1655 
1656   template <int KIND, typename A>
1657   std::optional<Expr<Type<TypeCategory::Integer, KIND>>> GetSpecificIntExpr(
1658       const A &x) {
1659     return ToSpecificInt<KIND>(exprAnalyzer_.Analyze(x));
1660   }
1661 
1662   // Nested array constructors all reference the same ExpressionAnalyzer,
1663   // which represents the nest of active implied DO loop indices.
1664   ExpressionAnalyzer &exprAnalyzer_;
1665   std::optional<DynamicTypeWithLength> type_;
1666   bool explicitType_{type_.has_value()};
1667   std::optional<std::int64_t> constantLength_;
1668   ArrayConstructorValues<SomeType> values_;
1669   std::uint64_t messageDisplayedSet_{0};
1670 };
1671 
1672 void ArrayConstructorContext::Push(MaybeExpr &&x) {
1673   if (!x) {
1674     return;
1675   }
1676   if (!type_) {
1677     if (auto *boz{std::get_if<BOZLiteralConstant>(&x->u)}) {
1678       // Treat an array constructor of BOZ as if default integer.
1679       exprAnalyzer_.Warn(common::LanguageFeature::BOZAsDefaultInteger,
1680           "BOZ literal in array constructor without explicit type is assumed to be default INTEGER"_port_en_US);
1681       x = AsGenericExpr(ConvertToKind<TypeCategory::Integer>(
1682           exprAnalyzer_.GetDefaultKind(TypeCategory::Integer),
1683           std::move(*boz)));
1684     }
1685   }
1686   std::optional<DynamicType> dyType{x->GetType()};
1687   if (!dyType) {
1688     if (auto *boz{std::get_if<BOZLiteralConstant>(&x->u)}) {
1689       if (!type_) {
1690         // Treat an array constructor of BOZ as if default integer.
1691         exprAnalyzer_.Warn(common::LanguageFeature::BOZAsDefaultInteger,
1692             "BOZ literal in array constructor without explicit type is assumed to be default INTEGER"_port_en_US);
1693         x = AsGenericExpr(ConvertToKind<TypeCategory::Integer>(
1694             exprAnalyzer_.GetDefaultKind(TypeCategory::Integer),
1695             std::move(*boz)));
1696         dyType = x.value().GetType();
1697       } else if (auto cast{ConvertToType(*type_, std::move(*x))}) {
1698         x = std::move(cast);
1699         dyType = *type_;
1700       } else {
1701         if (!(messageDisplayedSet_ & 0x80)) {
1702           exprAnalyzer_.Say(
1703               "BOZ literal is not suitable for use in this array constructor"_err_en_US);
1704           messageDisplayedSet_ |= 0x80;
1705         }
1706         return;
1707       }
1708     } else { // procedure name, &c.
1709       if (!(messageDisplayedSet_ & 0x40)) {
1710         exprAnalyzer_.Say(
1711             "Item is not suitable for use in an array constructor"_err_en_US);
1712         messageDisplayedSet_ |= 0x40;
1713       }
1714       return;
1715     }
1716   } else if (dyType->IsUnlimitedPolymorphic()) {
1717     if (!(messageDisplayedSet_ & 8)) {
1718       exprAnalyzer_.Say("Cannot have an unlimited polymorphic value in an "
1719                         "array constructor"_err_en_US); // C7113
1720       messageDisplayedSet_ |= 8;
1721     }
1722     return;
1723   } else if (dyType->category() == TypeCategory::Derived &&
1724       dyType->GetDerivedTypeSpec().typeSymbol().attrs().test(
1725           semantics::Attr::ABSTRACT)) { // F'2023 C7125
1726     if (!(messageDisplayedSet_ & 0x200)) {
1727       exprAnalyzer_.Say(
1728           "An item whose declared type is ABSTRACT may not appear in an array constructor"_err_en_US);
1729       messageDisplayedSet_ |= 0x200;
1730     }
1731   }
1732   DynamicTypeWithLength xType{dyType.value()};
1733   if (Expr<SomeCharacter> * charExpr{UnwrapExpr<Expr<SomeCharacter>>(*x)}) {
1734     CHECK(xType.category() == TypeCategory::Character);
1735     xType.length =
1736         common::visit([](const auto &kc) { return kc.LEN(); }, charExpr->u);
1737   }
1738   if (!type_) {
1739     // If there is no explicit type-spec in an array constructor, the type
1740     // of the array is the declared type of all of the elements, which must
1741     // be well-defined and all match.
1742     // TODO: Possible language extension: use the most general type of
1743     // the values as the type of a numeric constructed array, convert all
1744     // of the other values to that type.  Alternative: let the first value
1745     // determine the type, and convert the others to that type.
1746     CHECK(!explicitType_);
1747     type_ = std::move(xType);
1748     constantLength_ = ToInt64(type_->length);
1749     values_.Push(std::move(*x));
1750   } else if (!explicitType_) {
1751     if (type_->IsTkCompatibleWith(xType) && xType.IsTkCompatibleWith(*type_)) {
1752       values_.Push(std::move(*x));
1753       auto xLen{xType.LEN()};
1754       if (auto thisLen{ToInt64(xLen)}) {
1755         if (constantLength_) {
1756           if (*thisLen != *constantLength_ && !(messageDisplayedSet_ & 1)) {
1757             exprAnalyzer_.Warn(
1758                 common::LanguageFeature::DistinctArrayConstructorLengths,
1759                 "Character literal in array constructor without explicit "
1760                 "type has different length than earlier elements"_port_en_US);
1761             messageDisplayedSet_ |= 1;
1762           }
1763           if (*thisLen > *constantLength_) {
1764             // Language extension: use the longest literal to determine the
1765             // length of the array constructor's character elements, not the
1766             // first, when there is no explicit type.
1767             *constantLength_ = *thisLen;
1768             type_->length = std::move(xLen);
1769           }
1770         } else {
1771           constantLength_ = *thisLen;
1772           type_->length = std::move(xLen);
1773         }
1774       } else if (xLen && NeedLength()) {
1775         type_->length = std::move(xLen);
1776       }
1777     } else {
1778       if (!(messageDisplayedSet_ & 2)) {
1779         exprAnalyzer_.Say(
1780             "Values in array constructor must have the same declared type "
1781             "when no explicit type appears"_err_en_US); // C7110
1782         messageDisplayedSet_ |= 2;
1783       }
1784     }
1785   } else {
1786     if (auto cast{ConvertToType(*type_, std::move(*x))}) {
1787       values_.Push(std::move(*cast));
1788     } else if (!(messageDisplayedSet_ & 4)) {
1789       exprAnalyzer_.Say("Value in array constructor of type '%s' could not "
1790                         "be converted to the type of the array '%s'"_err_en_US,
1791           x->GetType()->AsFortran(), type_->AsFortran()); // C7111, C7112
1792       messageDisplayedSet_ |= 4;
1793     }
1794   }
1795 }
1796 
1797 void ArrayConstructorContext::Add(const parser::AcValue &x) {
1798   common::visit(
1799       common::visitors{
1800           [&](const parser::AcValue::Triplet &triplet) { Add(triplet); },
1801           [&](const common::Indirection<parser::Expr> &expr) {
1802             Add(expr.value());
1803           },
1804           [&](const common::Indirection<parser::AcImpliedDo> &impliedDo) {
1805             Add(impliedDo.value());
1806           },
1807       },
1808       x.u);
1809 }
1810 
1811 // Transforms l:u(:s) into (_,_=l,u(,s)) with an anonymous index '_'
1812 void ArrayConstructorContext::Add(const parser::AcValue::Triplet &triplet) {
1813   MaybeExpr lowerExpr{exprAnalyzer_.Analyze(std::get<0>(triplet.t))};
1814   MaybeExpr upperExpr{exprAnalyzer_.Analyze(std::get<1>(triplet.t))};
1815   MaybeExpr strideExpr{exprAnalyzer_.Analyze(std::get<2>(triplet.t))};
1816   if (lowerExpr && upperExpr) {
1817     auto lowerType{lowerExpr->GetType()};
1818     auto upperType{upperExpr->GetType()};
1819     auto strideType{strideExpr ? strideExpr->GetType() : lowerType};
1820     if (lowerType && upperType && strideType) {
1821       int kind{lowerType->kind()};
1822       if (upperType->kind() > kind) {
1823         kind = upperType->kind();
1824       }
1825       if (strideType->kind() > kind) {
1826         kind = strideType->kind();
1827       }
1828       auto lower{ToSpecificInt<ImpliedDoIntType::kind>(std::move(lowerExpr))};
1829       auto upper{ToSpecificInt<ImpliedDoIntType::kind>(std::move(upperExpr))};
1830       if (lower && upper) {
1831         auto stride{
1832             ToSpecificInt<ImpliedDoIntType::kind>(std::move(strideExpr))};
1833         if (!stride) {
1834           stride = Expr<ImpliedDoIntType>{1};
1835         }
1836         DynamicType type{TypeCategory::Integer, kind};
1837         if (!type_) {
1838           type_ = DynamicTypeWithLength{type};
1839         }
1840         parser::CharBlock anonymous;
1841         if (auto converted{ConvertToType(type,
1842                 AsGenericExpr(
1843                     Expr<ImpliedDoIntType>{ImpliedDoIndex{anonymous}}))}) {
1844           auto v{std::move(values_)};
1845           Push(std::move(converted));
1846           std::swap(v, values_);
1847           values_.Push(ImpliedDo<SomeType>{anonymous, std::move(*lower),
1848               std::move(*upper), std::move(*stride), std::move(v)});
1849         }
1850       }
1851     }
1852   }
1853 }
1854 
1855 void ArrayConstructorContext::Add(const parser::Expr &expr) {
1856   auto restorer{exprAnalyzer_.GetContextualMessages().SetLocation(expr.source)};
1857   Push(exprAnalyzer_.Analyze(expr));
1858 }
1859 
1860 void ArrayConstructorContext::Add(const parser::AcImpliedDo &impliedDo) {
1861   const auto &control{std::get<parser::AcImpliedDoControl>(impliedDo.t)};
1862   const auto &bounds{std::get<parser::AcImpliedDoControl::Bounds>(control.t)};
1863   exprAnalyzer_.Analyze(bounds.name);
1864   parser::CharBlock name{bounds.name.thing.thing.source};
1865   int kind{ImpliedDoIntType::kind};
1866   if (const Symbol * symbol{bounds.name.thing.thing.symbol}) {
1867     if (auto dynamicType{DynamicType::From(symbol)}) {
1868       if (dynamicType->category() == TypeCategory::Integer) {
1869         kind = dynamicType->kind();
1870       }
1871     }
1872   }
1873   std::optional<Expr<ImpliedDoIntType>> lower{
1874       GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.lower)};
1875   std::optional<Expr<ImpliedDoIntType>> upper{
1876       GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.upper)};
1877   if (lower && upper) {
1878     std::optional<Expr<ImpliedDoIntType>> stride{
1879         GetSpecificIntExpr<ImpliedDoIntType::kind>(bounds.step)};
1880     if (!stride) {
1881       stride = Expr<ImpliedDoIntType>{1};
1882     }
1883     if (exprAnalyzer_.AddImpliedDo(name, kind)) {
1884       // Check for constant bounds; the loop may require complete unrolling
1885       // of the parse tree if all bounds are constant in order to allow the
1886       // implied DO loop index to qualify as a constant expression.
1887       auto cLower{ToInt64(lower)};
1888       auto cUpper{ToInt64(upper)};
1889       auto cStride{ToInt64(stride)};
1890       if (!(messageDisplayedSet_ & 0x10) && cStride && *cStride == 0) {
1891         exprAnalyzer_.SayAt(bounds.step.value().thing.thing.value().source,
1892             "The stride of an implied DO loop must not be zero"_err_en_US);
1893         messageDisplayedSet_ |= 0x10;
1894       }
1895       bool isConstant{cLower && cUpper && cStride && *cStride != 0};
1896       bool isNonemptyConstant{isConstant &&
1897           ((*cStride > 0 && *cLower <= *cUpper) ||
1898               (*cStride < 0 && *cLower >= *cUpper))};
1899       bool isEmpty{isConstant && !isNonemptyConstant};
1900       bool unrollConstantLoop{false};
1901       parser::Messages buffer;
1902       auto saveMessagesDisplayed{messageDisplayedSet_};
1903       {
1904         auto messageRestorer{
1905             exprAnalyzer_.GetContextualMessages().SetMessages(buffer)};
1906         auto v{std::move(values_)};
1907         for (const auto &value :
1908             std::get<std::list<parser::AcValue>>(impliedDo.t)) {
1909           Add(value);
1910         }
1911         std::swap(v, values_);
1912         if (isNonemptyConstant && buffer.AnyFatalError()) {
1913           unrollConstantLoop = true;
1914         } else {
1915           values_.Push(ImpliedDo<SomeType>{name, std::move(*lower),
1916               std::move(*upper), std::move(*stride), std::move(v)});
1917         }
1918       }
1919       // F'2023 7.8 p5
1920       if (!(messageDisplayedSet_ & 0x100) && isEmpty && NeedLength()) {
1921         exprAnalyzer_.SayAt(name,
1922             "Array constructor implied DO loop has no iterations and indeterminate character length"_err_en_US);
1923         messageDisplayedSet_ |= 0x100;
1924       }
1925       if (unrollConstantLoop) {
1926         messageDisplayedSet_ = saveMessagesDisplayed;
1927         UnrollConstantImpliedDo(impliedDo, name, *cLower, *cUpper, *cStride);
1928       } else if (auto *messages{
1929                      exprAnalyzer_.GetContextualMessages().messages()}) {
1930         messages->Annex(std::move(buffer));
1931       }
1932       exprAnalyzer_.RemoveImpliedDo(name);
1933     } else if (!(messageDisplayedSet_ & 0x20)) {
1934       exprAnalyzer_.SayAt(name,
1935           "Implied DO index '%s' is active in a surrounding implied DO loop "
1936           "and may not have the same name"_err_en_US,
1937           name); // C7115
1938       messageDisplayedSet_ |= 0x20;
1939     }
1940   }
1941 }
1942 
1943 // Fortran considers an implied DO index of an array constructor to be
1944 // a constant expression if the bounds of the implied DO loop are constant.
1945 // Usually this doesn't matter, but if we emitted spurious messages as a
1946 // result of not using constant values for the index while analyzing the
1947 // items, we need to do it again the "hard" way with multiple iterations over
1948 // the parse tree.
1949 void ArrayConstructorContext::UnrollConstantImpliedDo(
1950     const parser::AcImpliedDo &impliedDo, parser::CharBlock name,
1951     std::int64_t lower, std::int64_t upper, std::int64_t stride) {
1952   auto &foldingContext{exprAnalyzer_.GetFoldingContext()};
1953   auto restorer{exprAnalyzer_.DoNotUseSavedTypedExprs()};
1954   for (auto &at{foldingContext.StartImpliedDo(name, lower)};
1955        (stride > 0 && at <= upper) || (stride < 0 && at >= upper);
1956        at += stride) {
1957     for (const auto &value :
1958         std::get<std::list<parser::AcValue>>(impliedDo.t)) {
1959       Add(value);
1960     }
1961   }
1962   foldingContext.EndImpliedDo(name);
1963 }
1964 
1965 MaybeExpr ArrayConstructorContext::ToExpr() {
1966   return common::SearchTypes(std::move(*this));
1967 }
1968 
1969 MaybeExpr ExpressionAnalyzer::Analyze(const parser::ArrayConstructor &array) {
1970   const parser::AcSpec &acSpec{array.v};
1971   ArrayConstructorContext acContext{
1972       *this, AnalyzeTypeSpec(acSpec.type, GetFoldingContext())};
1973   for (const parser::AcValue &value : acSpec.values) {
1974     acContext.Add(value);
1975   }
1976   return acContext.ToExpr();
1977 }
1978 
1979 // Check if implicit conversion of expr to the symbol type is legal (if needed),
1980 // and make it explicit if requested.
1981 static MaybeExpr ImplicitConvertTo(const semantics::Symbol &sym,
1982     Expr<SomeType> &&expr, bool keepConvertImplicit) {
1983   if (!keepConvertImplicit) {
1984     return ConvertToType(sym, std::move(expr));
1985   } else {
1986     // Test if a convert could be inserted, but do not make it explicit to
1987     // preserve the information that expr is a variable.
1988     if (ConvertToType(sym, common::Clone(expr))) {
1989       return MaybeExpr{std::move(expr)};
1990     }
1991   }
1992   // Illegal implicit convert.
1993   return std::nullopt;
1994 }
1995 
1996 MaybeExpr ExpressionAnalyzer::Analyze(
1997     const parser::StructureConstructor &structure) {
1998   auto &parsedType{std::get<parser::DerivedTypeSpec>(structure.t)};
1999   parser::Name structureType{std::get<parser::Name>(parsedType.t)};
2000   parser::CharBlock &typeName{structureType.source};
2001   if (semantics::Symbol *typeSymbol{structureType.symbol}) {
2002     if (typeSymbol->has<semantics::DerivedTypeDetails>()) {
2003       semantics::DerivedTypeSpec dtSpec{typeName, typeSymbol->GetUltimate()};
2004       if (!CheckIsValidForwardReference(dtSpec)) {
2005         return std::nullopt;
2006       }
2007     }
2008   }
2009   if (!parsedType.derivedTypeSpec) {
2010     return std::nullopt;
2011   }
2012   const auto &spec{*parsedType.derivedTypeSpec};
2013   const Symbol &typeSymbol{spec.typeSymbol()};
2014   if (!spec.scope() || !typeSymbol.has<semantics::DerivedTypeDetails>()) {
2015     return std::nullopt; // error recovery
2016   }
2017   const semantics::Scope &scope{context_.FindScope(typeName)};
2018   const semantics::Scope *pureContext{FindPureProcedureContaining(scope)};
2019   const auto &typeDetails{typeSymbol.get<semantics::DerivedTypeDetails>()};
2020   const Symbol *parentComponent{typeDetails.GetParentComponent(*spec.scope())};
2021 
2022   if (typeSymbol.attrs().test(semantics::Attr::ABSTRACT)) { // C796
2023     AttachDeclaration(Say(typeName,
2024                           "ABSTRACT derived type '%s' may not be used in a "
2025                           "structure constructor"_err_en_US,
2026                           typeName),
2027         typeSymbol); // C7114
2028   }
2029 
2030   // This iterator traverses all of the components in the derived type and its
2031   // parents.  The symbols for whole parent components appear after their
2032   // own components and before the components of the types that extend them.
2033   // E.g., TYPE :: A; REAL X; END TYPE
2034   //       TYPE, EXTENDS(A) :: B; REAL Y; END TYPE
2035   // produces the component list X, A, Y.
2036   // The order is important below because a structure constructor can
2037   // initialize X or A by name, but not both.
2038   auto components{semantics::OrderedComponentIterator{spec}};
2039   auto nextAnonymous{components.begin()};
2040   auto afterLastParentComponentIter{components.end()};
2041   if (parentComponent) {
2042     for (auto iter{components.begin()}; iter != components.end(); ++iter) {
2043       if (iter->test(Symbol::Flag::ParentComp)) {
2044         afterLastParentComponentIter = iter;
2045         ++afterLastParentComponentIter;
2046       }
2047     }
2048   }
2049 
2050   std::set<parser::CharBlock> unavailable;
2051   bool anyKeyword{false};
2052   StructureConstructor result{spec};
2053   bool checkConflicts{true}; // until we hit one
2054   auto &messages{GetContextualMessages()};
2055 
2056   // NULL() can be a valid component
2057   auto restorer{AllowNullPointer()};
2058 
2059   for (const auto &component :
2060       std::get<std::list<parser::ComponentSpec>>(structure.t)) {
2061     const parser::Expr &expr{
2062         std::get<parser::ComponentDataSource>(component.t).v.value()};
2063     parser::CharBlock source{expr.source};
2064     auto restorer{messages.SetLocation(source)};
2065     const Symbol *symbol{nullptr};
2066     MaybeExpr value{Analyze(expr)};
2067     std::optional<DynamicType> valueType{DynamicType::From(value)};
2068     if (const auto &kw{std::get<std::optional<parser::Keyword>>(component.t)}) {
2069       anyKeyword = true;
2070       source = kw->v.source;
2071       symbol = kw->v.symbol;
2072       if (!symbol) {
2073         // Skip overridden inaccessible parent components in favor of
2074         // their later overrides.
2075         for (const Symbol &sym : components) {
2076           if (sym.name() == source) {
2077             symbol = &sym;
2078           }
2079         }
2080       }
2081       if (!symbol) { // C7101
2082         Say(source,
2083             "Keyword '%s=' does not name a component of derived type '%s'"_err_en_US,
2084             source, typeName);
2085       }
2086     } else {
2087       if (anyKeyword) { // C7100
2088         Say(source,
2089             "Value in structure constructor lacks a component name"_err_en_US);
2090         checkConflicts = false; // stem cascade
2091       }
2092       // Here's a regrettably common extension of the standard: anonymous
2093       // initialization of parent components, e.g., T(PT(1)) rather than
2094       // T(1) or T(PT=PT(1)).  There may be multiple parent components.
2095       if (nextAnonymous == components.begin() && parentComponent && valueType &&
2096           context().IsEnabled(LanguageFeature::AnonymousParents)) {
2097         for (auto parent{components.begin()};
2098              parent != afterLastParentComponentIter; ++parent) {
2099           if (auto parentType{DynamicType::From(*parent)}; parentType &&
2100               parent->test(Symbol::Flag::ParentComp) &&
2101               valueType->IsEquivalentTo(*parentType)) {
2102             symbol = &*parent;
2103             nextAnonymous = ++parent;
2104             Warn(LanguageFeature::AnonymousParents, source,
2105                 "Whole parent component '%s' in structure constructor should not be anonymous"_port_en_US,
2106                 symbol->name());
2107             break;
2108           }
2109         }
2110       }
2111       while (!symbol && nextAnonymous != components.end()) {
2112         const Symbol &next{*nextAnonymous};
2113         ++nextAnonymous;
2114         if (!next.test(Symbol::Flag::ParentComp)) {
2115           symbol = &next;
2116         }
2117       }
2118       if (!symbol) {
2119         Say(source, "Unexpected value in structure constructor"_err_en_US);
2120       }
2121     }
2122     if (symbol) {
2123       const semantics::Scope &innermost{context_.FindScope(expr.source)};
2124       if (auto msg{CheckAccessibleSymbol(innermost, *symbol)}) {
2125         Say(expr.source, std::move(*msg));
2126       }
2127       if (checkConflicts) {
2128         auto componentIter{
2129             std::find(components.begin(), components.end(), *symbol)};
2130         if (unavailable.find(symbol->name()) != unavailable.cend()) {
2131           // C797, C798
2132           Say(source,
2133               "Component '%s' conflicts with another component earlier in "
2134               "this structure constructor"_err_en_US,
2135               symbol->name());
2136         } else if (symbol->test(Symbol::Flag::ParentComp)) {
2137           // Make earlier components unavailable once a whole parent appears.
2138           for (auto it{components.begin()}; it != componentIter; ++it) {
2139             unavailable.insert(it->name());
2140           }
2141         } else {
2142           // Make whole parent components unavailable after any of their
2143           // constituents appear.
2144           for (auto it{componentIter}; it != components.end(); ++it) {
2145             if (it->test(Symbol::Flag::ParentComp)) {
2146               unavailable.insert(it->name());
2147             }
2148           }
2149         }
2150       }
2151       unavailable.insert(symbol->name());
2152       if (value) {
2153         if (symbol->has<semantics::TypeParamDetails>()) {
2154           Say(expr.source,
2155               "Type parameter '%s' may not appear as a component of a structure constructor"_err_en_US,
2156               symbol->name());
2157         }
2158         if (!(symbol->has<semantics::ProcEntityDetails>() ||
2159                 symbol->has<semantics::ObjectEntityDetails>())) {
2160           continue; // recovery
2161         }
2162         if (IsPointer(*symbol)) { // C7104, C7105, C1594(4)
2163           semantics::CheckStructConstructorPointerComponent(
2164               context_, *symbol, *value, innermost);
2165           result.Add(*symbol, Fold(std::move(*value)));
2166           continue;
2167         }
2168         if (IsNullPointer(*value)) {
2169           if (IsAllocatable(*symbol)) {
2170             if (IsBareNullPointer(&*value)) {
2171               // NULL() with no arguments allowed by 7.5.10 para 6 for
2172               // ALLOCATABLE.
2173               result.Add(*symbol, Expr<SomeType>{NullPointer{}});
2174               continue;
2175             }
2176             if (IsNullObjectPointer(*value)) {
2177               AttachDeclaration(
2178                   Warn(common::LanguageFeature::
2179                            NullMoldAllocatableComponentValue,
2180                       expr.source,
2181                       "NULL() with arguments is not standard conforming as the value for allocatable component '%s'"_port_en_US,
2182                       symbol->name()),
2183                   *symbol);
2184               // proceed to check type & shape
2185             } else {
2186               AttachDeclaration(
2187                   Say(expr.source,
2188                       "A NULL procedure pointer may not be used as the value for component '%s'"_err_en_US,
2189                       symbol->name()),
2190                   *symbol);
2191               continue;
2192             }
2193           } else {
2194             AttachDeclaration(
2195                 Say(expr.source,
2196                     "A NULL pointer may not be used as the value for component '%s'"_err_en_US,
2197                     symbol->name()),
2198                 *symbol);
2199             continue;
2200           }
2201         } else if (const Symbol * pointer{FindPointerComponent(*symbol)};
2202                    pointer && pureContext) { // C1594(4)
2203           if (const Symbol *
2204               visible{semantics::FindExternallyVisibleObject(
2205                   *value, *pureContext)}) {
2206             Say(expr.source,
2207                 "The externally visible object '%s' may not be used in a pure procedure as the value for component '%s' which has the pointer component '%s'"_err_en_US,
2208                 visible->name(), symbol->name(), pointer->name());
2209           }
2210         }
2211         // Make implicit conversion explicit to allow folding of the structure
2212         // constructors and help semantic checking, unless the component is
2213         // allocatable, in which case the value could be an unallocated
2214         // allocatable (see Fortran 2018 7.5.10 point 7). The explicit
2215         // convert would cause a segfault. Lowering will deal with
2216         // conditionally converting and preserving the lower bounds in this
2217         // case.
2218         if (MaybeExpr converted{ImplicitConvertTo(
2219                 *symbol, std::move(*value), IsAllocatable(*symbol))}) {
2220           if (auto componentShape{GetShape(GetFoldingContext(), *symbol)}) {
2221             if (auto valueShape{GetShape(GetFoldingContext(), *converted)}) {
2222               if (GetRank(*componentShape) == 0 && GetRank(*valueShape) > 0) {
2223                 AttachDeclaration(
2224                     Say(expr.source,
2225                         "Rank-%d array value is not compatible with scalar component '%s'"_err_en_US,
2226                         GetRank(*valueShape), symbol->name()),
2227                     *symbol);
2228               } else {
2229                 auto checked{
2230                     CheckConformance(messages, *componentShape, *valueShape,
2231                         CheckConformanceFlags::RightIsExpandableDeferred,
2232                         "component", "value")};
2233                 if (checked && *checked && GetRank(*componentShape) > 0 &&
2234                     GetRank(*valueShape) == 0 &&
2235                     (IsDeferredShape(*symbol) ||
2236                         !IsExpandableScalar(*converted, GetFoldingContext(),
2237                             *componentShape, true /*admit PURE call*/))) {
2238                   AttachDeclaration(
2239                       Say(expr.source,
2240                           "Scalar value cannot be expanded to shape of array component '%s'"_err_en_US,
2241                           symbol->name()),
2242                       *symbol);
2243                 }
2244                 if (checked.value_or(true)) {
2245                   result.Add(*symbol, std::move(*converted));
2246                 }
2247               }
2248             } else {
2249               Say(expr.source, "Shape of value cannot be determined"_err_en_US);
2250             }
2251           } else {
2252             AttachDeclaration(
2253                 Say(expr.source,
2254                     "Shape of component '%s' cannot be determined"_err_en_US,
2255                     symbol->name()),
2256                 *symbol);
2257           }
2258         } else if (auto symType{DynamicType::From(symbol)}) {
2259           if (IsAllocatable(*symbol) && symType->IsUnlimitedPolymorphic() &&
2260               valueType) {
2261             // ok
2262           } else if (valueType) {
2263             AttachDeclaration(
2264                 Say(expr.source,
2265                     "Value in structure constructor of type '%s' is "
2266                     "incompatible with component '%s' of type '%s'"_err_en_US,
2267                     valueType->AsFortran(), symbol->name(),
2268                     symType->AsFortran()),
2269                 *symbol);
2270           } else {
2271             AttachDeclaration(
2272                 Say(expr.source,
2273                     "Value in structure constructor is incompatible with "
2274                     "component '%s' of type %s"_err_en_US,
2275                     symbol->name(), symType->AsFortran()),
2276                 *symbol);
2277           }
2278         }
2279       }
2280     }
2281   }
2282 
2283   // Ensure that unmentioned component objects have default initializers.
2284   for (const Symbol &symbol : components) {
2285     if (!symbol.test(Symbol::Flag::ParentComp) &&
2286         unavailable.find(symbol.name()) == unavailable.cend()) {
2287       if (IsAllocatable(symbol)) {
2288         // Set all remaining allocatables to explicit NULL().
2289         result.Add(symbol, Expr<SomeType>{NullPointer{}});
2290       } else {
2291         const auto *object{symbol.detailsIf<semantics::ObjectEntityDetails>()};
2292         if (object && object->init()) {
2293           result.Add(symbol, common::Clone(*object->init()));
2294         } else if (IsPointer(symbol)) {
2295           result.Add(symbol, Expr<SomeType>{NullPointer{}});
2296         } else if (object) { // C799
2297           AttachDeclaration(Say(typeName,
2298                                 "Structure constructor lacks a value for "
2299                                 "component '%s'"_err_en_US,
2300                                 symbol.name()),
2301               symbol);
2302         }
2303       }
2304     }
2305   }
2306 
2307   return AsMaybeExpr(Expr<SomeDerived>{std::move(result)});
2308 }
2309 
2310 static std::optional<parser::CharBlock> GetPassName(
2311     const semantics::Symbol &proc) {
2312   return common::visit(
2313       [](const auto &details) {
2314         if constexpr (std::is_base_of_v<semantics::WithPassArg,
2315                           std::decay_t<decltype(details)>>) {
2316           return details.passName();
2317         } else {
2318           return std::optional<parser::CharBlock>{};
2319         }
2320       },
2321       proc.details());
2322 }
2323 
2324 static std::optional<int> GetPassIndex(const Symbol &proc) {
2325   CHECK(!proc.attrs().test(semantics::Attr::NOPASS));
2326   std::optional<parser::CharBlock> passName{GetPassName(proc)};
2327   const auto *interface {
2328     semantics::FindInterface(proc)
2329   };
2330   if (!passName || !interface) {
2331     return 0; // first argument is passed-object
2332   }
2333   const auto &subp{interface->get<semantics::SubprogramDetails>()};
2334   int index{0};
2335   for (const auto *arg : subp.dummyArgs()) {
2336     if (arg && arg->name() == passName) {
2337       return index;
2338     }
2339     ++index;
2340   }
2341   return std::nullopt;
2342 }
2343 
2344 // Injects an expression into an actual argument list as the "passed object"
2345 // for a type-bound procedure reference that is not NOPASS.  Adds an
2346 // argument keyword if possible, but not when the passed object goes
2347 // before a positional argument.
2348 // e.g., obj%tbp(x) -> tbp(obj,x).
2349 static void AddPassArg(ActualArguments &actuals, const Expr<SomeDerived> &expr,
2350     const Symbol &component, bool isPassedObject = true) {
2351   if (component.attrs().test(semantics::Attr::NOPASS)) {
2352     return;
2353   }
2354   std::optional<int> passIndex{GetPassIndex(component)};
2355   if (!passIndex) {
2356     return; // error recovery
2357   }
2358   auto iter{actuals.begin()};
2359   int at{0};
2360   while (iter < actuals.end() && at < *passIndex) {
2361     if (*iter && (*iter)->keyword()) {
2362       iter = actuals.end();
2363       break;
2364     }
2365     ++iter;
2366     ++at;
2367   }
2368   ActualArgument passed{AsGenericExpr(common::Clone(expr))};
2369   passed.set_isPassedObject(isPassedObject);
2370   if (iter == actuals.end()) {
2371     if (auto passName{GetPassName(component)}) {
2372       passed.set_keyword(*passName);
2373     }
2374   }
2375   actuals.emplace(iter, std::move(passed));
2376 }
2377 
2378 // Return the compile-time resolution of a procedure binding, if possible.
2379 static const Symbol *GetBindingResolution(
2380     const std::optional<DynamicType> &baseType, const Symbol &component) {
2381   const auto *binding{component.detailsIf<semantics::ProcBindingDetails>()};
2382   if (!binding) {
2383     return nullptr;
2384   }
2385   if (!component.attrs().test(semantics::Attr::NON_OVERRIDABLE) &&
2386       (!baseType || baseType->IsPolymorphic())) {
2387     return nullptr;
2388   }
2389   return &binding->symbol();
2390 }
2391 
2392 auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
2393     const parser::ProcComponentRef &pcr, ActualArguments &&arguments,
2394     bool isSubroutine) -> std::optional<CalleeAndArguments> {
2395   const parser::StructureComponent &sc{pcr.v.thing};
2396   if (MaybeExpr base{Analyze(sc.base)}) {
2397     if (const Symbol *sym{sc.component.symbol}) {
2398       if (context_.HasError(sym)) {
2399         return std::nullopt;
2400       }
2401       if (!IsProcedure(*sym)) {
2402         AttachDeclaration(
2403             Say(sc.component.source, "'%s' is not a procedure"_err_en_US,
2404                 sc.component.source),
2405             *sym);
2406         return std::nullopt;
2407       }
2408       if (auto *dtExpr{UnwrapExpr<Expr<SomeDerived>>(*base)}) {
2409         if (sym->has<semantics::GenericDetails>()) {
2410           const Symbol &generic{*sym};
2411           auto dyType{dtExpr->GetType()};
2412           AdjustActuals adjustment{
2413               [&](const Symbol &proc, ActualArguments &actuals) {
2414                 if (!proc.attrs().test(semantics::Attr::NOPASS)) {
2415                   AddPassArg(actuals, std::move(*dtExpr), proc);
2416                 }
2417                 return true;
2418               }};
2419           auto pair{
2420               ResolveGeneric(generic, arguments, adjustment, isSubroutine)};
2421           sym = pair.first;
2422           if (!sym) {
2423             EmitGenericResolutionError(generic, pair.second, isSubroutine);
2424             return std::nullopt;
2425           }
2426           // re-resolve the name to the specific binding
2427           CHECK(sym->has<semantics::ProcBindingDetails>());
2428           // Use the most recent override of a binding, respecting
2429           // the rule that inaccessible bindings may not be overridden
2430           // outside their module.  Fortran doesn't allow a PUBLIC
2431           // binding to be overridden by a PRIVATE one.
2432           CHECK(dyType && dyType->category() == TypeCategory::Derived &&
2433               !dyType->IsUnlimitedPolymorphic());
2434           if (const Symbol *
2435               latest{DEREF(dyType->GetDerivedTypeSpec().typeSymbol().scope())
2436                          .FindComponent(sym->name())}) {
2437             if (sym->attrs().test(semantics::Attr::PRIVATE)) {
2438               const auto *bindingModule{FindModuleContaining(generic.owner())};
2439               const Symbol *s{latest};
2440               while (s && FindModuleContaining(s->owner()) != bindingModule) {
2441                 if (const auto *parent{s->owner().GetDerivedTypeParent()}) {
2442                   s = parent->FindComponent(sym->name());
2443                 } else {
2444                   s = nullptr;
2445                 }
2446               }
2447               if (s && !s->attrs().test(semantics::Attr::PRIVATE)) {
2448                 // The latest override in the same module as the binding
2449                 // is public, so it can be overridden.
2450               } else {
2451                 latest = s;
2452               }
2453             }
2454             if (latest) {
2455               sym = latest;
2456             }
2457           }
2458           sc.component.symbol = const_cast<Symbol *>(sym);
2459         }
2460         std::optional<DataRef> dataRef{ExtractDataRef(std::move(*dtExpr))};
2461         if (dataRef && !CheckDataRef(*dataRef)) {
2462           return std::nullopt;
2463         }
2464         if (dataRef && dataRef->Rank() > 0) {
2465           if (sym->has<semantics::ProcBindingDetails>() &&
2466               sym->attrs().test(semantics::Attr::NOPASS)) {
2467             // F'2023 C1529 seems unnecessary and most compilers don't
2468             // enforce it.
2469             AttachDeclaration(
2470                 Warn(common::LanguageFeature::NopassScalarBase,
2471                     sc.component.source,
2472                     "Base of NOPASS type-bound procedure reference should be scalar"_port_en_US),
2473                 *sym);
2474           } else if (IsProcedurePointer(*sym)) { // C919
2475             Say(sc.component.source,
2476                 "Base of procedure component reference must be scalar"_err_en_US);
2477           }
2478         }
2479         if (const Symbol *resolution{
2480                 GetBindingResolution(dtExpr->GetType(), *sym)}) {
2481           AddPassArg(arguments, std::move(*dtExpr), *sym, false);
2482           return CalleeAndArguments{
2483               ProcedureDesignator{*resolution}, std::move(arguments)};
2484         } else if (dataRef.has_value()) {
2485           if (sym->attrs().test(semantics::Attr::NOPASS)) {
2486             const auto *dtSpec{GetDerivedTypeSpec(dtExpr->GetType())};
2487             if (dtSpec && dtSpec->scope()) {
2488               if (auto component{CreateComponent(std::move(*dataRef), *sym,
2489                       *dtSpec->scope(), /*C919bAlreadyEnforced=*/true)}) {
2490                 return CalleeAndArguments{
2491                     ProcedureDesignator{std::move(*component)},
2492                     std::move(arguments)};
2493               }
2494             }
2495             Say(sc.component.source,
2496                 "Component is not in scope of base derived type"_err_en_US);
2497             return std::nullopt;
2498           } else {
2499             AddPassArg(arguments,
2500                 Expr<SomeDerived>{Designator<SomeDerived>{std::move(*dataRef)}},
2501                 *sym);
2502             return CalleeAndArguments{
2503                 ProcedureDesignator{*sym}, std::move(arguments)};
2504           }
2505         }
2506       }
2507       Say(sc.component.source,
2508           "Base of procedure component reference is not a derived-type object"_err_en_US);
2509     }
2510   }
2511   CHECK(context_.AnyFatalError());
2512   return std::nullopt;
2513 }
2514 
2515 // Can actual be argument associated with dummy?
2516 static bool CheckCompatibleArgument(bool isElemental,
2517     const ActualArgument &actual, const characteristics::DummyArgument &dummy,
2518     FoldingContext &foldingContext) {
2519   const auto *expr{actual.UnwrapExpr()};
2520   return common::visit(
2521       common::visitors{
2522           [&](const characteristics::DummyDataObject &x) {
2523             if (x.attrs.test(characteristics::DummyDataObject::Attr::Pointer) &&
2524                 IsBareNullPointer(expr)) {
2525               // NULL() without MOLD= is compatible with any dummy data pointer
2526               // but cannot be allowed to lead to ambiguity.
2527               return true;
2528             } else if (!isElemental && actual.Rank() != x.type.Rank() &&
2529                 !x.type.attrs().test(
2530                     characteristics::TypeAndShape::Attr::AssumedRank) &&
2531                 !x.ignoreTKR.test(common::IgnoreTKR::Rank)) {
2532               return false;
2533             } else if (auto actualType{actual.GetType()}) {
2534               return x.type.type().IsTkCompatibleWith(*actualType, x.ignoreTKR);
2535             }
2536             return false;
2537           },
2538           [&](const characteristics::DummyProcedure &dummy) {
2539             if ((dummy.attrs.test(
2540                      characteristics::DummyProcedure::Attr::Optional) ||
2541                     dummy.attrs.test(
2542                         characteristics::DummyProcedure::Attr::Pointer)) &&
2543                 IsBareNullPointer(expr)) {
2544               // NULL() is compatible with any dummy pointer
2545               // or optional dummy procedure.
2546               return true;
2547             }
2548             if (!expr || !IsProcedurePointerTarget(*expr)) {
2549               return false;
2550             }
2551             if (auto actualProc{characteristics::Procedure::Characterize(
2552                     *expr, foldingContext)}) {
2553               const auto &dummyResult{dummy.procedure.value().functionResult};
2554               const auto *dummyTypeAndShape{
2555                   dummyResult ? dummyResult->GetTypeAndShape() : nullptr};
2556               const auto &actualResult{actualProc->functionResult};
2557               const auto *actualTypeAndShape{
2558                   actualResult ? actualResult->GetTypeAndShape() : nullptr};
2559               if (dummyTypeAndShape && actualTypeAndShape) {
2560                 // Return false when the function results' types are both
2561                 // known and not compatible.
2562                 return actualTypeAndShape->type().IsTkCompatibleWith(
2563                     dummyTypeAndShape->type());
2564               }
2565             }
2566             return true;
2567           },
2568           [&](const characteristics::AlternateReturn &) {
2569             return actual.isAlternateReturn();
2570           },
2571       },
2572       dummy.u);
2573 }
2574 
2575 // Are the actual arguments compatible with the dummy arguments of procedure?
2576 static bool CheckCompatibleArguments(
2577     const characteristics::Procedure &procedure, const ActualArguments &actuals,
2578     FoldingContext &foldingContext) {
2579   bool isElemental{procedure.IsElemental()};
2580   const auto &dummies{procedure.dummyArguments};
2581   CHECK(dummies.size() == actuals.size());
2582   for (std::size_t i{0}; i < dummies.size(); ++i) {
2583     const characteristics::DummyArgument &dummy{dummies[i]};
2584     const std::optional<ActualArgument> &actual{actuals[i]};
2585     if (actual &&
2586         !CheckCompatibleArgument(isElemental, *actual, dummy, foldingContext)) {
2587       return false;
2588     }
2589   }
2590   return true;
2591 }
2592 
2593 static constexpr int cudaInfMatchingValue{std::numeric_limits<int>::max()};
2594 
2595 // Compute the matching distance as described in section 3.2.3 of the CUDA
2596 // Fortran references.
2597 static int GetMatchingDistance(const common::LanguageFeatureControl &features,
2598     const characteristics::DummyArgument &dummy,
2599     const std::optional<ActualArgument> &actual) {
2600   bool isCudaManaged{features.IsEnabled(common::LanguageFeature::CudaManaged)};
2601   bool isCudaUnified{features.IsEnabled(common::LanguageFeature::CudaUnified)};
2602   CHECK(!(isCudaUnified && isCudaManaged) && "expect only one enabled.");
2603 
2604   std::optional<common::CUDADataAttr> actualDataAttr, dummyDataAttr;
2605   if (actual) {
2606     if (auto *expr{actual->UnwrapExpr()}) {
2607       const auto *actualLastSymbol{evaluate::GetLastSymbol(*expr)};
2608       if (actualLastSymbol) {
2609         actualLastSymbol = &semantics::ResolveAssociations(*actualLastSymbol);
2610         if (const auto *actualObject{actualLastSymbol
2611                     ? actualLastSymbol
2612                           ->detailsIf<semantics::ObjectEntityDetails>()
2613                     : nullptr}) {
2614           actualDataAttr = actualObject->cudaDataAttr();
2615         }
2616       }
2617     }
2618   }
2619 
2620   common::visit(common::visitors{
2621                     [&](const characteristics::DummyDataObject &object) {
2622                       dummyDataAttr = object.cudaDataAttr;
2623                     },
2624                     [&](const auto &) {},
2625                 },
2626       dummy.u);
2627 
2628   if (!dummyDataAttr) {
2629     if (!actualDataAttr) {
2630       if (isCudaUnified || isCudaManaged) {
2631         return 3;
2632       }
2633       return 0;
2634     } else if (*actualDataAttr == common::CUDADataAttr::Device) {
2635       return cudaInfMatchingValue;
2636     } else if (*actualDataAttr == common::CUDADataAttr::Managed ||
2637         *actualDataAttr == common::CUDADataAttr::Unified) {
2638       return 3;
2639     }
2640   } else if (*dummyDataAttr == common::CUDADataAttr::Device) {
2641     if (!actualDataAttr) {
2642       if (isCudaUnified || isCudaManaged) {
2643         return 2;
2644       }
2645       return cudaInfMatchingValue;
2646     } else if (*actualDataAttr == common::CUDADataAttr::Device) {
2647       return 0;
2648     } else if (*actualDataAttr == common::CUDADataAttr::Managed ||
2649         *actualDataAttr == common::CUDADataAttr::Unified) {
2650       return 2;
2651     }
2652   } else if (*dummyDataAttr == common::CUDADataAttr::Managed) {
2653     if (!actualDataAttr) {
2654       return isCudaUnified ? 1 : isCudaManaged ? 0 : cudaInfMatchingValue;
2655     }
2656     if (*actualDataAttr == common::CUDADataAttr::Device) {
2657       return cudaInfMatchingValue;
2658     } else if (*actualDataAttr == common::CUDADataAttr::Managed) {
2659       return 0;
2660     } else if (*actualDataAttr == common::CUDADataAttr::Unified) {
2661       return 1;
2662     }
2663   } else if (*dummyDataAttr == common::CUDADataAttr::Unified) {
2664     if (!actualDataAttr) {
2665       return isCudaUnified ? 0 : isCudaManaged ? 1 : cudaInfMatchingValue;
2666     }
2667     if (*actualDataAttr == common::CUDADataAttr::Device) {
2668       return cudaInfMatchingValue;
2669     } else if (*actualDataAttr == common::CUDADataAttr::Managed) {
2670       return 1;
2671     } else if (*actualDataAttr == common::CUDADataAttr::Unified) {
2672       return 0;
2673     }
2674   }
2675   return cudaInfMatchingValue;
2676 }
2677 
2678 static int ComputeCudaMatchingDistance(
2679     const common::LanguageFeatureControl &features,
2680     const characteristics::Procedure &procedure,
2681     const ActualArguments &actuals) {
2682   const auto &dummies{procedure.dummyArguments};
2683   CHECK(dummies.size() == actuals.size());
2684   int distance{0};
2685   for (std::size_t i{0}; i < dummies.size(); ++i) {
2686     const characteristics::DummyArgument &dummy{dummies[i]};
2687     const std::optional<ActualArgument> &actual{actuals[i]};
2688     int d{GetMatchingDistance(features, dummy, actual)};
2689     if (d == cudaInfMatchingValue)
2690       return d;
2691     distance += d;
2692   }
2693   return distance;
2694 }
2695 
2696 // Handles a forward reference to a module function from what must
2697 // be a specification expression.  Return false if the symbol is
2698 // an invalid forward reference.
2699 const Symbol *ExpressionAnalyzer::ResolveForward(const Symbol &symbol) {
2700   if (context_.HasError(symbol)) {
2701     return nullptr;
2702   }
2703   if (const auto *details{
2704           symbol.detailsIf<semantics::SubprogramNameDetails>()}) {
2705     if (details->kind() == semantics::SubprogramKind::Module) {
2706       // If this symbol is still a SubprogramNameDetails, we must be
2707       // checking a specification expression in a sibling module
2708       // procedure.  Resolve its names now so that its interface
2709       // is known.
2710       const semantics::Scope &scope{symbol.owner()};
2711       semantics::ResolveSpecificationParts(context_, symbol);
2712       const Symbol *resolved{nullptr};
2713       if (auto iter{scope.find(symbol.name())}; iter != scope.cend()) {
2714         resolved = &*iter->second;
2715       }
2716       if (!resolved || resolved->has<semantics::SubprogramNameDetails>()) {
2717         // When the symbol hasn't had its details updated, we must have
2718         // already been in the process of resolving the function's
2719         // specification part; but recursive function calls are not
2720         // allowed in specification parts (10.1.11 para 5).
2721         Say("The module function '%s' may not be referenced recursively in a specification expression"_err_en_US,
2722             symbol.name());
2723         context_.SetError(symbol);
2724       }
2725       return resolved;
2726     } else if (inStmtFunctionDefinition_) {
2727       semantics::ResolveSpecificationParts(context_, symbol);
2728       CHECK(symbol.has<semantics::SubprogramDetails>());
2729     } else { // 10.1.11 para 4
2730       Say("The internal function '%s' may not be referenced in a specification expression"_err_en_US,
2731           symbol.name());
2732       context_.SetError(symbol);
2733       return nullptr;
2734     }
2735   }
2736   return &symbol;
2737 }
2738 
2739 // Resolve a call to a generic procedure with given actual arguments.
2740 // adjustActuals is called on procedure bindings to handle pass arg.
2741 std::pair<const Symbol *, bool> ExpressionAnalyzer::ResolveGeneric(
2742     const Symbol &symbol, const ActualArguments &actuals,
2743     const AdjustActuals &adjustActuals, bool isSubroutine,
2744     bool mightBeStructureConstructor) {
2745   const Symbol *elemental{nullptr}; // matching elemental specific proc
2746   const Symbol *nonElemental{nullptr}; // matching non-elemental specific
2747   const Symbol &ultimate{symbol.GetUltimate()};
2748   int crtMatchingDistance{cudaInfMatchingValue};
2749   // Check for a match with an explicit INTRINSIC
2750   if (ultimate.attrs().test(semantics::Attr::INTRINSIC)) {
2751     parser::Messages buffer;
2752     auto restorer{foldingContext_.messages().SetMessages(buffer)};
2753     ActualArguments localActuals{actuals};
2754     if (context_.intrinsics().Probe(
2755             CallCharacteristics{ultimate.name().ToString(), isSubroutine},
2756             localActuals, foldingContext_) &&
2757         !buffer.AnyFatalError()) {
2758       return {&ultimate, false};
2759     }
2760   }
2761   if (const auto *details{ultimate.detailsIf<semantics::GenericDetails>()}) {
2762     for (const Symbol &specific0 : details->specificProcs()) {
2763       const Symbol &specific1{BypassGeneric(specific0)};
2764       if (isSubroutine != !IsFunction(specific1)) {
2765         continue;
2766       }
2767       const Symbol *specific{ResolveForward(specific1)};
2768       if (!specific) {
2769         continue;
2770       }
2771       if (std::optional<characteristics::Procedure> procedure{
2772               characteristics::Procedure::Characterize(
2773                   ProcedureDesignator{*specific}, context_.foldingContext(),
2774                   /*emitError=*/false)}) {
2775         ActualArguments localActuals{actuals};
2776         if (specific->has<semantics::ProcBindingDetails>()) {
2777           if (!adjustActuals.value()(*specific, localActuals)) {
2778             continue;
2779           }
2780         }
2781         if (semantics::CheckInterfaceForGeneric(*procedure, localActuals,
2782                 context_, false /* no integer conversions */) &&
2783             CheckCompatibleArguments(
2784                 *procedure, localActuals, foldingContext_)) {
2785           if ((procedure->IsElemental() && elemental) ||
2786               (!procedure->IsElemental() && nonElemental)) {
2787             int d{ComputeCudaMatchingDistance(
2788                 context_.languageFeatures(), *procedure, localActuals)};
2789             if (d != crtMatchingDistance) {
2790               if (d > crtMatchingDistance) {
2791                 continue;
2792               }
2793               // Matching distance is smaller than the previously matched
2794               // specific. Let it go thourgh so the current procedure is picked.
2795             } else {
2796               // 16.9.144(6): a bare NULL() is not allowed as an actual
2797               // argument to a generic procedure if the specific procedure
2798               // cannot be unambiguously distinguished
2799               // Underspecified external procedure actual arguments can
2800               // also lead to ambiguity.
2801               return {nullptr, true /* due to ambiguity */};
2802             }
2803           }
2804           if (!procedure->IsElemental()) {
2805             // takes priority over elemental match
2806             nonElemental = specific;
2807           } else {
2808             elemental = specific;
2809           }
2810           crtMatchingDistance = ComputeCudaMatchingDistance(
2811               context_.languageFeatures(), *procedure, localActuals);
2812         }
2813       }
2814     }
2815     if (nonElemental) {
2816       return {&AccessSpecific(symbol, *nonElemental), false};
2817     } else if (elemental) {
2818       return {&AccessSpecific(symbol, *elemental), false};
2819     }
2820     // Check parent derived type
2821     if (const auto *parentScope{symbol.owner().GetDerivedTypeParent()}) {
2822       if (const Symbol *extended{parentScope->FindComponent(symbol.name())}) {
2823         auto pair{ResolveGeneric(
2824             *extended, actuals, adjustActuals, isSubroutine, false)};
2825         if (pair.first) {
2826           return pair;
2827         }
2828       }
2829     }
2830     if (mightBeStructureConstructor && details->derivedType()) {
2831       return {details->derivedType(), false};
2832     }
2833   }
2834   // Check for generic or explicit INTRINSIC of the same name in outer scopes.
2835   // See 15.5.5.2 for details.
2836   if (!symbol.owner().IsGlobal() && !symbol.owner().IsDerivedType()) {
2837     for (const std::string &n : GetAllNames(context_, symbol.name())) {
2838       if (const Symbol *outer{symbol.owner().parent().FindSymbol(n)}) {
2839         auto pair{ResolveGeneric(*outer, actuals, adjustActuals, isSubroutine,
2840             mightBeStructureConstructor)};
2841         if (pair.first) {
2842           return pair;
2843         }
2844       }
2845     }
2846   }
2847   return {nullptr, false};
2848 }
2849 
2850 const Symbol &ExpressionAnalyzer::AccessSpecific(
2851     const Symbol &originalGeneric, const Symbol &specific) {
2852   if (const auto *hosted{
2853           originalGeneric.detailsIf<semantics::HostAssocDetails>()}) {
2854     return AccessSpecific(hosted->symbol(), specific);
2855   } else if (const auto *used{
2856                  originalGeneric.detailsIf<semantics::UseDetails>()}) {
2857     const auto &scope{originalGeneric.owner()};
2858     if (auto iter{scope.find(specific.name())}; iter != scope.end()) {
2859       if (const auto *useDetails{
2860               iter->second->detailsIf<semantics::UseDetails>()}) {
2861         const Symbol &usedSymbol{useDetails->symbol()};
2862         const auto *usedGeneric{
2863             usedSymbol.detailsIf<semantics::GenericDetails>()};
2864         if (&usedSymbol == &specific ||
2865             (usedGeneric && usedGeneric->specific() == &specific)) {
2866           return specific;
2867         }
2868       }
2869     }
2870     // Create a renaming USE of the specific procedure.
2871     auto rename{context_.SaveTempName(
2872         used->symbol().owner().GetName().value().ToString() + "$" +
2873         specific.owner().GetName().value().ToString() + "$" +
2874         specific.name().ToString())};
2875     return *const_cast<semantics::Scope &>(scope)
2876                 .try_emplace(rename, specific.attrs(),
2877                     semantics::UseDetails{rename, specific})
2878                 .first->second;
2879   } else {
2880     return specific;
2881   }
2882 }
2883 
2884 void ExpressionAnalyzer::EmitGenericResolutionError(
2885     const Symbol &symbol, bool dueToAmbiguity, bool isSubroutine) {
2886   Say(dueToAmbiguity
2887           ? "The actual arguments to the generic procedure '%s' matched multiple specific procedures, perhaps due to use of NULL() without MOLD= or an actual procedure with an implicit interface"_err_en_US
2888           : semantics::IsGenericDefinedOp(symbol)
2889           ? "No specific procedure of generic operator '%s' matches the actual arguments"_err_en_US
2890           : isSubroutine
2891           ? "No specific subroutine of generic '%s' matches the actual arguments"_err_en_US
2892           : "No specific function of generic '%s' matches the actual arguments"_err_en_US,
2893       symbol.name());
2894 }
2895 
2896 auto ExpressionAnalyzer::GetCalleeAndArguments(
2897     const parser::ProcedureDesignator &pd, ActualArguments &&arguments,
2898     bool isSubroutine, bool mightBeStructureConstructor)
2899     -> std::optional<CalleeAndArguments> {
2900   return common::visit(common::visitors{
2901                            [&](const parser::Name &name) {
2902                              return GetCalleeAndArguments(name,
2903                                  std::move(arguments), isSubroutine,
2904                                  mightBeStructureConstructor);
2905                            },
2906                            [&](const parser::ProcComponentRef &pcr) {
2907                              return AnalyzeProcedureComponentRef(
2908                                  pcr, std::move(arguments), isSubroutine);
2909                            },
2910                        },
2911       pd.u);
2912 }
2913 
2914 auto ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name,
2915     ActualArguments &&arguments, bool isSubroutine,
2916     bool mightBeStructureConstructor) -> std::optional<CalleeAndArguments> {
2917   const Symbol *symbol{name.symbol};
2918   if (context_.HasError(symbol)) {
2919     return std::nullopt; // also handles null symbol
2920   }
2921   symbol = ResolveForward(*symbol);
2922   if (!symbol) {
2923     return std::nullopt;
2924   }
2925   name.symbol = const_cast<Symbol *>(symbol);
2926   const Symbol &ultimate{symbol->GetUltimate()};
2927   CheckForBadRecursion(name.source, ultimate);
2928   bool dueToAmbiguity{false};
2929   bool isGenericInterface{ultimate.has<semantics::GenericDetails>()};
2930   bool isExplicitIntrinsic{ultimate.attrs().test(semantics::Attr::INTRINSIC)};
2931   const Symbol *resolution{nullptr};
2932   if (isGenericInterface || isExplicitIntrinsic) {
2933     ExpressionAnalyzer::AdjustActuals noAdjustment;
2934     auto pair{ResolveGeneric(*symbol, arguments, noAdjustment, isSubroutine,
2935         mightBeStructureConstructor)};
2936     resolution = pair.first;
2937     dueToAmbiguity = pair.second;
2938     if (resolution) {
2939       if (context_.GetPPCBuiltinsScope() &&
2940           resolution->name().ToString().rfind("__ppc_", 0) == 0) {
2941         semantics::CheckPPCIntrinsic(
2942             *symbol, *resolution, arguments, GetFoldingContext());
2943       }
2944       // re-resolve name to the specific procedure
2945       name.symbol = const_cast<Symbol *>(resolution);
2946     }
2947   } else if (IsProcedure(ultimate) &&
2948       ultimate.attrs().test(semantics::Attr::ABSTRACT)) {
2949     Say("Abstract procedure interface '%s' may not be referenced"_err_en_US,
2950         name.source);
2951   } else {
2952     resolution = symbol;
2953   }
2954   if (resolution && context_.targetCharacteristics().isOSWindows()) {
2955     semantics::CheckWindowsIntrinsic(*resolution, GetFoldingContext());
2956   }
2957   if (!resolution || resolution->attrs().test(semantics::Attr::INTRINSIC)) {
2958     auto name{resolution ? resolution->name() : ultimate.name()};
2959     if (std::optional<SpecificCall> specificCall{context_.intrinsics().Probe(
2960             CallCharacteristics{name.ToString(), isSubroutine}, arguments,
2961             GetFoldingContext())}) {
2962       CheckBadExplicitType(*specificCall, *symbol);
2963       return CalleeAndArguments{
2964           ProcedureDesignator{std::move(specificCall->specificIntrinsic)},
2965           std::move(specificCall->arguments)};
2966     } else {
2967       if (isGenericInterface) {
2968         EmitGenericResolutionError(*symbol, dueToAmbiguity, isSubroutine);
2969       }
2970       return std::nullopt;
2971     }
2972   }
2973   if (resolution->GetUltimate().has<semantics::DerivedTypeDetails>()) {
2974     if (mightBeStructureConstructor) {
2975       return CalleeAndArguments{
2976           semantics::SymbolRef{*resolution}, std::move(arguments)};
2977     }
2978   } else if (IsProcedure(*resolution)) {
2979     return CalleeAndArguments{
2980         ProcedureDesignator{*resolution}, std::move(arguments)};
2981   }
2982   if (!context_.HasError(*resolution)) {
2983     AttachDeclaration(
2984         Say(name.source, "'%s' is not a callable procedure"_err_en_US,
2985             name.source),
2986         *resolution);
2987   }
2988   return std::nullopt;
2989 }
2990 
2991 // Fortran 2018 expressly states (8.2 p3) that any declared type for a
2992 // generic intrinsic function "has no effect" on the result type of a
2993 // call to that intrinsic.  So one can declare "character*8 cos" and
2994 // still get a real result from "cos(1.)".  This is a dangerous feature,
2995 // especially since implementations are free to extend their sets of
2996 // intrinsics, and in doing so might clash with a name in a program.
2997 // So we emit a warning in this situation, and perhaps it should be an
2998 // error -- any correctly working program can silence the message by
2999 // simply deleting the pointless type declaration.
3000 void ExpressionAnalyzer::CheckBadExplicitType(
3001     const SpecificCall &call, const Symbol &intrinsic) {
3002   if (intrinsic.GetUltimate().GetType()) {
3003     const auto &procedure{call.specificIntrinsic.characteristics.value()};
3004     if (const auto &result{procedure.functionResult}) {
3005       if (const auto *typeAndShape{result->GetTypeAndShape()}) {
3006         if (auto declared{
3007                 typeAndShape->Characterize(intrinsic, GetFoldingContext())}) {
3008           if (!declared->type().IsTkCompatibleWith(typeAndShape->type())) {
3009             if (auto *msg{Warn(
3010                     common::UsageWarning::IgnoredIntrinsicFunctionType,
3011                     "The result type '%s' of the intrinsic function '%s' is not the explicit declared type '%s'"_warn_en_US,
3012                     typeAndShape->AsFortran(), intrinsic.name(),
3013                     declared->AsFortran())}) {
3014               msg->Attach(intrinsic.name(),
3015                   "Ignored declaration of intrinsic function '%s'"_en_US,
3016                   intrinsic.name());
3017             }
3018           }
3019         }
3020       }
3021     }
3022   }
3023 }
3024 
3025 void ExpressionAnalyzer::CheckForBadRecursion(
3026     parser::CharBlock callSite, const semantics::Symbol &proc) {
3027   if (const auto *scope{proc.scope()}) {
3028     if (scope->sourceRange().Contains(callSite)) {
3029       parser::Message *msg{nullptr};
3030       if (proc.attrs().test(semantics::Attr::NON_RECURSIVE)) { // 15.6.2.1(3)
3031         msg = Say("NON_RECURSIVE procedure '%s' cannot call itself"_err_en_US,
3032             callSite);
3033       } else if (IsAssumedLengthCharacter(proc) && IsExternal(proc)) {
3034         // TODO: Also catch assumed PDT type parameters
3035         msg = Say( // 15.6.2.1(3)
3036             "Assumed-length CHARACTER(*) function '%s' cannot call itself"_err_en_US,
3037             callSite);
3038       } else if (FindCUDADeviceContext(scope)) {
3039         msg = Say(
3040             "Device subprogram '%s' cannot call itself"_err_en_US, callSite);
3041       }
3042       AttachDeclaration(msg, proc);
3043     }
3044   }
3045 }
3046 
3047 template <typename A> static const Symbol *AssumedTypeDummy(const A &x) {
3048   if (const auto *designator{
3049           std::get_if<common::Indirection<parser::Designator>>(&x.u)}) {
3050     if (const auto *dataRef{
3051             std::get_if<parser::DataRef>(&designator->value().u)}) {
3052       if (const auto *name{std::get_if<parser::Name>(&dataRef->u)}) {
3053         return AssumedTypeDummy(*name);
3054       }
3055     }
3056   }
3057   return nullptr;
3058 }
3059 template <>
3060 const Symbol *AssumedTypeDummy<parser::Name>(const parser::Name &name) {
3061   if (const Symbol *symbol{name.symbol}) {
3062     if (const auto *type{symbol->GetType()}) {
3063       if (type->category() == semantics::DeclTypeSpec::TypeStar) {
3064         return symbol;
3065       }
3066     }
3067   }
3068   return nullptr;
3069 }
3070 template <typename A>
3071 static const Symbol *AssumedTypePointerOrAllocatableDummy(const A &object) {
3072   // It is illegal for allocatable of pointer objects to be TYPE(*), but at that
3073   // point it is not guaranteed that it has been checked the object has
3074   // POINTER or ALLOCATABLE attribute, so do not assume nullptr can be directly
3075   // returned.
3076   return common::visit(
3077       common::visitors{
3078           [&](const parser::StructureComponent &x) {
3079             return AssumedTypeDummy(x.component);
3080           },
3081           [&](const parser::Name &x) { return AssumedTypeDummy(x); },
3082       },
3083       object.u);
3084 }
3085 template <>
3086 const Symbol *AssumedTypeDummy<parser::AllocateObject>(
3087     const parser::AllocateObject &x) {
3088   return AssumedTypePointerOrAllocatableDummy(x);
3089 }
3090 template <>
3091 const Symbol *AssumedTypeDummy<parser::PointerObject>(
3092     const parser::PointerObject &x) {
3093   return AssumedTypePointerOrAllocatableDummy(x);
3094 }
3095 
3096 bool ExpressionAnalyzer::CheckIsValidForwardReference(
3097     const semantics::DerivedTypeSpec &dtSpec) {
3098   if (dtSpec.IsForwardReferenced()) {
3099     Say("Cannot construct value for derived type '%s' before it is defined"_err_en_US,
3100         dtSpec.name());
3101     return false;
3102   }
3103   return true;
3104 }
3105 
3106 std::optional<Chevrons> ExpressionAnalyzer::AnalyzeChevrons(
3107     const parser::CallStmt &call) {
3108   Chevrons result;
3109   auto checkLaunchArg{[&](const Expr<SomeType> &expr, const char *which) {
3110     if (auto dyType{expr.GetType()}) {
3111       if (dyType->category() == TypeCategory::Integer) {
3112         return true;
3113       }
3114       if (dyType->category() == TypeCategory::Derived &&
3115           !dyType->IsPolymorphic() &&
3116           IsBuiltinDerivedType(&dyType->GetDerivedTypeSpec(), "dim3")) {
3117         return true;
3118       }
3119     }
3120     Say("Kernel launch %s parameter must be either integer or TYPE(dim3)"_err_en_US,
3121         which);
3122     return false;
3123   }};
3124   if (const auto &chevrons{call.chevrons}) {
3125     auto &starOrExpr{std::get<0>(chevrons->t)};
3126     if (starOrExpr.v) {
3127       if (auto expr{Analyze(*starOrExpr.v)};
3128           expr && checkLaunchArg(*expr, "grid")) {
3129         result.emplace_back(*expr);
3130       } else {
3131         return std::nullopt;
3132       }
3133     } else {
3134       result.emplace_back(
3135           AsGenericExpr(evaluate::Constant<evaluate::CInteger>{-1}));
3136     }
3137     if (auto expr{Analyze(std::get<1>(chevrons->t))};
3138         expr && checkLaunchArg(*expr, "block")) {
3139       result.emplace_back(*expr);
3140     } else {
3141       return std::nullopt;
3142     }
3143     if (const auto &maybeExpr{std::get<2>(chevrons->t)}) {
3144       if (auto expr{Analyze(*maybeExpr)}) {
3145         result.emplace_back(*expr);
3146       } else {
3147         return std::nullopt;
3148       }
3149     }
3150     if (const auto &maybeExpr{std::get<3>(chevrons->t)}) {
3151       if (auto expr{Analyze(*maybeExpr)}) {
3152         result.emplace_back(*expr);
3153       } else {
3154         return std::nullopt;
3155       }
3156     }
3157   }
3158   return std::move(result);
3159 }
3160 
3161 MaybeExpr ExpressionAnalyzer::Analyze(const parser::FunctionReference &funcRef,
3162     std::optional<parser::StructureConstructor> *structureConstructor) {
3163   const parser::Call &call{funcRef.v};
3164   auto restorer{GetContextualMessages().SetLocation(funcRef.source)};
3165   ArgumentAnalyzer analyzer{*this, funcRef.source, true /* isProcedureCall */};
3166   for (const auto &arg : std::get<std::list<parser::ActualArgSpec>>(call.t)) {
3167     analyzer.Analyze(arg, false /* not subroutine call */);
3168   }
3169   if (analyzer.fatalErrors()) {
3170     return std::nullopt;
3171   }
3172   bool mightBeStructureConstructor{structureConstructor != nullptr};
3173   if (std::optional<CalleeAndArguments> callee{GetCalleeAndArguments(
3174           std::get<parser::ProcedureDesignator>(call.t), analyzer.GetActuals(),
3175           false /* not subroutine */, mightBeStructureConstructor)}) {
3176     if (auto *proc{std::get_if<ProcedureDesignator>(&callee->u)}) {
3177       return MakeFunctionRef(
3178           funcRef.source, std::move(*proc), std::move(callee->arguments));
3179     }
3180     CHECK(std::holds_alternative<semantics::SymbolRef>(callee->u));
3181     const Symbol &symbol{*std::get<semantics::SymbolRef>(callee->u)};
3182     if (mightBeStructureConstructor) {
3183       // Structure constructor misparsed as function reference?
3184       const auto &designator{std::get<parser::ProcedureDesignator>(call.t)};
3185       if (const auto *name{std::get_if<parser::Name>(&designator.u)}) {
3186         semantics::Scope &scope{context_.FindScope(name->source)};
3187         semantics::DerivedTypeSpec dtSpec{name->source, symbol.GetUltimate()};
3188         if (!CheckIsValidForwardReference(dtSpec)) {
3189           return std::nullopt;
3190         }
3191         const semantics::DeclTypeSpec &type{
3192             semantics::FindOrInstantiateDerivedType(scope, std::move(dtSpec))};
3193         auto &mutableRef{const_cast<parser::FunctionReference &>(funcRef)};
3194         *structureConstructor =
3195             mutableRef.ConvertToStructureConstructor(type.derivedTypeSpec());
3196         return Analyze(structureConstructor->value());
3197       }
3198     }
3199     if (!context_.HasError(symbol)) {
3200       AttachDeclaration(
3201           Say("'%s' is called like a function but is not a procedure"_err_en_US,
3202               symbol.name()),
3203           symbol);
3204       context_.SetError(symbol);
3205     }
3206   }
3207   return std::nullopt;
3208 }
3209 
3210 static bool HasAlternateReturns(const evaluate::ActualArguments &args) {
3211   for (const auto &arg : args) {
3212     if (arg && arg->isAlternateReturn()) {
3213       return true;
3214     }
3215   }
3216   return false;
3217 }
3218 
3219 void ExpressionAnalyzer::Analyze(const parser::CallStmt &callStmt) {
3220   const parser::Call &call{callStmt.call};
3221   auto restorer{GetContextualMessages().SetLocation(callStmt.source)};
3222   ArgumentAnalyzer analyzer{*this, callStmt.source, true /* isProcedureCall */};
3223   const auto &actualArgList{std::get<std::list<parser::ActualArgSpec>>(call.t)};
3224   for (const auto &arg : actualArgList) {
3225     analyzer.Analyze(arg, true /* is subroutine call */);
3226   }
3227   if (auto chevrons{AnalyzeChevrons(callStmt)};
3228       chevrons && !analyzer.fatalErrors()) {
3229     if (std::optional<CalleeAndArguments> callee{
3230             GetCalleeAndArguments(std::get<parser::ProcedureDesignator>(call.t),
3231                 analyzer.GetActuals(), true /* subroutine */)}) {
3232       ProcedureDesignator *proc{std::get_if<ProcedureDesignator>(&callee->u)};
3233       CHECK(proc);
3234       bool isKernel{false};
3235       if (const Symbol * procSym{proc->GetSymbol()}) {
3236         const Symbol &ultimate{procSym->GetUltimate()};
3237         if (const auto *subpDetails{
3238                 ultimate.detailsIf<semantics::SubprogramDetails>()}) {
3239           if (auto attrs{subpDetails->cudaSubprogramAttrs()}) {
3240             isKernel = *attrs == common::CUDASubprogramAttrs::Global ||
3241                 *attrs == common::CUDASubprogramAttrs::Grid_Global;
3242           }
3243         } else if (const auto *procDetails{
3244                        ultimate.detailsIf<semantics::ProcEntityDetails>()}) {
3245           isKernel = procDetails->isCUDAKernel();
3246         }
3247         if (isKernel && chevrons->empty()) {
3248           Say("'%s' is a kernel subroutine and must be called with kernel launch parameters in chevrons"_err_en_US,
3249               procSym->name());
3250         }
3251       }
3252       if (!isKernel && !chevrons->empty()) {
3253         Say("Kernel launch parameters in chevrons may not be used unless calling a kernel subroutine"_err_en_US);
3254       }
3255       if (CheckCall(callStmt.source, *proc, callee->arguments)) {
3256         callStmt.typedCall.Reset(
3257             new ProcedureRef{std::move(*proc), std::move(callee->arguments),
3258                 HasAlternateReturns(callee->arguments)},
3259             ProcedureRef::Deleter);
3260         DEREF(callStmt.typedCall.get()).set_chevrons(std::move(*chevrons));
3261         return;
3262       }
3263     }
3264     if (!context_.AnyFatalError()) {
3265       std::string buf;
3266       llvm::raw_string_ostream dump{buf};
3267       parser::DumpTree(dump, callStmt);
3268       Say("Internal error: Expression analysis failed on CALL statement: %s"_err_en_US,
3269           buf);
3270     }
3271   }
3272 }
3273 
3274 const Assignment *ExpressionAnalyzer::Analyze(const parser::AssignmentStmt &x) {
3275   if (!x.typedAssignment) {
3276     ArgumentAnalyzer analyzer{*this};
3277     const auto &variable{std::get<parser::Variable>(x.t)};
3278     analyzer.Analyze(variable);
3279     analyzer.Analyze(std::get<parser::Expr>(x.t));
3280     std::optional<Assignment> assignment;
3281     if (!analyzer.fatalErrors()) {
3282       auto restorer{GetContextualMessages().SetLocation(variable.GetSource())};
3283       std::optional<ProcedureRef> procRef{analyzer.TryDefinedAssignment()};
3284       if (!procRef) {
3285         analyzer.CheckForNullPointer(
3286             "in a non-pointer intrinsic assignment statement");
3287         analyzer.CheckForAssumedRank("in an assignment statement");
3288         const Expr<SomeType> &lhs{analyzer.GetExpr(0)};
3289         if (auto dyType{lhs.GetType()};
3290             dyType && dyType->IsPolymorphic()) { // 10.2.1.2p1(1)
3291           const Symbol *lastWhole0{UnwrapWholeSymbolOrComponentDataRef(lhs)};
3292           const Symbol *lastWhole{
3293               lastWhole0 ? &lastWhole0->GetUltimate() : nullptr};
3294           if (!lastWhole || !IsAllocatable(*lastWhole)) {
3295             Say("Left-hand side of assignment may not be polymorphic unless assignment is to an entire allocatable"_err_en_US);
3296           } else if (evaluate::IsCoarray(*lastWhole)) {
3297             Say("Left-hand side of assignment may not be polymorphic if it is a coarray"_err_en_US);
3298           }
3299         }
3300       }
3301       assignment.emplace(analyzer.MoveExpr(0), analyzer.MoveExpr(1));
3302       if (procRef) {
3303         assignment->u = std::move(*procRef);
3304       }
3305     }
3306     x.typedAssignment.Reset(new GenericAssignmentWrapper{std::move(assignment)},
3307         GenericAssignmentWrapper::Deleter);
3308   }
3309   return common::GetPtrFromOptional(x.typedAssignment->v);
3310 }
3311 
3312 const Assignment *ExpressionAnalyzer::Analyze(
3313     const parser::PointerAssignmentStmt &x) {
3314   if (!x.typedAssignment) {
3315     MaybeExpr lhs{Analyze(std::get<parser::DataRef>(x.t))};
3316     MaybeExpr rhs;
3317     {
3318       auto restorer{AllowNullPointer()};
3319       rhs = Analyze(std::get<parser::Expr>(x.t));
3320     }
3321     if (!lhs || !rhs) {
3322       x.typedAssignment.Reset(
3323           new GenericAssignmentWrapper{}, GenericAssignmentWrapper::Deleter);
3324     } else {
3325       Assignment assignment{std::move(*lhs), std::move(*rhs)};
3326       common::visit(
3327           common::visitors{
3328               [&](const std::list<parser::BoundsRemapping> &list) {
3329                 Assignment::BoundsRemapping bounds;
3330                 for (const auto &elem : list) {
3331                   auto lower{AsSubscript(Analyze(std::get<0>(elem.t)))};
3332                   auto upper{AsSubscript(Analyze(std::get<1>(elem.t)))};
3333                   if (lower && upper) {
3334                     bounds.emplace_back(
3335                         Fold(std::move(*lower)), Fold(std::move(*upper)));
3336                   }
3337                 }
3338                 assignment.u = std::move(bounds);
3339               },
3340               [&](const std::list<parser::BoundsSpec> &list) {
3341                 Assignment::BoundsSpec bounds;
3342                 for (const auto &bound : list) {
3343                   if (auto lower{AsSubscript(Analyze(bound.v))}) {
3344                     bounds.emplace_back(Fold(std::move(*lower)));
3345                   }
3346                 }
3347                 assignment.u = std::move(bounds);
3348               },
3349           },
3350           std::get<parser::PointerAssignmentStmt::Bounds>(x.t).u);
3351       x.typedAssignment.Reset(
3352           new GenericAssignmentWrapper{std::move(assignment)},
3353           GenericAssignmentWrapper::Deleter);
3354     }
3355   }
3356   return common::GetPtrFromOptional(x.typedAssignment->v);
3357 }
3358 
3359 static bool IsExternalCalledImplicitly(
3360     parser::CharBlock callSite, const Symbol *symbol) {
3361   return symbol && symbol->owner().IsGlobal() &&
3362       symbol->has<semantics::SubprogramDetails>() &&
3363       (!symbol->scope() /*ENTRY*/ ||
3364           !symbol->scope()->sourceRange().Contains(callSite));
3365 }
3366 
3367 std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
3368     parser::CharBlock callSite, const ProcedureDesignator &proc,
3369     ActualArguments &arguments) {
3370   bool treatExternalAsImplicit{
3371       IsExternalCalledImplicitly(callSite, proc.GetSymbol())};
3372   const Symbol *procSymbol{proc.GetSymbol()};
3373   std::optional<characteristics::Procedure> chars;
3374   if (procSymbol && procSymbol->has<semantics::ProcEntityDetails>() &&
3375       procSymbol->owner().IsGlobal()) {
3376     // Unknown global external, implicit interface; assume
3377     // characteristics from the actual arguments, and check
3378     // for consistency with other references.
3379     chars = characteristics::Procedure::FromActuals(
3380         proc, arguments, context_.foldingContext());
3381     if (chars && procSymbol) {
3382       // Ensure calls over implicit interfaces are consistent
3383       auto name{procSymbol->name()};
3384       if (auto iter{implicitInterfaces_.find(name)};
3385           iter != implicitInterfaces_.end()) {
3386         std::string whyNot;
3387         if (!chars->IsCompatibleWith(iter->second.second,
3388                 /*ignoreImplicitVsExplicit=*/false, &whyNot)) {
3389           if (auto *msg{Warn(
3390                   common::UsageWarning::IncompatibleImplicitInterfaces,
3391                   callSite,
3392                   "Reference to the procedure '%s' has an implicit interface that is distinct from another reference: %s"_warn_en_US,
3393                   name, whyNot)}) {
3394             msg->Attach(
3395                 iter->second.first, "previous reference to '%s'"_en_US, name);
3396           }
3397         }
3398       } else {
3399         implicitInterfaces_.insert(
3400             std::make_pair(name, std::make_pair(callSite, *chars)));
3401       }
3402     }
3403   }
3404   if (!chars) {
3405     chars = characteristics::Procedure::Characterize(
3406         proc, context_.foldingContext(), /*emitError=*/true);
3407   }
3408   bool ok{true};
3409   if (chars) {
3410     std::string whyNot;
3411     if (treatExternalAsImplicit &&
3412         !chars->CanBeCalledViaImplicitInterface(&whyNot)) {
3413       if (auto *msg{Say(callSite,
3414               "References to the procedure '%s' require an explicit interface"_err_en_US,
3415               DEREF(procSymbol).name())};
3416           msg && !whyNot.empty()) {
3417         msg->Attach(callSite, "%s"_because_en_US, whyNot);
3418       }
3419     }
3420     const SpecificIntrinsic *specificIntrinsic{proc.GetSpecificIntrinsic()};
3421     bool procIsDummy{procSymbol && IsDummy(*procSymbol)};
3422     if (chars->functionResult &&
3423         chars->functionResult->IsAssumedLengthCharacter() &&
3424         !specificIntrinsic && !procIsDummy) {
3425       Say(callSite,
3426           "Assumed-length character function must be defined with a length to be called"_err_en_US);
3427     }
3428     ok &= semantics::CheckArguments(*chars, arguments, context_,
3429         context_.FindScope(callSite), treatExternalAsImplicit,
3430         /*ignoreImplicitVsExplicit=*/false, specificIntrinsic);
3431   }
3432   if (procSymbol && !IsPureProcedure(*procSymbol)) {
3433     if (const semantics::Scope *
3434         pure{semantics::FindPureProcedureContaining(
3435             context_.FindScope(callSite))}) {
3436       Say(callSite,
3437           "Procedure '%s' referenced in pure subprogram '%s' must be pure too"_err_en_US,
3438           procSymbol->name(), DEREF(pure->symbol()).name());
3439     }
3440   }
3441   if (ok && !treatExternalAsImplicit && procSymbol &&
3442       !(chars && chars->HasExplicitInterface())) {
3443     if (const Symbol *global{FindGlobal(*procSymbol)};
3444         global && global != procSymbol && IsProcedure(*global)) {
3445       // Check a known global definition behind a local interface
3446       if (auto globalChars{characteristics::Procedure::Characterize(
3447               *global, context_.foldingContext())}) {
3448         semantics::CheckArguments(*globalChars, arguments, context_,
3449             context_.FindScope(callSite), /*treatExternalAsImplicit=*/true,
3450             /*ignoreImplicitVsExplicit=*/false,
3451             nullptr /*not specific intrinsic*/);
3452       }
3453     }
3454   }
3455   return chars;
3456 }
3457 
3458 // Unary operations
3459 
3460 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Parentheses &x) {
3461   if (MaybeExpr operand{Analyze(x.v.value())}) {
3462     if (const semantics::Symbol *symbol{GetLastSymbol(*operand)}) {
3463       if (const semantics::Symbol *result{FindFunctionResult(*symbol)}) {
3464         if (semantics::IsProcedurePointer(*result)) {
3465           Say("A function reference that returns a procedure "
3466               "pointer may not be parenthesized"_err_en_US); // C1003
3467         }
3468       }
3469     }
3470     return Parenthesize(std::move(*operand));
3471   }
3472   return std::nullopt;
3473 }
3474 
3475 static MaybeExpr NumericUnaryHelper(ExpressionAnalyzer &context,
3476     NumericOperator opr, const parser::Expr::IntrinsicUnary &x) {
3477   ArgumentAnalyzer analyzer{context};
3478   analyzer.Analyze(x.v);
3479   if (!analyzer.fatalErrors()) {
3480     if (analyzer.IsIntrinsicNumeric(opr)) {
3481       analyzer.CheckForNullPointer();
3482       analyzer.CheckForAssumedRank();
3483       if (opr == NumericOperator::Add) {
3484         return analyzer.MoveExpr(0);
3485       } else {
3486         return Negation(context.GetContextualMessages(), analyzer.MoveExpr(0));
3487       }
3488     } else {
3489       return analyzer.TryDefinedOp(AsFortran(opr),
3490           "Operand of unary %s must be numeric; have %s"_err_en_US);
3491     }
3492   }
3493   return std::nullopt;
3494 }
3495 
3496 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::UnaryPlus &x) {
3497   return NumericUnaryHelper(*this, NumericOperator::Add, x);
3498 }
3499 
3500 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Negate &x) {
3501   if (const auto *litConst{
3502           std::get_if<parser::LiteralConstant>(&x.v.value().u)}) {
3503     if (const auto *intConst{
3504             std::get_if<parser::IntLiteralConstant>(&litConst->u)}) {
3505       return Analyze(*intConst, true);
3506     }
3507   }
3508   return NumericUnaryHelper(*this, NumericOperator::Subtract, x);
3509 }
3510 
3511 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::NOT &x) {
3512   ArgumentAnalyzer analyzer{*this};
3513   analyzer.Analyze(x.v);
3514   if (!analyzer.fatalErrors()) {
3515     if (analyzer.IsIntrinsicLogical()) {
3516       analyzer.CheckForNullPointer();
3517       analyzer.CheckForAssumedRank();
3518       return AsGenericExpr(
3519           LogicalNegation(std::get<Expr<SomeLogical>>(analyzer.MoveExpr(0).u)));
3520     } else {
3521       return analyzer.TryDefinedOp(LogicalOperator::Not,
3522           "Operand of %s must be LOGICAL; have %s"_err_en_US);
3523     }
3524   }
3525   return std::nullopt;
3526 }
3527 
3528 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::PercentLoc &x) {
3529   // Represent %LOC() exactly as if it had been a call to the LOC() extension
3530   // intrinsic function.
3531   // Use the actual source for the name of the call for error reporting.
3532   std::optional<ActualArgument> arg;
3533   if (const Symbol *assumedTypeDummy{AssumedTypeDummy(x.v.value())}) {
3534     arg = ActualArgument{ActualArgument::AssumedType{*assumedTypeDummy}};
3535   } else if (MaybeExpr argExpr{Analyze(x.v.value())}) {
3536     arg = ActualArgument{std::move(*argExpr)};
3537   } else {
3538     return std::nullopt;
3539   }
3540   parser::CharBlock at{GetContextualMessages().at()};
3541   CHECK(at.size() >= 4);
3542   parser::CharBlock loc{at.begin() + 1, 3};
3543   CHECK(loc == "loc");
3544   return MakeFunctionRef(loc, ActualArguments{std::move(*arg)});
3545 }
3546 
3547 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::DefinedUnary &x) {
3548   const auto &name{std::get<parser::DefinedOpName>(x.t).v};
3549   ArgumentAnalyzer analyzer{*this, name.source};
3550   analyzer.Analyze(std::get<1>(x.t));
3551   return analyzer.TryDefinedOp(name.source.ToString().c_str(),
3552       "No operator %s defined for %s"_err_en_US, true);
3553 }
3554 
3555 // Binary (dyadic) operations
3556 
3557 template <template <typename> class OPR, NumericOperator opr>
3558 MaybeExpr NumericBinaryHelper(
3559     ExpressionAnalyzer &context, const parser::Expr::IntrinsicBinary &x) {
3560   ArgumentAnalyzer analyzer{context};
3561   analyzer.Analyze(std::get<0>(x.t));
3562   analyzer.Analyze(std::get<1>(x.t));
3563   if (!analyzer.fatalErrors()) {
3564     if (analyzer.IsIntrinsicNumeric(opr)) {
3565       analyzer.CheckForNullPointer();
3566       analyzer.CheckForAssumedRank();
3567       analyzer.CheckConformance();
3568       constexpr bool canBeUnsigned{opr != NumericOperator::Power};
3569       return NumericOperation<OPR, canBeUnsigned>(
3570           context.GetContextualMessages(), analyzer.MoveExpr(0),
3571           analyzer.MoveExpr(1), context.GetDefaultKind(TypeCategory::Real));
3572     } else {
3573       return analyzer.TryDefinedOp(AsFortran(opr),
3574           "Operands of %s must be numeric; have %s and %s"_err_en_US);
3575     }
3576   }
3577   return std::nullopt;
3578 }
3579 
3580 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Power &x) {
3581   return NumericBinaryHelper<Power, NumericOperator::Power>(*this, x);
3582 }
3583 
3584 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Multiply &x) {
3585   return NumericBinaryHelper<Multiply, NumericOperator::Multiply>(*this, x);
3586 }
3587 
3588 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Divide &x) {
3589   return NumericBinaryHelper<Divide, NumericOperator::Divide>(*this, x);
3590 }
3591 
3592 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Add &x) {
3593   return NumericBinaryHelper<Add, NumericOperator::Add>(*this, x);
3594 }
3595 
3596 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Subtract &x) {
3597   return NumericBinaryHelper<Subtract, NumericOperator::Subtract>(*this, x);
3598 }
3599 
3600 MaybeExpr ExpressionAnalyzer::Analyze(
3601     const parser::Expr::ComplexConstructor &z) {
3602   Warn(common::LanguageFeature::ComplexConstructor,
3603       "nonstandard usage: generalized COMPLEX constructor"_port_en_US);
3604   return AnalyzeComplex(Analyze(std::get<0>(z.t).value()),
3605       Analyze(std::get<1>(z.t).value()), "complex constructor");
3606 }
3607 
3608 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Concat &x) {
3609   ArgumentAnalyzer analyzer{*this};
3610   analyzer.Analyze(std::get<0>(x.t));
3611   analyzer.Analyze(std::get<1>(x.t));
3612   if (!analyzer.fatalErrors()) {
3613     if (analyzer.IsIntrinsicConcat()) {
3614       analyzer.CheckForNullPointer();
3615       analyzer.CheckForAssumedRank();
3616       return common::visit(
3617           [&](auto &&x, auto &&y) -> MaybeExpr {
3618             using T = ResultType<decltype(x)>;
3619             if constexpr (std::is_same_v<T, ResultType<decltype(y)>>) {
3620               return AsGenericExpr(Concat<T::kind>{std::move(x), std::move(y)});
3621             } else {
3622               DIE("different types for intrinsic concat");
3623             }
3624           },
3625           std::move(std::get<Expr<SomeCharacter>>(analyzer.MoveExpr(0).u).u),
3626           std::move(std::get<Expr<SomeCharacter>>(analyzer.MoveExpr(1).u).u));
3627     } else {
3628       return analyzer.TryDefinedOp("//",
3629           "Operands of %s must be CHARACTER with the same kind; have %s and %s"_err_en_US);
3630     }
3631   }
3632   return std::nullopt;
3633 }
3634 
3635 // The Name represents a user-defined intrinsic operator.
3636 // If the actuals match one of the specific procedures, return a function ref.
3637 // Otherwise report the error in messages.
3638 MaybeExpr ExpressionAnalyzer::AnalyzeDefinedOp(
3639     const parser::Name &name, ActualArguments &&actuals) {
3640   if (auto callee{GetCalleeAndArguments(name, std::move(actuals))}) {
3641     CHECK(std::holds_alternative<ProcedureDesignator>(callee->u));
3642     return MakeFunctionRef(name.source,
3643         std::move(std::get<ProcedureDesignator>(callee->u)),
3644         std::move(callee->arguments));
3645   } else {
3646     return std::nullopt;
3647   }
3648 }
3649 
3650 MaybeExpr RelationHelper(ExpressionAnalyzer &context, RelationalOperator opr,
3651     const parser::Expr::IntrinsicBinary &x) {
3652   ArgumentAnalyzer analyzer{context};
3653   analyzer.Analyze(std::get<0>(x.t));
3654   analyzer.Analyze(std::get<1>(x.t));
3655   if (!analyzer.fatalErrors()) {
3656     std::optional<DynamicType> leftType{analyzer.GetType(0)};
3657     std::optional<DynamicType> rightType{analyzer.GetType(1)};
3658     analyzer.ConvertBOZ(&leftType, 0, rightType);
3659     analyzer.ConvertBOZ(&rightType, 1, leftType);
3660     if (leftType && rightType &&
3661         analyzer.IsIntrinsicRelational(opr, *leftType, *rightType)) {
3662       analyzer.CheckForNullPointer("as a relational operand");
3663       analyzer.CheckForAssumedRank("as a relational operand");
3664       if (auto cmp{Relate(context.GetContextualMessages(), opr,
3665               analyzer.MoveExpr(0), analyzer.MoveExpr(1))}) {
3666         return AsMaybeExpr(ConvertToKind<TypeCategory::Logical>(
3667             context.GetDefaultKind(TypeCategory::Logical),
3668             AsExpr(std::move(*cmp))));
3669       }
3670     } else {
3671       return analyzer.TryDefinedOp(opr,
3672           leftType && leftType->category() == TypeCategory::Logical &&
3673                   rightType && rightType->category() == TypeCategory::Logical
3674               ? "LOGICAL operands must be compared using .EQV. or .NEQV."_err_en_US
3675               : "Operands of %s must have comparable types; have %s and %s"_err_en_US);
3676     }
3677   }
3678   return std::nullopt;
3679 }
3680 
3681 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::LT &x) {
3682   return RelationHelper(*this, RelationalOperator::LT, x);
3683 }
3684 
3685 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::LE &x) {
3686   return RelationHelper(*this, RelationalOperator::LE, x);
3687 }
3688 
3689 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::EQ &x) {
3690   return RelationHelper(*this, RelationalOperator::EQ, x);
3691 }
3692 
3693 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::NE &x) {
3694   return RelationHelper(*this, RelationalOperator::NE, x);
3695 }
3696 
3697 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::GE &x) {
3698   return RelationHelper(*this, RelationalOperator::GE, x);
3699 }
3700 
3701 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::GT &x) {
3702   return RelationHelper(*this, RelationalOperator::GT, x);
3703 }
3704 
3705 MaybeExpr LogicalBinaryHelper(ExpressionAnalyzer &context, LogicalOperator opr,
3706     const parser::Expr::IntrinsicBinary &x) {
3707   ArgumentAnalyzer analyzer{context};
3708   analyzer.Analyze(std::get<0>(x.t));
3709   analyzer.Analyze(std::get<1>(x.t));
3710   if (!analyzer.fatalErrors()) {
3711     if (analyzer.IsIntrinsicLogical()) {
3712       analyzer.CheckForNullPointer("as a logical operand");
3713       analyzer.CheckForAssumedRank("as a logical operand");
3714       return AsGenericExpr(BinaryLogicalOperation(opr,
3715           std::get<Expr<SomeLogical>>(analyzer.MoveExpr(0).u),
3716           std::get<Expr<SomeLogical>>(analyzer.MoveExpr(1).u)));
3717     } else {
3718       return analyzer.TryDefinedOp(
3719           opr, "Operands of %s must be LOGICAL; have %s and %s"_err_en_US);
3720     }
3721   }
3722   return std::nullopt;
3723 }
3724 
3725 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::AND &x) {
3726   return LogicalBinaryHelper(*this, LogicalOperator::And, x);
3727 }
3728 
3729 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::OR &x) {
3730   return LogicalBinaryHelper(*this, LogicalOperator::Or, x);
3731 }
3732 
3733 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::EQV &x) {
3734   return LogicalBinaryHelper(*this, LogicalOperator::Eqv, x);
3735 }
3736 
3737 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::NEQV &x) {
3738   return LogicalBinaryHelper(*this, LogicalOperator::Neqv, x);
3739 }
3740 
3741 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::DefinedBinary &x) {
3742   const auto &name{std::get<parser::DefinedOpName>(x.t).v};
3743   ArgumentAnalyzer analyzer{*this, name.source};
3744   analyzer.Analyze(std::get<1>(x.t));
3745   analyzer.Analyze(std::get<2>(x.t));
3746   return analyzer.TryDefinedOp(name.source.ToString().c_str(),
3747       "No operator %s defined for %s and %s"_err_en_US, true);
3748 }
3749 
3750 // Returns true if a parsed function reference should be converted
3751 // into an array element reference.
3752 static bool CheckFuncRefToArrayElement(semantics::SemanticsContext &context,
3753     const parser::FunctionReference &funcRef) {
3754   // Emit message if the function reference fix will end up an array element
3755   // reference with no subscripts, or subscripts on a scalar, because it will
3756   // not be possible to later distinguish in expressions between an empty
3757   // subscript list due to bad subscripts error recovery or because the
3758   // user did not put any.
3759   auto &proc{std::get<parser::ProcedureDesignator>(funcRef.v.t)};
3760   const auto *name{std::get_if<parser::Name>(&proc.u)};
3761   if (!name) {
3762     name = &std::get<parser::ProcComponentRef>(proc.u).v.thing.component;
3763   }
3764   if (!name->symbol) {
3765     return false;
3766   } else if (name->symbol->Rank() == 0) {
3767     if (const Symbol *function{
3768             semantics::IsFunctionResultWithSameNameAsFunction(*name->symbol)}) {
3769       auto &msg{context.Say(funcRef.source,
3770           function->flags().test(Symbol::Flag::StmtFunction)
3771               ? "Recursive call to statement function '%s' is not allowed"_err_en_US
3772               : "Recursive call to '%s' requires a distinct RESULT in its declaration"_err_en_US,
3773           name->source)};
3774       AttachDeclaration(&msg, *function);
3775       name->symbol = const_cast<Symbol *>(function);
3776     }
3777     return false;
3778   } else {
3779     if (std::get<std::list<parser::ActualArgSpec>>(funcRef.v.t).empty()) {
3780       auto &msg{context.Say(funcRef.source,
3781           "Reference to array '%s' with empty subscript list"_err_en_US,
3782           name->source)};
3783       if (name->symbol) {
3784         AttachDeclaration(&msg, *name->symbol);
3785       }
3786     }
3787     return true;
3788   }
3789 }
3790 
3791 // Converts, if appropriate, an original misparse of ambiguous syntax like
3792 // A(1) as a function reference into an array reference.
3793 // Misparsed structure constructors are detected elsewhere after generic
3794 // function call resolution fails.
3795 template <typename... A>
3796 static void FixMisparsedFunctionReference(
3797     semantics::SemanticsContext &context, const std::variant<A...> &constU) {
3798   // The parse tree is updated in situ when resolving an ambiguous parse.
3799   using uType = std::decay_t<decltype(constU)>;
3800   auto &u{const_cast<uType &>(constU)};
3801   if (auto *func{
3802           std::get_if<common::Indirection<parser::FunctionReference>>(&u)}) {
3803     parser::FunctionReference &funcRef{func->value()};
3804     // Ensure that there are no argument keywords
3805     for (const auto &arg :
3806         std::get<std::list<parser::ActualArgSpec>>(funcRef.v.t)) {
3807       if (std::get<std::optional<parser::Keyword>>(arg.t)) {
3808         return;
3809       }
3810     }
3811     auto &proc{std::get<parser::ProcedureDesignator>(funcRef.v.t)};
3812     if (Symbol *origSymbol{
3813             common::visit(common::visitors{
3814                               [&](parser::Name &name) { return name.symbol; },
3815                               [&](parser::ProcComponentRef &pcr) {
3816                                 return pcr.v.thing.component.symbol;
3817                               },
3818                           },
3819                 proc.u)}) {
3820       Symbol &symbol{origSymbol->GetUltimate()};
3821       if (symbol.has<semantics::ObjectEntityDetails>() ||
3822           symbol.has<semantics::AssocEntityDetails>()) {
3823         // Note that expression in AssocEntityDetails cannot be a procedure
3824         // pointer as per C1105 so this cannot be a function reference.
3825         if constexpr (common::HasMember<common::Indirection<parser::Designator>,
3826                           uType>) {
3827           if (CheckFuncRefToArrayElement(context, funcRef)) {
3828             u = common::Indirection{funcRef.ConvertToArrayElementRef()};
3829           }
3830         } else {
3831           DIE("can't fix misparsed function as array reference");
3832         }
3833       }
3834     }
3835   }
3836 }
3837 
3838 // Common handling of parse tree node types that retain the
3839 // representation of the analyzed expression.
3840 template <typename PARSED>
3841 MaybeExpr ExpressionAnalyzer::ExprOrVariable(
3842     const PARSED &x, parser::CharBlock source) {
3843   auto restorer{GetContextualMessages().SetLocation(source)};
3844   if constexpr (std::is_same_v<PARSED, parser::Expr> ||
3845       std::is_same_v<PARSED, parser::Variable>) {
3846     FixMisparsedFunctionReference(context_, x.u);
3847   }
3848   if (AssumedTypeDummy(x)) { // C710
3849     Say("TYPE(*) dummy argument may only be used as an actual argument"_err_en_US);
3850     ResetExpr(x);
3851     return std::nullopt;
3852   }
3853   MaybeExpr result;
3854   if constexpr (common::HasMember<parser::StructureConstructor,
3855                     std::decay_t<decltype(x.u)>> &&
3856       common::HasMember<common::Indirection<parser::FunctionReference>,
3857           std::decay_t<decltype(x.u)>>) {
3858     if (const auto *funcRef{
3859             std::get_if<common::Indirection<parser::FunctionReference>>(
3860                 &x.u)}) {
3861       // Function references in Exprs might turn out to be misparsed structure
3862       // constructors; we have to try generic procedure resolution
3863       // first to be sure.
3864       std::optional<parser::StructureConstructor> ctor;
3865       result = Analyze(funcRef->value(), &ctor);
3866       if (result && ctor) {
3867         // A misparsed function reference is really a structure
3868         // constructor.  Repair the parse tree in situ.
3869         const_cast<PARSED &>(x).u = std::move(*ctor);
3870       }
3871     } else {
3872       result = Analyze(x.u);
3873     }
3874   } else {
3875     result = Analyze(x.u);
3876   }
3877   if (result) {
3878     if constexpr (std::is_same_v<PARSED, parser::Expr>) {
3879       if (!isNullPointerOk_ && IsNullPointer(*result)) {
3880         Say(source,
3881             "NULL() may not be used as an expression in this context"_err_en_US);
3882       }
3883     }
3884     SetExpr(x, Fold(std::move(*result)));
3885     return x.typedExpr->v;
3886   } else {
3887     ResetExpr(x);
3888     if (!context_.AnyFatalError()) {
3889       std::string buf;
3890       llvm::raw_string_ostream dump{buf};
3891       parser::DumpTree(dump, x);
3892       Say("Internal error: Expression analysis failed on: %s"_err_en_US, buf);
3893     }
3894     return std::nullopt;
3895   }
3896 }
3897 
3898 // This is an optional preliminary pass over parser::Expr subtrees.
3899 // Given an expression tree, iteratively traverse it in a bottom-up order
3900 // to analyze all of its subexpressions.  A later normal top-down analysis
3901 // will then be able to use the results that will have been saved in the
3902 // parse tree without having to recurse deeply.  This technique keeps
3903 // absurdly deep expression parse trees from causing the analyzer to overflow
3904 // its stack.
3905 MaybeExpr ExpressionAnalyzer::IterativelyAnalyzeSubexpressions(
3906     const parser::Expr &top) {
3907   std::vector<const parser::Expr *> queue, finish;
3908   queue.push_back(&top);
3909   do {
3910     const parser::Expr &expr{*queue.back()};
3911     queue.pop_back();
3912     if (!expr.typedExpr) {
3913       const parser::Expr::IntrinsicUnary *unary{nullptr};
3914       const parser::Expr::IntrinsicBinary *binary{nullptr};
3915       common::visit(
3916           [&unary, &binary](auto &y) {
3917             if constexpr (std::is_convertible_v<decltype(&y),
3918                               decltype(unary)>) {
3919               // Don't evaluate a constant operand to Negate
3920               if (!std::holds_alternative<parser::LiteralConstant>(
3921                       y.v.value().u)) {
3922                 unary = &y;
3923               }
3924             } else if constexpr (std::is_convertible_v<decltype(&y),
3925                                      decltype(binary)>) {
3926               binary = &y;
3927             }
3928           },
3929           expr.u);
3930       if (unary) {
3931         queue.push_back(&unary->v.value());
3932       } else if (binary) {
3933         queue.push_back(&std::get<0>(binary->t).value());
3934         queue.push_back(&std::get<1>(binary->t).value());
3935       }
3936       finish.push_back(&expr);
3937     }
3938   } while (!queue.empty());
3939   // Analyze the collected subexpressions in bottom-up order.
3940   // On an error, bail out and leave partial results in place.
3941   MaybeExpr result;
3942   for (auto riter{finish.rbegin()}; riter != finish.rend(); ++riter) {
3943     const parser::Expr &expr{**riter};
3944     result = ExprOrVariable(expr, expr.source);
3945     if (!result) {
3946       return result;
3947     }
3948   }
3949   return result; // last value was from analysis of "top"
3950 }
3951 
3952 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr &expr) {
3953   bool wasIterativelyAnalyzing{iterativelyAnalyzingSubexpressions_};
3954   MaybeExpr result;
3955   if (useSavedTypedExprs_) {
3956     if (expr.typedExpr) {
3957       return expr.typedExpr->v;
3958     }
3959     if (!wasIterativelyAnalyzing) {
3960       iterativelyAnalyzingSubexpressions_ = true;
3961       result = IterativelyAnalyzeSubexpressions(expr);
3962     }
3963   }
3964   if (!result) {
3965     result = ExprOrVariable(expr, expr.source);
3966   }
3967   iterativelyAnalyzingSubexpressions_ = wasIterativelyAnalyzing;
3968   return result;
3969 }
3970 
3971 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Variable &variable) {
3972   if (useSavedTypedExprs_ && variable.typedExpr) {
3973     return variable.typedExpr->v;
3974   }
3975   return ExprOrVariable(variable, variable.GetSource());
3976 }
3977 
3978 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Selector &selector) {
3979   if (const auto *var{std::get_if<parser::Variable>(&selector.u)}) {
3980     if (!useSavedTypedExprs_ || !var->typedExpr) {
3981       parser::CharBlock source{var->GetSource()};
3982       auto restorer{GetContextualMessages().SetLocation(source)};
3983       FixMisparsedFunctionReference(context_, var->u);
3984       if (const auto *funcRef{
3985               std::get_if<common::Indirection<parser::FunctionReference>>(
3986                   &var->u)}) {
3987         // A Selector that parsed as a Variable might turn out during analysis
3988         // to actually be a structure constructor.  In that case, repair the
3989         // Variable parse tree node into an Expr
3990         std::optional<parser::StructureConstructor> ctor;
3991         if (MaybeExpr result{Analyze(funcRef->value(), &ctor)}) {
3992           if (ctor) {
3993             auto &writable{const_cast<parser::Selector &>(selector)};
3994             writable.u = parser::Expr{std::move(*ctor)};
3995             auto &expr{std::get<parser::Expr>(writable.u)};
3996             expr.source = source;
3997             SetExpr(expr, Fold(std::move(*result)));
3998             return expr.typedExpr->v;
3999           } else {
4000             SetExpr(*var, Fold(std::move(*result)));
4001             return var->typedExpr->v;
4002           }
4003         } else {
4004           ResetExpr(*var);
4005           if (context_.AnyFatalError()) {
4006             return std::nullopt;
4007           }
4008         }
4009       }
4010     }
4011     // Not a Variable -> FunctionReference
4012     auto restorer{AllowWholeAssumedSizeArray()};
4013     return Analyze(selector.u);
4014   } else { // Expr
4015     return Analyze(selector.u);
4016   }
4017 }
4018 
4019 MaybeExpr ExpressionAnalyzer::Analyze(const parser::DataStmtConstant &x) {
4020   auto restorer{common::ScopedSet(inDataStmtConstant_, true)};
4021   return ExprOrVariable(x, x.source);
4022 }
4023 
4024 MaybeExpr ExpressionAnalyzer::Analyze(const parser::AllocateObject &x) {
4025   return ExprOrVariable(x, parser::FindSourceLocation(x));
4026 }
4027 
4028 MaybeExpr ExpressionAnalyzer::Analyze(const parser::PointerObject &x) {
4029   return ExprOrVariable(x, parser::FindSourceLocation(x));
4030 }
4031 
4032 Expr<SubscriptInteger> ExpressionAnalyzer::AnalyzeKindSelector(
4033     TypeCategory category,
4034     const std::optional<parser::KindSelector> &selector) {
4035   int defaultKind{GetDefaultKind(category)};
4036   if (!selector) {
4037     return Expr<SubscriptInteger>{defaultKind};
4038   }
4039   return common::visit(
4040       common::visitors{
4041           [&](const parser::ScalarIntConstantExpr &x) {
4042             if (MaybeExpr kind{Analyze(x)}) {
4043               if (std::optional<std::int64_t> code{ToInt64(*kind)}) {
4044                 if (CheckIntrinsicKind(category, *code)) {
4045                   return Expr<SubscriptInteger>{*code};
4046                 }
4047               } else if (auto *intExpr{UnwrapExpr<Expr<SomeInteger>>(*kind)}) {
4048                 return ConvertToType<SubscriptInteger>(std::move(*intExpr));
4049               }
4050             }
4051             return Expr<SubscriptInteger>{defaultKind};
4052           },
4053           [&](const parser::KindSelector::StarSize &x) {
4054             std::intmax_t size = x.v;
4055             if (!CheckIntrinsicSize(category, size)) {
4056               size = defaultKind;
4057             } else if (category == TypeCategory::Complex) {
4058               size /= 2;
4059             }
4060             return Expr<SubscriptInteger>{size};
4061           },
4062       },
4063       selector->u);
4064 }
4065 
4066 int ExpressionAnalyzer::GetDefaultKind(common::TypeCategory category) {
4067   return context_.GetDefaultKind(category);
4068 }
4069 
4070 DynamicType ExpressionAnalyzer::GetDefaultKindOfType(
4071     common::TypeCategory category) {
4072   return {category, GetDefaultKind(category)};
4073 }
4074 
4075 bool ExpressionAnalyzer::CheckIntrinsicKind(
4076     TypeCategory category, std::int64_t kind) {
4077   if (foldingContext_.targetCharacteristics().IsTypeEnabled(
4078           category, kind)) { // C712, C714, C715, C727
4079     return true;
4080   } else if (foldingContext_.targetCharacteristics().CanSupportType(
4081                  category, kind)) {
4082     Warn(common::UsageWarning::BadTypeForTarget,
4083         "%s(KIND=%jd) is not an enabled type for this target"_warn_en_US,
4084         ToUpperCase(EnumToString(category)), kind);
4085     return true;
4086   } else {
4087     Say("%s(KIND=%jd) is not a supported type"_err_en_US,
4088         ToUpperCase(EnumToString(category)), kind);
4089     return false;
4090   }
4091 }
4092 
4093 bool ExpressionAnalyzer::CheckIntrinsicSize(
4094     TypeCategory category, std::int64_t size) {
4095   std::int64_t kind{size};
4096   if (category == TypeCategory::Complex) {
4097     // COMPLEX*16 == COMPLEX(KIND=8)
4098     if (size % 2 == 0) {
4099       kind = size / 2;
4100     } else {
4101       Say("COMPLEX*%jd is not a supported type"_err_en_US, size);
4102       return false;
4103     }
4104   }
4105   if (foldingContext_.targetCharacteristics().IsTypeEnabled(
4106           category, kind)) { // C712, C714, C715, C727
4107     return true;
4108   } else if (foldingContext_.targetCharacteristics().CanSupportType(
4109                  category, kind)) {
4110     Warn(common::UsageWarning::BadTypeForTarget,
4111         "%s*%jd is not an enabled type for this target"_warn_en_US,
4112         ToUpperCase(EnumToString(category)), size);
4113     return true;
4114   } else {
4115     Say("%s*%jd is not a supported type"_err_en_US,
4116         ToUpperCase(EnumToString(category)), size);
4117     return false;
4118   }
4119 }
4120 
4121 bool ExpressionAnalyzer::AddImpliedDo(parser::CharBlock name, int kind) {
4122   return impliedDos_.insert(std::make_pair(name, kind)).second;
4123 }
4124 
4125 void ExpressionAnalyzer::RemoveImpliedDo(parser::CharBlock name) {
4126   auto iter{impliedDos_.find(name)};
4127   if (iter != impliedDos_.end()) {
4128     impliedDos_.erase(iter);
4129   }
4130 }
4131 
4132 std::optional<int> ExpressionAnalyzer::IsImpliedDo(
4133     parser::CharBlock name) const {
4134   auto iter{impliedDos_.find(name)};
4135   if (iter != impliedDos_.cend()) {
4136     return {iter->second};
4137   } else {
4138     return std::nullopt;
4139   }
4140 }
4141 
4142 bool ExpressionAnalyzer::EnforceTypeConstraint(parser::CharBlock at,
4143     const MaybeExpr &result, TypeCategory category, bool defaultKind) {
4144   if (result) {
4145     if (auto type{result->GetType()}) {
4146       if (type->category() != category) { // C885
4147         Say(at, "Must have %s type, but is %s"_err_en_US,
4148             ToUpperCase(EnumToString(category)),
4149             ToUpperCase(type->AsFortran()));
4150         return false;
4151       } else if (defaultKind) {
4152         int kind{context_.GetDefaultKind(category)};
4153         if (type->kind() != kind) {
4154           Say(at, "Must have default kind(%d) of %s type, but is %s"_err_en_US,
4155               kind, ToUpperCase(EnumToString(category)),
4156               ToUpperCase(type->AsFortran()));
4157           return false;
4158         }
4159       }
4160     } else {
4161       Say(at, "Must have %s type, but is typeless"_err_en_US,
4162           ToUpperCase(EnumToString(category)));
4163       return false;
4164     }
4165   }
4166   return true;
4167 }
4168 
4169 MaybeExpr ExpressionAnalyzer::MakeFunctionRef(parser::CharBlock callSite,
4170     ProcedureDesignator &&proc, ActualArguments &&arguments) {
4171   if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&proc.u)}) {
4172     if (intrinsic->characteristics.value().attrs.test(
4173             characteristics::Procedure::Attr::NullPointer) &&
4174         arguments.empty()) {
4175       return Expr<SomeType>{NullPointer{}};
4176     }
4177   }
4178   if (const Symbol *symbol{proc.GetSymbol()}) {
4179     if (!ResolveForward(*symbol)) {
4180       return std::nullopt;
4181     }
4182   }
4183   if (auto chars{CheckCall(callSite, proc, arguments)}) {
4184     if (chars->functionResult) {
4185       const auto &result{*chars->functionResult};
4186       ProcedureRef procRef{std::move(proc), std::move(arguments)};
4187       if (result.IsProcedurePointer()) {
4188         return Expr<SomeType>{std::move(procRef)};
4189       } else {
4190         // Not a procedure pointer, so type and shape are known.
4191         return TypedWrapper<FunctionRef, ProcedureRef>(
4192             DEREF(result.GetTypeAndShape()).type(), std::move(procRef));
4193       }
4194     } else {
4195       Say("Function result characteristics are not known"_err_en_US);
4196     }
4197   }
4198   return std::nullopt;
4199 }
4200 
4201 MaybeExpr ExpressionAnalyzer::MakeFunctionRef(
4202     parser::CharBlock intrinsic, ActualArguments &&arguments) {
4203   if (std::optional<SpecificCall> specificCall{
4204           context_.intrinsics().Probe(CallCharacteristics{intrinsic.ToString()},
4205               arguments, GetFoldingContext())}) {
4206     return MakeFunctionRef(intrinsic,
4207         ProcedureDesignator{std::move(specificCall->specificIntrinsic)},
4208         std::move(specificCall->arguments));
4209   } else {
4210     return std::nullopt;
4211   }
4212 }
4213 
4214 MaybeExpr ExpressionAnalyzer::AnalyzeComplex(
4215     MaybeExpr &&re, MaybeExpr &&im, const char *what) {
4216   if (re && re->Rank() > 0) {
4217     Warn(common::LanguageFeature::ComplexConstructor,
4218         "Real part of %s is not scalar"_port_en_US, what);
4219   }
4220   if (im && im->Rank() > 0) {
4221     Warn(common::LanguageFeature::ComplexConstructor,
4222         "Imaginary part of %s is not scalar"_port_en_US, what);
4223   }
4224   if (re && im) {
4225     ConformabilityCheck(GetContextualMessages(), *re, *im);
4226   }
4227   return AsMaybeExpr(ConstructComplex(GetContextualMessages(), std::move(re),
4228       std::move(im), GetDefaultKind(TypeCategory::Real)));
4229 }
4230 
4231 std::optional<ActualArgument> ArgumentAnalyzer::AnalyzeVariable(
4232     const parser::Variable &x) {
4233   source_.ExtendToCover(x.GetSource());
4234   if (MaybeExpr expr{context_.Analyze(x)}) {
4235     if (!IsConstantExpr(*expr)) {
4236       ActualArgument actual{std::move(*expr)};
4237       SetArgSourceLocation(actual, x.GetSource());
4238       return actual;
4239     }
4240     const Symbol *symbol{GetLastSymbol(*expr)};
4241     if (!symbol) {
4242       context_.SayAt(x, "Assignment to constant '%s' is not allowed"_err_en_US,
4243           x.GetSource());
4244     } else if (IsProcedure(*symbol)) {
4245       if (auto *msg{context_.SayAt(x,
4246               "Assignment to procedure '%s' is not allowed"_err_en_US,
4247               symbol->name())}) {
4248         if (auto *subp{symbol->detailsIf<semantics::SubprogramDetails>()}) {
4249           if (subp->isFunction()) {
4250             const auto &result{subp->result().name()};
4251             msg->Attach(result, "Function result is '%s'"_en_US, result);
4252           }
4253         }
4254       }
4255     } else {
4256       context_.SayAt(
4257           x, "Assignment to '%s' is not allowed"_err_en_US, symbol->name());
4258     }
4259   }
4260   fatalErrors_ = true;
4261   return std::nullopt;
4262 }
4263 
4264 void ArgumentAnalyzer::Analyze(const parser::Variable &x) {
4265   if (auto actual = AnalyzeVariable(x)) {
4266     actuals_.emplace_back(std::move(actual));
4267   }
4268 }
4269 
4270 void ArgumentAnalyzer::Analyze(
4271     const parser::ActualArgSpec &arg, bool isSubroutine) {
4272   // TODO: C1534: Don't allow a "restricted" specific intrinsic to be passed.
4273   std::optional<ActualArgument> actual;
4274   auto restorer{context_.AllowWholeAssumedSizeArray()};
4275   common::visit(
4276       common::visitors{
4277           [&](const common::Indirection<parser::Expr> &x) {
4278             actual = AnalyzeExpr(x.value());
4279           },
4280           [&](const parser::AltReturnSpec &label) {
4281             if (!isSubroutine) {
4282               context_.Say(
4283                   "alternate return specification may not appear on function reference"_err_en_US);
4284             }
4285             actual = ActualArgument(label.v);
4286           },
4287           [&](const parser::ActualArg::PercentRef &percentRef) {
4288             actual = AnalyzeExpr(percentRef.v);
4289             if (actual.has_value()) {
4290               actual->set_isPercentRef();
4291             }
4292           },
4293           [&](const parser::ActualArg::PercentVal &percentVal) {
4294             actual = AnalyzeExpr(percentVal.v);
4295             if (actual.has_value()) {
4296               actual->set_isPercentVal();
4297             }
4298           },
4299       },
4300       std::get<parser::ActualArg>(arg.t).u);
4301   if (actual) {
4302     if (const auto &argKW{std::get<std::optional<parser::Keyword>>(arg.t)}) {
4303       actual->set_keyword(argKW->v.source);
4304     }
4305     actuals_.emplace_back(std::move(*actual));
4306   } else {
4307     fatalErrors_ = true;
4308   }
4309 }
4310 
4311 bool ArgumentAnalyzer::IsIntrinsicRelational(RelationalOperator opr,
4312     const DynamicType &leftType, const DynamicType &rightType) const {
4313   CHECK(actuals_.size() == 2);
4314   return semantics::IsIntrinsicRelational(
4315       opr, leftType, GetRank(0), rightType, GetRank(1));
4316 }
4317 
4318 bool ArgumentAnalyzer::IsIntrinsicNumeric(NumericOperator opr) const {
4319   std::optional<DynamicType> leftType{GetType(0)};
4320   if (actuals_.size() == 1) {
4321     if (IsBOZLiteral(0)) {
4322       return opr == NumericOperator::Add; // unary '+'
4323     } else {
4324       return leftType && semantics::IsIntrinsicNumeric(*leftType);
4325     }
4326   } else {
4327     std::optional<DynamicType> rightType{GetType(1)};
4328     if (IsBOZLiteral(0) && rightType) { // BOZ opr Integer/Unsigned/Real
4329       auto cat1{rightType->category()};
4330       return cat1 == TypeCategory::Integer || cat1 == TypeCategory::Unsigned ||
4331           cat1 == TypeCategory::Real;
4332     } else if (IsBOZLiteral(1) && leftType) { // Integer/Unsigned/Real opr BOZ
4333       auto cat0{leftType->category()};
4334       return cat0 == TypeCategory::Integer || cat0 == TypeCategory::Unsigned ||
4335           cat0 == TypeCategory::Real;
4336     } else {
4337       return leftType && rightType &&
4338           semantics::IsIntrinsicNumeric(
4339               *leftType, GetRank(0), *rightType, GetRank(1));
4340     }
4341   }
4342 }
4343 
4344 bool ArgumentAnalyzer::IsIntrinsicLogical() const {
4345   if (std::optional<DynamicType> leftType{GetType(0)}) {
4346     if (actuals_.size() == 1) {
4347       return semantics::IsIntrinsicLogical(*leftType);
4348     } else if (std::optional<DynamicType> rightType{GetType(1)}) {
4349       return semantics::IsIntrinsicLogical(
4350           *leftType, GetRank(0), *rightType, GetRank(1));
4351     }
4352   }
4353   return false;
4354 }
4355 
4356 bool ArgumentAnalyzer::IsIntrinsicConcat() const {
4357   if (std::optional<DynamicType> leftType{GetType(0)}) {
4358     if (std::optional<DynamicType> rightType{GetType(1)}) {
4359       return semantics::IsIntrinsicConcat(
4360           *leftType, GetRank(0), *rightType, GetRank(1));
4361     }
4362   }
4363   return false;
4364 }
4365 
4366 bool ArgumentAnalyzer::CheckConformance() {
4367   if (actuals_.size() == 2) {
4368     const auto *lhs{actuals_.at(0).value().UnwrapExpr()};
4369     const auto *rhs{actuals_.at(1).value().UnwrapExpr()};
4370     if (lhs && rhs) {
4371       auto &foldingContext{context_.GetFoldingContext()};
4372       auto lhShape{GetShape(foldingContext, *lhs)};
4373       auto rhShape{GetShape(foldingContext, *rhs)};
4374       if (lhShape && rhShape) {
4375         if (!evaluate::CheckConformance(foldingContext.messages(), *lhShape,
4376                 *rhShape, CheckConformanceFlags::EitherScalarExpandable,
4377                 "left operand", "right operand")
4378                  .value_or(false /*fail when conformance is not known now*/)) {
4379           fatalErrors_ = true;
4380           return false;
4381         }
4382       }
4383     }
4384   }
4385   return true; // no proven problem
4386 }
4387 
4388 bool ArgumentAnalyzer::CheckAssignmentConformance() {
4389   if (actuals_.size() == 2 && actuals_[0] && actuals_[1]) {
4390     const auto *lhs{actuals_[0]->UnwrapExpr()};
4391     const auto *rhs{actuals_[1]->UnwrapExpr()};
4392     if (lhs && rhs) {
4393       auto &foldingContext{context_.GetFoldingContext()};
4394       auto lhShape{GetShape(foldingContext, *lhs)};
4395       auto rhShape{GetShape(foldingContext, *rhs)};
4396       if (lhShape && rhShape) {
4397         if (!evaluate::CheckConformance(foldingContext.messages(), *lhShape,
4398                 *rhShape, CheckConformanceFlags::RightScalarExpandable,
4399                 "left-hand side", "right-hand side")
4400                  .value_or(true /*ok when conformance is not known now*/)) {
4401           fatalErrors_ = true;
4402           return false;
4403         }
4404       }
4405     }
4406   }
4407   return true; // no proven problem
4408 }
4409 
4410 bool ArgumentAnalyzer::CheckForNullPointer(const char *where) {
4411   for (const std::optional<ActualArgument> &arg : actuals_) {
4412     if (arg) {
4413       if (const Expr<SomeType> *expr{arg->UnwrapExpr()}) {
4414         if (IsNullPointer(*expr)) {
4415           context_.Say(
4416               source_, "A NULL() pointer is not allowed %s"_err_en_US, where);
4417           fatalErrors_ = true;
4418           return false;
4419         }
4420       }
4421     }
4422   }
4423   return true;
4424 }
4425 
4426 bool ArgumentAnalyzer::CheckForAssumedRank(const char *where) {
4427   for (const std::optional<ActualArgument> &arg : actuals_) {
4428     if (arg && IsAssumedRank(arg->UnwrapExpr())) {
4429       context_.Say(source_,
4430           "An assumed-rank dummy argument is not allowed %s"_err_en_US, where);
4431       fatalErrors_ = true;
4432       return false;
4433     }
4434   }
4435   return true;
4436 }
4437 
4438 MaybeExpr ArgumentAnalyzer::TryDefinedOp(
4439     const char *opr, parser::MessageFixedText error, bool isUserOp) {
4440   if (AnyUntypedOrMissingOperand()) {
4441     context_.Say(error, ToUpperCase(opr), TypeAsFortran(0), TypeAsFortran(1));
4442     return std::nullopt;
4443   }
4444   MaybeExpr result;
4445   bool anyPossibilities{false};
4446   std::optional<parser::MessageFormattedText> inaccessible;
4447   std::vector<const Symbol *> hit;
4448   std::string oprNameString{
4449       isUserOp ? std::string{opr} : "operator("s + opr + ')'};
4450   parser::CharBlock oprName{oprNameString};
4451   parser::Messages hitBuffer;
4452   {
4453     parser::Messages buffer;
4454     auto restorer{context_.GetContextualMessages().SetMessages(buffer)};
4455     const auto &scope{context_.context().FindScope(source_)};
4456     if (Symbol *symbol{scope.FindSymbol(oprName)}) {
4457       anyPossibilities = true;
4458       parser::Name name{symbol->name(), symbol};
4459       if (!fatalErrors_) {
4460         result = context_.AnalyzeDefinedOp(name, GetActuals());
4461       }
4462       if (result) {
4463         inaccessible = CheckAccessibleSymbol(scope, *symbol);
4464         if (inaccessible) {
4465           result.reset();
4466         } else {
4467           hit.push_back(symbol);
4468           hitBuffer = std::move(buffer);
4469         }
4470       }
4471     }
4472     for (std::size_t passIndex{0}; passIndex < actuals_.size(); ++passIndex) {
4473       buffer.clear();
4474       const Symbol *generic{nullptr};
4475       if (const Symbol *binding{
4476               FindBoundOp(oprName, passIndex, generic, false)}) {
4477         anyPossibilities = true;
4478         if (MaybeExpr thisResult{TryBoundOp(*binding, passIndex)}) {
4479           if (auto thisInaccessible{
4480                   CheckAccessibleSymbol(scope, DEREF(generic))}) {
4481             inaccessible = thisInaccessible;
4482           } else {
4483             result = std::move(thisResult);
4484             hit.push_back(binding);
4485             hitBuffer = std::move(buffer);
4486           }
4487         }
4488       }
4489     }
4490   }
4491   if (result) {
4492     if (hit.size() > 1) {
4493       if (auto *msg{context_.Say(
4494               "%zd matching accessible generic interfaces for %s were found"_err_en_US,
4495               hit.size(), ToUpperCase(opr))}) {
4496         for (const Symbol *symbol : hit) {
4497           AttachDeclaration(*msg, *symbol);
4498         }
4499       }
4500     }
4501     if (auto *msgs{context_.GetContextualMessages().messages()}) {
4502       msgs->Annex(std::move(hitBuffer));
4503     }
4504   } else if (inaccessible) {
4505     context_.Say(source_, std::move(*inaccessible));
4506   } else if (anyPossibilities) {
4507     SayNoMatch(ToUpperCase(oprNameString), false);
4508   } else if (actuals_.size() == 2 && !AreConformable()) {
4509     context_.Say(
4510         "Operands of %s are not conformable; have rank %d and rank %d"_err_en_US,
4511         ToUpperCase(opr), actuals_[0]->Rank(), actuals_[1]->Rank());
4512   } else if (CheckForNullPointer() && CheckForAssumedRank()) {
4513     context_.Say(error, ToUpperCase(opr), TypeAsFortran(0), TypeAsFortran(1));
4514   }
4515   return result;
4516 }
4517 
4518 MaybeExpr ArgumentAnalyzer::TryDefinedOp(
4519     const std::vector<const char *> &oprs, parser::MessageFixedText error) {
4520   if (oprs.size() == 1) {
4521     return TryDefinedOp(oprs[0], error);
4522   }
4523   MaybeExpr result;
4524   std::vector<const char *> hit;
4525   parser::Messages hitBuffer;
4526   {
4527     for (std::size_t i{0}; i < oprs.size(); ++i) {
4528       parser::Messages buffer;
4529       auto restorer{context_.GetContextualMessages().SetMessages(buffer)};
4530       if (MaybeExpr thisResult{TryDefinedOp(oprs[i], error)}) {
4531         result = std::move(thisResult);
4532         hit.push_back(oprs[i]);
4533         hitBuffer = std::move(buffer);
4534       }
4535     }
4536   }
4537   if (hit.empty()) { // for the error
4538     result = TryDefinedOp(oprs[0], error);
4539   } else if (hit.size() > 1) {
4540     context_.Say(
4541         "Matching accessible definitions were found with %zd variant spellings of the generic operator ('%s', '%s')"_err_en_US,
4542         hit.size(), ToUpperCase(hit[0]), ToUpperCase(hit[1]));
4543   } else { // one hit; preserve errors
4544     context_.context().messages().Annex(std::move(hitBuffer));
4545   }
4546   return result;
4547 }
4548 
4549 MaybeExpr ArgumentAnalyzer::TryBoundOp(const Symbol &symbol, int passIndex) {
4550   ActualArguments localActuals{actuals_};
4551   const Symbol *proc{GetBindingResolution(GetType(passIndex), symbol)};
4552   if (!proc) {
4553     proc = &symbol;
4554     localActuals.at(passIndex).value().set_isPassedObject();
4555   }
4556   CheckConformance();
4557   return context_.MakeFunctionRef(
4558       source_, ProcedureDesignator{*proc}, std::move(localActuals));
4559 }
4560 
4561 std::optional<ProcedureRef> ArgumentAnalyzer::TryDefinedAssignment() {
4562   using semantics::Tristate;
4563   const Expr<SomeType> &lhs{GetExpr(0)};
4564   const Expr<SomeType> &rhs{GetExpr(1)};
4565   std::optional<DynamicType> lhsType{lhs.GetType()};
4566   std::optional<DynamicType> rhsType{rhs.GetType()};
4567   int lhsRank{lhs.Rank()};
4568   int rhsRank{rhs.Rank()};
4569   Tristate isDefined{
4570       semantics::IsDefinedAssignment(lhsType, lhsRank, rhsType, rhsRank)};
4571   if (isDefined == Tristate::No) {
4572     // Make implicit conversion explicit, unless it is an assignment to a whole
4573     // allocatable (the explicit conversion would prevent the propagation of the
4574     // right hand side if it is a variable). Lowering will deal with the
4575     // conversion in this case.
4576     if (lhsType) {
4577       if (rhsType) {
4578         if (!IsAllocatableDesignator(lhs) || context_.inWhereBody()) {
4579           AddAssignmentConversion(*lhsType, *rhsType);
4580         }
4581       } else {
4582         if (lhsType->category() == TypeCategory::Integer ||
4583             lhsType->category() == TypeCategory::Unsigned ||
4584             lhsType->category() == TypeCategory::Real) {
4585           ConvertBOZ(nullptr, 1, lhsType);
4586         }
4587         if (IsBOZLiteral(1)) {
4588           context_.Say(
4589               "Right-hand side of this assignment may not be BOZ"_err_en_US);
4590           fatalErrors_ = true;
4591         }
4592       }
4593     }
4594     if (!fatalErrors_) {
4595       CheckAssignmentConformance();
4596     }
4597     return std::nullopt; // user-defined assignment not allowed for these args
4598   }
4599   auto restorer{context_.GetContextualMessages().SetLocation(source_)};
4600   if (std::optional<ProcedureRef> procRef{GetDefinedAssignmentProc()}) {
4601     if (context_.inWhereBody() && !procRef->proc().IsElemental()) { // C1032
4602       context_.Say(
4603           "Defined assignment in WHERE must be elemental, but '%s' is not"_err_en_US,
4604           DEREF(procRef->proc().GetSymbol()).name());
4605     }
4606     context_.CheckCall(source_, procRef->proc(), procRef->arguments());
4607     return std::move(*procRef);
4608   }
4609   if (isDefined == Tristate::Yes) {
4610     if (!lhsType || !rhsType || (lhsRank != rhsRank && rhsRank != 0) ||
4611         !OkLogicalIntegerAssignment(lhsType->category(), rhsType->category())) {
4612       SayNoMatch("ASSIGNMENT(=)", true);
4613     }
4614   } else if (!fatalErrors_) {
4615     CheckAssignmentConformance();
4616   }
4617   return std::nullopt;
4618 }
4619 
4620 bool ArgumentAnalyzer::OkLogicalIntegerAssignment(
4621     TypeCategory lhs, TypeCategory rhs) {
4622   if (!context_.context().languageFeatures().IsEnabled(
4623           common::LanguageFeature::LogicalIntegerAssignment)) {
4624     return false;
4625   }
4626   std::optional<parser::MessageFixedText> msg;
4627   if (lhs == TypeCategory::Integer && rhs == TypeCategory::Logical) {
4628     // allow assignment to LOGICAL from INTEGER as a legacy extension
4629     msg = "assignment of LOGICAL to INTEGER"_port_en_US;
4630   } else if (lhs == TypeCategory::Logical && rhs == TypeCategory::Integer) {
4631     // ... and assignment to LOGICAL from INTEGER
4632     msg = "assignment of INTEGER to LOGICAL"_port_en_US;
4633   } else {
4634     return false;
4635   }
4636   context_.Warn(
4637       common::LanguageFeature::LogicalIntegerAssignment, std::move(*msg));
4638   return true;
4639 }
4640 
4641 std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc() {
4642   const Symbol *proc{nullptr};
4643   std::optional<int> passedObjectIndex;
4644   std::string oprNameString{"assignment(=)"};
4645   parser::CharBlock oprName{oprNameString};
4646   const auto &scope{context_.context().FindScope(source_)};
4647   // If multiple resolutions were possible, they will have been already
4648   // diagnosed.
4649   {
4650     auto restorer{context_.GetContextualMessages().DiscardMessages()};
4651     if (const Symbol *symbol{scope.FindSymbol(oprName)}) {
4652       ExpressionAnalyzer::AdjustActuals noAdjustment;
4653       proc =
4654           context_.ResolveGeneric(*symbol, actuals_, noAdjustment, true).first;
4655     }
4656     for (std::size_t i{0}; !proc && i < actuals_.size(); ++i) {
4657       const Symbol *generic{nullptr};
4658       if (const Symbol *binding{FindBoundOp(oprName, i, generic, true)}) {
4659         if (CheckAccessibleSymbol(scope, DEREF(generic))) {
4660           // ignore inaccessible type-bound ASSIGNMENT(=) generic
4661         } else if (const Symbol *
4662             resolution{GetBindingResolution(GetType(i), *binding)}) {
4663           proc = resolution;
4664         } else {
4665           proc = binding;
4666           passedObjectIndex = i;
4667         }
4668       }
4669     }
4670   }
4671   if (!proc) {
4672     return std::nullopt;
4673   }
4674   ActualArguments actualsCopy{actuals_};
4675   // Ensure that the RHS argument is not passed as a variable unless
4676   // the dummy argument has the VALUE attribute.
4677   if (evaluate::IsVariable(actualsCopy.at(1).value().UnwrapExpr())) {
4678     auto chars{evaluate::characteristics::Procedure::Characterize(
4679         *proc, context_.GetFoldingContext())};
4680     const auto *rhsDummy{chars && chars->dummyArguments.size() == 2
4681             ? std::get_if<evaluate::characteristics::DummyDataObject>(
4682                   &chars->dummyArguments.at(1).u)
4683             : nullptr};
4684     if (!rhsDummy ||
4685         !rhsDummy->attrs.test(
4686             evaluate::characteristics::DummyDataObject::Attr::Value)) {
4687       actualsCopy.at(1).value().Parenthesize();
4688     }
4689   }
4690   if (passedObjectIndex) {
4691     actualsCopy[*passedObjectIndex]->set_isPassedObject();
4692   }
4693   return ProcedureRef{ProcedureDesignator{*proc}, std::move(actualsCopy)};
4694 }
4695 
4696 void ArgumentAnalyzer::Dump(llvm::raw_ostream &os) {
4697   os << "source_: " << source_.ToString() << " fatalErrors_ = " << fatalErrors_
4698      << '\n';
4699   for (const auto &actual : actuals_) {
4700     if (!actual.has_value()) {
4701       os << "- error\n";
4702     } else if (const Symbol *symbol{actual->GetAssumedTypeDummy()}) {
4703       os << "- assumed type: " << symbol->name().ToString() << '\n';
4704     } else if (const Expr<SomeType> *expr{actual->UnwrapExpr()}) {
4705       expr->AsFortran(os << "- expr: ") << '\n';
4706     } else {
4707       DIE("bad ActualArgument");
4708     }
4709   }
4710 }
4711 
4712 std::optional<ActualArgument> ArgumentAnalyzer::AnalyzeExpr(
4713     const parser::Expr &expr) {
4714   source_.ExtendToCover(expr.source);
4715   if (const Symbol *assumedTypeDummy{AssumedTypeDummy(expr)}) {
4716     ResetExpr(expr);
4717     if (isProcedureCall_) {
4718       ActualArgument arg{ActualArgument::AssumedType{*assumedTypeDummy}};
4719       SetArgSourceLocation(arg, expr.source);
4720       return std::move(arg);
4721     }
4722     context_.SayAt(expr.source,
4723         "TYPE(*) dummy argument may only be used as an actual argument"_err_en_US);
4724   } else if (MaybeExpr argExpr{AnalyzeExprOrWholeAssumedSizeArray(expr)}) {
4725     if (isProcedureCall_ || !IsProcedureDesignator(*argExpr)) {
4726       ActualArgument arg{std::move(*argExpr)};
4727       SetArgSourceLocation(arg, expr.source);
4728       return std::move(arg);
4729     }
4730     context_.SayAt(expr.source,
4731         IsFunctionDesignator(*argExpr)
4732             ? "Function call must have argument list"_err_en_US
4733             : "Subroutine name is not allowed here"_err_en_US);
4734   }
4735   return std::nullopt;
4736 }
4737 
4738 MaybeExpr ArgumentAnalyzer::AnalyzeExprOrWholeAssumedSizeArray(
4739     const parser::Expr &expr) {
4740   // If an expression's parse tree is a whole assumed-size array:
4741   //   Expr -> Designator -> DataRef -> Name
4742   // treat it as a special case for argument passing and bypass
4743   // the C1002/C1014 constraint checking in expression semantics.
4744   if (const auto *name{parser::Unwrap<parser::Name>(expr)}) {
4745     if (name->symbol && semantics::IsAssumedSizeArray(*name->symbol)) {
4746       auto restorer{context_.AllowWholeAssumedSizeArray()};
4747       return context_.Analyze(expr);
4748     }
4749   }
4750   auto restorer{context_.AllowNullPointer()};
4751   return context_.Analyze(expr);
4752 }
4753 
4754 bool ArgumentAnalyzer::AreConformable() const {
4755   CHECK(actuals_.size() == 2);
4756   return actuals_[0] && actuals_[1] &&
4757       evaluate::AreConformable(*actuals_[0], *actuals_[1]);
4758 }
4759 
4760 // Look for a type-bound operator in the type of arg number passIndex.
4761 const Symbol *ArgumentAnalyzer::FindBoundOp(parser::CharBlock oprName,
4762     int passIndex, const Symbol *&generic, bool isSubroutine) {
4763   const auto *type{GetDerivedTypeSpec(GetType(passIndex))};
4764   const semantics::Scope *scope{type ? type->scope() : nullptr};
4765   if (scope) {
4766     // Use the original type definition's scope, since PDT
4767     // instantiations don't have redundant copies of bindings or
4768     // generics.
4769     scope = DEREF(scope->derivedTypeSpec()).typeSymbol().scope();
4770   }
4771   generic = scope ? scope->FindComponent(oprName) : nullptr;
4772   if (generic) {
4773     ExpressionAnalyzer::AdjustActuals adjustment{
4774         [&](const Symbol &proc, ActualArguments &) {
4775           return passIndex == GetPassIndex(proc).value_or(-1);
4776         }};
4777     auto pair{
4778         context_.ResolveGeneric(*generic, actuals_, adjustment, isSubroutine)};
4779     if (const Symbol *binding{pair.first}) {
4780       CHECK(binding->has<semantics::ProcBindingDetails>());
4781       // Use the most recent override of the binding, if any
4782       return scope->FindComponent(binding->name());
4783     } else {
4784       context_.EmitGenericResolutionError(*generic, pair.second, isSubroutine);
4785     }
4786   }
4787   return nullptr;
4788 }
4789 
4790 // If there is an implicit conversion between intrinsic types, make it explicit
4791 void ArgumentAnalyzer::AddAssignmentConversion(
4792     const DynamicType &lhsType, const DynamicType &rhsType) {
4793   if (lhsType.category() == rhsType.category() &&
4794       (lhsType.category() == TypeCategory::Derived ||
4795           lhsType.kind() == rhsType.kind())) {
4796     // no conversion necessary
4797   } else if (auto rhsExpr{evaluate::Fold(context_.GetFoldingContext(),
4798                  evaluate::ConvertToType(lhsType, MoveExpr(1)))}) {
4799     std::optional<parser::CharBlock> source;
4800     if (actuals_[1]) {
4801       source = actuals_[1]->sourceLocation();
4802     }
4803     actuals_[1] = ActualArgument{*rhsExpr};
4804     SetArgSourceLocation(actuals_[1], source);
4805   } else {
4806     actuals_[1] = std::nullopt;
4807   }
4808 }
4809 
4810 std::optional<DynamicType> ArgumentAnalyzer::GetType(std::size_t i) const {
4811   return i < actuals_.size() ? actuals_[i].value().GetType() : std::nullopt;
4812 }
4813 int ArgumentAnalyzer::GetRank(std::size_t i) const {
4814   return i < actuals_.size() ? actuals_[i].value().Rank() : 0;
4815 }
4816 
4817 // If the argument at index i is a BOZ literal, convert its type to match the
4818 // otherType.  If it's REAL, convert to REAL; if it's UNSIGNED, convert to
4819 // UNSIGNED; otherwise, convert to INTEGER.
4820 // Note that IBM supports comparing BOZ literals to CHARACTER operands.  That
4821 // is not currently supported.
4822 void ArgumentAnalyzer::ConvertBOZ(std::optional<DynamicType> *thisType,
4823     std::size_t i, std::optional<DynamicType> otherType) {
4824   if (IsBOZLiteral(i)) {
4825     Expr<SomeType> &&argExpr{MoveExpr(i)};
4826     auto *boz{std::get_if<BOZLiteralConstant>(&argExpr.u)};
4827     if (otherType && otherType->category() == TypeCategory::Real) {
4828       int kind{context_.context().GetDefaultKind(TypeCategory::Real)};
4829       MaybeExpr realExpr{
4830           ConvertToKind<TypeCategory::Real>(kind, std::move(*boz))};
4831       actuals_[i] = std::move(realExpr.value());
4832       if (thisType) {
4833         thisType->emplace(TypeCategory::Real, kind);
4834       }
4835     } else if (otherType && otherType->category() == TypeCategory::Unsigned) {
4836       int kind{context_.context().GetDefaultKind(TypeCategory::Unsigned)};
4837       MaybeExpr unsignedExpr{
4838           ConvertToKind<TypeCategory::Unsigned>(kind, std::move(*boz))};
4839       actuals_[i] = std::move(unsignedExpr.value());
4840       if (thisType) {
4841         thisType->emplace(TypeCategory::Unsigned, kind);
4842       }
4843     } else {
4844       int kind{context_.context().GetDefaultKind(TypeCategory::Integer)};
4845       MaybeExpr intExpr{
4846           ConvertToKind<TypeCategory::Integer>(kind, std::move(*boz))};
4847       actuals_[i] = std::move(*intExpr);
4848       if (thisType) {
4849         thisType->emplace(TypeCategory::Integer, kind);
4850       }
4851     }
4852   }
4853 }
4854 
4855 // Report error resolving opr when there is a user-defined one available
4856 void ArgumentAnalyzer::SayNoMatch(const std::string &opr, bool isAssignment) {
4857   std::string type0{TypeAsFortran(0)};
4858   auto rank0{actuals_[0]->Rank()};
4859   if (actuals_.size() == 1) {
4860     if (rank0 > 0) {
4861       context_.Say("No intrinsic or user-defined %s matches "
4862                    "rank %d array of %s"_err_en_US,
4863           opr, rank0, type0);
4864     } else {
4865       context_.Say("No intrinsic or user-defined %s matches "
4866                    "operand type %s"_err_en_US,
4867           opr, type0);
4868     }
4869   } else {
4870     std::string type1{TypeAsFortran(1)};
4871     auto rank1{actuals_[1]->Rank()};
4872     if (rank0 > 0 && rank1 > 0 && rank0 != rank1) {
4873       context_.Say("No intrinsic or user-defined %s matches "
4874                    "rank %d array of %s and rank %d array of %s"_err_en_US,
4875           opr, rank0, type0, rank1, type1);
4876     } else if (isAssignment && rank0 != rank1) {
4877       if (rank0 == 0) {
4878         context_.Say("No intrinsic or user-defined %s matches "
4879                      "scalar %s and rank %d array of %s"_err_en_US,
4880             opr, type0, rank1, type1);
4881       } else {
4882         context_.Say("No intrinsic or user-defined %s matches "
4883                      "rank %d array of %s and scalar %s"_err_en_US,
4884             opr, rank0, type0, type1);
4885       }
4886     } else {
4887       context_.Say("No intrinsic or user-defined %s matches "
4888                    "operand types %s and %s"_err_en_US,
4889           opr, type0, type1);
4890     }
4891   }
4892 }
4893 
4894 std::string ArgumentAnalyzer::TypeAsFortran(std::size_t i) {
4895   if (i >= actuals_.size() || !actuals_[i]) {
4896     return "missing argument";
4897   } else if (std::optional<DynamicType> type{GetType(i)}) {
4898     return type->IsAssumedType()         ? "TYPE(*)"s
4899         : type->IsUnlimitedPolymorphic() ? "CLASS(*)"s
4900         : type->IsPolymorphic()          ? type->AsFortran()
4901         : type->category() == TypeCategory::Derived
4902         ? "TYPE("s + type->AsFortran() + ')'
4903         : type->category() == TypeCategory::Character
4904         ? "CHARACTER(KIND="s + std::to_string(type->kind()) + ')'
4905         : ToUpperCase(type->AsFortran());
4906   } else {
4907     return "untyped";
4908   }
4909 }
4910 
4911 bool ArgumentAnalyzer::AnyUntypedOrMissingOperand() {
4912   for (const auto &actual : actuals_) {
4913     if (!actual ||
4914         (!actual->GetType() && !IsBareNullPointer(actual->UnwrapExpr()))) {
4915       return true;
4916     }
4917   }
4918   return false;
4919 }
4920 } // namespace Fortran::evaluate
4921 
4922 namespace Fortran::semantics {
4923 evaluate::Expr<evaluate::SubscriptInteger> AnalyzeKindSelector(
4924     SemanticsContext &context, common::TypeCategory category,
4925     const std::optional<parser::KindSelector> &selector) {
4926   evaluate::ExpressionAnalyzer analyzer{context};
4927   CHECK(context.location().has_value());
4928   auto restorer{
4929       analyzer.GetContextualMessages().SetLocation(*context.location())};
4930   return analyzer.AnalyzeKindSelector(category, selector);
4931 }
4932 
4933 ExprChecker::ExprChecker(SemanticsContext &context) : context_{context} {}
4934 
4935 bool ExprChecker::Pre(const parser::DataStmtObject &obj) {
4936   exprAnalyzer_.set_inDataStmtObject(true);
4937   return true;
4938 }
4939 
4940 void ExprChecker::Post(const parser::DataStmtObject &obj) {
4941   exprAnalyzer_.set_inDataStmtObject(false);
4942 }
4943 
4944 bool ExprChecker::Pre(const parser::DataImpliedDo &ido) {
4945   parser::Walk(std::get<parser::DataImpliedDo::Bounds>(ido.t), *this);
4946   const auto &bounds{std::get<parser::DataImpliedDo::Bounds>(ido.t)};
4947   auto name{bounds.name.thing.thing};
4948   int kind{evaluate::ResultType<evaluate::ImpliedDoIndex>::kind};
4949   if (const auto dynamicType{evaluate::DynamicType::From(*name.symbol)}) {
4950     if (dynamicType->category() == TypeCategory::Integer) {
4951       kind = dynamicType->kind();
4952     }
4953   }
4954   exprAnalyzer_.AddImpliedDo(name.source, kind);
4955   parser::Walk(std::get<std::list<parser::DataIDoObject>>(ido.t), *this);
4956   exprAnalyzer_.RemoveImpliedDo(name.source);
4957   return false;
4958 }
4959 
4960 bool ExprChecker::Walk(const parser::Program &program) {
4961   parser::Walk(program, *this);
4962   return !context_.AnyFatalError();
4963 }
4964 } // namespace Fortran::semantics
4965