xref: /llvm-project/flang/lib/Semantics/data-to-inits.cpp (revision 0f973ac783aa100cfbce1cd2c6e8a3a8f648fae7)
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