[flang] Support for image selectors
authorPete Steinfeld <psteinfeld@nvidia.com>
Tue, 7 Jul 2020 19:15:39 +0000 (12:15 -0700)
committerPete Steinfeld <psteinfeld@nvidia.com>
Wed, 8 Jul 2020 14:31:54 +0000 (07:31 -0700)
Summary:
This change implements support for image selectors and image selector
specifications as described in section 9.6.

In check-coarray[.h,cpp] I changed the `Leave()` function for
`parser::ImageSelectorSpec` to take a `parser::ImageSelector`, which
contains a list of image selector specifications.  This allows us to
detect when the same specification is used more than once.  I also added
code to analyze the expressions for the image selector specifications to
expression.cpp and a test for all of the conditions to check at
compile-time.

Note that we do not check at compile-time to see if the value of the
cosubscripts are within the specified cobounds.  We also do not check anything
related to selecting a valid team.  We also do not check that the denotation of
the `stat-variable` is not dependent on the evaluation of an entity in the
same statement.

Reviewers: klausler, tskeith, DavidTruby

Subscribers: llvm-commits

Tags: #llvm, #flang

Differential Revision: https://reviews.llvm.org/D83336

flang/include/flang/Parser/tools.h
flang/lib/Parser/tools.cpp
flang/lib/Semantics/check-coarray.cpp
flang/lib/Semantics/check-coarray.h
flang/lib/Semantics/expression.cpp
flang/test/Semantics/resolve94.f90 [new file with mode: 0644]

index c918425..fa6ecd0 100644 (file)
@@ -99,6 +99,8 @@ template <typename A, typename B> A *Unwrap(B &x) {
 // Get the CoindexedNamedObject if the entity is a coindexed object.
 const CoindexedNamedObject *GetCoindexedNamedObject(const AllocateObject &);
 const CoindexedNamedObject *GetCoindexedNamedObject(const DataRef &);
+const CoindexedNamedObject *GetCoindexedNamedObject(const Designator &);
+const CoindexedNamedObject *GetCoindexedNamedObject(const Variable &);
 
 // Detects parse tree nodes with "source" members.
 template <typename A, typename = int> struct HasSource : std::false_type {};
index 0a21e73..2db832a 100644 (file)
@@ -136,6 +136,30 @@ const CoindexedNamedObject *GetCoindexedNamedObject(const DataRef &base) {
       base.u);
 }
 const CoindexedNamedObject *GetCoindexedNamedObject(
+    const Designator &designator) {
+  return std::visit(common::visitors{
+                        [](const DataRef &x) -> const CoindexedNamedObject * {
+                          return GetCoindexedNamedObject(x);
+                        },
+                        [](const Substring &x) -> const CoindexedNamedObject * {
+                          return GetCoindexedNamedObject(
+                              std::get<DataRef>(x.t));
+                        },
+                    },
+      designator.u);
+}
+const CoindexedNamedObject *GetCoindexedNamedObject(const Variable &variable) {
+  return std::visit(
+      common::visitors{
+          [](const common::Indirection<Designator> &designator)
+              -> const CoindexedNamedObject * {
+            return GetCoindexedNamedObject(designator.value());
+          },
+          [](const auto &) -> const CoindexedNamedObject * { return nullptr; },
+      },
+      variable.u);
+}
+const CoindexedNamedObject *GetCoindexedNamedObject(
     const AllocateObject &allocateObject) {
   return std::visit(
       common::visitors{
index a9d649f..4ce286d 100644 (file)
@@ -72,6 +72,16 @@ static void CheckTeamType(SemanticsContext &context, const T &x) {
   }
 }
 
+static void CheckTeamStat(
+    SemanticsContext &context, const parser::ImageSelectorSpec::Stat &stat) {
+  const parser::Variable &var{stat.v.thing.thing.value()};
+  if (parser::GetCoindexedNamedObject(var)) {
+    context.Say(parser::FindSourceLocation(var), // C931
+        "Image selector STAT variable must not be a coindexed "
+        "object"_err_en_US);
+  }
+}
+
 void CoarrayChecker::Leave(const parser::ChangeTeamStmt &x) {
   CheckNamesAreDistinct(std::get<std::list<parser::CoarrayAssociation>>(x.t));
   CheckTeamType(context_, std::get<parser::TeamValue>(x.t));
@@ -81,9 +91,42 @@ void CoarrayChecker::Leave(const parser::SyncTeamStmt &x) {
   CheckTeamType(context_, std::get<parser::TeamValue>(x.t));
 }
 
-void CoarrayChecker::Leave(const parser::ImageSelectorSpec &x) {
-  if (const auto *team{std::get_if<parser::TeamValue>(&x.u)}) {
-    CheckTeamType(context_, *team);
+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);
   }
 }
 
index 2e91c7b..5f30dda 100644 (file)
@@ -18,9 +18,8 @@ class MessageFixedText;
 struct ChangeTeamStmt;
 struct CoarrayAssociation;
 struct FormTeamStmt;
-struct ImageSelectorSpec;
+struct ImageSelector;
 struct SyncTeamStmt;
-struct TeamValue;
 } // namespace Fortran::parser
 
 namespace Fortran::semantics {
@@ -30,13 +29,16 @@ public:
   CoarrayChecker(SemanticsContext &context) : context_{context} {}
   void Leave(const parser::ChangeTeamStmt &);
   void Leave(const parser::SyncTeamStmt &);
-  void Leave(const parser::ImageSelectorSpec &);
+  void Leave(const parser::ImageSelector &);
   void Leave(const parser::FormTeamStmt &);
 
   void Enter(const parser::CriticalConstruct &);
 
 private:
   SemanticsContext &context_;
+  bool haveStat_;
+  bool haveTeam_;
+  bool haveTeamNumber_;
 
   void CheckNamesAreDistinct(const std::list<parser::CoarrayAssociation> &);
   void Say2(const parser::CharBlock &, parser::MessageFixedText &&,
index 27fcf5e..7191171 100644 (file)
@@ -1085,7 +1085,14 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::CoindexedNamedObject &x) {
             symbol.name(), symbol.Corank(), numCosubscripts);
       }
     }
-    // TODO: stat=/team=/team_number=
+    for (const auto &imageSelSpec :
+        std::get<std::list<parser::ImageSelectorSpec>>(x.imageSelector.t)) {
+      std::visit(
+          common::visitors{
+              [&](const auto &x) {Analyze(x.v); },
+          },
+          imageSelSpec.u);
+    }
     // Reverse the chain of symbols so that the base is first and coarray
     // ultimate component is last.
     return Designate(
diff --git a/flang/test/Semantics/resolve94.f90 b/flang/test/Semantics/resolve94.f90
new file mode 100644 (file)
index 0000000..b38037e
--- /dev/null
@@ -0,0 +1,69 @@
+! RUN: %S/test_errors.sh %s %t %f18
+! C929   No specifier shall appear more than once in a given 
+!   image-selector-spec-list.
+! C930 TEAM and TEAM_NUMBER shall not both appear in the same
+!   image-selector-spec-list.
+! C931 A stat-variable in an image-selector shall not be a coindexed object.
+subroutine s1()
+  use ISO_FORTRAN_ENV
+  type(team_type) :: team1, team2
+  real :: rCoarray[10,20,*]
+  real :: rVar1, rVar2
+  integer :: iVar1, iVar2
+  integer, dimension(4) :: intArray
+  integer :: intScalarCoarray[*]
+  integer :: intCoarray[3, 4, *]
+  intCoVar = 343
+  ! OK
+  rVar1 = rCoarray[1,2,3]
+  !ERROR: 'rcoarray' has corank 3, but coindexed reference has 2 cosubscripts
+  rVar1 = rCoarray[1,2]
+  !ERROR: Must have INTEGER type, but is REAL(4)
+  rVar1 = rCoarray[1,2,3.4]
+  !ERROR: Must be a scalar value, but is a rank-1 array
+  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
+  rVar1 = rCoarray[1,2,3,STAT=iVar1, TEAM=2]
+  ! OK
+  rVar1 = rCoarray[1,2,3,STAT=iVar1, TEAM_NUMBER=38]
+  ! OK
+  rVar1 = rCoarray[1,2,3,STAT=iVar1]
+  ! OK
+  rVar1 = rCoarray[1,2,3,STAT=intArray(2)]
+  !ERROR: Must have INTEGER type, but is REAL(4)
+  rVar1 = rCoarray[1,2,3,STAT=rVar2]
+  !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
+  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
+  rVar1 = rCoarray[1,2,3,TEAM=team1, TEAM=team2]
+  ! OK
+  rVar1 = rCoarray[1,2,3,TEAM_NUMBER=37]
+  ! OK
+  rVar1 = rCoarray[1,2,3,TEAM_NUMBER=iVar1]
+  ! Error, team number is a scalar integer expression
+  !ERROR: Must be a scalar value, but is a rank-1 array
+  rVar1 = rCoarray[1,2,3,TEAM_NUMBER=intArray]
+  ! Error, team number is a scalar integer expression
+  !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
+  rVar1 = rCoarray[1,2,3,TEAM_NUMBER=37, TEAM_NUMBER=37]
+  !ERROR: Cannot specify both TEAM and TEAM_NUMBER
+  rVar1 = rCoarray[1,2,3,TEAM=team1, TEAM_NUMBER=37]
+  !ERROR: Cannot specify both TEAM and TEAM_NUMBER
+  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]
+  ! Error for a STAT variable to be a coindexed object
+  !ERROR: Image selector STAT variable must not be a coindexed object
+  rVar1 = rCoarray[1,2,3,stat=intCoarray[2,3, 4]]
+end subroutine s1