[flang-commits] [flang] [flang] Revamp evaluate::CoarrayRef (PR #136628)
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Mon Apr 21 15:46:41 PDT 2025
https://github.com/klausler created https://github.com/llvm/llvm-project/pull/136628
Bring the typed expression representation of a coindexed reference up to F'2023, which removed some restrictions that had allowed the current representation to suffice for older revisions of the language. This new representation is somewhat more simple -- it uses a DataRef as its base, so any subscripts in a part-ref can be represented as an ArrayRef there.
Update the code that creates the CoarrayRef, and add more checking to it, as well as actually capturing any STAT=, TEAM=, & TEAM_NUMBER= specifiers that might appear. Enforce the constraint that the part-ref must have subscripts if it is an array. (And update a pile of copied-and-pasted test code that lacked such subscripts.)
>From 5a05e30caeb4d029ea3f840e00df29bad82c3c39 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Mon, 21 Apr 2025 08:20:56 -0700
Subject: [PATCH] [flang] Revamp evaluate::CoarrayRef
Bring the typed expression representation of a coindexed reference
up to F'2023, which removed some restrictions that had allowed the
current representation to suffice for older revisions of the language.
This new representation is somewhat more simple -- it uses a DataRef
as its base, so any subscripts in a part-ref can be represented as
an ArrayRef there.
Update the code that creates the CoarrayRef, and add more checking
to it, as well as actually capturing any STAT=, TEAM=, & TEAM_NUMBER=
specifiers that might appear. Enforce the constraint that the
part-ref must have subscripts if it is an array. (And update a pile
of copied-and-pasted test code that lacked such subscripts.)
---
flang/include/flang/Evaluate/tools.h | 38 ++++-------
flang/include/flang/Evaluate/traverse.h | 3 +-
flang/include/flang/Evaluate/variable.h | 41 ++++--------
flang/lib/Evaluate/check-expression.cpp | 5 +-
flang/lib/Evaluate/fold.cpp | 13 ++--
flang/lib/Evaluate/formatting.cpp | 26 ++------
flang/lib/Evaluate/shape.cpp | 15 +----
flang/lib/Evaluate/tools.cpp | 15 ++++-
flang/lib/Evaluate/variable.cpp | 57 ++++------------
flang/lib/Lower/Support/Utils.cpp | 11 +---
flang/lib/Semantics/check-coarray.cpp | 29 --------
flang/lib/Semantics/check-coarray.h | 3 -
flang/lib/Semantics/dump-expr.cpp | 1 -
flang/lib/Semantics/expression.cpp | 88 +++++++++++++------------
flang/test/Semantics/atomic02.f90 | 2 +-
flang/test/Semantics/atomic03.f90 | 4 +-
flang/test/Semantics/atomic04.f90 | 4 +-
flang/test/Semantics/atomic05.f90 | 2 +-
flang/test/Semantics/atomic06.f90 | 2 +-
flang/test/Semantics/atomic07.f90 | 2 +-
flang/test/Semantics/atomic08.f90 | 2 +-
flang/test/Semantics/atomic09.f90 | 2 +-
flang/test/Semantics/atomic10.f90 | 4 +-
flang/test/Semantics/atomic11.f90 | 2 +-
flang/test/Semantics/coarrays02.f90 | 24 +++++++
flang/test/Semantics/coshape.f90 | 4 +-
flang/test/Semantics/error_stop1b.f90 | 2 +-
flang/test/Semantics/event01b.f90 | 2 +-
flang/test/Semantics/resolve94.f90 | 12 ++--
29 files changed, 162 insertions(+), 253 deletions(-)
diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index 1414eaf14f7d6..650c5b2163f63 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -391,20 +391,17 @@ template <typename T>
bool IsArrayElement(const Expr<T> &expr, bool intoSubstring = true,
bool skipComponents = false) {
if (auto dataRef{ExtractDataRef(expr, intoSubstring)}) {
- const DataRef *ref{&*dataRef};
- if (skipComponents) {
- while (const Component * component{std::get_if<Component>(&ref->u)}) {
- ref = &component->base();
+ for (const DataRef *ref{&*dataRef}; ref;) {
+ if (const Component *component{std::get_if<Component>(&ref->u)}) {
+ ref = skipComponents ? &component->base() : nullptr;
+ } else if (const auto *coarrayRef{std::get_if<CoarrayRef>(&ref->u)}) {
+ ref = &coarrayRef->base();
+ } else {
+ return std::holds_alternative<ArrayRef>(ref->u);
}
}
- if (const auto *coarrayRef{std::get_if<CoarrayRef>(&ref->u)}) {
- return !coarrayRef->subscript().empty();
- } else {
- return std::holds_alternative<ArrayRef>(ref->u);
- }
- } else {
- return false;
}
+ return false;
}
template <typename A>
@@ -418,9 +415,6 @@ std::optional<NamedEntity> ExtractNamedEntity(const A &x) {
[](Component &&component) -> std::optional<NamedEntity> {
return NamedEntity{std::move(component)};
},
- [](CoarrayRef &&co) -> std::optional<NamedEntity> {
- return co.GetBase();
- },
[](auto &&) { return std::optional<NamedEntity>{}; },
},
std::move(dataRef->u));
@@ -528,22 +522,14 @@ const Symbol *UnwrapWholeSymbolOrComponentDataRef(const A &x) {
// If an expression is a whole symbol or a whole component designator,
// potentially followed by an image selector, extract and return that symbol,
// else null.
+const Symbol *UnwrapWholeSymbolOrComponentOrCoarrayRef(const DataRef &);
template <typename A>
const Symbol *UnwrapWholeSymbolOrComponentOrCoarrayRef(const A &x) {
if (auto dataRef{ExtractDataRef(x)}) {
- if (const SymbolRef * p{std::get_if<SymbolRef>(&dataRef->u)}) {
- return &p->get();
- } else if (const Component * c{std::get_if<Component>(&dataRef->u)}) {
- if (c->base().Rank() == 0) {
- return &c->GetLastSymbol();
- }
- } else if (const CoarrayRef * c{std::get_if<CoarrayRef>(&dataRef->u)}) {
- if (c->subscript().empty()) {
- return &c->GetLastSymbol();
- }
- }
+ return UnwrapWholeSymbolOrComponentOrCoarrayRef(*dataRef);
+ } else {
+ return nullptr;
}
- return nullptr;
}
// GetFirstSymbol(A%B%C[I]%D) -> A
diff --git a/flang/include/flang/Evaluate/traverse.h b/flang/include/flang/Evaluate/traverse.h
index 45402143604f4..48aafa8982559 100644
--- a/flang/include/flang/Evaluate/traverse.h
+++ b/flang/include/flang/Evaluate/traverse.h
@@ -146,8 +146,7 @@ class Traverse {
return Combine(x.base(), x.subscript());
}
Result operator()(const CoarrayRef &x) const {
- return Combine(
- x.base(), x.subscript(), x.cosubscript(), x.stat(), x.team());
+ return Combine(x.base(), x.cosubscript(), x.stat(), x.team());
}
Result operator()(const DataRef &x) const { return visitor_(x.u); }
Result operator()(const Substring &x) const {
diff --git a/flang/include/flang/Evaluate/variable.h b/flang/include/flang/Evaluate/variable.h
index 7f1518fd26e78..5c14421fd3a1b 100644
--- a/flang/include/flang/Evaluate/variable.h
+++ b/flang/include/flang/Evaluate/variable.h
@@ -98,8 +98,6 @@ class Component {
// A NamedEntity is either a whole Symbol or a component in an instance
// of a derived type. It may be a descriptor.
-// TODO: this is basically a symbol with an optional DataRef base;
-// could be used to replace Component.
class NamedEntity {
public:
CLASS_BOILERPLATE(NamedEntity)
@@ -239,28 +237,16 @@ class ArrayRef {
std::vector<Subscript> subscript_;
};
-// R914 coindexed-named-object
-// R924 image-selector, R926 image-selector-spec.
-// C825 severely limits the usage of derived types with coarray ultimate
-// components: they can't be pointers, allocatables, arrays, coarrays, or
-// function results. They can be components of other derived types.
-// Although the F'2018 Standard never prohibits multiple image-selectors
-// per se in the same data-ref or designator, nor the presence of an
-// image-selector after a part-ref with rank, the constraints on the
-// derived types that would have be involved make it impossible to declare
-// an object that could be referenced in these ways (esp. C748 & C825).
-// C930 precludes having both TEAM= and TEAM_NUMBER=.
-// TODO C931 prohibits the use of a coindexed object as a stat-variable.
+// A coindexed data-ref. The base is represented as a general
+// DataRef, but the base may not contain a CoarrayRef and may
+// have rank > 0 only in an uppermost ArrayRef.
class CoarrayRef {
public:
CLASS_BOILERPLATE(CoarrayRef)
- CoarrayRef(SymbolVector &&, std::vector<Subscript> &&,
- std::vector<Expr<SubscriptInteger>> &&);
+ CoarrayRef(DataRef &&, std::vector<Expr<SubscriptInteger>> &&);
- const SymbolVector &base() const { return base_; }
- SymbolVector &base() { return base_; }
- const std::vector<Subscript> &subscript() const { return subscript_; }
- std::vector<Subscript> &subscript() { return subscript_; }
+ const DataRef &base() const { return base_.value(); }
+ DataRef &base() { return base_.value(); }
const std::vector<Expr<SubscriptInteger>> &cosubscript() const {
return cosubscript_;
}
@@ -270,25 +256,24 @@ class CoarrayRef {
// (i.e., Designator or pointer-valued FunctionRef).
std::optional<Expr<SomeInteger>> stat() const;
CoarrayRef &set_stat(Expr<SomeInteger> &&);
- std::optional<Expr<SomeInteger>> team() const;
- bool teamIsTeamNumber() const { return teamIsTeamNumber_; }
- CoarrayRef &set_team(Expr<SomeInteger> &&, bool isTeamNumber = false);
+ // When team() is Expr<SomeInteger>, it's TEAM_NUMBER=; otherwise,
+ // it's TEAM=.
+ std::optional<Expr<SomeType>> team() const;
+ CoarrayRef &set_team(Expr<SomeType> &&);
int Rank() const;
int Corank() const { return 0; }
const Symbol &GetFirstSymbol() const;
const Symbol &GetLastSymbol() const;
- NamedEntity GetBase() const;
std::optional<Expr<SubscriptInteger>> LEN() const;
bool operator==(const CoarrayRef &) const;
llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
private:
- SymbolVector base_;
- std::vector<Subscript> subscript_;
+ common::CopyableIndirection<DataRef> base_;
std::vector<Expr<SubscriptInteger>> cosubscript_;
- std::optional<common::CopyableIndirection<Expr<SomeInteger>>> stat_, team_;
- bool teamIsTeamNumber_{false}; // false: TEAM=, true: TEAM_NUMBER=
+ std::optional<common::CopyableIndirection<Expr<SomeInteger>>> stat_;
+ std::optional<common::CopyableIndirection<Expr<SomeType>>> team_;
};
// R911 data-ref is defined syntactically as a series of part-refs, which
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index d8baaf2e2a7ac..3d7f01d56c465 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -946,10 +946,7 @@ class IsContiguousHelper
return std::nullopt;
}
}
- Result operator()(const CoarrayRef &x) const {
- int rank{0};
- return CheckSubscripts(x.subscript(), rank).has_value();
- }
+ Result operator()(const CoarrayRef &x) const { return (*this)(x.base()); }
Result operator()(const Component &x) const {
if (x.base().Rank() == 0) {
return (*this)(x.GetLastSymbol());
diff --git a/flang/lib/Evaluate/fold.cpp b/flang/lib/Evaluate/fold.cpp
index 5fc31728ce5d6..45e842abf589f 100644
--- a/flang/lib/Evaluate/fold.cpp
+++ b/flang/lib/Evaluate/fold.cpp
@@ -162,22 +162,17 @@ ArrayRef FoldOperation(FoldingContext &context, ArrayRef &&arrayRef) {
}
CoarrayRef FoldOperation(FoldingContext &context, CoarrayRef &&coarrayRef) {
- std::vector<Subscript> subscript;
- for (Subscript x : coarrayRef.subscript()) {
- subscript.emplace_back(FoldOperation(context, std::move(x)));
- }
+ DataRef base{FoldOperation(context, std::move(coarrayRef.base()))};
std::vector<Expr<SubscriptInteger>> cosubscript;
for (Expr<SubscriptInteger> x : coarrayRef.cosubscript()) {
cosubscript.emplace_back(Fold(context, std::move(x)));
}
- CoarrayRef folded{std::move(coarrayRef.base()), std::move(subscript),
- std::move(cosubscript)};
+ CoarrayRef folded{std::move(base), std::move(cosubscript)};
if (std::optional<Expr<SomeInteger>> stat{coarrayRef.stat()}) {
folded.set_stat(Fold(context, std::move(*stat)));
}
- if (std::optional<Expr<SomeInteger>> team{coarrayRef.team()}) {
- folded.set_team(
- Fold(context, std::move(*team)), coarrayRef.teamIsTeamNumber());
+ if (std::optional<Expr<SomeType>> team{coarrayRef.team()}) {
+ folded.set_team(Fold(context, std::move(*team)));
}
return folded;
}
diff --git a/flang/lib/Evaluate/formatting.cpp b/flang/lib/Evaluate/formatting.cpp
index 6778fac9a44fd..121afc6f0f8bf 100644
--- a/flang/lib/Evaluate/formatting.cpp
+++ b/flang/lib/Evaluate/formatting.cpp
@@ -723,24 +723,8 @@ llvm::raw_ostream &ArrayRef::AsFortran(llvm::raw_ostream &o) const {
}
llvm::raw_ostream &CoarrayRef::AsFortran(llvm::raw_ostream &o) const {
- bool first{true};
- for (const Symbol &part : base_) {
- if (first) {
- first = false;
- } else {
- o << '%';
- }
- EmitVar(o, part);
- }
- char separator{'('};
- for (const auto &sscript : subscript_) {
- EmitVar(o << separator, sscript);
- separator = ',';
- }
- if (separator == ',') {
- o << ')';
- }
- separator = '[';
+ base().AsFortran(o);
+ char separator{'['};
for (const auto &css : cosubscript_) {
EmitVar(o << separator, css);
separator = ',';
@@ -750,8 +734,10 @@ llvm::raw_ostream &CoarrayRef::AsFortran(llvm::raw_ostream &o) const {
separator = ',';
}
if (team_) {
- EmitVar(
- o << separator, team_, teamIsTeamNumber_ ? "TEAM_NUMBER=" : "TEAM=");
+ EmitVar(o << separator, team_,
+ std::holds_alternative<Expr<SomeInteger>>(team_->value().u)
+ ? "TEAM_NUMBER="
+ : "TEAM=");
}
return o << ']';
}
diff --git a/flang/lib/Evaluate/shape.cpp b/flang/lib/Evaluate/shape.cpp
index f620ecd4a24bb..ac4811e9978eb 100644
--- a/flang/lib/Evaluate/shape.cpp
+++ b/flang/lib/Evaluate/shape.cpp
@@ -891,20 +891,7 @@ auto GetShapeHelper::operator()(const ArrayRef &arrayRef) const -> Result {
}
auto GetShapeHelper::operator()(const CoarrayRef &coarrayRef) const -> Result {
- NamedEntity base{coarrayRef.GetBase()};
- if (coarrayRef.subscript().empty()) {
- return (*this)(base);
- } else {
- Shape shape;
- int dimension{0};
- for (const Subscript &ss : coarrayRef.subscript()) {
- if (ss.Rank() > 0) {
- shape.emplace_back(GetExtent(ss, base, dimension));
- }
- ++dimension;
- }
- return shape;
- }
+ return (*this)(coarrayRef.base());
}
auto GetShapeHelper::operator()(const Substring &substring) const -> Result {
diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index 702711e3cff53..16e2d6c0f7a55 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -1090,7 +1090,7 @@ auto GetSymbolVectorHelper::operator()(const ArrayRef &x) const -> Result {
return GetSymbolVector(x.base());
}
auto GetSymbolVectorHelper::operator()(const CoarrayRef &x) const -> Result {
- return x.base();
+ return GetSymbolVector(x.base());
}
const Symbol *GetLastTarget(const SymbolVector &symbols) {
@@ -1320,6 +1320,19 @@ std::optional<parser::MessageFixedText> CheckProcCompatibility(bool isCall,
return msg;
}
+const Symbol *UnwrapWholeSymbolOrComponentOrCoarrayRef(const DataRef &dataRef) {
+ if (const SymbolRef *p{std::get_if<SymbolRef>(&dataRef.u)}) {
+ return &p->get();
+ } else if (const Component *c{std::get_if<Component>(&dataRef.u)}) {
+ if (c->base().Rank() == 0) {
+ return &c->GetLastSymbol();
+ }
+ } else if (const CoarrayRef *c{std::get_if<CoarrayRef>(&dataRef.u)}) {
+ return UnwrapWholeSymbolOrComponentOrCoarrayRef(c->base());
+ }
+ return nullptr;
+}
+
// GetLastPointerSymbol()
static const Symbol *GetLastPointerSymbol(const Symbol &symbol) {
return IsPointer(GetAssociationRoot(symbol)) ? &symbol : nullptr;
diff --git a/flang/lib/Evaluate/variable.cpp b/flang/lib/Evaluate/variable.cpp
index 849194b492053..d1bff03a6ea5f 100644
--- a/flang/lib/Evaluate/variable.cpp
+++ b/flang/lib/Evaluate/variable.cpp
@@ -69,13 +69,9 @@ Triplet &Triplet::set_stride(Expr<SubscriptInteger> &&expr) {
return *this;
}
-CoarrayRef::CoarrayRef(SymbolVector &&base, std::vector<Subscript> &&ss,
- std::vector<Expr<SubscriptInteger>> &&css)
- : base_{std::move(base)}, subscript_(std::move(ss)),
- cosubscript_(std::move(css)) {
- CHECK(!base_.empty());
- CHECK(!cosubscript_.empty());
-}
+CoarrayRef::CoarrayRef(
+ DataRef &&base, std::vector<Expr<SubscriptInteger>> &&css)
+ : base_{std::move(base)}, cosubscript_(std::move(css)) {}
std::optional<Expr<SomeInteger>> CoarrayRef::stat() const {
if (stat_) {
@@ -85,7 +81,7 @@ std::optional<Expr<SomeInteger>> CoarrayRef::stat() const {
}
}
-std::optional<Expr<SomeInteger>> CoarrayRef::team() const {
+std::optional<Expr<SomeType>> CoarrayRef::team() const {
if (team_) {
return team_.value().value();
} else {
@@ -99,16 +95,18 @@ CoarrayRef &CoarrayRef::set_stat(Expr<SomeInteger> &&v) {
return *this;
}
-CoarrayRef &CoarrayRef::set_team(Expr<SomeInteger> &&v, bool isTeamNumber) {
- CHECK(IsVariable(v));
+CoarrayRef &CoarrayRef::set_team(Expr<SomeType> &&v) {
team_.emplace(std::move(v));
- teamIsTeamNumber_ = isTeamNumber;
return *this;
}
-const Symbol &CoarrayRef::GetFirstSymbol() const { return base_.front(); }
+const Symbol &CoarrayRef::GetFirstSymbol() const {
+ return base().GetFirstSymbol();
+}
-const Symbol &CoarrayRef::GetLastSymbol() const { return base_.back(); }
+const Symbol &CoarrayRef::GetLastSymbol() const {
+ return base().GetLastSymbol();
+}
void Substring::SetBounds(std::optional<Expr<SubscriptInteger>> &lower,
std::optional<Expr<SubscriptInteger>> &upper) {
@@ -426,17 +424,7 @@ int ArrayRef::Rank() const {
}
}
-int CoarrayRef::Rank() const {
- if (!subscript_.empty()) {
- int rank{0};
- for (const auto &expr : subscript_) {
- rank += expr.Rank();
- }
- return rank;
- } else {
- return base_.back()->Rank();
- }
-}
+int CoarrayRef::Rank() const { return base().Rank(); }
int DataRef::Rank() const {
return common::visit(common::visitors{
@@ -671,22 +659,6 @@ std::optional<DynamicType> Designator<T>::GetType() const {
return std::nullopt;
}
-static NamedEntity AsNamedEntity(const SymbolVector &x) {
- CHECK(!x.empty());
- NamedEntity result{x.front()};
- int j{0};
- for (const Symbol &symbol : x) {
- if (j++ != 0) {
- DataRef base{result.IsSymbol() ? DataRef{result.GetLastSymbol()}
- : DataRef{result.GetComponent()}};
- result = NamedEntity{Component{std::move(base), symbol}};
- }
- }
- return result;
-}
-
-NamedEntity CoarrayRef::GetBase() const { return AsNamedEntity(base_); }
-
// Equality testing
// For the purposes of comparing type parameter expressions while
@@ -759,9 +731,8 @@ bool ArrayRef::operator==(const ArrayRef &that) const {
return base_ == that.base_ && subscript_ == that.subscript_;
}
bool CoarrayRef::operator==(const CoarrayRef &that) const {
- return base_ == that.base_ && subscript_ == that.subscript_ &&
- cosubscript_ == that.cosubscript_ && stat_ == that.stat_ &&
- team_ == that.team_ && teamIsTeamNumber_ == that.teamIsTeamNumber_;
+ return base_ == that.base_ && cosubscript_ == that.cosubscript_ &&
+ stat_ == that.stat_ && team_ == that.team_;
}
bool DataRef::operator==(const DataRef &that) const {
return TestVariableEquality(*this, that);
diff --git a/flang/lib/Lower/Support/Utils.cpp b/flang/lib/Lower/Support/Utils.cpp
index ed2700c42fc55..668ee31a36bc3 100644
--- a/flang/lib/Lower/Support/Utils.cpp
+++ b/flang/lib/Lower/Support/Utils.cpp
@@ -70,18 +70,12 @@ class HashEvaluateExpr {
return getHashValue(x.base()) * 89u - subs;
}
static unsigned getHashValue(const Fortran::evaluate::CoarrayRef &x) {
- unsigned subs = 1u;
- for (const Fortran::evaluate::Subscript &v : x.subscript())
- subs -= getHashValue(v);
unsigned cosubs = 3u;
for (const Fortran::evaluate::Expr<Fortran::evaluate::SubscriptInteger> &v :
x.cosubscript())
cosubs -= getHashValue(v);
- unsigned syms = 7u;
- for (const Fortran::evaluate::SymbolRef &v : x.base())
- syms += getHashValue(v);
- return syms * 97u - subs - cosubs + getHashValue(x.stat()) + 257u +
- getHashValue(x.team());
+ return getHashValue(x.base()) * 97u - cosubs + getHashValue(x.stat()) +
+ 257u + getHashValue(x.team());
}
static unsigned getHashValue(const Fortran::evaluate::NamedEntity &x) {
if (x.IsSymbol())
@@ -339,7 +333,6 @@ class IsEqualEvaluateExpr {
static bool isEqual(const Fortran::evaluate::CoarrayRef &x,
const Fortran::evaluate::CoarrayRef &y) {
return isEqual(x.base(), y.base()) &&
- isEqual(x.subscript(), y.subscript()) &&
isEqual(x.cosubscript(), y.cosubscript()) &&
isEqual(x.stat(), y.stat()) && isEqual(x.team(), y.team());
}
diff --git a/flang/lib/Semantics/check-coarray.cpp b/flang/lib/Semantics/check-coarray.cpp
index b21e3cd757d6b..0e444f155f116 100644
--- a/flang/lib/Semantics/check-coarray.cpp
+++ b/flang/lib/Semantics/check-coarray.cpp
@@ -373,41 +373,12 @@ void CoarrayChecker::Leave(const parser::CriticalStmt &x) {
}
void CoarrayChecker::Leave(const parser::ImageSelector &imageSelector) {
- haveStat_ = false;
- haveTeam_ = false;
- haveTeamNumber_ = false;
for (const auto &imageSelectorSpec :
std::get<std::list<parser::ImageSelectorSpec>>(imageSelector.t)) {
- if (const auto *team{
- std::get_if<parser::TeamValue>(&imageSelectorSpec.u)}) {
- if (haveTeam_) {
- context_.Say(parser::FindSourceLocation(imageSelectorSpec), // C929
- "TEAM value can only be specified once"_err_en_US);
- }
- CheckTeamType(context_, *team);
- haveTeam_ = true;
- }
if (const auto *stat{std::get_if<parser::ImageSelectorSpec::Stat>(
&imageSelectorSpec.u)}) {
- if (haveStat_) {
- context_.Say(parser::FindSourceLocation(imageSelectorSpec), // C929
- "STAT variable can only be specified once"_err_en_US);
- }
CheckTeamStat(context_, *stat);
- haveStat_ = true;
}
- if (std::get_if<parser::ImageSelectorSpec::Team_Number>(
- &imageSelectorSpec.u)) {
- if (haveTeamNumber_) {
- context_.Say(parser::FindSourceLocation(imageSelectorSpec), // C929
- "TEAM_NUMBER value can only be specified once"_err_en_US);
- }
- haveTeamNumber_ = true;
- }
- }
- if (haveTeam_ && haveTeamNumber_) {
- context_.Say(parser::FindSourceLocation(imageSelector), // C930
- "Cannot specify both TEAM and TEAM_NUMBER"_err_en_US);
}
}
diff --git a/flang/lib/Semantics/check-coarray.h b/flang/lib/Semantics/check-coarray.h
index f156959019383..51de47f123558 100644
--- a/flang/lib/Semantics/check-coarray.h
+++ b/flang/lib/Semantics/check-coarray.h
@@ -37,9 +37,6 @@ class CoarrayChecker : public virtual BaseChecker {
private:
SemanticsContext &context_;
- bool haveStat_;
- bool haveTeam_;
- bool haveTeamNumber_;
void CheckNamesAreDistinct(const std::list<parser::CoarrayAssociation> &);
void Say2(const parser::CharBlock &, parser::MessageFixedText &&,
diff --git a/flang/lib/Semantics/dump-expr.cpp b/flang/lib/Semantics/dump-expr.cpp
index 850904bf897b9..aa0b4e0f03398 100644
--- a/flang/lib/Semantics/dump-expr.cpp
+++ b/flang/lib/Semantics/dump-expr.cpp
@@ -22,7 +22,6 @@ inline const char *DumpEvaluateExpr::GetIndentString() const {
void DumpEvaluateExpr::Show(const evaluate::CoarrayRef &x) {
Indent("coarray ref");
Show(x.base());
- Show(x.subscript());
Show(x.cosubscript());
Show(x.stat());
Show(x.team());
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index e139bda7e4950..0659536aab98c 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -419,13 +419,9 @@ static void CheckSubscripts(
}
}
-static void CheckSubscripts(
+static void CheckCosubscripts(
semantics::SemanticsContext &context, CoarrayRef &ref) {
- const Symbol &coarraySymbol{ref.GetBase().GetLastSymbol()};
- Shape lb, ub;
- if (FoldSubscripts(context, coarraySymbol, ref.subscript(), lb, ub)) {
- ValidateSubscripts(context, coarraySymbol, ref.subscript(), lb, ub);
- }
+ const Symbol &coarraySymbol{ref.GetLastSymbol()};
FoldingContext &foldingContext{context.foldingContext()};
int dim{0};
for (auto &expr : ref.cosubscript()) {
@@ -1534,29 +1530,10 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::StructureComponent &sc) {
}
MaybeExpr ExpressionAnalyzer::Analyze(const parser::CoindexedNamedObject &x) {
- if (auto maybeDataRef{ExtractDataRef(Analyze(x.base))}) {
- DataRef *dataRef{&*maybeDataRef};
- std::vector<Subscript> subscripts;
- SymbolVector reversed;
- if (auto *aRef{std::get_if<ArrayRef>(&dataRef->u)}) {
- subscripts = std::move(aRef->subscript());
- reversed.push_back(aRef->GetLastSymbol());
- if (Component *component{aRef->base().UnwrapComponent()}) {
- dataRef = &component->base();
- } else {
- dataRef = nullptr;
- }
- }
- if (dataRef) {
- while (auto *component{std::get_if<Component>(&dataRef->u)}) {
- reversed.push_back(component->GetLastSymbol());
- dataRef = &component->base();
- }
- if (auto *baseSym{std::get_if<SymbolRef>(&dataRef->u)}) {
- reversed.push_back(*baseSym);
- } else {
- Say("Base of coindexed named object has subscripts or cosubscripts"_err_en_US);
- }
+ if (auto dataRef{ExtractDataRef(Analyze(x.base))}) {
+ if (!std::holds_alternative<ArrayRef>(dataRef->u) &&
+ dataRef->GetLastSymbol().Rank() > 0) { // F'2023 C916
+ Say("Subscripts must appear in a coindexed reference when its base is an array"_err_en_US);
}
std::vector<Expr<SubscriptInteger>> cosubscripts;
bool cosubsOk{true};
@@ -1570,30 +1547,59 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::CoindexedNamedObject &x) {
cosubsOk = false;
}
}
- if (cosubsOk && !reversed.empty()) {
+ if (cosubsOk) {
int numCosubscripts{static_cast<int>(cosubscripts.size())};
- const Symbol &symbol{reversed.front()};
+ const Symbol &symbol{dataRef->GetLastSymbol()};
if (numCosubscripts != GetCorank(symbol)) {
Say("'%s' has corank %d, but coindexed reference has %d cosubscripts"_err_en_US,
symbol.name(), GetCorank(symbol), numCosubscripts);
}
}
+ CoarrayRef coarrayRef{std::move(*dataRef), std::move(cosubscripts)};
for (const auto &imageSelSpec :
std::get<std::list<parser::ImageSelectorSpec>>(x.imageSelector.t)) {
common::visit(
common::visitors{
- [&](const auto &x) { Analyze(x.v); },
- },
+ [&](const parser::ImageSelectorSpec::Stat &x) {
+ Analyze(x.v);
+ if (const auto *expr{GetExpr(context_, x.v)}) {
+ if (const auto *intExpr{
+ std::get_if<Expr<SomeInteger>>(&expr->u)}) {
+ if (coarrayRef.stat()) {
+ Say("coindexed reference has multiple STAT= specifiers"_err_en_US);
+ } else {
+ coarrayRef.set_stat(Expr<SomeInteger>{*intExpr});
+ }
+ }
+ }
+ },
+ [&](const parser::TeamValue &x) {
+ Analyze(x.v);
+ if (const auto *expr{GetExpr(context_, x.v)}) {
+ if (coarrayRef.team()) {
+ Say("coindexed reference has multiple TEAM= or TEAM_NUMBER= specifiers"_err_en_US);
+ } else if (auto dyType{expr->GetType()};
+ dyType && IsTeamType(GetDerivedTypeSpec(*dyType))) {
+ coarrayRef.set_team(Expr<SomeType>{*expr});
+ } else {
+ Say("TEAM= specifier must have type TEAM_TYPE from ISO_FORTRAN_ENV"_err_en_US);
+ }
+ }
+ },
+ [&](const parser::ImageSelectorSpec::Team_Number &x) {
+ Analyze(x.v);
+ if (const auto *expr{GetExpr(context_, x.v)}) {
+ if (coarrayRef.team()) {
+ Say("coindexed reference has multiple TEAM= or TEAM_NUMBER= specifiers"_err_en_US);
+ } else {
+ coarrayRef.set_team(Expr<SomeType>{*expr});
+ }
+ }
+ }},
imageSelSpec.u);
}
- // Reverse the chain of symbols so that the base is first and coarray
- // ultimate component is last.
- if (cosubsOk) {
- CoarrayRef coarrayRef{SymbolVector{reversed.crbegin(), reversed.crend()},
- std::move(subscripts), std::move(cosubscripts)};
- CheckSubscripts(context_, coarrayRef);
- return Designate(DataRef{std::move(coarrayRef)});
- }
+ CheckCosubscripts(context_, coarrayRef);
+ return Designate(DataRef{std::move(coarrayRef)});
}
return std::nullopt;
}
diff --git a/flang/test/Semantics/atomic02.f90 b/flang/test/Semantics/atomic02.f90
index 484239a23ede2..0d107152a8c14 100644
--- a/flang/test/Semantics/atomic02.f90
+++ b/flang/test/Semantics/atomic02.f90
@@ -31,7 +31,7 @@ program test_atomic_and
call atomic_and(non_scalar_coarray, val)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_and'
- call atomic_and(non_scalar_coarray[1], val)
+ call atomic_and(non_scalar_coarray(:)[1], val)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_and'
call atomic_and(non_coarray, val)
diff --git a/flang/test/Semantics/atomic03.f90 b/flang/test/Semantics/atomic03.f90
index 495df5eb97192..cef21d002dd68 100644
--- a/flang/test/Semantics/atomic03.f90
+++ b/flang/test/Semantics/atomic03.f90
@@ -51,13 +51,13 @@ program test_atomic_cas
call atomic_cas(non_scalar_coarray, old_int, compare_int, new_int)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_cas'
- call atomic_cas(non_scalar_coarray[1], old_int, compare_int, new_int)
+ call atomic_cas(non_scalar_coarray(:)[1], old_int, compare_int, new_int)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_cas'
call atomic_cas(non_scalar_logical_coarray, old_logical, compare_logical, new_logical)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_cas'
- call atomic_cas(non_scalar_logical_coarray[1], old_logical, compare_logical, new_logical)
+ call atomic_cas(non_scalar_logical_coarray(:)[1], old_logical, compare_logical, new_logical)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_cas'
call atomic_cas(non_coarray, old_int, compare_int, new_int)
diff --git a/flang/test/Semantics/atomic04.f90 b/flang/test/Semantics/atomic04.f90
index 9df0b56d192a8..453fdb10e7f49 100644
--- a/flang/test/Semantics/atomic04.f90
+++ b/flang/test/Semantics/atomic04.f90
@@ -47,13 +47,13 @@ program test_atomic_define
call atomic_define(non_scalar_coarray, val)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_define'
- call atomic_define(non_scalar_coarray[1], val)
+ call atomic_define(non_scalar_coarray(:)[1], val)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_define'
call atomic_define(non_scalar_logical_coarray, val_logical)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_define'
- call atomic_define(non_scalar_logical_coarray[1], val_logical)
+ call atomic_define(non_scalar_logical_coarray(:)[1], val_logical)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_define'
call atomic_define(non_coarray, val)
diff --git a/flang/test/Semantics/atomic05.f90 b/flang/test/Semantics/atomic05.f90
index 98d6b19b1f23d..c1e67b0d454fe 100644
--- a/flang/test/Semantics/atomic05.f90
+++ b/flang/test/Semantics/atomic05.f90
@@ -41,7 +41,7 @@ program test_atomic_fetch_add
call atomic_fetch_add(array, val, old_val)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_fetch_add'
- call atomic_fetch_add(non_scalar_coarray[1], val, old_val)
+ call atomic_fetch_add(non_scalar_coarray(:)[1], val, old_val)
!ERROR: Actual argument for 'atom=' must have kind=atomic_int_kind, but is 'INTEGER(4)'
call atomic_fetch_add(default_kind_coarray, val, old_val)
diff --git a/flang/test/Semantics/atomic06.f90 b/flang/test/Semantics/atomic06.f90
index c6a23dd0077ca..57cc81e9c4a97 100644
--- a/flang/test/Semantics/atomic06.f90
+++ b/flang/test/Semantics/atomic06.f90
@@ -41,7 +41,7 @@ program test_atomic_fetch_and
call atomic_fetch_and(array, val, old_val)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_fetch_and'
- call atomic_fetch_and(non_scalar_coarray[1], val, old_val)
+ call atomic_fetch_and(non_scalar_coarray(:)[1], val, old_val)
!ERROR: Actual argument for 'atom=' must have kind=atomic_int_kind, but is 'INTEGER(4)'
call atomic_fetch_and(default_kind_coarray, val, old_val)
diff --git a/flang/test/Semantics/atomic07.f90 b/flang/test/Semantics/atomic07.f90
index 2bc544b757864..e4d80956ed036 100644
--- a/flang/test/Semantics/atomic07.f90
+++ b/flang/test/Semantics/atomic07.f90
@@ -34,7 +34,7 @@ program test_atomic_fetch_or
call atomic_fetch_or(array, val, old_val)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_fetch_or'
- call atomic_fetch_or(non_scalar_coarray[1], val, old_val)
+ call atomic_fetch_or(non_scalar_coarray(:)[1], val, old_val)
!ERROR: Actual argument for 'atom=' must have kind=atomic_int_kind, but is 'INTEGER(4)'
call atomic_fetch_or(default_kind_coarray, val, old_val)
diff --git a/flang/test/Semantics/atomic08.f90 b/flang/test/Semantics/atomic08.f90
index f519f9735e00e..234e6e3923620 100644
--- a/flang/test/Semantics/atomic08.f90
+++ b/flang/test/Semantics/atomic08.f90
@@ -41,7 +41,7 @@ program test_atomic_fetch_xor
call atomic_fetch_xor(array, val, old_val)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_fetch_xor'
- call atomic_fetch_xor(non_scalar_coarray[1], val, old_val)
+ call atomic_fetch_xor(non_scalar_coarray(:)[1], val, old_val)
!ERROR: Actual argument for 'atom=' must have kind=atomic_int_kind, but is 'INTEGER(4)'
call atomic_fetch_xor(default_kind_coarray, val, old_val)
diff --git a/flang/test/Semantics/atomic09.f90 b/flang/test/Semantics/atomic09.f90
index e4e062252659a..4f78ccb977186 100644
--- a/flang/test/Semantics/atomic09.f90
+++ b/flang/test/Semantics/atomic09.f90
@@ -31,7 +31,7 @@ program test_atomic_or
call atomic_or(non_scalar_coarray, val)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_or'
- call atomic_or(non_scalar_coarray[1], val)
+ call atomic_or(non_scalar_coarray(:)[1], val)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_or'
call atomic_or(non_coarray, val)
diff --git a/flang/test/Semantics/atomic10.f90 b/flang/test/Semantics/atomic10.f90
index 04efbd6e80fd2..e206326786042 100644
--- a/flang/test/Semantics/atomic10.f90
+++ b/flang/test/Semantics/atomic10.f90
@@ -47,13 +47,13 @@ program test_atomic_ref
call atomic_ref(val, non_scalar_coarray)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_ref'
- call atomic_ref(val, non_scalar_coarray[1])
+ call atomic_ref(val, non_scalar_coarray(:)[1])
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_ref'
call atomic_ref(val_logical, non_scalar_logical_coarray)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_ref'
- call atomic_ref(val_logical, non_scalar_logical_coarray[1])
+ call atomic_ref(val_logical, non_scalar_logical_coarray(:)[1])
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_ref'
call atomic_ref(val, non_coarray)
diff --git a/flang/test/Semantics/atomic11.f90 b/flang/test/Semantics/atomic11.f90
index d4f951ea02c32..dba7dfdf5ae47 100644
--- a/flang/test/Semantics/atomic11.f90
+++ b/flang/test/Semantics/atomic11.f90
@@ -31,7 +31,7 @@ program test_atomic_xor
call atomic_xor(non_scalar_coarray, val)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_xor'
- call atomic_xor(non_scalar_coarray[1], val)
+ call atomic_xor(non_scalar_coarray(:)[1], val)
!ERROR: 'atom=' argument must be a scalar coarray or coindexed object for intrinsic 'atomic_xor'
call atomic_xor(non_coarray, val)
diff --git a/flang/test/Semantics/coarrays02.f90 b/flang/test/Semantics/coarrays02.f90
index dc907161250ab..b16e0ccb58797 100644
--- a/flang/test/Semantics/coarrays02.f90
+++ b/flang/test/Semantics/coarrays02.f90
@@ -96,3 +96,27 @@ subroutine test(cat)
call sub(cat%p)
end
end
+
+subroutine s4
+ type t
+ real, allocatable :: a(:)[:]
+ end type
+ type t2
+ !ERROR: Allocatable or array component 'bad1' may not have a coarray ultimate component '%a'
+ type(t), allocatable :: bad1
+ !ERROR: Pointer 'bad2' may not have a coarray potential component '%a'
+ type(t), pointer :: bad2
+ !ERROR: Allocatable or array component 'bad3' may not have a coarray ultimate component '%a'
+ type(t) :: bad3(2)
+ !ERROR: Component 'bad4' is a coarray and must have the ALLOCATABLE attribute and have a deferred coshape
+ !ERROR: Coarray 'bad4' may not have a coarray potential component '%a'
+ type(t) :: bad4[*]
+ end type
+ type(t), save :: ta(2)
+ !ERROR: 'a' has corank 1, but coindexed reference has 2 cosubscripts
+ print *, ta(1)%a(1)[1,2]
+ !ERROR: An allocatable or pointer component reference must be applied to a scalar base
+ print *, ta(:)%a(1)[1]
+ !ERROR: Subscripts must appear in a coindexed reference when its base is an array
+ print *, ta(1)%a[1]
+end
diff --git a/flang/test/Semantics/coshape.f90 b/flang/test/Semantics/coshape.f90
index d4fb45df6600c..d4e3f2d25280d 100644
--- a/flang/test/Semantics/coshape.f90
+++ b/flang/test/Semantics/coshape.f90
@@ -40,9 +40,9 @@ program coshape_tests
!ERROR: 'coarray=' argument must have corank > 0 for intrinsic 'coshape'
codimensions = coshape(derived_scalar_coarray[1]%x)
!ERROR: 'coarray=' argument must have corank > 0 for intrinsic 'coshape'
- codimensions = coshape(derived_array_coarray[1]%x)
+ codimensions = coshape(derived_array_coarray(:)[1]%x)
!ERROR: 'coarray=' argument must have corank > 0 for intrinsic 'coshape'
- codimensions = coshape(array_coarray[1])
+ codimensions = coshape(array_coarray(:)[1])
!ERROR: 'coarray=' argument must have corank > 0 for intrinsic 'coshape'
codimensions = coshape(scalar_coarray[1])
diff --git a/flang/test/Semantics/error_stop1b.f90 b/flang/test/Semantics/error_stop1b.f90
index 355a049560102..3c9ace13693ac 100644
--- a/flang/test/Semantics/error_stop1b.f90
+++ b/flang/test/Semantics/error_stop1b.f90
@@ -32,7 +32,7 @@ program test_error_stop
error stop char_array
!ERROR: Must be a scalar value, but is a rank-1 array
- error stop array_coarray[1]
+ error stop array_coarray(:)[1]
!ERROR: Must have LOGICAL type, but is CHARACTER(KIND=1,LEN=128_8)
error stop int_code, quiet=non_logical
diff --git a/flang/test/Semantics/event01b.f90 b/flang/test/Semantics/event01b.f90
index 0cd8a5bcb1f1f..b11118783eaee 100644
--- a/flang/test/Semantics/event01b.f90
+++ b/flang/test/Semantics/event01b.f90
@@ -62,7 +62,7 @@ program test_event_post
event post(occurrences)
!ERROR: Must be a scalar value, but is a rank-1 array
- event post(occurrences[1])
+ event post(occurrences(:)[1])
!______ invalid sync-stat-lists: invalid stat= ____________
diff --git a/flang/test/Semantics/resolve94.f90 b/flang/test/Semantics/resolve94.f90
index 75755fb2b2038..1d0b106bd1171 100644
--- a/flang/test/Semantics/resolve94.f90
+++ b/flang/test/Semantics/resolve94.f90
@@ -35,7 +35,7 @@ subroutine s1()
rVar1 = rCoarray[1,intArray,3]
! OK
rVar1 = rCoarray[1,2,3,STAT=iVar1, TEAM=team2]
- !ERROR: Team value must be of type TEAM_TYPE from module ISO_FORTRAN_ENV
+ !ERROR: TEAM= specifier must have type TEAM_TYPE from ISO_FORTRAN_ENV
rVar1 = rCoarray[1,2,3,STAT=iVar1, TEAM=2]
! OK
rVar1 = rCoarray[1,2,3,STAT=iVar1, TEAM_NUMBER=38]
@@ -48,12 +48,12 @@ subroutine s1()
!ERROR: Must be a scalar value, but is a rank-1 array
rVar1 = rCoarray[1,2,3,STAT=intArray]
! Error on C929, no specifier can appear more than once
- !ERROR: STAT variable can only be specified once
+ !ERROR: coindexed reference has multiple STAT= specifiers
rVar1 = rCoarray[1,2,3,STAT=iVar1, STAT=iVar2]
! OK
rVar1 = rCoarray[1,2,3,TEAM=team1]
! Error on C929, no specifier can appear more than once
- !ERROR: TEAM value can only be specified once
+ !ERROR: coindexed reference has multiple TEAM= or TEAM_NUMBER= specifiers
rVar1 = rCoarray[1,2,3,TEAM=team1, TEAM=team2]
! OK
rVar1 = rCoarray[1,2,3,TEAM_NUMBER=37]
@@ -66,11 +66,11 @@ subroutine s1()
!ERROR: Must have INTEGER type, but is REAL(4)
rVar1 = rCoarray[1,2,3,TEAM_NUMBER=3.7]
! Error on C929, no specifier can appear more than once
- !ERROR: TEAM_NUMBER value can only be specified once
+ !ERROR: coindexed reference has multiple TEAM= or TEAM_NUMBER= specifiers
rVar1 = rCoarray[1,2,3,TEAM_NUMBER=37, TEAM_NUMBER=37]
- !ERROR: Cannot specify both TEAM and TEAM_NUMBER
+ !ERROR: coindexed reference has multiple TEAM= or TEAM_NUMBER= specifiers
rVar1 = rCoarray[1,2,3,TEAM=team1, TEAM_NUMBER=37]
- !ERROR: Cannot specify both TEAM and TEAM_NUMBER
+ !ERROR: coindexed reference has multiple TEAM= or TEAM_NUMBER= specifiers
rVar1 = rCoarray[1,2,3,TEAM_number=43, TEAM=team1]
! OK for a STAT variable to be a coarray integer
rVar1 = rCoarray[1,2,3,stat=intScalarCoarray]
More information about the flang-commits
mailing list