[flang-commits] [flang] [flang][OpenACC] Reland data-clause designator path handling (PR #220781)

Eugene Epshteyn via flang-commits flang-commits at lists.llvm.org
Thu Oct 8 19:58:35 PDT 2026


================
@@ -0,0 +1,507 @@
+//===-- flang/unittests/Evaluate/designator-path.cpp ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Evaluate/designator-path.h"
+#include "flang/Evaluate/expression.h"
+#include "flang/Parser/provenance.h"
+#include "flang/Semantics/scope.h"
+#include "flang/Semantics/semantics.h"
+#include "flang/Semantics/symbol.h"
+#include "flang/Support/Fortran-features.h"
+#include "flang/Support/LangOptions.h"
+#include "flang/Support/default-kinds.h"
+#include "flang/Testing/testing.h"
+#include <initializer_list>
+
+using namespace Fortran::evaluate;
+
+namespace {
+namespace common = Fortran::common;
+namespace parser = Fortran::parser;
+namespace semantics = Fortran::semantics;
+using IntExpr = Expr<SubscriptInteger>;
+
+IntExpr Int(int n) { return IntExpr{n}; }
+
+Subscript Scalar(int n) { return Subscript{Int(n)}; }
+
+Triplet TripletSubscript(
+    std::optional<int> lower, std::optional<int> upper, int stride = 1) {
+  return Triplet{lower ? std::optional<IntExpr>{Int(*lower)} : std::nullopt,
+      upper ? std::optional<IntExpr>{Int(*upper)} : std::nullopt, Int(stride)};
+}
+
+Subscript Section(
+    std::optional<int> lower, std::optional<int> upper, int stride = 1) {
+  return Subscript{TripletSubscript(lower, upper, stride)};
+}
+
+Subscript FullSection() {
+  return Subscript{Triplet{std::nullopt, std::nullopt, Int(1)}};
+}
+
+DesignatorPath PathWithSubscripts(std::vector<Subscript> subscripts) {
+  DesignatorPath path;
+  path.AddSubscripts(std::move(subscripts));
+  return path;
+}
+
+DesignatorPath PathWithComponent(const semantics::Symbol *symbol) {
+  DesignatorPath path;
+  path.AddComponent(*symbol);
+  return path;
+}
+
+void CheckRelation(const DesignatorPath &x, const DesignatorPath &y,
+    DesignatorRelation relation) {
+  TEST(x.Compare(y) == relation);
+}
+
+// Compare the selection of a single subscript with that of another.
+void CheckSubscriptRelation(
+    const Subscript &x, const Subscript &y, DesignatorRelation relation) {
+  CheckRelation(PathWithSubscripts({x}), PathWithSubscripts({y}), relation);
+}
+
+void CheckSubscriptMayContain(
+    const Subscript &x, const Subscript &y, bool expected) {
+  TEST(PathWithSubscripts({x}).MayContain(PathWithSubscripts({y})) == expected);
+}
+
+class SymbolFixture {
+public:
+  const semantics::Symbol &MakeSymbol(const char *name) {
+    return scope_.MakeSymbol(parser::CharBlock{name}, semantics::Attrs{},
+        semantics::UnknownDetails{});
+  }
+
+  semantics::Symbol &MakeCommonBlock(const char *name) {
+    return scope_.MakeSymbol(parser::CharBlock{name}, semantics::Attrs{},
+        semantics::CommonBlockDetails{parser::CharBlock{name}});
+  }
+
+  const semantics::Symbol &MakeCommonMember(
+      const char *name, semantics::Symbol &block) {
+    auto &symbol{scope_.MakeSymbol(parser::CharBlock{name}, semantics::Attrs{},
+        semantics::ObjectEntityDetails{})};
+    symbol.get<semantics::ObjectEntityDetails>().set_commonBlock(block);
+    block.get<semantics::CommonBlockDetails>().add_object(symbol);
+    return symbol;
+  }
+
+  const semantics::Symbol &MakeHostAssociated(
+      const char *name, const semantics::Symbol &symbol) {
+    return scope_.MakeSymbol(parser::CharBlock{name}, semantics::Attrs{},
+        semantics::HostAssocDetails{symbol});
+  }
+
+private:
+  parser::AllSources allSources_;
+  parser::AllCookedSources allCookedSources_{allSources_};
+  common::IntrinsicTypeDefaultKinds defaultKinds_;
+  common::LanguageFeatureControl languageFeatures_;
+  common::LangOptions langOptions_;
+  semantics::SemanticsContext context_{
+      defaultKinds_, languageFeatures_, langOptions_, allCookedSources_};
+  semantics::Scope &scope_{
+      context_.globalScope().MakeScope(semantics::Scope::Kind::MainProgram)};
+};
+
+void TestCompareSubscripts() {
+  CheckSubscriptRelation(Scalar(3), Scalar(3), DesignatorRelation::Equal);
+  CheckSubscriptRelation(Scalar(3), Scalar(4), DesignatorRelation::Disjoint);
+  CheckSubscriptRelation(
+      FullSection(), Scalar(3), DesignatorRelation::Contains);
+  CheckSubscriptRelation(
+      FullSection(), FullSection(), DesignatorRelation::Equal);
+  CheckSubscriptRelation(
+      Scalar(3), FullSection(), DesignatorRelation::ContainedBy);
+  CheckSubscriptRelation(
+      Section(1, 5), Section(6, 10), DesignatorRelation::Disjoint);
+  CheckSubscriptRelation(
+      Section(1, 5), Section(1, 5), DesignatorRelation::Equal);
+  CheckSubscriptRelation(
+      Section(1, 10), Section(3, 5), DesignatorRelation::Contains);
+  CheckSubscriptRelation(
+      Section(3, 5), Section(1, 10), DesignatorRelation::ContainedBy);
+  CheckSubscriptRelation(
+      Section(1, 5), Section(5, 10), DesignatorRelation::Overlaps);
+  // A scalar and a one-element section select the same element.
+  CheckSubscriptRelation(Scalar(3), Section(3, 3), DesignatorRelation::Equal);
+  // Strided sections are not compared precisely and are reported as Disjoint.
+  CheckSubscriptRelation(
+      Section(1, 5, 2), Section(1, 5), DesignatorRelation::Disjoint);
+}
+
+void TestCompareSubscriptLists() {
+  CheckRelation(PathWithSubscripts({}), PathWithSubscripts({FullSection()}),
+      DesignatorRelation::Equal);
+  CheckRelation(PathWithSubscripts({FullSection()}), PathWithSubscripts({}),
+      DesignatorRelation::Equal);
+  CheckRelation(PathWithSubscripts({FullSection()}),
+      PathWithSubscripts({FullSection(), FullSection()}),
+      DesignatorRelation::Disjoint);
+  CheckRelation(PathWithSubscripts({Scalar(1)}),
+      PathWithSubscripts({Scalar(1), Scalar(2)}), DesignatorRelation::Disjoint);
+  CheckRelation(PathWithSubscripts({Scalar(1), Scalar(2)}),
+      PathWithSubscripts({Scalar(1), Scalar(2)}), DesignatorRelation::Equal);
+  CheckRelation(PathWithSubscripts({Section(1, 10), Scalar(2)}),
+      PathWithSubscripts({Section(3, 5), Scalar(2)}),
+      DesignatorRelation::Contains);
+  CheckRelation(PathWithSubscripts({Section(3, 5), Scalar(2)}),
+      PathWithSubscripts({Section(1, 10), Scalar(2)}),
+      DesignatorRelation::ContainedBy);
+  // One dimension contains and the other is contained, so they only overlap.
+  CheckRelation(PathWithSubscripts({Section(1, 10), Scalar(2)}),
+      PathWithSubscripts({Section(3, 5), FullSection()}),
+      DesignatorRelation::Overlaps);
+  CheckRelation(PathWithSubscripts({Section(1, 5), Scalar(2)}),
+      PathWithSubscripts({Section(6, 10), Scalar(2)}),
+      DesignatorRelation::Disjoint);
+}
+
+void TestCompareParts() {
+  SymbolFixture symbols;
+  const semantics::Symbol &symbol1{symbols.MakeSymbol("a")};
+  const semantics::Symbol &symbol2{symbols.MakeSymbol("b")};
+  DesignatorPath component1{PathWithComponent(&symbol1)};
+  DesignatorPath component1Again{PathWithComponent(&symbol1)};
+  DesignatorPath component2{PathWithComponent(&symbol2)};
+  DesignatorPath subscripts{PathWithSubscripts({Section(1, 5)})};
+  DesignatorPath subscriptedComponent{PathWithSubscripts({Scalar(3)})};
+  subscriptedComponent.AddComponent(symbol1);
+
+  CheckRelation(component1, component1Again, DesignatorRelation::Equal);
+  CheckRelation(component1, component2, DesignatorRelation::Disjoint);
+  CheckRelation(component1, subscripts, DesignatorRelation::Overlaps);
+  CheckRelation(subscripts, subscriptedComponent, DesignatorRelation::Contains);
+}
+
+void TestComparePaths() {
+  DesignatorPath empty;
+  CheckRelation(empty, empty, DesignatorRelation::Equal);
+  CheckRelation(
+      empty, PathWithSubscripts({Scalar(1)}), DesignatorRelation::Disjoint);
+
+  SymbolFixture symbols;
+  const semantics::Symbol &symbol{symbols.MakeSymbol("c")};
+  DesignatorPath parent{PathWithComponent(&symbol)};
+  DesignatorPath child{PathWithComponent(&symbol)};
+  child.AddSubscripts({Scalar(1)});
+  CheckRelation(parent, child, DesignatorRelation::Contains);
+  CheckRelation(child, parent, DesignatorRelation::ContainedBy);
+}
+
+void TestMayContainSubscripts() {
----------------
eugeneepshteyn wrote:

The rewrite dropped the negative cases for half-open and strided triplets against the full section — previously `TripletSubscript(1,{})`, `({},10)`, and `({},{},2)`. Could you restore them as path-level assertions (`a(2:)`, `a(:5)`, `a(::2)` against `a(:)`) so `IsFullTriplet`'s rejections stay pinned through the public interface?

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


More information about the flang-commits mailing list