[flang-commits] [flang] [flang][semantic] Implement semantic checks and new data structure (PR #203030)

Eugene Epshteyn via flang-commits flang-commits at lists.llvm.org
Wed Jul 1 07:47:57 PDT 2026


================
@@ -343,11 +350,138 @@ void ArraySpecAnalyzer::Analyze(const parser::ExplicitShapeSpec &x) {
       std::get<parser::SpecificationExpr>(x.t));
 }
 
+std::optional<ArraySpecAnalyzer::ExplicitShapeBoundsResult>
+ArraySpecAnalyzer::checkExplicitShapeBoundsSpec(
+    const parser::ExplicitShapeBoundsSpec &x) {
+  const auto &lowerBoundOpt{std::get<0>(x.t)};
+  const auto &upperBound{std::get<1>(x.t)};
+
+  // Analyze, validate, fold, and wrap one bound expression in a Bound.
+  // Returns the Bound and, for rank-1, the constant extent; for scalar
+  // the extent is 0 (meaning "broadcast").
+  bool hasError{false};
+  auto analyzeBound =
+      [&](const auto &parseBound,
+          bool isUpper) -> std::optional<std::pair<Bound, std::int64_t>> {
+    MaybeExpr expr{AnalyzeExpr(context_, parseBound.thing)};
+    if (expr->Rank() > 1) {
+      context_.Say(parser::FindSourceLocation(parseBound),
+          "Integer array used as %s bounds in DECLARATION must be rank-1 "
+          "but is rank-%d"_err_en_US,
+          isUpper ? "upper" : "lower", expr->Rank());
+      hasError = true;
+      return std::nullopt;
+    }
+    auto folded{evaluate::Fold(context_.foldingContext(), std::move(*expr))};
+    const auto *someInt{evaluate::UnwrapExpr<SomeIntExpr>(folded)};
+    if (!someInt) {
+      hasError = true;
+      return std::nullopt;
+    }
+    auto asSI{evaluate::Fold(context_.foldingContext(),
+        evaluate::ConvertToType<evaluate::SubscriptInteger>(
+            common::Clone(*someInt)))};
+    if (folded.Rank() == 0) {
+      return std::make_pair(
+          Bound{MaybeSubscriptIntExpr{std::move(asSI)}}, std::int64_t{0});
+    }
+    // Rank-1: must have constant extent.
+    auto extents{
+        evaluate::GetConstantExtents(context_.foldingContext(), folded)};
+    if (!extents) {
+      context_.Say(parser::FindSourceLocation(parseBound),
+          "Rank-1 integer array used as %s bounds in DECLARATION must "
+          "have constant size"_err_en_US,
+          isUpper ? "upper" : "lower");
+      hasError = true;
+      return std::nullopt;
+    }
+    return std::make_pair(
+        Bound{MaybeSubscriptIntExpr{std::move(asSI)}}, (*extents)[0]);
+  };
+
+  // Upper bound (required)
+  auto ubResult{analyzeBound(upperBound, /*isUpper=*/true)};
+
+  // Lower bound (optional)
+  std::optional<std::pair<Bound, std::int64_t>> lbResult;
+  if (lowerBoundOpt) {
+    lbResult = analyzeBound(*lowerBoundOpt, /*isUpper=*/false);
+  }
+
+  if (hasError) {
+    return std::nullopt;
+  }
+
+  std::int64_t ubExtent{ubResult->second};
+  std::int64_t lbExtent{lbResult ? lbResult->second : 0};
+
+  // Determine numDims from whichever is rank-1 (extent > 0).
+  std::int64_t numDims{std::max(ubExtent, lbExtent)};
----------------
eugeneepshteyn wrote:

(If don't already have it, please add a test for too many dims resulting from using explicit shape bounds.)

https://github.com/llvm/llvm-project/pull/203030


More information about the flang-commits mailing list