brintos

brintos / llvm-project-archived public Read only

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