14ac617f4Speter klausler //===-- lib/Semantics/data-to-inits.cpp -----------------------------------===// 24ac617f4Speter klausler // 34ac617f4Speter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 44ac617f4Speter klausler // See https://llvm.org/LICENSE.txt for license information. 54ac617f4Speter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64ac617f4Speter klausler // 74ac617f4Speter klausler //===----------------------------------------------------------------------===// 84ac617f4Speter klausler 94ac617f4Speter klausler // DATA statement object/value checking and conversion to static 104ac617f4Speter klausler // initializers 114ac617f4Speter klausler // - Applies specific checks to each scalar element initialization with a 124ac617f4Speter klausler // constant value or pointer target with class DataInitializationCompiler; 134ac617f4Speter klausler // - Collects the elemental initializations for each symbol and converts them 144ac617f4Speter klausler // into a single init() expression with member function 154ac617f4Speter klausler // DataChecker::ConstructInitializer(). 164ac617f4Speter klausler 174ac617f4Speter klausler #include "data-to-inits.h" 184ac617f4Speter klausler #include "pointer-assignment.h" 194ac617f4Speter klausler #include "flang/Evaluate/fold-designator.h" 20571673ceSPeter Steinfeld #include "flang/Evaluate/tools.h" 214ac617f4Speter klausler #include "flang/Semantics/tools.h" 224ac617f4Speter klausler 23d60a0220Speter klausler // The job of generating explicit static initializers for objects that don't 24d60a0220Speter klausler // have them in order to implement default component initialization is now being 25d60a0220Speter klausler // done in lowering, so don't do it here in semantics; but the code remains here 26d60a0220Speter klausler // in case we change our minds. 27d60a0220Speter klausler static constexpr bool makeDefaultInitializationExplicit{false}; 28d60a0220Speter klausler 29d60a0220Speter klausler // Whether to delete the original "init()" initializers from storage-associated 30d60a0220Speter klausler // objects and pointers. 31d60a0220Speter klausler static constexpr bool removeOriginalInits{false}; 32d60a0220Speter klausler 33815fddfaSPeter Klausler // Impose a hard limit that's more than large enough for real applications but 34815fddfaSPeter Klausler // small enough to cause artificial stress tests to fail reasonably instead of 35815fddfaSPeter Klausler // crashing the compiler with a memory allocation failure. 36815fddfaSPeter Klausler static constexpr auto maxDataInitBytes{std::size_t{1000000000}}; // 1GiB 37815fddfaSPeter Klausler 384ac617f4Speter klausler namespace Fortran::semantics { 394ac617f4Speter klausler 404ac617f4Speter klausler // Steps through a list of values in a DATA statement set; implements 414ac617f4Speter klausler // repetition. 42c14cf92bSPeter Klausler template <typename DSV = parser::DataStmtValue> class ValueListIterator { 434ac617f4Speter klausler public: 447e225423SPeter Klausler ValueListIterator(SemanticsContext &context, const std::list<DSV> &list) 457e225423SPeter Klausler : context_{context}, end_{list.end()}, at_{list.begin()} { 464ac617f4Speter klausler SetRepetitionCount(); 474ac617f4Speter klausler } 484ac617f4Speter klausler bool hasFatalError() const { return hasFatalError_; } 494ac617f4Speter klausler bool IsAtEnd() const { return at_ == end_; } 507e225423SPeter Klausler const SomeExpr *operator*() const { return GetExpr(context_, GetConstant()); } 512c27d5b3SDaniil Dudkin std::optional<parser::CharBlock> LocateSource() const { 522c27d5b3SDaniil Dudkin if (!hasFatalError_) { 532c27d5b3SDaniil Dudkin return GetConstant().source; 542c27d5b3SDaniil Dudkin } 552c27d5b3SDaniil Dudkin return {}; 562c27d5b3SDaniil Dudkin } 574ac617f4Speter klausler ValueListIterator &operator++() { 584ac617f4Speter klausler if (repetitionsRemaining_ > 0) { 594ac617f4Speter klausler --repetitionsRemaining_; 604ac617f4Speter klausler } else if (at_ != end_) { 614ac617f4Speter klausler ++at_; 624ac617f4Speter klausler SetRepetitionCount(); 634ac617f4Speter klausler } 644ac617f4Speter klausler return *this; 654ac617f4Speter klausler } 664ac617f4Speter klausler 674ac617f4Speter klausler private: 68c14cf92bSPeter Klausler using listIterator = typename std::list<DSV>::const_iterator; 694ac617f4Speter klausler void SetRepetitionCount(); 70c14cf92bSPeter Klausler const parser::DataStmtValue &GetValue() const { 71c14cf92bSPeter Klausler return DEREF(common::Unwrap<const parser::DataStmtValue>(*at_)); 72c14cf92bSPeter Klausler } 734ac617f4Speter klausler const parser::DataStmtConstant &GetConstant() const { 74c14cf92bSPeter Klausler return std::get<parser::DataStmtConstant>(GetValue().t); 754ac617f4Speter klausler } 764ac617f4Speter klausler 777e225423SPeter Klausler SemanticsContext &context_; 78c14cf92bSPeter Klausler listIterator end_, at_; 794ac617f4Speter klausler ConstantSubscript repetitionsRemaining_{0}; 804ac617f4Speter klausler bool hasFatalError_{false}; 814ac617f4Speter klausler }; 824ac617f4Speter klausler 83c14cf92bSPeter Klausler template <typename DSV> void ValueListIterator<DSV>::SetRepetitionCount() { 8428a686a7SPeter Klausler for (; at_ != end_; ++at_) { 85c14cf92bSPeter Klausler auto repetitions{GetValue().repetitions}; 86c14cf92bSPeter Klausler if (repetitions < 0) { 874ac617f4Speter klausler hasFatalError_ = true; 88c14cf92bSPeter Klausler } else if (repetitions > 0) { 89c14cf92bSPeter Klausler repetitionsRemaining_ = repetitions - 1; 904ac617f4Speter klausler return; 914ac617f4Speter klausler } 924ac617f4Speter klausler } 934ac617f4Speter klausler repetitionsRemaining_ = 0; 944ac617f4Speter klausler } 954ac617f4Speter klausler 964ac617f4Speter klausler // Collects all of the elemental initializations from DATA statements 974ac617f4Speter klausler // into a single image for each symbol that appears in any DATA. 984ac617f4Speter klausler // Expands the implied DO loops and array references. 994ac617f4Speter klausler // Applies checks that validate each distinct elemental initialization 1004ac617f4Speter klausler // of the variables in a data-stmt-set, as well as those that apply 101c14cf92bSPeter Klausler // to the corresponding values being used to initialize each element. 102c14cf92bSPeter Klausler template <typename DSV = parser::DataStmtValue> 1034ac617f4Speter klausler class DataInitializationCompiler { 1044ac617f4Speter klausler public: 1054ac617f4Speter klausler DataInitializationCompiler(DataInitializations &inits, 106c14cf92bSPeter Klausler evaluate::ExpressionAnalyzer &a, const std::list<DSV> &list) 1077e225423SPeter Klausler : inits_{inits}, exprAnalyzer_{a}, values_{a.context(), list} {} 1084ac617f4Speter klausler const DataInitializations &inits() const { return inits_; } 1094ac617f4Speter klausler bool HasSurplusValues() const { return !values_.IsAtEnd(); } 1104ac617f4Speter klausler bool Scan(const parser::DataStmtObject &); 111c14cf92bSPeter Klausler // Initializes all elements of whole variable or component 112c14cf92bSPeter Klausler bool Scan(const Symbol &); 1134ac617f4Speter klausler 1144ac617f4Speter klausler private: 1154ac617f4Speter klausler bool Scan(const parser::Variable &); 1164ac617f4Speter klausler bool Scan(const parser::Designator &); 1174ac617f4Speter klausler bool Scan(const parser::DataImpliedDo &); 1184ac617f4Speter klausler bool Scan(const parser::DataIDoObject &); 1194ac617f4Speter klausler 1204ac617f4Speter klausler // Initializes all elements of a designator, which can be an array or section. 121d0d9839bSPeter Klausler bool InitDesignator(const SomeExpr &, const Scope &); 122c14cf92bSPeter Klausler // Initializes a single scalar object. 123d0d9839bSPeter Klausler bool InitElement(const evaluate::OffsetSymbol &, const SomeExpr &designator, 124d0d9839bSPeter Klausler const Scope &); 1254ac617f4Speter klausler // If the returned flag is true, emit a warning about CHARACTER misusage. 1264ac617f4Speter klausler std::optional<std::pair<SomeExpr, bool>> ConvertElement( 1274ac617f4Speter klausler const SomeExpr &, const evaluate::DynamicType &); 1284ac617f4Speter klausler 1294ac617f4Speter klausler DataInitializations &inits_; 1304ac617f4Speter klausler evaluate::ExpressionAnalyzer &exprAnalyzer_; 131c14cf92bSPeter Klausler ValueListIterator<DSV> values_; 1324ac617f4Speter klausler }; 1334ac617f4Speter klausler 134c14cf92bSPeter Klausler template <typename DSV> 135c14cf92bSPeter Klausler bool DataInitializationCompiler<DSV>::Scan( 136c14cf92bSPeter Klausler const parser::DataStmtObject &object) { 137cd03e96fSPeter Klausler return common::visit( 1384ac617f4Speter klausler common::visitors{ 1394ac617f4Speter klausler [&](const common::Indirection<parser::Variable> &var) { 1404ac617f4Speter klausler return Scan(var.value()); 1414ac617f4Speter klausler }, 1424ac617f4Speter klausler [&](const parser::DataImpliedDo &ido) { return Scan(ido); }, 1434ac617f4Speter klausler }, 1444ac617f4Speter klausler object.u); 1454ac617f4Speter klausler } 1464ac617f4Speter klausler 147c14cf92bSPeter Klausler template <typename DSV> 148c14cf92bSPeter Klausler bool DataInitializationCompiler<DSV>::Scan(const parser::Variable &var) { 1497e225423SPeter Klausler if (const auto *expr{GetExpr(exprAnalyzer_.context(), var)}) { 150573fc618SPeter Klausler parser::CharBlock at{var.GetSource()}; 151573fc618SPeter Klausler exprAnalyzer_.GetFoldingContext().messages().SetLocation(at); 152d0d9839bSPeter Klausler if (InitDesignator(*expr, exprAnalyzer_.context().FindScope(at))) { 1534ac617f4Speter klausler return true; 1544ac617f4Speter klausler } 1554ac617f4Speter klausler } 1564ac617f4Speter klausler return false; 1574ac617f4Speter klausler } 1584ac617f4Speter klausler 159c14cf92bSPeter Klausler template <typename DSV> 160c14cf92bSPeter Klausler bool DataInitializationCompiler<DSV>::Scan( 161c14cf92bSPeter Klausler const parser::Designator &designator) { 16210b990a0SPeter Klausler MaybeExpr expr; 16310b990a0SPeter Klausler { // The out-of-range subscript errors from the designator folder are a 16410b990a0SPeter Klausler // more specific than the default ones from expression semantics, so 16510b990a0SPeter Klausler // disable those to avoid piling on. 16610b990a0SPeter Klausler auto restorer{exprAnalyzer_.GetContextualMessages().DiscardMessages()}; 16710b990a0SPeter Klausler expr = exprAnalyzer_.Analyze(designator); 16810b990a0SPeter Klausler } 16910b990a0SPeter Klausler if (expr) { 170573fc618SPeter Klausler parser::CharBlock at{parser::FindSourceLocation(designator)}; 171573fc618SPeter Klausler exprAnalyzer_.GetFoldingContext().messages().SetLocation(at); 172d0d9839bSPeter Klausler if (InitDesignator(*expr, exprAnalyzer_.context().FindScope(at))) { 1734ac617f4Speter klausler return true; 1744ac617f4Speter klausler } 1754ac617f4Speter klausler } 1764ac617f4Speter klausler return false; 1774ac617f4Speter klausler } 1784ac617f4Speter klausler 179c14cf92bSPeter Klausler template <typename DSV> 180c14cf92bSPeter Klausler bool DataInitializationCompiler<DSV>::Scan(const parser::DataImpliedDo &ido) { 1814ac617f4Speter klausler const auto &bounds{std::get<parser::DataImpliedDo::Bounds>(ido.t)}; 1824ac617f4Speter klausler auto name{bounds.name.thing.thing}; 1837e225423SPeter Klausler const auto *lowerExpr{ 1847e225423SPeter Klausler GetExpr(exprAnalyzer_.context(), bounds.lower.thing.thing)}; 1857e225423SPeter Klausler const auto *upperExpr{ 1867e225423SPeter Klausler GetExpr(exprAnalyzer_.context(), bounds.upper.thing.thing)}; 1877e225423SPeter Klausler const auto *stepExpr{bounds.step 1887e225423SPeter Klausler ? GetExpr(exprAnalyzer_.context(), bounds.step->thing.thing) 1897e225423SPeter Klausler : nullptr}; 1904ac617f4Speter klausler if (lowerExpr && upperExpr) { 191cbd445e4SPeter Klausler // Fold the bounds expressions (again) in case any of them depend 192cbd445e4SPeter Klausler // on outer implied DO loops. 193cbd445e4SPeter Klausler evaluate::FoldingContext &context{exprAnalyzer_.GetFoldingContext()}; 194cbd445e4SPeter Klausler std::int64_t stepVal{1}; 195cbd445e4SPeter Klausler if (stepExpr) { 196cbd445e4SPeter Klausler auto foldedStep{evaluate::Fold(context, SomeExpr{*stepExpr})}; 197cbd445e4SPeter Klausler stepVal = ToInt64(foldedStep).value_or(1); 1984ac617f4Speter klausler if (stepVal == 0) { 1994ac617f4Speter klausler exprAnalyzer_.Say(name.source, 2004ac617f4Speter klausler "DATA statement implied DO loop has a step value of zero"_err_en_US); 201cbd445e4SPeter Klausler return false; 202cbd445e4SPeter Klausler } 203cbd445e4SPeter Klausler } 204cbd445e4SPeter Klausler auto foldedLower{evaluate::Fold(context, SomeExpr{*lowerExpr})}; 205cbd445e4SPeter Klausler auto lower{ToInt64(foldedLower)}; 206cbd445e4SPeter Klausler auto foldedUpper{evaluate::Fold(context, SomeExpr{*upperExpr})}; 207cbd445e4SPeter Klausler auto upper{ToInt64(foldedUpper)}; 208cbd445e4SPeter Klausler if (lower && upper) { 2094ac617f4Speter klausler int kind{evaluate::ResultType<evaluate::ImpliedDoIndex>::kind}; 2104ac617f4Speter klausler if (const auto dynamicType{evaluate::DynamicType::From(*name.symbol)}) { 2114ac617f4Speter klausler if (dynamicType->category() == TypeCategory::Integer) { 2124ac617f4Speter klausler kind = dynamicType->kind(); 2134ac617f4Speter klausler } 2144ac617f4Speter klausler } 2154ac617f4Speter klausler if (exprAnalyzer_.AddImpliedDo(name.source, kind)) { 216cbd445e4SPeter Klausler auto &value{context.StartImpliedDo(name.source, *lower)}; 2174ac617f4Speter klausler bool result{true}; 2184ac617f4Speter klausler for (auto n{(*upper - value + stepVal) / stepVal}; n > 0; 2194ac617f4Speter klausler --n, value += stepVal) { 2204ac617f4Speter klausler for (const auto &object : 2214ac617f4Speter klausler std::get<std::list<parser::DataIDoObject>>(ido.t)) { 2224ac617f4Speter klausler if (!Scan(object)) { 2234ac617f4Speter klausler result = false; 2244ac617f4Speter klausler break; 2254ac617f4Speter klausler } 2264ac617f4Speter klausler } 2274ac617f4Speter klausler } 228cbd445e4SPeter Klausler context.EndImpliedDo(name.source); 2294ac617f4Speter klausler exprAnalyzer_.RemoveImpliedDo(name.source); 2304ac617f4Speter klausler return result; 2314ac617f4Speter klausler } 2324ac617f4Speter klausler } 2334ac617f4Speter klausler } 2344ac617f4Speter klausler return false; 2354ac617f4Speter klausler } 2364ac617f4Speter klausler 237c14cf92bSPeter Klausler template <typename DSV> 238c14cf92bSPeter Klausler bool DataInitializationCompiler<DSV>::Scan( 239c14cf92bSPeter Klausler const parser::DataIDoObject &object) { 240cd03e96fSPeter Klausler return common::visit( 2414ac617f4Speter klausler common::visitors{ 2424ac617f4Speter klausler [&](const parser::Scalar<common::Indirection<parser::Designator>> 2434ac617f4Speter klausler &var) { return Scan(var.thing.value()); }, 2444ac617f4Speter klausler [&](const common::Indirection<parser::DataImpliedDo> &ido) { 2454ac617f4Speter klausler return Scan(ido.value()); 2464ac617f4Speter klausler }, 2474ac617f4Speter klausler }, 2484ac617f4Speter klausler object.u); 2494ac617f4Speter klausler } 2504ac617f4Speter klausler 251c14cf92bSPeter Klausler template <typename DSV> 252c14cf92bSPeter Klausler bool DataInitializationCompiler<DSV>::Scan(const Symbol &symbol) { 253c14cf92bSPeter Klausler auto designator{exprAnalyzer_.Designate(evaluate::DataRef{symbol})}; 254c14cf92bSPeter Klausler CHECK(designator.has_value()); 255d0d9839bSPeter Klausler return InitDesignator(*designator, symbol.owner()); 256c14cf92bSPeter Klausler } 257c14cf92bSPeter Klausler 258c14cf92bSPeter Klausler template <typename DSV> 259c14cf92bSPeter Klausler bool DataInitializationCompiler<DSV>::InitDesignator( 260d0d9839bSPeter Klausler const SomeExpr &designator, const Scope &scope) { 2614ac617f4Speter klausler evaluate::FoldingContext &context{exprAnalyzer_.GetFoldingContext()}; 2624ac617f4Speter klausler evaluate::DesignatorFolder folder{context}; 2634ac617f4Speter klausler while (auto offsetSymbol{folder.FoldDesignator(designator)}) { 2644ac617f4Speter klausler if (folder.isOutOfRange()) { 2654ac617f4Speter klausler if (auto bad{evaluate::OffsetToDesignator(context, *offsetSymbol)}) { 2664ac617f4Speter klausler exprAnalyzer_.context().Say( 2674ac617f4Speter klausler "DATA statement designator '%s' is out of range"_err_en_US, 2684ac617f4Speter klausler bad->AsFortran()); 2694ac617f4Speter klausler } else { 2704ac617f4Speter klausler exprAnalyzer_.context().Say( 2714ac617f4Speter klausler "DATA statement designator '%s' is out of range"_err_en_US, 2724ac617f4Speter klausler designator.AsFortran()); 2734ac617f4Speter klausler } 2744ac617f4Speter klausler return false; 275d0d9839bSPeter Klausler } else if (!InitElement(*offsetSymbol, designator, scope)) { 2764ac617f4Speter klausler return false; 2774ac617f4Speter klausler } else { 2784ac617f4Speter klausler ++values_; 2794ac617f4Speter klausler } 2804ac617f4Speter klausler } 2814ac617f4Speter klausler return folder.isEmpty(); 2824ac617f4Speter klausler } 2834ac617f4Speter klausler 284c14cf92bSPeter Klausler template <typename DSV> 2854ac617f4Speter klausler std::optional<std::pair<SomeExpr, bool>> 286c14cf92bSPeter Klausler DataInitializationCompiler<DSV>::ConvertElement( 2874ac617f4Speter klausler const SomeExpr &expr, const evaluate::DynamicType &type) { 2884ac617f4Speter klausler if (auto converted{evaluate::ConvertToType(type, SomeExpr{expr})}) { 2894ac617f4Speter klausler return {std::make_pair(std::move(*converted), false)}; 2904ac617f4Speter klausler } 2914ac617f4Speter klausler // Allow DATA initialization with Hollerith and kind=1 CHARACTER like 292574f9dfeSPeter Klausler // (most) other Fortran compilers do. 293574f9dfeSPeter Klausler if (auto converted{evaluate::HollerithToBOZ( 294574f9dfeSPeter Klausler exprAnalyzer_.GetFoldingContext(), expr, type)}) { 2954ac617f4Speter klausler return {std::make_pair(std::move(*converted), true)}; 2964ac617f4Speter klausler } 29700e0de05SPeter Klausler SemanticsContext &context{exprAnalyzer_.context()}; 29800e0de05SPeter Klausler if (context.IsEnabled(common::LanguageFeature::LogicalIntegerAssignment)) { 29900e0de05SPeter Klausler if (MaybeExpr converted{evaluate::DataConstantConversionExtension( 30000e0de05SPeter Klausler exprAnalyzer_.GetFoldingContext(), type, expr)}) { 301*0f973ac7SPeter Klausler context.Warn(common::LanguageFeature::LogicalIntegerAssignment, 302*0f973ac7SPeter Klausler exprAnalyzer_.GetFoldingContext().messages().at(), 303a53967cdSPeter Klausler "nonstandard usage: initialization of %s with %s"_port_en_US, 30400e0de05SPeter Klausler type.AsFortran(), expr.GetType().value().AsFortran()); 30500e0de05SPeter Klausler return {std::make_pair(std::move(*converted), false)}; 30600e0de05SPeter Klausler } 30700e0de05SPeter Klausler } 3084ac617f4Speter klausler return std::nullopt; 3094ac617f4Speter klausler } 3104ac617f4Speter klausler 311c14cf92bSPeter Klausler template <typename DSV> 312c14cf92bSPeter Klausler bool DataInitializationCompiler<DSV>::InitElement( 313d0d9839bSPeter Klausler const evaluate::OffsetSymbol &offsetSymbol, const SomeExpr &designator, 314d0d9839bSPeter Klausler const Scope &scope) { 3154ac617f4Speter klausler const Symbol &symbol{offsetSymbol.symbol()}; 3164ac617f4Speter klausler const Symbol *lastSymbol{GetLastSymbol(designator)}; 3174ac617f4Speter klausler bool isPointer{lastSymbol && IsPointer(*lastSymbol)}; 3184ac617f4Speter klausler bool isProcPointer{lastSymbol && IsProcedurePointer(*lastSymbol)}; 3194ac617f4Speter klausler evaluate::FoldingContext &context{exprAnalyzer_.GetFoldingContext()}; 3204ac617f4Speter klausler 3214ac617f4Speter klausler const auto DescribeElement{[&]() { 3224ac617f4Speter klausler if (auto badDesignator{ 3234ac617f4Speter klausler evaluate::OffsetToDesignator(context, offsetSymbol)}) { 3244ac617f4Speter klausler return badDesignator->AsFortran(); 3254ac617f4Speter klausler } else { 3264ac617f4Speter klausler // Error recovery 3274ac617f4Speter klausler std::string buf; 3284ac617f4Speter klausler llvm::raw_string_ostream ss{buf}; 3294ac617f4Speter klausler ss << offsetSymbol.symbol().name() << " offset " << offsetSymbol.offset() 3304ac617f4Speter klausler << " bytes for " << offsetSymbol.size() << " bytes"; 3314ac617f4Speter klausler return ss.str(); 3324ac617f4Speter klausler } 3334ac617f4Speter klausler }}; 3344ac617f4Speter klausler const auto GetImage{[&]() -> evaluate::InitialImage & { 33528a686a7SPeter Klausler // This could be (and was) written to always call std::map<>::emplace(), 33628a686a7SPeter Klausler // which should handle duplicate entries gracefully, but it was still 33728a686a7SPeter Klausler // causing memory allocation & deallocation with gcc. 33828a686a7SPeter Klausler auto iter{inits_.find(&symbol)}; 33928a686a7SPeter Klausler if (iter == inits_.end()) { 34028a686a7SPeter Klausler iter = inits_.emplace(&symbol, symbol.size()).first; 34128a686a7SPeter Klausler } 34228a686a7SPeter Klausler auto &symbolInit{iter->second}; 34328a686a7SPeter Klausler symbolInit.NoteInitializedRange(offsetSymbol); 3444ac617f4Speter klausler return symbolInit.image; 3454ac617f4Speter klausler }}; 3464ac617f4Speter klausler const auto OutOfRangeError{[&]() { 3474ac617f4Speter klausler evaluate::AttachDeclaration( 3484ac617f4Speter klausler exprAnalyzer_.context().Say( 3494ac617f4Speter klausler "DATA statement designator '%s' is out of range for its variable '%s'"_err_en_US, 3504ac617f4Speter klausler DescribeElement(), symbol.name()), 3514ac617f4Speter klausler symbol); 3524ac617f4Speter klausler }}; 3534ac617f4Speter klausler 3544ac617f4Speter klausler if (values_.hasFatalError()) { 3554ac617f4Speter klausler return false; 3564ac617f4Speter klausler } else if (values_.IsAtEnd()) { 3574ac617f4Speter klausler exprAnalyzer_.context().Say( 3584ac617f4Speter klausler "DATA statement set has no value for '%s'"_err_en_US, 3594ac617f4Speter klausler DescribeElement()); 3604ac617f4Speter klausler return false; 3614ac617f4Speter klausler } else if (static_cast<std::size_t>( 3624ac617f4Speter klausler offsetSymbol.offset() + offsetSymbol.size()) > symbol.size()) { 3634ac617f4Speter klausler OutOfRangeError(); 3644ac617f4Speter klausler return false; 3654ac617f4Speter klausler } 3664ac617f4Speter klausler 36769c625bfSPeter Klausler auto &messages{context.messages()}; 36869c625bfSPeter Klausler auto restorer{ 36969c625bfSPeter Klausler messages.SetLocation(values_.LocateSource().value_or(messages.at()))}; 3704ac617f4Speter klausler const SomeExpr *expr{*values_}; 3714ac617f4Speter klausler if (!expr) { 3724ac617f4Speter klausler CHECK(exprAnalyzer_.context().AnyFatalError()); 373815fddfaSPeter Klausler } else if (symbol.size() > maxDataInitBytes) { 374815fddfaSPeter Klausler evaluate::AttachDeclaration( 375815fddfaSPeter Klausler exprAnalyzer_.context().Say( 376815fddfaSPeter Klausler "'%s' is too large to initialize with a DATA statement"_todo_en_US, 377815fddfaSPeter Klausler symbol.name()), 378815fddfaSPeter Klausler symbol); 379815fddfaSPeter Klausler return false; 3804ac617f4Speter klausler } else if (isPointer) { 3814ac617f4Speter klausler if (static_cast<std::size_t>(offsetSymbol.offset() + offsetSymbol.size()) > 3824ac617f4Speter klausler symbol.size()) { 3834ac617f4Speter klausler OutOfRangeError(); 3844ac617f4Speter klausler } else if (evaluate::IsNullPointer(*expr)) { 3854ac617f4Speter klausler // nothing to do; rely on zero initialization 3864ac617f4Speter klausler return true; 3875349f991Speter klausler } else if (isProcPointer) { 388c7593344SPeter Klausler if (evaluate::IsProcedureDesignator(*expr)) { 389f82ee155SPeter Klausler if (CheckPointerAssignment(exprAnalyzer_.context(), designator, *expr, 390d0d9839bSPeter Klausler scope, 391f82ee155SPeter Klausler /*isBoundsRemapping=*/false, /*isAssumedRank=*/false)) { 3928594b051SPeter Klausler if (lastSymbol->has<ProcEntityDetails>()) { 3934ac617f4Speter klausler GetImage().AddPointer(offsetSymbol.offset(), *expr); 3944ac617f4Speter klausler return true; 3958594b051SPeter Klausler } else { 3968594b051SPeter Klausler evaluate::AttachDeclaration( 3978594b051SPeter Klausler exprAnalyzer_.context().Say( 3988594b051SPeter Klausler "DATA statement initialization of procedure pointer '%s' declared using a POINTER statement and an INTERFACE instead of a PROCEDURE statement"_todo_en_US, 3998594b051SPeter Klausler DescribeElement()), 4008594b051SPeter Klausler *lastSymbol); 4018594b051SPeter Klausler } 4024ac617f4Speter klausler } 4034ac617f4Speter klausler } else { 4045349f991Speter klausler exprAnalyzer_.Say( 4055349f991Speter klausler "Data object '%s' may not be used to initialize '%s', which is a procedure pointer"_err_en_US, 4064ac617f4Speter klausler expr->AsFortran(), DescribeElement()); 4074ac617f4Speter klausler } 4085349f991Speter klausler } else if (evaluate::IsProcedure(*expr)) { 4095349f991Speter klausler exprAnalyzer_.Say( 4105349f991Speter klausler "Procedure '%s' may not be used to initialize '%s', which is not a procedure pointer"_err_en_US, 4114ac617f4Speter klausler expr->AsFortran(), DescribeElement()); 4120c0b2ea9SPeter Klausler } else if (CheckInitialDataPointerTarget( 413d0d9839bSPeter Klausler exprAnalyzer_.context(), designator, *expr, scope)) { 4144ac617f4Speter klausler GetImage().AddPointer(offsetSymbol.offset(), *expr); 4154ac617f4Speter klausler return true; 4164ac617f4Speter klausler } 4174ac617f4Speter klausler } else if (evaluate::IsNullPointer(*expr)) { 4185349f991Speter klausler exprAnalyzer_.Say("Initializer for '%s' must not be a pointer"_err_en_US, 4194ac617f4Speter klausler DescribeElement()); 420c7593344SPeter Klausler } else if (evaluate::IsProcedureDesignator(*expr)) { 4215349f991Speter klausler exprAnalyzer_.Say("Initializer for '%s' must not be a procedure"_err_en_US, 4224ac617f4Speter klausler DescribeElement()); 4234ac617f4Speter klausler } else if (auto designatorType{designator.GetType()}) { 4249a883bfaSpeter klausler if (expr->Rank() > 0) { 4259a883bfaSpeter klausler // Because initial-data-target is ambiguous with scalar-constant and 4269a883bfaSpeter klausler // scalar-constant-subobject at parse time, enforcement of scalar-* 4279a883bfaSpeter klausler // must be deferred to here. 4289a883bfaSpeter klausler exprAnalyzer_.Say( 4299a883bfaSpeter klausler "DATA statement value initializes '%s' with an array"_err_en_US, 4309a883bfaSpeter klausler DescribeElement()); 4319a883bfaSpeter klausler } else if (auto converted{ConvertElement(*expr, *designatorType)}) { 4324ac617f4Speter klausler // value non-pointer initialization 433571673ceSPeter Steinfeld if (IsBOZLiteral(*expr) && 4344ac617f4Speter klausler designatorType->category() != TypeCategory::Integer) { // 8.6.7(11) 435*0f973ac7SPeter Klausler exprAnalyzer_.Warn(common::LanguageFeature::DataStmtExtensions, 436a53967cdSPeter Klausler "BOZ literal should appear in a DATA statement only as a value for an integer object, but '%s' is '%s'"_port_en_US, 4374ac617f4Speter klausler DescribeElement(), designatorType->AsFortran()); 438*0f973ac7SPeter Klausler } else if (converted->second) { 439*0f973ac7SPeter Klausler exprAnalyzer_.Warn(common::LanguageFeature::DataStmtExtensions, 440a53967cdSPeter Klausler "DATA statement value initializes '%s' of type '%s' with CHARACTER"_port_en_US, 4414ac617f4Speter klausler DescribeElement(), designatorType->AsFortran()); 4424ac617f4Speter klausler } 4434ac617f4Speter klausler auto folded{evaluate::Fold(context, std::move(converted->first))}; 4444f1037f8SPeter Klausler // Rewritten from a switch() in order to avoid getting complaints 4454f1037f8SPeter Klausler // about a missing "default:" from some compilers and complaints 4464f1037f8SPeter Klausler // about a redundant "default:" from others. 4474f1037f8SPeter Klausler auto status{GetImage().Add( 4484f1037f8SPeter Klausler offsetSymbol.offset(), offsetSymbol.size(), folded, context)}; 4494f1037f8SPeter Klausler if (status == evaluate::InitialImage::Ok) { 4504ac617f4Speter klausler return true; 4514f1037f8SPeter Klausler } else if (status == evaluate::InitialImage::NotAConstant) { 4525349f991Speter klausler exprAnalyzer_.Say( 4534ac617f4Speter klausler "DATA statement value '%s' for '%s' is not a constant"_err_en_US, 4544ac617f4Speter klausler folded.AsFortran(), DescribeElement()); 4554f1037f8SPeter Klausler } else if (status == evaluate::InitialImage::OutOfRange) { 4564ac617f4Speter klausler OutOfRangeError(); 457ab261eb3SjeanPerier } else if (status == evaluate::InitialImage::LengthMismatch) { 458*0f973ac7SPeter Klausler exprAnalyzer_.Warn(common::UsageWarning::DataLength, 4592dab5bdfSPeter Klausler "DATA statement value '%s' for '%s' has the wrong length"_warn_en_US, 4602dab5bdfSPeter Klausler folded.AsFortran(), DescribeElement()); 461ab261eb3SjeanPerier return true; 4627358c26dSLeandro Lupori } else if (status == evaluate::InitialImage::TooManyElems) { 4637358c26dSLeandro Lupori exprAnalyzer_.Say("DATA statement has too many elements"_err_en_US); 4644f1037f8SPeter Klausler } else { 4654ac617f4Speter klausler CHECK(exprAnalyzer_.context().AnyFatalError()); 4664ac617f4Speter klausler } 4674ac617f4Speter klausler } else { 4684ac617f4Speter klausler exprAnalyzer_.context().Say( 4694ac617f4Speter klausler "DATA statement value could not be converted to the type '%s' of the object '%s'"_err_en_US, 4704ac617f4Speter klausler designatorType->AsFortran(), DescribeElement()); 4714ac617f4Speter klausler } 4724ac617f4Speter klausler } else { 4734ac617f4Speter klausler CHECK(exprAnalyzer_.context().AnyFatalError()); 4744ac617f4Speter klausler } 4754ac617f4Speter klausler return false; 4764ac617f4Speter klausler } 4774ac617f4Speter klausler 4784ac617f4Speter klausler void AccumulateDataInitializations(DataInitializations &inits, 4794ac617f4Speter klausler evaluate::ExpressionAnalyzer &exprAnalyzer, 4804ac617f4Speter klausler const parser::DataStmtSet &set) { 481c14cf92bSPeter Klausler DataInitializationCompiler scanner{ 482c14cf92bSPeter Klausler inits, exprAnalyzer, std::get<std::list<parser::DataStmtValue>>(set.t)}; 4834ac617f4Speter klausler for (const auto &object : 4844ac617f4Speter klausler std::get<std::list<parser::DataStmtObject>>(set.t)) { 4854ac617f4Speter klausler if (!scanner.Scan(object)) { 4864ac617f4Speter klausler return; 4874ac617f4Speter klausler } 4884ac617f4Speter klausler } 4894ac617f4Speter klausler if (scanner.HasSurplusValues()) { 4904ac617f4Speter klausler exprAnalyzer.context().Say( 4914ac617f4Speter klausler "DATA statement set has more values than objects"_err_en_US); 4924ac617f4Speter klausler } 4934ac617f4Speter klausler } 4944ac617f4Speter klausler 495c14cf92bSPeter Klausler void AccumulateDataInitializations(DataInitializations &inits, 496c14cf92bSPeter Klausler evaluate::ExpressionAnalyzer &exprAnalyzer, const Symbol &symbol, 497c14cf92bSPeter Klausler const std::list<common::Indirection<parser::DataStmtValue>> &list) { 498c14cf92bSPeter Klausler DataInitializationCompiler<common::Indirection<parser::DataStmtValue>> 499c14cf92bSPeter Klausler scanner{inits, exprAnalyzer, list}; 500c14cf92bSPeter Klausler if (scanner.Scan(symbol) && scanner.HasSurplusValues()) { 501c14cf92bSPeter Klausler exprAnalyzer.context().Say( 502c14cf92bSPeter Klausler "DATA statement set has more values than objects"_err_en_US); 503c14cf92bSPeter Klausler } 504c14cf92bSPeter Klausler } 505c14cf92bSPeter Klausler 506d60a0220Speter klausler // Looks for default derived type component initialization -- but 507d60a0220Speter klausler // *not* allocatables. 508d60a0220Speter klausler static const DerivedTypeSpec *HasDefaultInitialization(const Symbol &symbol) { 509d60a0220Speter klausler if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 510d60a0220Speter klausler if (object->init().has_value()) { 511d60a0220Speter klausler return nullptr; // init is explicit, not default 512d60a0220Speter klausler } else if (!object->isDummy() && object->type()) { 513d60a0220Speter klausler if (const DerivedTypeSpec * derived{object->type()->AsDerived()}) { 514d60a0220Speter klausler DirectComponentIterator directs{*derived}; 5158470cdd4SKazu Hirata if (llvm::any_of(directs, [](const Symbol &component) { 516d60a0220Speter klausler return !IsAllocatable(component) && 517d60a0220Speter klausler HasDeclarationInitializer(component); 5188470cdd4SKazu Hirata })) { 519d60a0220Speter klausler return derived; 5204ac617f4Speter klausler } 521d60a0220Speter klausler } 522d60a0220Speter klausler } 523d60a0220Speter klausler } 524d60a0220Speter klausler return nullptr; 525d60a0220Speter klausler } 526d60a0220Speter klausler 527d60a0220Speter klausler // PopulateWithComponentDefaults() adds initializations to an instance 528d60a0220Speter klausler // of SymbolDataInitialization containing all of the default component 529d60a0220Speter klausler // initializers 530d60a0220Speter klausler 531d60a0220Speter klausler static void PopulateWithComponentDefaults(SymbolDataInitialization &init, 532d60a0220Speter klausler std::size_t offset, const DerivedTypeSpec &derived, 533d60a0220Speter klausler evaluate::FoldingContext &foldingContext); 534d60a0220Speter klausler 535d60a0220Speter klausler static void PopulateWithComponentDefaults(SymbolDataInitialization &init, 536d60a0220Speter klausler std::size_t offset, const DerivedTypeSpec &derived, 537d60a0220Speter klausler evaluate::FoldingContext &foldingContext, const Symbol &symbol) { 538d60a0220Speter klausler if (auto extents{evaluate::GetConstantExtents(foldingContext, symbol)}) { 539d60a0220Speter klausler const Scope &scope{derived.scope() ? *derived.scope() 540d60a0220Speter klausler : DEREF(derived.typeSymbol().scope())}; 541d60a0220Speter klausler std::size_t stride{scope.size()}; 542d60a0220Speter klausler if (std::size_t alignment{scope.alignment().value_or(0)}) { 543d60a0220Speter klausler stride = ((stride + alignment - 1) / alignment) * alignment; 544d60a0220Speter klausler } 545d60a0220Speter klausler for (auto elements{evaluate::GetSize(*extents)}; elements-- > 0; 546d60a0220Speter klausler offset += stride) { 547d60a0220Speter klausler PopulateWithComponentDefaults(init, offset, derived, foldingContext); 548d60a0220Speter klausler } 549d60a0220Speter klausler } 550d60a0220Speter klausler } 551d60a0220Speter klausler 552d60a0220Speter klausler // F'2018 19.5.3(10) allows storage-associated default component initialization 553d60a0220Speter klausler // when the values are identical. 554d60a0220Speter klausler static void PopulateWithComponentDefaults(SymbolDataInitialization &init, 555d60a0220Speter klausler std::size_t offset, const DerivedTypeSpec &derived, 556d60a0220Speter klausler evaluate::FoldingContext &foldingContext) { 557d60a0220Speter klausler const Scope &scope{ 558d60a0220Speter klausler derived.scope() ? *derived.scope() : DEREF(derived.typeSymbol().scope())}; 559d60a0220Speter klausler for (const auto &pair : scope) { 560d60a0220Speter klausler const Symbol &component{*pair.second}; 561d60a0220Speter klausler std::size_t componentOffset{offset + component.offset()}; 562d60a0220Speter klausler if (const auto *object{component.detailsIf<ObjectEntityDetails>()}) { 563d60a0220Speter klausler if (!IsAllocatable(component) && !IsAutomatic(component)) { 564d60a0220Speter klausler bool initialized{false}; 565d60a0220Speter klausler if (object->init()) { 566d60a0220Speter klausler initialized = true; 567d60a0220Speter klausler if (IsPointer(component)) { 568d60a0220Speter klausler if (auto extant{init.image.AsConstantPointer(componentOffset)}) { 569d60a0220Speter klausler initialized = !(*extant == *object->init()); 570d60a0220Speter klausler } 571d60a0220Speter klausler if (initialized) { 572d60a0220Speter klausler init.image.AddPointer(componentOffset, *object->init()); 573d60a0220Speter klausler } 574d60a0220Speter klausler } else { // data, not pointer 575d60a0220Speter klausler if (auto dyType{evaluate::DynamicType::From(component)}) { 576d60a0220Speter klausler if (auto extents{evaluate::GetConstantExtents( 577d60a0220Speter klausler foldingContext, component)}) { 578ae93d8eaSPeter Klausler if (auto extant{init.image.AsConstant(foldingContext, *dyType, 579e6be8da1SPeter Klausler std::nullopt, *extents, false /*don't pad*/, 580e6be8da1SPeter Klausler componentOffset)}) { 581d60a0220Speter klausler initialized = !(*extant == *object->init()); 582d60a0220Speter klausler } 583d60a0220Speter klausler } 584d60a0220Speter klausler } 585d60a0220Speter klausler if (initialized) { 586d60a0220Speter klausler init.image.Add(componentOffset, component.size(), *object->init(), 587d60a0220Speter klausler foldingContext); 588d60a0220Speter klausler } 589d60a0220Speter klausler } 590d60a0220Speter klausler } else if (const DeclTypeSpec * type{component.GetType()}) { 591d60a0220Speter klausler if (const DerivedTypeSpec * componentDerived{type->AsDerived()}) { 592d60a0220Speter klausler PopulateWithComponentDefaults(init, componentOffset, 593d60a0220Speter klausler *componentDerived, foldingContext, component); 594d60a0220Speter klausler } 595d60a0220Speter klausler } 596d60a0220Speter klausler if (initialized) { 59728a686a7SPeter Klausler init.NoteInitializedRange(componentOffset, component.size()); 598d60a0220Speter klausler } 599d60a0220Speter klausler } 600d60a0220Speter klausler } else if (const auto *proc{component.detailsIf<ProcEntityDetails>()}) { 601d60a0220Speter klausler if (proc->init() && *proc->init()) { 602d60a0220Speter klausler SomeExpr procPtrInit{evaluate::ProcedureDesignator{**proc->init()}}; 603d60a0220Speter klausler auto extant{init.image.AsConstantPointer(componentOffset)}; 604d60a0220Speter klausler if (!extant || !(*extant == procPtrInit)) { 60528a686a7SPeter Klausler init.NoteInitializedRange(componentOffset, component.size()); 606d60a0220Speter klausler init.image.AddPointer(componentOffset, std::move(procPtrInit)); 607d60a0220Speter klausler } 608d60a0220Speter klausler } 609d60a0220Speter klausler } 610d60a0220Speter klausler } 611d60a0220Speter klausler } 612d60a0220Speter klausler 613d60a0220Speter klausler static bool CheckForOverlappingInitialization( 614d60a0220Speter klausler const std::list<SymbolRef> &symbols, 615d60a0220Speter klausler SymbolDataInitialization &initialization, 616d60a0220Speter klausler evaluate::ExpressionAnalyzer &exprAnalyzer, const std::string &what) { 617d60a0220Speter klausler bool result{true}; 618d60a0220Speter klausler auto &context{exprAnalyzer.GetFoldingContext()}; 619d60a0220Speter klausler initialization.initializedRanges.sort(); 620d60a0220Speter klausler ConstantSubscript next{0}; 621d60a0220Speter klausler for (const auto &range : initialization.initializedRanges) { 622d60a0220Speter klausler if (range.start() < next) { 623d60a0220Speter klausler result = false; // error: overlap 624d60a0220Speter klausler bool hit{false}; 625d60a0220Speter klausler for (const Symbol &symbol : symbols) { 626d60a0220Speter klausler auto offset{range.start() - 627d60a0220Speter klausler static_cast<ConstantSubscript>( 628d60a0220Speter klausler symbol.offset() - symbols.front()->offset())}; 629d60a0220Speter klausler if (offset >= 0) { 630d60a0220Speter klausler if (auto badDesignator{evaluate::OffsetToDesignator( 631d60a0220Speter klausler context, symbol, offset, range.size())}) { 632d60a0220Speter klausler hit = true; 633d60a0220Speter klausler exprAnalyzer.Say(symbol.name(), 634d60a0220Speter klausler "%s affect '%s' more than once"_err_en_US, what, 635d60a0220Speter klausler badDesignator->AsFortran()); 636d60a0220Speter klausler } 637d60a0220Speter klausler } 638d60a0220Speter klausler } 639d60a0220Speter klausler CHECK(hit); 640d60a0220Speter klausler } 641d60a0220Speter klausler next = range.start() + range.size(); 642d60a0220Speter klausler CHECK(next <= static_cast<ConstantSubscript>(initialization.image.size())); 643d60a0220Speter klausler } 644d60a0220Speter klausler return result; 645d60a0220Speter klausler } 646d60a0220Speter klausler 647d60a0220Speter klausler static void IncorporateExplicitInitialization( 648d60a0220Speter klausler SymbolDataInitialization &combined, DataInitializations &inits, 649d60a0220Speter klausler const Symbol &symbol, ConstantSubscript firstOffset, 650d60a0220Speter klausler evaluate::FoldingContext &foldingContext) { 651d60a0220Speter klausler auto iter{inits.find(&symbol)}; 652d60a0220Speter klausler const auto offset{symbol.offset() - firstOffset}; 653d60a0220Speter klausler if (iter != inits.end()) { // DATA statement initialization 654d60a0220Speter klausler for (const auto &range : iter->second.initializedRanges) { 655d60a0220Speter klausler auto at{offset + range.start()}; 65628a686a7SPeter Klausler combined.NoteInitializedRange(at, range.size()); 657d60a0220Speter klausler combined.image.Incorporate( 658d60a0220Speter klausler at, iter->second.image, range.start(), range.size()); 659d60a0220Speter klausler } 660d60a0220Speter klausler if (removeOriginalInits) { 661d60a0220Speter klausler inits.erase(iter); 662d60a0220Speter klausler } 663d60a0220Speter klausler } else { // Declaration initialization 664d60a0220Speter klausler Symbol &mutableSymbol{const_cast<Symbol &>(symbol)}; 665d60a0220Speter klausler if (IsPointer(mutableSymbol)) { 666d60a0220Speter klausler if (auto *object{mutableSymbol.detailsIf<ObjectEntityDetails>()}) { 667d60a0220Speter klausler if (object->init()) { 66828a686a7SPeter Klausler combined.NoteInitializedRange(offset, mutableSymbol.size()); 669d60a0220Speter klausler combined.image.AddPointer(offset, *object->init()); 670d60a0220Speter klausler if (removeOriginalInits) { 671d60a0220Speter klausler object->init().reset(); 672d60a0220Speter klausler } 673d60a0220Speter klausler } 674d60a0220Speter klausler } else if (auto *proc{mutableSymbol.detailsIf<ProcEntityDetails>()}) { 675d60a0220Speter klausler if (proc->init() && *proc->init()) { 67628a686a7SPeter Klausler combined.NoteInitializedRange(offset, mutableSymbol.size()); 677d60a0220Speter klausler combined.image.AddPointer( 678d60a0220Speter klausler offset, SomeExpr{evaluate::ProcedureDesignator{**proc->init()}}); 679d60a0220Speter klausler if (removeOriginalInits) { 680d60a0220Speter klausler proc->init().reset(); 681d60a0220Speter klausler } 682d60a0220Speter klausler } 683d60a0220Speter klausler } 684d60a0220Speter klausler } else if (auto *object{mutableSymbol.detailsIf<ObjectEntityDetails>()}) { 685d60a0220Speter klausler if (!IsNamedConstant(mutableSymbol) && object->init()) { 68628a686a7SPeter Klausler combined.NoteInitializedRange(offset, mutableSymbol.size()); 687d60a0220Speter klausler combined.image.Add( 688d60a0220Speter klausler offset, mutableSymbol.size(), *object->init(), foldingContext); 689d60a0220Speter klausler if (removeOriginalInits) { 690d60a0220Speter klausler object->init().reset(); 691d60a0220Speter klausler } 692d60a0220Speter klausler } 693d60a0220Speter klausler } 694d60a0220Speter klausler } 695d60a0220Speter klausler } 696d60a0220Speter klausler 697d60a0220Speter klausler // Finds the size of the smallest element type in a list of 698d60a0220Speter klausler // storage-associated objects. 699d60a0220Speter klausler static std::size_t ComputeMinElementBytes( 700d60a0220Speter klausler const std::list<SymbolRef> &associated, 701d60a0220Speter klausler evaluate::FoldingContext &foldingContext) { 7024ac617f4Speter klausler std::size_t minElementBytes{1}; 703d60a0220Speter klausler const Symbol &first{*associated.front()}; 704d60a0220Speter klausler for (const Symbol &s : associated) { 705d60a0220Speter klausler if (auto dyType{evaluate::DynamicType::From(s)}) { 706d60a0220Speter klausler auto size{static_cast<std::size_t>( 707d60a0220Speter klausler evaluate::ToInt64(dyType->MeasureSizeInBytes(foldingContext, true)) 708d60a0220Speter klausler .value_or(1))}; 70923c2bedfSPeter Klausler if (std::size_t alignment{ 71023c2bedfSPeter Klausler dyType->GetAlignment(foldingContext.targetCharacteristics())}) { 711d60a0220Speter klausler size = ((size + alignment - 1) / alignment) * alignment; 7124ac617f4Speter klausler } 713d60a0220Speter klausler if (&s == &first) { 714d60a0220Speter klausler minElementBytes = size; 715d60a0220Speter klausler } else { 716d60a0220Speter klausler minElementBytes = std::min(minElementBytes, size); 7174ac617f4Speter klausler } 7184ac617f4Speter klausler } else { 7194ac617f4Speter klausler minElementBytes = 1; 7204ac617f4Speter klausler } 7214ac617f4Speter klausler } 722d60a0220Speter klausler return minElementBytes; 723d60a0220Speter klausler } 724d60a0220Speter klausler 725d60a0220Speter klausler // Checks for overlapping initialization errors in a list of 726d60a0220Speter klausler // storage-associated objects. Default component initializations 727d60a0220Speter klausler // are allowed to be overridden by explicit initializations. 728d60a0220Speter klausler // If the objects are static, save the combined initializer as 729d60a0220Speter klausler // a compiler-created object that covers all of them. 730d60a0220Speter klausler static bool CombineEquivalencedInitialization( 731d60a0220Speter klausler const std::list<SymbolRef> &associated, 732d60a0220Speter klausler evaluate::ExpressionAnalyzer &exprAnalyzer, DataInitializations &inits) { 733d60a0220Speter klausler // Compute the minimum common granularity and total size 734d60a0220Speter klausler const Symbol &first{*associated.front()}; 735d60a0220Speter klausler std::size_t maxLimit{0}; 736d60a0220Speter klausler for (const Symbol &s : associated) { 737d60a0220Speter klausler CHECK(s.offset() >= first.offset()); 738d60a0220Speter klausler auto limit{s.offset() + s.size()}; 739d60a0220Speter klausler if (limit > maxLimit) { 740d60a0220Speter klausler maxLimit = limit; 741d60a0220Speter klausler } 742d60a0220Speter klausler } 743d60a0220Speter klausler auto bytes{static_cast<common::ConstantSubscript>(maxLimit - first.offset())}; 744d60a0220Speter klausler Scope &scope{const_cast<Scope &>(first.owner())}; 745d60a0220Speter klausler // Combine the initializations of the associated objects. 746d60a0220Speter klausler // Apply all default initializations first. 747d60a0220Speter klausler SymbolDataInitialization combined{static_cast<std::size_t>(bytes)}; 748d60a0220Speter klausler auto &foldingContext{exprAnalyzer.GetFoldingContext()}; 749d60a0220Speter klausler for (const Symbol &s : associated) { 750d60a0220Speter klausler if (!IsNamedConstant(s)) { 751d60a0220Speter klausler if (const auto *derived{HasDefaultInitialization(s)}) { 752d60a0220Speter klausler PopulateWithComponentDefaults( 753d60a0220Speter klausler combined, s.offset() - first.offset(), *derived, foldingContext, s); 754d60a0220Speter klausler } 755d60a0220Speter klausler } 756d60a0220Speter klausler } 757d60a0220Speter klausler if (!CheckForOverlappingInitialization(associated, combined, exprAnalyzer, 758d60a0220Speter klausler "Distinct default component initializations of equivalenced objects"s)) { 759d60a0220Speter klausler return false; 760d60a0220Speter klausler } 761d60a0220Speter klausler // Don't complain about overlap between explicit initializations and 762d60a0220Speter klausler // default initializations. 763d60a0220Speter klausler combined.initializedRanges.clear(); 764d60a0220Speter klausler // Now overlay all explicit initializations from DATA statements and 765d60a0220Speter klausler // from initializers in declarations. 766d60a0220Speter klausler for (const Symbol &symbol : associated) { 767d60a0220Speter klausler IncorporateExplicitInitialization( 768d60a0220Speter klausler combined, inits, symbol, first.offset(), foldingContext); 769d60a0220Speter klausler } 770d60a0220Speter klausler if (!CheckForOverlappingInitialization(associated, combined, exprAnalyzer, 771d60a0220Speter klausler "Explicit initializations of equivalenced objects"s)) { 772d60a0220Speter klausler return false; 773d60a0220Speter klausler } 774d60a0220Speter klausler // If the items are in static storage, save the final initialization. 775dc554bd0SKazu Hirata if (llvm::any_of(associated, [](SymbolRef ref) { return IsSaved(*ref); })) { 776d60a0220Speter klausler // Create a compiler array temp that overlaps all the items. 7774ac617f4Speter klausler SourceName name{exprAnalyzer.context().GetTempName(scope)}; 7784ac617f4Speter klausler auto emplaced{ 7794ac617f4Speter klausler scope.try_emplace(name, Attrs{Attr::SAVE}, ObjectEntityDetails{})}; 7804ac617f4Speter klausler CHECK(emplaced.second); 7814ac617f4Speter klausler Symbol &combinedSymbol{*emplaced.first->second}; 782d60a0220Speter klausler combinedSymbol.set(Symbol::Flag::CompilerCreated); 783d60a0220Speter klausler inits.emplace(&combinedSymbol, std::move(combined)); 7844ac617f4Speter klausler auto &details{combinedSymbol.get<ObjectEntityDetails>()}; 785d60a0220Speter klausler combinedSymbol.set_offset(first.offset()); 7864ac617f4Speter klausler combinedSymbol.set_size(bytes); 787d60a0220Speter klausler std::size_t minElementBytes{ 788d60a0220Speter klausler ComputeMinElementBytes(associated, foldingContext)}; 78923c2bedfSPeter Klausler if (!exprAnalyzer.GetFoldingContext().targetCharacteristics().IsTypeEnabled( 790d60a0220Speter klausler TypeCategory::Integer, minElementBytes) || 791d60a0220Speter klausler (bytes % minElementBytes) != 0) { 792d60a0220Speter klausler minElementBytes = 1; 793d60a0220Speter klausler } 794d60a0220Speter klausler const DeclTypeSpec &typeSpec{scope.MakeNumericType( 795d60a0220Speter klausler TypeCategory::Integer, KindExpr{minElementBytes})}; 7964ac617f4Speter klausler details.set_type(typeSpec); 7974ac617f4Speter klausler ArraySpec arraySpec; 7984ac617f4Speter klausler arraySpec.emplace_back(ShapeSpec::MakeExplicit(Bound{ 7994ac617f4Speter klausler bytes / static_cast<common::ConstantSubscript>(minElementBytes)})); 8004ac617f4Speter klausler details.set_shape(arraySpec); 801d60a0220Speter klausler if (const auto *commonBlock{FindCommonBlockContaining(first)}) { 8024ac617f4Speter klausler details.set_commonBlock(*commonBlock); 8034ac617f4Speter klausler } 804d60a0220Speter klausler // Add an EQUIVALENCE set to the scope so that the new object appears in 805d60a0220Speter klausler // the results of GetStorageAssociations(). 806d60a0220Speter klausler auto &newSet{scope.equivalenceSets().emplace_back()}; 807d60a0220Speter klausler newSet.emplace_back(combinedSymbol); 808d60a0220Speter klausler newSet.emplace_back(const_cast<Symbol &>(first)); 8094ac617f4Speter klausler } 810d60a0220Speter klausler return true; 8114ac617f4Speter klausler } 8124ac617f4Speter klausler 813d60a0220Speter klausler // When a statically-allocated derived type variable has no explicit 814d60a0220Speter klausler // initialization, but its type has at least one nonallocatable ultimate 815d60a0220Speter klausler // component with default initialization, make its initialization explicit. 816d60a0220Speter klausler [[maybe_unused]] static void MakeDefaultInitializationExplicit( 817d60a0220Speter klausler const Scope &scope, const std::list<std::list<SymbolRef>> &associations, 818d60a0220Speter klausler evaluate::FoldingContext &foldingContext, DataInitializations &inits) { 819d60a0220Speter klausler UnorderedSymbolSet equivalenced; 820d60a0220Speter klausler for (const std::list<SymbolRef> &association : associations) { 821d60a0220Speter klausler for (const Symbol &symbol : association) { 822d60a0220Speter klausler equivalenced.emplace(symbol); 823d60a0220Speter klausler } 824d60a0220Speter klausler } 825d60a0220Speter klausler for (const auto &pair : scope) { 826d60a0220Speter klausler const Symbol &symbol{*pair.second}; 827d60a0220Speter klausler if (!symbol.test(Symbol::Flag::InDataStmt) && 828d60a0220Speter klausler !HasDeclarationInitializer(symbol) && IsSaved(symbol) && 829d60a0220Speter klausler equivalenced.find(symbol) == equivalenced.end()) { 830d60a0220Speter klausler // Static object, no local storage association, no explicit initialization 831d60a0220Speter klausler if (const DerivedTypeSpec * derived{HasDefaultInitialization(symbol)}) { 832d60a0220Speter klausler auto newInitIter{inits.emplace(&symbol, symbol.size())}; 833d60a0220Speter klausler CHECK(newInitIter.second); 834d60a0220Speter klausler auto &newInit{newInitIter.first->second}; 835d60a0220Speter klausler PopulateWithComponentDefaults( 836d60a0220Speter klausler newInit, 0, *derived, foldingContext, symbol); 837d60a0220Speter klausler } 838d60a0220Speter klausler } 839d60a0220Speter klausler } 840d60a0220Speter klausler } 841d60a0220Speter klausler 842d60a0220Speter klausler // Traverses the Scopes to: 843d60a0220Speter klausler // 1) combine initialization of equivalenced objects, & 844d60a0220Speter klausler // 2) optionally make initialization explicit for otherwise uninitialized static 845d60a0220Speter klausler // objects of derived types with default component initialization 846d60a0220Speter klausler // Returns false on error. 847d60a0220Speter klausler static bool ProcessScopes(const Scope &scope, 848d60a0220Speter klausler evaluate::ExpressionAnalyzer &exprAnalyzer, DataInitializations &inits) { 849d60a0220Speter klausler bool result{true}; // no error 850d60a0220Speter klausler switch (scope.kind()) { 851d60a0220Speter klausler case Scope::Kind::Global: 852d60a0220Speter klausler case Scope::Kind::Module: 853d60a0220Speter klausler case Scope::Kind::MainProgram: 854d60a0220Speter klausler case Scope::Kind::Subprogram: 855d60a0220Speter klausler case Scope::Kind::BlockData: 856a9782feaSPeter Klausler case Scope::Kind::BlockConstruct: { 857d60a0220Speter klausler std::list<std::list<SymbolRef>> associations{GetStorageAssociations(scope)}; 858d60a0220Speter klausler for (const std::list<SymbolRef> &associated : associations) { 859d60a0220Speter klausler if (std::find_if(associated.begin(), associated.end(), [](SymbolRef ref) { 860d60a0220Speter klausler return IsInitialized(*ref); 861d60a0220Speter klausler }) != associated.end()) { 862d60a0220Speter klausler result &= 863d60a0220Speter klausler CombineEquivalencedInitialization(associated, exprAnalyzer, inits); 864d60a0220Speter klausler } 865d60a0220Speter klausler } 866d60a0220Speter klausler if constexpr (makeDefaultInitializationExplicit) { 867d60a0220Speter klausler MakeDefaultInitializationExplicit( 868d60a0220Speter klausler scope, associations, exprAnalyzer.GetFoldingContext(), inits); 869d60a0220Speter klausler } 870d60a0220Speter klausler for (const Scope &child : scope.children()) { 871d60a0220Speter klausler result &= ProcessScopes(child, exprAnalyzer, inits); 872d60a0220Speter klausler } 873d60a0220Speter klausler } break; 874d60a0220Speter klausler default:; 875d60a0220Speter klausler } 876d60a0220Speter klausler return result; 877d60a0220Speter klausler } 878d60a0220Speter klausler 879d60a0220Speter klausler // Converts the static initialization image for a single symbol with 880d60a0220Speter klausler // one or more DATA statement appearances. 8814ac617f4Speter klausler void ConstructInitializer(const Symbol &symbol, 8824ac617f4Speter klausler SymbolDataInitialization &initialization, 8834ac617f4Speter klausler evaluate::ExpressionAnalyzer &exprAnalyzer) { 884d60a0220Speter klausler std::list<SymbolRef> symbols{symbol}; 885d60a0220Speter klausler CheckForOverlappingInitialization( 886d60a0220Speter klausler symbols, initialization, exprAnalyzer, "DATA statement initializations"s); 8874ac617f4Speter klausler auto &context{exprAnalyzer.GetFoldingContext()}; 8884ac617f4Speter klausler if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) { 8894ac617f4Speter klausler CHECK(IsProcedurePointer(symbol)); 8904ac617f4Speter klausler auto &mutableProc{const_cast<ProcEntityDetails &>(*proc)}; 891d60a0220Speter klausler if (MaybeExpr expr{initialization.image.AsConstantPointer()}) { 892d60a0220Speter klausler if (const auto *procDesignator{ 893d60a0220Speter klausler std::get_if<evaluate::ProcedureDesignator>(&expr->u)}) { 894d60a0220Speter klausler CHECK(!procDesignator->GetComponent()); 895b942c248SPeter Klausler if (const auto *intrin{procDesignator->GetSpecificIntrinsic()}) { 896b942c248SPeter Klausler const Symbol *intrinSymbol{ 897b942c248SPeter Klausler symbol.owner().FindSymbol(SourceName{intrin->name})}; 898b942c248SPeter Klausler mutableProc.set_init(DEREF(intrinSymbol)); 899b942c248SPeter Klausler } else { 900d60a0220Speter klausler mutableProc.set_init(DEREF(procDesignator->GetSymbol())); 901b942c248SPeter Klausler } 902d60a0220Speter klausler } else { 9034e3bf225SPeter Klausler CHECK(evaluate::IsNullProcedurePointer(*expr)); 904d60a0220Speter klausler mutableProc.set_init(nullptr); 905d60a0220Speter klausler } 906d60a0220Speter klausler } else { 907d60a0220Speter klausler mutableProc.set_init(nullptr); 908d60a0220Speter klausler } 9094ac617f4Speter klausler } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 9104ac617f4Speter klausler auto &mutableObject{const_cast<ObjectEntityDetails &>(*object)}; 9114ac617f4Speter klausler if (IsPointer(symbol)) { 912d60a0220Speter klausler if (auto ptr{initialization.image.AsConstantPointer()}) { 913d60a0220Speter klausler mutableObject.set_init(*ptr); 9144ac617f4Speter klausler } else { 915d60a0220Speter klausler mutableObject.set_init(SomeExpr{evaluate::NullPointer{}}); 916d60a0220Speter klausler } 917d60a0220Speter klausler } else if (auto symbolType{evaluate::DynamicType::From(symbol)}) { 9184ac617f4Speter klausler if (auto extents{evaluate::GetConstantExtents(context, symbol)}) { 919e6be8da1SPeter Klausler mutableObject.set_init(initialization.image.AsConstant( 920e6be8da1SPeter Klausler context, *symbolType, std::nullopt, *extents)); 9214ac617f4Speter klausler } else { 9224ac617f4Speter klausler exprAnalyzer.Say(symbol.name(), 9234ac617f4Speter klausler "internal: unknown shape for '%s' while constructing initializer from DATA"_err_en_US, 9244ac617f4Speter klausler symbol.name()); 9254ac617f4Speter klausler return; 9264ac617f4Speter klausler } 9274ac617f4Speter klausler } else { 9284ac617f4Speter klausler exprAnalyzer.Say(symbol.name(), 9294ac617f4Speter klausler "internal: no type for '%s' while constructing initializer from DATA"_err_en_US, 9304ac617f4Speter klausler symbol.name()); 9314ac617f4Speter klausler return; 9324ac617f4Speter klausler } 9334ac617f4Speter klausler if (!object->init()) { 9344ac617f4Speter klausler exprAnalyzer.Say(symbol.name(), 9354ac617f4Speter klausler "internal: could not construct an initializer from DATA statements for '%s'"_err_en_US, 9364ac617f4Speter klausler symbol.name()); 9374ac617f4Speter klausler } 9384ac617f4Speter klausler } else { 9394ac617f4Speter klausler CHECK(exprAnalyzer.context().AnyFatalError()); 9404ac617f4Speter klausler } 9414ac617f4Speter klausler } 9424ac617f4Speter klausler 9434ac617f4Speter klausler void ConvertToInitializers( 9444ac617f4Speter klausler DataInitializations &inits, evaluate::ExpressionAnalyzer &exprAnalyzer) { 945d60a0220Speter klausler if (ProcessScopes( 946d60a0220Speter klausler exprAnalyzer.context().globalScope(), exprAnalyzer, inits)) { 9474ac617f4Speter klausler for (auto &[symbolPtr, initialization] : inits) { 9484ac617f4Speter klausler ConstructInitializer(*symbolPtr, initialization, exprAnalyzer); 9494ac617f4Speter klausler } 9504ac617f4Speter klausler } 951d60a0220Speter klausler } 9524ac617f4Speter klausler } // namespace Fortran::semantics 953