[flang-commits] [flang] [flang][OpenMP] Use 'present-modifier' instead of 'expectation' in 5.1 (PR #214083)

Krzysztof Parzyszek via flang-commits flang-commits at lists.llvm.org
Wed Aug 5 05:51:10 PDT 2026


https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/214083

>From 3b924056bc1cfcc45d161a90053d7d79eb2b34c9 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 4 Aug 2026 15:56:59 -0500
Subject: [PATCH 1/3] [flang][OpenMP] Use 'present-modifier' instead of
 'expectation' in 5.1

The 5.1 spec lists PRESENT as an alternative in a 'motion-modifier'.
The other alternatives are mapper and iterator. These already exist
as separate modifiers, so 'motion-modifier' would best be expressed
as a modifier group. While modifier groups are not implemented yet,
borrow 'present-modifier' from the 6.0 spec.

The 'expectation' modifier only existed in 5.2, it was replaced by
'present-modifier' in 6.0.
---
 flang/include/flang/Parser/parse-tree.h       | 48 ++++++++-----
 flang/lib/Lower/OpenMP/Clauses.cpp            | 72 ++++++++++++-------
 flang/lib/Parser/openmp-parsers.cpp           | 30 +++++---
 flang/lib/Semantics/openmp-modifiers.cpp      |  9 ++-
 .../test/Semantics/OpenMP/from-clause-v45.f90 |  8 +--
 .../test/Semantics/OpenMP/from-clause-v51.f90 |  2 +-
 flang/test/Semantics/OpenMP/to-clause-v45.f90 |  8 +--
 flang/test/Semantics/OpenMP/to-clause-v51.f90 |  2 +-
 8 files changed, 117 insertions(+), 62 deletions(-)

diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index d647879c0dc92..6a21d5d8c79d7 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4292,14 +4292,16 @@ struct OmpPrescriptiveness {
   WRAPPER_CLASS_BOILERPLATE(OmpPrescriptiveness, Value);
 };
 
-// Ref: [4.5:216-219], [5.0:315-324], [5.1:347-355], [5.2:150-158],
-// [6.0:279-288]
+// Ref: [5.1:205-210], [6.0:279-288]
 //
 // present-modifier ->
-//    PRESENT                                       // since 5.1
+//    PRESENT                                       // since 5.1, until 5.1
+//                                                  // since 6.0
 //
-// Until 5.2, it was a part of map-type-modifier. Since 6.0 the
-// map-type-modifier has been split into individual modifiers.
+// In 5.1 it was a part of "motion-modifier" (on FROM and TO clauses), which
+// should really be modeled as a modifier-group. In 5.2 it was replaced by
+// "expectation". It was restored in 6.0 when map-type-modifier was broken up
+// into individual modifiers.
 struct OmpPresentModifier {
   ENUM_CLASS(Value, Present)
   WRAPPER_CLASS_BOILERPLATE(OmpPresentModifier, Value);
@@ -4711,17 +4713,24 @@ struct OmpFailClause {
   WRAPPER_CLASS_BOILERPLATE(OmpFailClause, MemoryOrder);
 };
 
-// Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
+// Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168],
+//      [6.0:298-299]
 //
 // from-clause ->
-//    FROM(locator-list) |
-//    FROM(mapper-modifier: locator-list) |         // since 5.0
-//    FROM(motion-modifier[,] ...: locator-list)    // since 5.1
+//    FROM(locator-list) |                          // since 4.5
+//    FROM(modifier[,] ...: locator-list) |         // since 5.0
+// modifier ->
+//    mapper |                                      // since 5.2
+//    motion-modifier |                             // since 5.1, until 5.1
+//    expectation | mapper | iterator               // since 5.2, until 5.2
+//    present-modifier | mapper | iterator |        // since 6.0
+//    directive-name-modifier                       // since 6.0
 //  motion-modifier ->
 //    PRESENT | mapper-modifier | iterator-modifier
 struct OmpFromClause {
   TUPLE_CLASS_BOILERPLATE(OmpFromClause);
-  MODIFIER_BOILERPLATE(OmpExpectation, OmpIterator, OmpMapper);
+  MODIFIER_BOILERPLATE(
+      OmpExpectation, OmpPresentModifier, OmpIterator, OmpMapper);
   std::tuple<MODIFIERS(), OmpObjectList, /*CommaSeparated=*/bool> t;
 };
 
@@ -5070,18 +5079,25 @@ struct OmpThreadsetClause {
 };
 
 // Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
+//      [6.0:297-298]
 //
 // to-clause (in DECLARE TARGET) ->
-//    TO(extended-list) |                           // until 5.1
+//    TO(extended-list) |                           // since 4.5, until 5.1
 // to-clause (in TARGET UPDATE) ->
-//    TO(locator-list) |
-//    TO(mapper-modifier: locator-list) |           // since 5.0
-//    TO(motion-modifier[,] ...: locator-list)      // since 5.1
-// motion-modifier ->
+//    TO(locator-list) |                            // since 4.5
+//    TO(modifier[,] ...: locator-list) |           // since 5.0
+// modifier ->
+//    mapper |                                      // since 5.2
+//    motion-modifier |                             // since 5.1, until 5.1
+//    expectation | mapper | iterator               // since 5.2, until 5.2
+//    present-modifier | mapper | iterator |        // since 6.0
+//    directive-name-modifier                       // since 6.0
+//  motion-modifier ->
 //    PRESENT | mapper-modifier | iterator-modifier
 struct OmpToClause {
   TUPLE_CLASS_BOILERPLATE(OmpToClause);
-  MODIFIER_BOILERPLATE(OmpExpectation, OmpIterator, OmpMapper);
+  MODIFIER_BOILERPLATE(
+      OmpExpectation, OmpPresentModifier, OmpIterator, OmpMapper);
   std::tuple<MODIFIERS(), OmpObjectList, /*CommaSeparated=*/bool> t;
 };
 
diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
index 1b9ce1401118e..a7912ecf6a57b 100644
--- a/flang/lib/Lower/OpenMP/Clauses.cpp
+++ b/flang/lib/Lower/OpenMP/Clauses.cpp
@@ -970,11 +970,17 @@ Firstprivate make(const parser::OmpClause::Firstprivate &inp,
 
 // Flush: empty
 
-From make(const parser::OmpClause::From &inp,
-          semantics::SemanticsContext &semaCtx) {
+From make(
+    const parser::OmpClause::From &inp, semantics::SemanticsContext &semaCtx) {
   // inp.v -> parser::OmpFromClause
   CLAUSET_ENUM_CONVERT( //
-      convert, parser::OmpExpectation::Value, From::Expectation,
+      convertExp, parser::OmpExpectation::Value, From::Expectation,
+      // clang-format off
+      MS(Present, Present)
+      // clang-format on
+  );
+  CLAUSET_ENUM_CONVERT( //
+      convertPre, parser::OmpPresentModifier::Value, From::Expectation,
       // clang-format off
       MS(Present, Present)
       // clang-format on
@@ -982,26 +988,32 @@ From make(const parser::OmpClause::From &inp,
 
   auto &mods = semantics::OmpGetModifiers(inp.v);
   auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpExpectation>(mods);
-  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods);
-  auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
-  auto &t3 = std::get<parser::OmpObjectList>(inp.v.t);
+  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpPresentModifier>(mods);
+  auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods);
+  auto *t3 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
+  auto &t4 = std::get<parser::OmpObjectList>(inp.v.t);
+
+  std::optional<From::Expectation> maybeExp = //
+      t0   ? maybeApplyToV(convertExp, t0)
+      : t1 ? maybeApplyToV(convertPre, t1)
+           : std::optional<From::Expectation>{};
 
   auto mappers = [&]() -> std::optional<List<Mapper>> {
-    if (t1)
-      return List<Mapper>{Mapper{makeObject(t1->v, semaCtx)}};
+    if (t2)
+      return List<Mapper>{Mapper{makeObject(t2->v, semaCtx)}};
     return std::nullopt;
   }();
 
   auto iterator = [&]() -> std::optional<Iterator> {
-    if (t2)
-      return makeIterator(*t2, semaCtx);
+    if (t3)
+      return makeIterator(*t3, semaCtx);
     return std::nullopt;
   }();
 
-  return From{{/*Expectation=*/maybeApplyToV(convert, t0),
-               /*Mappers=*/std::move(mappers),
-               /*Iterator=*/std::move(iterator),
-               /*LocatorList=*/makeObjects(t3, semaCtx)}};
+  return From{{/*Expectation=*/maybeExp,
+      /*Mappers=*/std::move(mappers),
+      /*Iterator=*/std::move(iterator),
+      /*LocatorList=*/makeObjects(t4, semaCtx)}};
 }
 
 // Full: empty
@@ -1694,7 +1706,13 @@ To make(const parser::OmpClause::To &inp,
         semantics::SemanticsContext &semaCtx) {
   // inp.v -> parser::OmpToClause
   CLAUSET_ENUM_CONVERT( //
-      convert, parser::OmpExpectation::Value, To::Expectation,
+      convertExp, parser::OmpExpectation::Value, To::Expectation,
+      // clang-format off
+      MS(Present, Present)
+      // clang-format on
+  );
+  CLAUSET_ENUM_CONVERT( //
+      convertPre, parser::OmpPresentModifier::Value, From::Expectation,
       // clang-format off
       MS(Present, Present)
       // clang-format on
@@ -1702,26 +1720,32 @@ To make(const parser::OmpClause::To &inp,
 
   auto &mods = semantics::OmpGetModifiers(inp.v);
   auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpExpectation>(mods);
-  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods);
-  auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
-  auto &t3 = std::get<parser::OmpObjectList>(inp.v.t);
+  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpPresentModifier>(mods);
+  auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods);
+  auto *t3 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
+  auto &t4 = std::get<parser::OmpObjectList>(inp.v.t);
+
+  std::optional<From::Expectation> maybeExp = //
+      t0   ? maybeApplyToV(convertExp, t0)
+      : t1 ? maybeApplyToV(convertPre, t1)
+           : std::optional<From::Expectation>{};
 
   auto mappers = [&]() -> std::optional<List<Mapper>> {
-    if (t1)
-      return List<Mapper>{Mapper{makeObject(t1->v, semaCtx)}};
+    if (t2)
+      return List<Mapper>{Mapper{makeObject(t2->v, semaCtx)}};
     return std::nullopt;
   }();
 
   auto iterator = [&]() -> std::optional<Iterator> {
-    if (t2)
-      return makeIterator(*t2, semaCtx);
+    if (t3)
+      return makeIterator(*t3, semaCtx);
     return std::nullopt;
   }();
 
-  return To{{/*Expectation=*/maybeApplyToV(convert, t0),
+  return To{{/*Expectation=*/maybeExp,
              /*Mappers=*/{std::move(mappers)},
              /*Iterator=*/std::move(iterator),
-             /*LocatorList=*/makeObjects(t3, semaCtx)}};
+             /*LocatorList=*/makeObjects(t4, semaCtx)}};
 }
 
 UnifiedAddress make(const parser::OmpClause::UnifiedAddress &inp,
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index ad74cb84aa8bf..7c4e49a673bb0 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1088,10 +1088,27 @@ TYPE_PARSER(
 TYPE_PARSER(
     sourced(construct<OmpEnterClause::Modifier>(Parser<OmpAutomapModifier>{})))
 
-TYPE_PARSER(sourced(construct<OmpFromClause::Modifier>(
-    sourced(construct<OmpFromClause::Modifier>(Parser<OmpExpectation>{}) ||
-        construct<OmpFromClause::Modifier>(Parser<OmpMapper>{}) ||
-        construct<OmpFromClause::Modifier>(Parser<OmpIterator>{})))))
+template <typename MotionClause> struct OmpMotionClauseModifierParser {
+  using resultType = typename MotionClause::Modifier;
+
+  std::optional<resultType> Parse(ParseState &state) const {
+    unsigned version{state.userState()->langOptions().OpenMPVersion};
+    if (version == 52) {
+      auto expect{sourced(construct<resultType>(Parser<OmpExpectation>{}))};
+      if (auto &&result{attempt(expect).Parse(state)}) {
+        return std::move(result);
+      }
+    }
+    auto parser{sourced( //
+        construct<resultType>(Parser<OmpPresentModifier>{}) ||
+        construct<resultType>(Parser<OmpMapper>{}) ||
+        construct<resultType>(Parser<OmpIterator>{}))};
+    return parser.Parse(state);
+  }
+};
+
+TYPE_PARSER(OmpMotionClauseModifierParser<OmpFromClause>{})
+TYPE_PARSER(OmpMotionClauseModifierParser<OmpToClause>{})
 
 TYPE_PARSER(sourced(
     construct<OmpGrainsizeClause::Modifier>(Parser<OmpPrescriptiveness>{})))
@@ -1176,11 +1193,6 @@ TYPE_PARSER(sourced(construct<OmpTaskReductionClause::Modifier>(
 TYPE_PARSER(sourced(
     construct<OmpThreadLimitClause::Modifier>(Parser<OmpDimsModifier>{})))
 
-TYPE_PARSER(sourced(construct<OmpToClause::Modifier>(
-    sourced(construct<OmpToClause::Modifier>(Parser<OmpExpectation>{}) ||
-        construct<OmpToClause::Modifier>(Parser<OmpMapper>{}) ||
-        construct<OmpToClause::Modifier>(Parser<OmpIterator>{})))))
-
 TYPE_PARSER(sourced(construct<OmpWhenClause::Modifier>( //
     Parser<OmpContextSelector>{})))
 
diff --git a/flang/lib/Semantics/openmp-modifiers.cpp b/flang/lib/Semantics/openmp-modifiers.cpp
index 972788aff1247..293136d3649ad 100644
--- a/flang/lib/Semantics/openmp-modifiers.cpp
+++ b/flang/lib/Semantics/openmp-modifiers.cpp
@@ -361,11 +361,12 @@ const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpExpectation>() {
       /*name=*/"expectation",
       /*props=*/
       {
-          {51, {OmpProperty::Unique}},
+          {52, {OmpProperty::Unique}},
       },
       /*clauses=*/
       {
-          {51, {Clause::OMPC_from, Clause::OMPC_to}},
+          {52, {Clause::OMPC_from, Clause::OMPC_to}},
+          {60, {}},
       },
   };
   return desc;
@@ -629,7 +630,9 @@ const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpPresentModifier>() {
       },
       /*clauses=*/
       {
-          {51, {Clause::OMPC_map}},
+          {51, {Clause::OMPC_from, Clause::OMPC_to}},
+          {52, {}},
+          {60, {Clause::OMPC_from, Clause::OMPC_map, Clause::OMPC_to}},
       },
   };
   return desc;
diff --git a/flang/test/Semantics/OpenMP/from-clause-v45.f90 b/flang/test/Semantics/OpenMP/from-clause-v45.f90
index 654af4b7dd9b7..284511acfdd59 100644
--- a/flang/test/Semantics/OpenMP/from-clause-v45.f90
+++ b/flang/test/Semantics/OpenMP/from-clause-v45.f90
@@ -14,16 +14,16 @@ subroutine f01(x)
 
 subroutine f02(x)
   integer :: x(10)
-!WARNING: 'expectation' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!WARNING: 'present-modifier' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
 !WARNING: 'iterator' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
   !$omp target update from(present, iterator(i = 1:5): x(i))
 end
 
 subroutine f03(x)
   integer :: x(10)
-!WARNING: 'expectation' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
-!WARNING: 'expectation' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
-!ERROR: 'expectation' modifier cannot occur multiple times
+!WARNING: 'present-modifier' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!WARNING: 'present-modifier' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!ERROR: 'present-modifier' modifier cannot occur multiple times
   !$omp target update from(present, present: x)
 end
 
diff --git a/flang/test/Semantics/OpenMP/from-clause-v51.f90 b/flang/test/Semantics/OpenMP/from-clause-v51.f90
index 8771f519fec03..60252a8a1745c 100644
--- a/flang/test/Semantics/OpenMP/from-clause-v51.f90
+++ b/flang/test/Semantics/OpenMP/from-clause-v51.f90
@@ -8,7 +8,7 @@ subroutine f01(x)
 
 subroutine f03(x)
   integer :: x(10)
-!ERROR: 'expectation' modifier cannot occur multiple times
+!ERROR: 'present-modifier' modifier cannot occur multiple times
   !$omp target update from(present, present: x)
 end
 
diff --git a/flang/test/Semantics/OpenMP/to-clause-v45.f90 b/flang/test/Semantics/OpenMP/to-clause-v45.f90
index 7e56817e1ff7c..2fff681d621b1 100644
--- a/flang/test/Semantics/OpenMP/to-clause-v45.f90
+++ b/flang/test/Semantics/OpenMP/to-clause-v45.f90
@@ -14,16 +14,16 @@ subroutine f01(x)
 
 subroutine f02(x)
   integer :: x(10)
-!WARNING: 'expectation' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!WARNING: 'present-modifier' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
 !WARNING: 'iterator' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
   !$omp target update to(present, iterator(i = 1:5): x(i))
 end
 
 subroutine f03(x)
   integer :: x(10)
-!WARNING: 'expectation' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
-!WARNING: 'expectation' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
-!ERROR: 'expectation' modifier cannot occur multiple times
+!WARNING: 'present-modifier' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!WARNING: 'present-modifier' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!ERROR: 'present-modifier' modifier cannot occur multiple times
   !$omp target update to(present, present: x)
 end
 
diff --git a/flang/test/Semantics/OpenMP/to-clause-v51.f90 b/flang/test/Semantics/OpenMP/to-clause-v51.f90
index 0db292a22238b..15e742c1ece22 100644
--- a/flang/test/Semantics/OpenMP/to-clause-v51.f90
+++ b/flang/test/Semantics/OpenMP/to-clause-v51.f90
@@ -8,7 +8,7 @@ subroutine f01(x)
 
 subroutine f03(x)
   integer :: x(10)
-!ERROR: 'expectation' modifier cannot occur multiple times
+!ERROR: 'present-modifier' modifier cannot occur multiple times
   !$omp target update to(present, present: x)
 end
 

>From 99fabb8ecc18980e465488bb6d10c330daad32af Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 4 Aug 2026 17:05:19 -0500
Subject: [PATCH 2/3] format

---
 flang/lib/Lower/OpenMP/Clauses.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
index a7912ecf6a57b..383b1274d148f 100644
--- a/flang/lib/Lower/OpenMP/Clauses.cpp
+++ b/flang/lib/Lower/OpenMP/Clauses.cpp
@@ -970,8 +970,8 @@ Firstprivate make(const parser::OmpClause::Firstprivate &inp,
 
 // Flush: empty
 
-From make(
-    const parser::OmpClause::From &inp, semantics::SemanticsContext &semaCtx) {
+From make(const parser::OmpClause::From &inp,
+          semantics::SemanticsContext &semaCtx) {
   // inp.v -> parser::OmpFromClause
   CLAUSET_ENUM_CONVERT( //
       convertExp, parser::OmpExpectation::Value, From::Expectation,
@@ -1011,9 +1011,9 @@ From make(
   }();
 
   return From{{/*Expectation=*/maybeExp,
-      /*Mappers=*/std::move(mappers),
-      /*Iterator=*/std::move(iterator),
-      /*LocatorList=*/makeObjects(t4, semaCtx)}};
+               /*Mappers=*/std::move(mappers),
+               /*Iterator=*/std::move(iterator),
+               /*LocatorList=*/makeObjects(t4, semaCtx)}};
 }
 
 // Full: empty

>From 63190015c23e1ba2b6bc9305750e728d04739835 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 5 Aug 2026 07:50:34 -0500
Subject: [PATCH 3/3] Fix copy/paste error: From -> To

---
 flang/lib/Lower/OpenMP/Clauses.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
index 383b1274d148f..0d315c218770a 100644
--- a/flang/lib/Lower/OpenMP/Clauses.cpp
+++ b/flang/lib/Lower/OpenMP/Clauses.cpp
@@ -1712,7 +1712,7 @@ To make(const parser::OmpClause::To &inp,
       // clang-format on
   );
   CLAUSET_ENUM_CONVERT( //
-      convertPre, parser::OmpPresentModifier::Value, From::Expectation,
+      convertPre, parser::OmpPresentModifier::Value, To::Expectation,
       // clang-format off
       MS(Present, Present)
       // clang-format on
@@ -1725,10 +1725,10 @@ To make(const parser::OmpClause::To &inp,
   auto *t3 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
   auto &t4 = std::get<parser::OmpObjectList>(inp.v.t);
 
-  std::optional<From::Expectation> maybeExp = //
+  std::optional<To::Expectation> maybeExp = //
       t0   ? maybeApplyToV(convertExp, t0)
       : t1 ? maybeApplyToV(convertPre, t1)
-           : std::optional<From::Expectation>{};
+           : std::optional<To::Expectation>{};
 
   auto mappers = [&]() -> std::optional<List<Mapper>> {
     if (t2)



More information about the flang-commits mailing list