[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