[flang-commits] [flang] [llvm] [Flang][OpenMP] Support certain directives in PURE procedures (PR #212676)

via flang-commits flang-commits at lists.llvm.org
Sun Aug 9 22:10:00 PDT 2026


https://github.com/ShashwathiNavada updated https://github.com/llvm/llvm-project/pull/212676

>From 1c3c1b7d9e3047650abfb7a80e1ed346c18b97ee Mon Sep 17 00:00:00 2001
From: ShashwathiNavada <shashwathinavada at gmail.com>
Date: Tue, 28 Jul 2026 22:52:45 -0500
Subject: [PATCH 1/7] [FLANG][OpenMP] support certain directives in PURE
 procedures

---
 flang/lib/Semantics/check-omp-structure.cpp   | 18 +++++
 flang/lib/Semantics/check-omp-structure.h     |  2 +
 .../test/Semantics/OpenMP/pure-procedure.f90  | 76 +++++++++++++++++++
 .../llvm/Frontend/Directive/DirectiveBase.td  |  5 ++
 llvm/include/llvm/Frontend/OpenMP/OMP.td      | 12 +++
 llvm/include/llvm/TableGen/DirectiveEmitter.h |  2 +
 .../utils/TableGen/Basic/DirectiveEmitter.cpp | 22 ++++++
 7 files changed, 137 insertions(+)
 create mode 100644 flang/test/Semantics/OpenMP/pure-procedure.f90

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index f77382c9045fc..76d0b0266838d 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -945,6 +945,22 @@ void OmpStructureChecker::CheckDirectiveDeprecation(
   // one another, but only the top-level directive should cause a warning.
 }
 
+void OmpStructureChecker::CheckDirectiveInPureProcedure(
+    parser::CharBlock source, llvm::omp::Directive id) {
+  // A directive that does not have the "pure" property is not permitted to
+  // appear in a Fortran PURE procedure, since it may introduce side effects.
+  if (llvm::omp::isDirectivePure(id)) {
+    return;
+  }
+  const Scope &scope{context_.FindScope(source)};
+  if (FindPureProcedureContaining(scope)) {
+    unsigned version{context_.langOptions().OpenMPVersion};
+    context_.Say(source,
+        "The OpenMP directive '%s' is not allowed in a PURE procedure"_err_en_US,
+        parser::omp::GetUpperName(id, version));
+  }
+}
+
 std::pair<const parser::OmpClause *, const parser::OmpClause *>
 OmpStructureChecker::FindMutuallyExclusiveClauses(
     llvm::omp::ClauseSet exclusive,
@@ -1293,6 +1309,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) {
   PushContextAndClauseSets(dirName.source, dirName.v);
   dirStack_.push_back(&GetOmpDirectiveSpecification(x));
   CheckDirectiveDeprecation(x);
+  CheckDirectiveInPureProcedure(dirName.source, dirName.v);
 
   // Verify clauses
   common::visit(
@@ -1349,6 +1366,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPDeclarativeConstruct &x) {
   CheckClauses(dirName, llvm::iterator_range(dirStack_.back()->Clauses().v),
       llvm::iterator_range(std::list<parser::OmpClause>{}));
 
+  CheckDirectiveInPureProcedure(dirName.source, dirName.v);
   EnterDirectiveNest(DeclarativeNest);
 }
 
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index f8aa47043a614..f275b2a6bd1e5 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -346,6 +346,8 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
   void CheckDirectiveSpelling(
       parser::CharBlock spelling, llvm::omp::Directive id);
   void CheckDirectiveDeprecation(const parser::OpenMPConstruct &x);
+  void CheckDirectiveInPureProcedure(
+      parser::CharBlock source, llvm::omp::Directive id);
   void CheckClauses(parser::OmpDirectiveName dirName,
       llvm::iterator_range<ClauseIterator> beginClauses,
       llvm::iterator_range<ClauseIterator> endClauses);
diff --git a/flang/test/Semantics/OpenMP/pure-procedure.f90 b/flang/test/Semantics/OpenMP/pure-procedure.f90
new file mode 100644
index 0000000000000..0270c1d5e0b79
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/pure-procedure.f90
@@ -0,0 +1,76 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=60
+
+! Only directives that have the "pure" property are permitted to appear in a
+! Fortran PURE procedure. These are: metadirective, assume, assumes, nothing,
+! error, and the loop-transforming directives (tile, unroll, reverse,
+! interchange, fuse, split, stripe).
+! (The SPLIT directive is omitted below only because its required COUNTS clause
+! is not yet parsed; it is still marked pure.)
+
+module m
+contains
+  pure subroutine pure_ok(a, n)
+    !$omp assumes no_openmp
+    integer, intent(in) :: n
+    integer, intent(inout) :: a(n)
+    integer :: i, j
+    !$omp nothing
+    !$omp assume no_openmp
+    !$omp end assume
+    !$omp metadirective when(user={condition(.true.)}: nothing)
+    !$omp error at(execution) severity(warning) message("ok")
+    !$omp tile sizes(4)
+    do i = 1, n
+      a(i) = a(i) + 1
+    end do
+    !$omp unroll partial(2)
+    do i = 1, n
+      a(i) = a(i) * 2
+    end do
+    !$omp reverse
+    do i = 1, n
+      a(i) = a(i) - 1
+    end do
+    !$omp interchange
+    do i = 1, n
+      do j = 1, n
+        a(i) = a(i) + j
+      end do
+    end do
+    !$omp stripe sizes(4)
+    do i = 1, n
+      a(i) = a(i) + 1
+    end do
+    !$omp fuse
+    do i = 1, n
+      a(i) = a(i) + 1
+    end do
+    do i = 1, n
+      a(i) = a(i) + 2
+    end do
+  end subroutine
+
+  pure subroutine pure_bad(a, n, r)
+    integer, intent(in) :: n
+    integer, intent(inout) :: a(n)
+    integer, intent(out) :: r
+    integer :: i
+    !ERROR: The OpenMP directive 'PARALLEL' is not allowed in a PURE procedure
+    !$omp parallel
+    !$omp end parallel
+    !ERROR: The OpenMP directive 'BARRIER' is not allowed in a PURE procedure
+    !$omp barrier
+    !ERROR: The OpenMP directive 'ATOMIC' is not allowed in a PURE procedure
+    !$omp atomic
+    r = r + 1
+    !ERROR: The OpenMP directive 'PARALLEL DO' is not allowed in a PURE procedure
+    !$omp parallel do
+    do i = 1, n
+      a(i) = a(i) + 1
+    end do
+    !$omp end parallel do
+    !ERROR: The OpenMP directive 'TASK' is not allowed in a PURE procedure
+    !$omp task
+    !$omp end task
+  end subroutine
+end module
diff --git a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
index 8c4fb1325400b..d41741bdd03c2 100644
--- a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
+++ b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
@@ -267,4 +267,9 @@ class Directive<list<Spelling> ss> {
 
   // The languages that allow this directive. Default: all languages.
   list<SourceLanguage> languages = [L_C, L_Fortran];
+
+  // Whether the directive has the "pure" property, i.e. it is permitted to
+  // appear in a context that must be free of side effects, such as a Fortran
+  // PURE procedure. Defaults to false.
+  bit isPure = false;
 }
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index dc2af1e62cfa4..4393ea37a9121 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -680,6 +680,7 @@ def OMP_Assumes : Directive<[Spelling<"assumes">]> {
     VersionedClause<OMPC_NoOpenMPRoutines, 51>,
     VersionedClause<OMPC_NoParallelism, 51>,
   ];
+  let isPure = true;
 }
 def OMP_Assume : Directive<[Spelling<"assume">]> {
   let association = AS_Block;
@@ -693,6 +694,7 @@ def OMP_Assume : Directive<[Spelling<"assume">]> {
     VersionedClause<OMPC_NoOpenMPRoutines, 51>,
     VersionedClause<OMPC_NoParallelism, 51>,
   ];
+  let isPure = true;
 }
 def OMP_Atomic : Directive<[Spelling<"atomic">]> {
   let allowedOnceClauses = [
@@ -936,6 +938,7 @@ def OMP_Error : Directive<[Spelling<"error">]> {
   ];
   let association = AS_None;
   let category = CA_Utility;
+  let isPure = true;
 }
 def OMP_Flatten : Directive<[Spelling<"flatten">]> {
   let allowedClauses = [
@@ -1004,6 +1007,7 @@ def OMP_Fuse : Directive<[Spelling<"fuse">]> {
   let allowedLoopModifiers = [
     LM_Fused,
   ];
+  let isPure = true;
 }
 def OMP_Interchange : Directive<[Spelling<"interchange">]> {
   let allowedClauses = [
@@ -1017,6 +1021,7 @@ def OMP_Interchange : Directive<[Spelling<"interchange">]> {
   let allowedLoopModifiers = [
     LM_Interchanged,
   ];
+  let isPure = true;
 }
 def OMP_interop : Directive<[Spelling<"interop">]> {
   let allowedClauses = [
@@ -1067,6 +1072,7 @@ def OMP_Metadirective : Directive<[Spelling<"metadirective">]> {
   ];
   let association = AS_None;
   let category = CA_Meta;
+  let isPure = true;  
 }
 def OMP_Nothing : Directive<[Spelling<"nothing">]> {
   let allowedClauses = [
@@ -1077,6 +1083,7 @@ def OMP_Nothing : Directive<[Spelling<"nothing">]> {
   let allowedLoopModifiers = [
     LM_Identity,
   ];
+  let isPure = true;
 }
 def OMP_Ordered : Directive<[Spelling<"ordered">]> {
   let allowedClauses = [
@@ -1134,6 +1141,7 @@ def OMP_Reverse : Directive<[Spelling<"reverse">]> {
   let allowedLoopModifiers = [
     LM_Reversed,
   ];
+  let isPure = true;
 }
 def OMP_Scan : Directive<[Spelling<"scan">]> {
   let allowedOnceClauses = [
@@ -1432,6 +1440,7 @@ def OMP_Tile : Directive<[Spelling<"tile">]> {
     LM_Grid,
     LM_Intratile,
   ];
+  let isPure = true;
 }
 def OMP_Stripe : Directive<[Spelling<"stripe">]> {
   let allowedClauses = [
@@ -1446,6 +1455,7 @@ def OMP_Stripe : Directive<[Spelling<"stripe">]> {
     LM_Grid,
     LM_Offsets,
   ];
+  let isPure = true;
 }
 def OMP_Split : Directive<[Spelling<"split">]> {
   let allowedClauses = [
@@ -1462,6 +1472,7 @@ def OMP_Split : Directive<[Spelling<"split">]> {
   let allowedLoopModifiers = [
     LM_Split,
   ];
+  let isPure = true;
 }
 def OMP_Unknown : Directive<[Spelling<"unknown">]> {
   let isDefault = true;
@@ -1481,6 +1492,7 @@ def OMP_Unroll : Directive<[Spelling<"unroll">]> {
   let allowedLoopModifiers = [
     LM_Unrolled,
   ];
+  let isPure = true;
 }
 def OMP_Workshare : Directive<[Spelling<"workshare">]> {
   let allowedOnceClauses = [
diff --git a/llvm/include/llvm/TableGen/DirectiveEmitter.h b/llvm/include/llvm/TableGen/DirectiveEmitter.h
index 00b2cec453aef..9f851ffd2ffea 100644
--- a/llvm/include/llvm/TableGen/DirectiveEmitter.h
+++ b/llvm/include/llvm/TableGen/DirectiveEmitter.h
@@ -274,6 +274,8 @@ class Directive : public BaseRecord {
     return Def->getValueAsListOfDefs("allowedLoopModifiers");
   }
 
+  bool isPure() const { return Def->getValueAsBit("isPure"); }
+
   // Clang uses a different format for names of its directives enum.
   std::string getClangAccSpelling() const {
     StringRef Name = getSpellingForIdentifier();
diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
index 390cb37cb3c94..833bd15ea4548 100644
--- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
@@ -899,6 +899,26 @@ static void generateGetDirectiveCategory(const DirectiveLanguage &DirLang,
   OS << "}\n";
 }
 
+static void generateIsDirectivePure(const DirectiveLanguage &DirLang,
+                                    raw_ostream &OS) {
+  OS << "constexpr bool isDirectivePure(Directive Dir) {\n";
+  OS << "  switch (Dir) {\n";
+
+  StringRef Prefix = DirLang.getDirectivePrefix();
+
+  for (const Record *R : DirLang.getDirectives()) {
+    Directive D(R);
+    if (!D.isPure())
+      continue;
+    OS << "  case " << getIdentifierName(R, Prefix) << ":\n";
+  }
+  OS << "    return true;\n";
+  OS << "  default:\n";
+  OS << "    return false;\n";
+  OS << "  } // switch (Dir)\n";
+  OS << "}\n";
+}
+
 static void generateGetDirectiveLanguages(const DirectiveLanguage &DirLang,
                                           raw_ostream &OS) {
   OS << "constexpr SourceLanguage getDirectiveLanguages(Directive D) {\n";
@@ -1383,6 +1403,8 @@ static void emitDirectivesConstexprImpl(const DirectiveLanguage &DirLang,
   OS << "\n";
   generateGetDirectiveCategory(DirLang, OS);
   OS << "\n";
+  generateIsDirectivePure(DirLang, OS);
+  OS << "\n";
   generateGetDirectiveLanguages(DirLang, OS);
 }
 

>From 6838e401fdd247502eeb4bc88aa010a0efef47f4 Mon Sep 17 00:00:00 2001
From: ShashwathiNavada <shashwathinavada at gmail.com>
Date: Tue, 28 Jul 2026 23:53:45 -0500
Subject: [PATCH 2/7] Added the property to the directives that was missed
 earlier

---
 llvm/include/llvm/Frontend/OpenMP/OMP.td | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 4393ea37a9121..7cf57c3fda68a 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -819,6 +819,7 @@ def OMP_DeclareReduction : Directive<[Spelling<"declare reduction", 1, 52>,
   ];
   let association = AS_None;
   let category = CA_Declarative;
+  let isPure = true;
 }
 def OMP_DeclareSimd : Directive<[Spelling<"declare simd", 1, 52>,
                                  Spelling<"declare_simd", 60>]> {
@@ -836,6 +837,7 @@ def OMP_DeclareSimd : Directive<[Spelling<"declare simd", 1, 52>,
   ];
   let association = AS_Declaration;
   let category = CA_Declarative;
+  let isPure = true;
 }
 def OMP_DeclareTarget : Directive<[Spelling<"declare target", 1, 52>,
                                    Spelling<"declare_target", 60>]> {
@@ -851,6 +853,7 @@ def OMP_DeclareTarget : Directive<[Spelling<"declare target", 1, 52>,
   ];
   let association = AS_None;
   let category = CA_Declarative;
+  let isPure = true;
 }
 def OMP_DeclareVariant : Directive<[Spelling<"declare variant", 1, 52>,
                                     Spelling<"declare_variant", 60>]> {
@@ -864,6 +867,7 @@ def OMP_DeclareVariant : Directive<[Spelling<"declare variant", 1, 52>,
   let association = AS_Declaration;
   let category = CA_Declarative;
   let languages = [L_C];
+  let isPure = true;
 }
 def OMP_Depobj : Directive<[Spelling<"depobj">]> {
   let allowedClauses = [

>From 2a522a22ed16625c561b3e7d0ba0029c25afcc7e Mon Sep 17 00:00:00 2001
From: ShashwathiNavada <shashwathinavada at gmail.com>
Date: Tue, 28 Jul 2026 23:53:45 -0500
Subject: [PATCH 3/7] Added the property to the directives that was missed
 earlier

---
 llvm/include/llvm/Frontend/OpenMP/OMP.td | 4 ++++
 llvm/test/TableGen/directive1.td         | 8 ++++++++
 llvm/test/TableGen/directive2.td         | 8 ++++++++
 3 files changed, 20 insertions(+)

diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 4393ea37a9121..7cf57c3fda68a 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -819,6 +819,7 @@ def OMP_DeclareReduction : Directive<[Spelling<"declare reduction", 1, 52>,
   ];
   let association = AS_None;
   let category = CA_Declarative;
+  let isPure = true;
 }
 def OMP_DeclareSimd : Directive<[Spelling<"declare simd", 1, 52>,
                                  Spelling<"declare_simd", 60>]> {
@@ -836,6 +837,7 @@ def OMP_DeclareSimd : Directive<[Spelling<"declare simd", 1, 52>,
   ];
   let association = AS_Declaration;
   let category = CA_Declarative;
+  let isPure = true;
 }
 def OMP_DeclareTarget : Directive<[Spelling<"declare target", 1, 52>,
                                    Spelling<"declare_target", 60>]> {
@@ -851,6 +853,7 @@ def OMP_DeclareTarget : Directive<[Spelling<"declare target", 1, 52>,
   ];
   let association = AS_None;
   let category = CA_Declarative;
+  let isPure = true;
 }
 def OMP_DeclareVariant : Directive<[Spelling<"declare variant", 1, 52>,
                                     Spelling<"declare_variant", 60>]> {
@@ -864,6 +867,7 @@ def OMP_DeclareVariant : Directive<[Spelling<"declare variant", 1, 52>,
   let association = AS_Declaration;
   let category = CA_Declarative;
   let languages = [L_C];
+  let isPure = true;
 }
 def OMP_Depobj : Directive<[Spelling<"depobj">]> {
   let allowedClauses = [
diff --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td
index a82ca6e2451ce..40c5e96d080ba 100644
--- a/llvm/test/TableGen/directive1.td
+++ b/llvm/test/TableGen/directive1.td
@@ -190,6 +190,14 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
 // CHECK-NEXT:  #endif
 // CHECK-NEXT:  }
 // CHECK-EMPTY:
+// CHECK-NEXT:  constexpr bool isDirectivePure(Directive Dir) {
+// CHECK-NEXT:    switch (Dir) {
+// CHECK-NEXT:      return true;
+// CHECK-NEXT:    default:
+// CHECK-NEXT:      return false;
+// CHECK-NEXT:    } // switch (Dir)
+// CHECK-NEXT:  }
+// CHECK-EMPTY:
 // CHECK-NEXT:  constexpr SourceLanguage getDirectiveLanguages(Directive D) {
 // CHECK-NEXT:    switch (D) {
 // CHECK-NEXT:    case TDLD_dira:
diff --git a/llvm/test/TableGen/directive2.td b/llvm/test/TableGen/directive2.td
index 76252e5f92303..2943a8eb3f1a6 100644
--- a/llvm/test/TableGen/directive2.td
+++ b/llvm/test/TableGen/directive2.td
@@ -155,6 +155,14 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
 // CHECK-NEXT:  #endif
 // CHECK-NEXT:  }
 // CHECK-EMPTY:
+// CHECK-NEXT:  constexpr bool isDirectivePure(Directive Dir) {
+// CHECK-NEXT:    switch (Dir) {
+// CHECK-NEXT:      return true;
+// CHECK-NEXT:    default:
+// CHECK-NEXT:      return false;
+// CHECK-NEXT:    } // switch (Dir)
+// CHECK-NEXT:  }
+// CHECK-EMPTY:
 // CHECK-NEXT:  constexpr SourceLanguage getDirectiveLanguages(Directive D) {
 // CHECK-NEXT:    switch (D) {
 // CHECK-NEXT:    case TDLD_dira:

>From 3510a97622c3fa1dff369c444eaab3b06f7520cf Mon Sep 17 00:00:00 2001
From: ShashwathiNavada <shashwathinavada at gmail.com>
Date: Thu, 30 Jul 2026 07:51:04 -0500
Subject: [PATCH 4/7] Added version guard

---
 flang/lib/Semantics/check-omp-structure.cpp   | 23 ++++++---
 .../OpenMP/pure-procedure-version.f90         | 49 +++++++++++++++++++
 2 files changed, 66 insertions(+), 6 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/pure-procedure-version.f90

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 76d0b0266838d..451560b7d812b 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -947,14 +947,25 @@ void OmpStructureChecker::CheckDirectiveDeprecation(
 
 void OmpStructureChecker::CheckDirectiveInPureProcedure(
     parser::CharBlock source, llvm::omp::Directive id) {
-  // A directive that does not have the "pure" property is not permitted to
-  // appear in a Fortran PURE procedure, since it may introduce side effects.
-  if (llvm::omp::isDirectivePure(id)) {
+  const Scope &scope{context_.FindScope(source)};
+  if (!FindPureProcedureContaining(scope)) {
     return;
   }
-  const Scope &scope{context_.FindScope(source)};
-  if (FindPureProcedureContaining(scope)) {
-    unsigned version{context_.langOptions().OpenMPVersion};
+  unsigned version{context_.langOptions().OpenMPVersion};
+  // OpenMP 5.1 permits only SIMD and declarative directives in a PURE
+  // procedure; OpenMP 5.2 additionally permits metadirective, assume(s),
+  // nothing, error, and the loop-transforming constructs).
+  bool alwaysAllowed{id == llvm::omp::Directive::OMPD_simd ||
+      llvm::omp::getDirectiveCategory(id) == llvm::omp::Category::Declarative};
+  if (alwaysAllowed || (version >= 52 && llvm::omp::isDirectivePure(id))) {
+    return;
+  }
+  if (llvm::omp::isDirectivePure(id)) {
+    context_.Say(source,
+        "The OpenMP directive '%s' is not allowed in a PURE procedure in %s, %s"_err_en_US,
+        parser::omp::GetUpperName(id, version), ThisVersion(version),
+        TryVersion(52));
+  } else {
     context_.Say(source,
         "The OpenMP directive '%s' is not allowed in a PURE procedure"_err_en_US,
         parser::omp::GetUpperName(id, version));
diff --git a/flang/test/Semantics/OpenMP/pure-procedure-version.f90 b/flang/test/Semantics/OpenMP/pure-procedure-version.f90
new file mode 100644
index 0000000000000..bda2ad18eef82
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/pure-procedure-version.f90
@@ -0,0 +1,49 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=51
+
+! In OpenMP 5.1, only SIMD and declarative directives are permitted in a PURE
+! procedure. The metadirective, assumption, nothing, error, and
+! loop-transforming directives were not added to that list until OpenMP 5.2, so
+! they are diagnosed here with a version-specific message. Directives that never
+! have the "pure" property (e.g. parallel, task) are rejected outright.
+
+module m
+contains
+  pure subroutine pure_ok(a, n)
+    integer, intent(in) :: n
+    integer, intent(inout) :: a(n)
+    integer :: i
+    ! SIMD and declarative directives are allowed in every version.
+    !$omp declare reduction(myadd : integer : omp_out = omp_out + omp_in) &
+    !$omp& initializer(omp_priv = 0)
+    !$omp simd
+    do i = 1, n
+      a(i) = a(i) + 1
+    end do
+  end subroutine
+
+  pure subroutine pure_bad(a, n)
+    integer, intent(in) :: n
+    integer, intent(inout) :: a(n)
+    integer :: i
+    !ERROR: The OpenMP directive 'NOTHING' is not allowed in a PURE procedure in OpenMP v5.1, try -fopenmp-version=52
+    !$omp nothing
+    !ERROR: The OpenMP directive 'METADIRECTIVE' is not allowed in a PURE procedure in OpenMP v5.1, try -fopenmp-version=52
+    !$omp metadirective when(user={condition(.true.)}: nothing)
+    !ERROR: The OpenMP directive 'TILE' is not allowed in a PURE procedure in OpenMP v5.1, try -fopenmp-version=52
+    !$omp tile sizes(4)
+    do i = 1, n
+      a(i) = a(i) + 1
+    end do
+    !ERROR: The OpenMP directive 'UNROLL' is not allowed in a PURE procedure in OpenMP v5.1, try -fopenmp-version=52
+    !$omp unroll partial(2)
+    do i = 1, n
+      a(i) = a(i) * 2
+    end do
+    !ERROR: The OpenMP directive 'PARALLEL' is not allowed in a PURE procedure
+    !$omp parallel
+    !$omp end parallel
+    !ERROR: The OpenMP directive 'TASK' is not allowed in a PURE procedure
+    !$omp task
+    !$omp end task
+  end subroutine
+end module

>From 485b0e57fb0f65a3a18cd2539b2e82b602f50458 Mon Sep 17 00:00:00 2001
From: Shashwathi N <nshashwa at pe34genoa.hpc.amslabs.hpecorp.net>
Date: Thu, 6 Aug 2026 10:49:04 -0500
Subject: [PATCH 5/7] Updated

---
 flang/lib/Semantics/check-omp-structure.cpp   |  9 ++++--
 .../test/Semantics/OpenMP/pure-procedure.f90  | 29 +++++++++++++++++--
 .../llvm/Frontend/Directive/DirectiveBase.td  |  6 ++--
 llvm/include/llvm/Frontend/OpenMP/OMP.td      | 29 +++++++++----------
 llvm/include/llvm/TableGen/DirectiveEmitter.h |  2 +-
 llvm/test/TableGen/directive1.td              |  5 ++--
 llvm/test/TableGen/directive2.td              |  5 ++--
 .../utils/TableGen/Basic/DirectiveEmitter.cpp | 18 +++++++-----
 8 files changed, 63 insertions(+), 40 deletions(-)

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 4fca4314aa585..41d1087a20a53 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -957,14 +957,17 @@ void OmpStructureChecker::CheckDirectiveInPureProcedure(
   // nothing, error, and the loop-transforming constructs).
   bool alwaysAllowed{id == llvm::omp::Directive::OMPD_simd ||
       llvm::omp::getDirectiveCategory(id) == llvm::omp::Category::Declarative};
-  if (alwaysAllowed || (version >= 52 && llvm::omp::isDirectivePure(id))) {
+  // A directive's "pure" property is version-specific: pureSince is the
+  // OpenMP version at which the directive gained that property.
+  unsigned pureSince{llvm::omp::getDirectivePureSince(id)};
+  if (alwaysAllowed || version >= pureSince) {
     return;
   }
-  if (llvm::omp::isDirectivePure(id)) {
+  if (pureSince != 0x7FFFFFFF) {
     context_.Say(source,
         "The OpenMP directive '%s' is not allowed in a PURE procedure in %s, %s"_err_en_US,
         parser::omp::GetUpperName(id, version), ThisVersion(version),
-        TryVersion(52));
+        TryVersion(pureSince));
   } else {
     context_.Say(source,
         "The OpenMP directive '%s' is not allowed in a PURE procedure"_err_en_US,
diff --git a/flang/test/Semantics/OpenMP/pure-procedure.f90 b/flang/test/Semantics/OpenMP/pure-procedure.f90
index 0270c1d5e0b79..d942d1b193b8e 100644
--- a/flang/test/Semantics/OpenMP/pure-procedure.f90
+++ b/flang/test/Semantics/OpenMP/pure-procedure.f90
@@ -1,9 +1,9 @@
 ! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -fopenmp-version=60
 
 ! Only directives that have the "pure" property are permitted to appear in a
-! Fortran PURE procedure. These are: metadirective, assume, assumes, nothing,
-! error, and the loop-transforming directives (tile, unroll, reverse,
-! interchange, fuse, split, stripe).
+! Fortran PURE procedure. These are: simd, scan, metadirective, assume,
+! assumes, nothing, error, and the loop-transforming directives (tile, unroll,
+! reverse, interchange, fuse, split, stripe).
 ! (The SPLIT directive is omitted below only because its required COUNTS clause
 ! is not yet parsed; it is still marked pure.)
 
@@ -50,6 +50,29 @@ pure subroutine pure_ok(a, n)
     end do
   end subroutine
 
+  pure subroutine pure_scan(a, n)
+    integer, intent(in) :: n
+    integer, intent(inout) :: a(n)
+    integer :: i, x
+    x = 0
+    !$omp simd reduction(inscan, +: x)
+    do i = 1, n
+      x = x + a(i)
+      !$omp scan inclusive(x)
+      a(i) = x
+    end do
+  end subroutine
+
+  pure subroutine pure_simd(a, n)
+    integer, intent(in) :: n
+    integer, intent(inout) :: a(n)
+    integer :: i
+    !$omp simd
+    do i = 1, n
+      a(i) = a(i) + 1
+    end do
+  end subroutine
+
   pure subroutine pure_bad(a, n, r)
     integer, intent(in) :: n
     integer, intent(inout) :: a(n)
diff --git a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
index d41741bdd03c2..c7653dd228f7c 100644
--- a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
+++ b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
@@ -268,8 +268,6 @@ class Directive<list<Spelling> ss> {
   // The languages that allow this directive. Default: all languages.
   list<SourceLanguage> languages = [L_C, L_Fortran];
 
-  // Whether the directive has the "pure" property, i.e. it is permitted to
-  // appear in a context that must be free of side effects, such as a Fortran
-  // PURE procedure. Defaults to false.
-  bit isPure = false;
+  // The OpenMP version at which the directive gained the "pure" property.
+  int pureSince = 0x7FFFFFFF;
 }
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 7cf57c3fda68a..c0838407d1af5 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -680,7 +680,7 @@ def OMP_Assumes : Directive<[Spelling<"assumes">]> {
     VersionedClause<OMPC_NoOpenMPRoutines, 51>,
     VersionedClause<OMPC_NoParallelism, 51>,
   ];
-  let isPure = true;
+  let pureSince = 52;
 }
 def OMP_Assume : Directive<[Spelling<"assume">]> {
   let association = AS_Block;
@@ -694,7 +694,7 @@ def OMP_Assume : Directive<[Spelling<"assume">]> {
     VersionedClause<OMPC_NoOpenMPRoutines, 51>,
     VersionedClause<OMPC_NoParallelism, 51>,
   ];
-  let isPure = true;
+  let pureSince = 52;
 }
 def OMP_Atomic : Directive<[Spelling<"atomic">]> {
   let allowedOnceClauses = [
@@ -819,7 +819,6 @@ def OMP_DeclareReduction : Directive<[Spelling<"declare reduction", 1, 52>,
   ];
   let association = AS_None;
   let category = CA_Declarative;
-  let isPure = true;
 }
 def OMP_DeclareSimd : Directive<[Spelling<"declare simd", 1, 52>,
                                  Spelling<"declare_simd", 60>]> {
@@ -837,7 +836,6 @@ def OMP_DeclareSimd : Directive<[Spelling<"declare simd", 1, 52>,
   ];
   let association = AS_Declaration;
   let category = CA_Declarative;
-  let isPure = true;
 }
 def OMP_DeclareTarget : Directive<[Spelling<"declare target", 1, 52>,
                                    Spelling<"declare_target", 60>]> {
@@ -853,7 +851,6 @@ def OMP_DeclareTarget : Directive<[Spelling<"declare target", 1, 52>,
   ];
   let association = AS_None;
   let category = CA_Declarative;
-  let isPure = true;
 }
 def OMP_DeclareVariant : Directive<[Spelling<"declare variant", 1, 52>,
                                     Spelling<"declare_variant", 60>]> {
@@ -867,7 +864,6 @@ def OMP_DeclareVariant : Directive<[Spelling<"declare variant", 1, 52>,
   let association = AS_Declaration;
   let category = CA_Declarative;
   let languages = [L_C];
-  let isPure = true;
 }
 def OMP_Depobj : Directive<[Spelling<"depobj">]> {
   let allowedClauses = [
@@ -942,7 +938,7 @@ def OMP_Error : Directive<[Spelling<"error">]> {
   ];
   let association = AS_None;
   let category = CA_Utility;
-  let isPure = true;
+  let pureSince = 52;
 }
 def OMP_Flatten : Directive<[Spelling<"flatten">]> {
   let allowedClauses = [
@@ -1011,7 +1007,7 @@ def OMP_Fuse : Directive<[Spelling<"fuse">]> {
   let allowedLoopModifiers = [
     LM_Fused,
   ];
-  let isPure = true;
+  let pureSince = 52;
 }
 def OMP_Interchange : Directive<[Spelling<"interchange">]> {
   let allowedClauses = [
@@ -1025,7 +1021,7 @@ def OMP_Interchange : Directive<[Spelling<"interchange">]> {
   let allowedLoopModifiers = [
     LM_Interchanged,
   ];
-  let isPure = true;
+  let pureSince = 52;
 }
 def OMP_interop : Directive<[Spelling<"interop">]> {
   let allowedClauses = [
@@ -1076,7 +1072,7 @@ def OMP_Metadirective : Directive<[Spelling<"metadirective">]> {
   ];
   let association = AS_None;
   let category = CA_Meta;
-  let isPure = true;  
+  let pureSince = 52;
 }
 def OMP_Nothing : Directive<[Spelling<"nothing">]> {
   let allowedClauses = [
@@ -1087,7 +1083,7 @@ def OMP_Nothing : Directive<[Spelling<"nothing">]> {
   let allowedLoopModifiers = [
     LM_Identity,
   ];
-  let isPure = true;
+  let pureSince = 52;
 }
 def OMP_Ordered : Directive<[Spelling<"ordered">]> {
   let allowedClauses = [
@@ -1145,7 +1141,7 @@ def OMP_Reverse : Directive<[Spelling<"reverse">]> {
   let allowedLoopModifiers = [
     LM_Reversed,
   ];
-  let isPure = true;
+  let pureSince = 52;
 }
 def OMP_Scan : Directive<[Spelling<"scan">]> {
   let allowedOnceClauses = [
@@ -1154,6 +1150,7 @@ def OMP_Scan : Directive<[Spelling<"scan">]> {
   ];
   let association = AS_Separating;
   let category = CA_Subsidiary;
+  let pureSince = 60;
 }
 def OMP_Scope : Directive<[Spelling<"scope">]> {
   let allowedClauses = [
@@ -1444,7 +1441,7 @@ def OMP_Tile : Directive<[Spelling<"tile">]> {
     LM_Grid,
     LM_Intratile,
   ];
-  let isPure = true;
+  let pureSince = 52;
 }
 def OMP_Stripe : Directive<[Spelling<"stripe">]> {
   let allowedClauses = [
@@ -1459,7 +1456,7 @@ def OMP_Stripe : Directive<[Spelling<"stripe">]> {
     LM_Grid,
     LM_Offsets,
   ];
-  let isPure = true;
+  let pureSince = 52;
 }
 def OMP_Split : Directive<[Spelling<"split">]> {
   let allowedClauses = [
@@ -1476,7 +1473,7 @@ def OMP_Split : Directive<[Spelling<"split">]> {
   let allowedLoopModifiers = [
     LM_Split,
   ];
-  let isPure = true;
+  let pureSince = 52;
 }
 def OMP_Unknown : Directive<[Spelling<"unknown">]> {
   let isDefault = true;
@@ -1496,7 +1493,7 @@ def OMP_Unroll : Directive<[Spelling<"unroll">]> {
   let allowedLoopModifiers = [
     LM_Unrolled,
   ];
-  let isPure = true;
+  let pureSince = 52;
 }
 def OMP_Workshare : Directive<[Spelling<"workshare">]> {
   let allowedOnceClauses = [
diff --git a/llvm/include/llvm/TableGen/DirectiveEmitter.h b/llvm/include/llvm/TableGen/DirectiveEmitter.h
index 9f851ffd2ffea..8e7854da50252 100644
--- a/llvm/include/llvm/TableGen/DirectiveEmitter.h
+++ b/llvm/include/llvm/TableGen/DirectiveEmitter.h
@@ -274,7 +274,7 @@ class Directive : public BaseRecord {
     return Def->getValueAsListOfDefs("allowedLoopModifiers");
   }
 
-  bool isPure() const { return Def->getValueAsBit("isPure"); }
+  int getPureSince() const { return Def->getValueAsInt("pureSince"); }
 
   // Clang uses a different format for names of its directives enum.
   std::string getClangAccSpelling() const {
diff --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td
index 40c5e96d080ba..2b3a3a14828e5 100644
--- a/llvm/test/TableGen/directive1.td
+++ b/llvm/test/TableGen/directive1.td
@@ -190,11 +190,10 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
 // CHECK-NEXT:  #endif
 // CHECK-NEXT:  }
 // CHECK-EMPTY:
-// CHECK-NEXT:  constexpr bool isDirectivePure(Directive Dir) {
+// CHECK-NEXT:  constexpr unsigned getDirectivePureSince(Directive Dir) {
 // CHECK-NEXT:    switch (Dir) {
-// CHECK-NEXT:      return true;
 // CHECK-NEXT:    default:
-// CHECK-NEXT:      return false;
+// CHECK-NEXT:      return 0x7FFFFFFF;
 // CHECK-NEXT:    } // switch (Dir)
 // CHECK-NEXT:  }
 // CHECK-EMPTY:
diff --git a/llvm/test/TableGen/directive2.td b/llvm/test/TableGen/directive2.td
index 2943a8eb3f1a6..367756206c6ac 100644
--- a/llvm/test/TableGen/directive2.td
+++ b/llvm/test/TableGen/directive2.td
@@ -155,11 +155,10 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
 // CHECK-NEXT:  #endif
 // CHECK-NEXT:  }
 // CHECK-EMPTY:
-// CHECK-NEXT:  constexpr bool isDirectivePure(Directive Dir) {
+// CHECK-NEXT:  constexpr unsigned getDirectivePureSince(Directive Dir) {
 // CHECK-NEXT:    switch (Dir) {
-// CHECK-NEXT:      return true;
 // CHECK-NEXT:    default:
-// CHECK-NEXT:      return false;
+// CHECK-NEXT:      return 0x7FFFFFFF;
 // CHECK-NEXT:    } // switch (Dir)
 // CHECK-NEXT:  }
 // CHECK-EMPTY:
diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
index 33a725f31b11b..c60f362eb2d85 100644
--- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
@@ -899,22 +899,26 @@ static void generateGetDirectiveCategory(const DirectiveLanguage &DirLang,
   OS << "}\n";
 }
 
-static void generateIsDirectivePure(const DirectiveLanguage &DirLang,
-                                    raw_ostream &OS) {
-  OS << "constexpr bool isDirectivePure(Directive Dir) {\n";
+static void generateGetDirectivePureSince(const DirectiveLanguage &DirLang,
+                                          raw_ostream &OS) {
+  // Must match the sentinel in DirectiveBase.td and in
+  // OmpStructureChecker::CheckDirectiveInPureProcedure.
+  constexpr int NeverPure = 0x7FFFFFFF;
+  OS << "constexpr unsigned getDirectivePureSince(Directive Dir) {\n";
   OS << "  switch (Dir) {\n";
 
   StringRef Prefix = DirLang.getDirectivePrefix();
 
   for (const Record *R : DirLang.getDirectives()) {
     Directive D(R);
-    if (!D.isPure())
+    int PureSince = D.getPureSince();
+    if (PureSince == NeverPure)
       continue;
     OS << "  case " << getIdentifierName(R, Prefix) << ":\n";
+    OS << "    return " << PureSince << ";\n";
   }
-  OS << "    return true;\n";
   OS << "  default:\n";
-  OS << "    return false;\n";
+  OS << "    return " << NeverPure << ";\n";
   OS << "  } // switch (Dir)\n";
   OS << "}\n";
 }
@@ -1403,7 +1407,7 @@ static void emitDirectivesConstexprImpl(const DirectiveLanguage &DirLang,
   OS << "\n";
   generateGetDirectiveCategory(DirLang, OS);
   OS << "\n";
-  generateIsDirectivePure(DirLang, OS);
+  generateGetDirectivePureSince(DirLang, OS);
   OS << "\n";
   generateGetDirectiveLanguages(DirLang, OS);
 }

>From 52fc199e2daed5af07acabdf9d64dad94689597c Mon Sep 17 00:00:00 2001
From: Shashwathi N <nshashwa at pe34genoa.hpc.amslabs.hpecorp.net>
Date: Thu, 6 Aug 2026 12:09:19 -0500
Subject: [PATCH 6/7] mend

---
 llvm/utils/TableGen/Basic/DirectiveEmitter.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
index c60f362eb2d85..7fe9406b27d64 100644
--- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
@@ -918,7 +918,7 @@ static void generateGetDirectivePureSince(const DirectiveLanguage &DirLang,
     OS << "    return " << PureSince << ";\n";
   }
   OS << "  default:\n";
-  OS << "    return " << NeverPure << ";\n";
+  OS << "    return 0x7FFFFFFF;\n";
   OS << "  } // switch (Dir)\n";
   OS << "}\n";
 }

>From 294c786369233173fe9e4d0d74d1d1b44386f398 Mon Sep 17 00:00:00 2001
From: Shashwathi N <nshashwa at pe34genoa.hpc.amslabs.hpecorp.net>
Date: Sun, 9 Aug 2026 23:28:57 -0500
Subject: [PATCH 7/7] Suggested Changes

---
 flang/lib/Semantics/check-omp-structure.cpp |  7 +------
 llvm/include/llvm/Frontend/OpenMP/OMP.td    | 23 +++++++++++++++++----
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index faf100224f0c3..8ed5fdb94c169 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -952,15 +952,10 @@ void OmpStructureChecker::CheckDirectiveInPureProcedure(
     return;
   }
   unsigned version{context_.langOptions().OpenMPVersion};
-  // OpenMP 5.1 permits only SIMD and declarative directives in a PURE
-  // procedure; OpenMP 5.2 additionally permits metadirective, assume(s),
-  // nothing, error, and the loop-transforming constructs).
-  bool alwaysAllowed{id == llvm::omp::Directive::OMPD_simd ||
-      llvm::omp::getDirectiveCategory(id) == llvm::omp::Category::Declarative};
   // A directive's "pure" property is version-specific: pureSince is the
   // OpenMP version at which the directive gained that property.
   unsigned pureSince{llvm::omp::getDirectivePureSince(id)};
-  if (alwaysAllowed || version >= pureSince) {
+  if (version >= pureSince) {
     return;
   }
   if (pureSince != 0x7FFFFFFF) {
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index ea6c6180e6405..61754828b8966 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -665,6 +665,7 @@ def OMP_Allocate : Directive<[Spelling<"allocate">]> {
   ];
   let association = AS_None;
   let category = CA_Declarative;
+  let pureSince = 50;
 }
 def OMP_Allocators : Directive<[Spelling<"allocators">]> {
   let allowedClauses = [
@@ -755,12 +756,14 @@ def OMP_BeginDeclareTarget : Directive<[Spelling<"begin declare target", 1, 52>,
   let association = AS_Delimited;
   let category = CA_Declarative;
   let languages = [L_C];
+  let pureSince = 45;
 }
 def OMP_EndDeclareTarget : Directive<[Spelling<"end declare target", 1, 52>,
                                       Spelling<"end declare_target", 60>]> {
   let association = AS_Delimited;
   let category = OMP_BeginDeclareTarget.category;
   let languages = OMP_BeginDeclareTarget.languages;
+  let pureSince = OMP_BeginDeclareTarget.pureSince;
 }
 def OMP_BeginDeclareVariant
     : Directive<[Spelling<"begin declare variant", 1, 52>,
@@ -768,12 +771,14 @@ def OMP_BeginDeclareVariant
   let association = AS_Delimited;
   let category = CA_Declarative;
   let languages = [L_C];
+  let pureSince = 50;
 }
 def OMP_EndDeclareVariant : Directive<[Spelling<"end declare variant", 1, 52>,
                                        Spelling<"end declare_variant", 60>]> {
   let association = AS_Delimited;
   let category = OMP_BeginDeclareVariant.category;
   let languages = OMP_BeginDeclareVariant.languages;
+  let pureSince = 50;
 }
 def OMP_Cancel : Directive<[Spelling<"cancel">]> {
   let allowedClauses = [
@@ -807,6 +812,7 @@ def OMP_DeclareInduction : Directive<[Spelling<"declare_induction">]> {
   ];
   let association = AS_None;
   let category = CA_Declarative;
+  let pureSince = 50;
 }
 def OMP_DeclareMapper : Directive<[Spelling<"declare mapper", 1, 52>,
                                    Spelling<"declare_mapper", 60>]> {
@@ -815,6 +821,7 @@ def OMP_DeclareMapper : Directive<[Spelling<"declare mapper", 1, 52>,
   ];
   let association = AS_None;
   let category = CA_Declarative;
+  let pureSince = 50;
 }
 def OMP_DeclareReduction : Directive<[Spelling<"declare reduction", 1, 52>,
                                       Spelling<"declare_reduction", 60>]> {
@@ -824,6 +831,7 @@ def OMP_DeclareReduction : Directive<[Spelling<"declare reduction", 1, 52>,
   ];
   let association = AS_None;
   let category = CA_Declarative;
+  let pureSince = 50;
 }
 def OMP_DeclareSimd : Directive<[Spelling<"declare simd", 1, 52>,
                                  Spelling<"declare_simd", 60>]> {
@@ -841,6 +849,7 @@ def OMP_DeclareSimd : Directive<[Spelling<"declare simd", 1, 52>,
   ];
   let association = AS_Declaration;
   let category = CA_Declarative;
+  let pureSince = 50;
 }
 def OMP_DeclareTarget : Directive<[Spelling<"declare target", 1, 52>,
                                    Spelling<"declare_target", 60>]> {
@@ -856,6 +865,7 @@ def OMP_DeclareTarget : Directive<[Spelling<"declare target", 1, 52>,
   ];
   let association = AS_None;
   let category = CA_Declarative;
+  let pureSince = 45;
 }
 def OMP_DeclareVariant : Directive<[Spelling<"declare variant", 1, 52>,
                                     Spelling<"declare_variant", 60>]> {
@@ -869,6 +879,7 @@ def OMP_DeclareVariant : Directive<[Spelling<"declare variant", 1, 52>,
   let association = AS_Declaration;
   let category = CA_Declarative;
   let languages = [L_C];
+  let pureSince = 50;
 }
 def OMP_Depobj : Directive<[Spelling<"depobj">]> {
   let allowedClauses = [
@@ -998,6 +1009,7 @@ def OMP_Groupprivate : Directive<[Spelling<"groupprivate">]> {
   let association = AS_None;
   let category = CA_Declarative;
   let languages = [L_C, L_Fortran];
+  let pureSince = 50;
 }
 def OMP_Fuse : Directive<[Spelling<"fuse">]> {
   let allowedClauses = [
@@ -1012,7 +1024,7 @@ def OMP_Fuse : Directive<[Spelling<"fuse">]> {
   let allowedLoopModifiers = [
     LM_Fused,
   ];
-  let pureSince = 52;
+  let pureSince = 60;
 }
 def OMP_Interchange : Directive<[Spelling<"interchange">]> {
   let allowedClauses = [
@@ -1136,6 +1148,7 @@ def OMP_Requires : Directive<[Spelling<"requires">]> {
   ];
   let association = AS_None;
   let category = CA_Informational;
+  let pureSince = 50;
 }
 def OMP_Reverse : Directive<[Spelling<"reverse">]> {
   let allowedClauses = [
@@ -1146,7 +1159,7 @@ def OMP_Reverse : Directive<[Spelling<"reverse">]> {
   let allowedLoopModifiers = [
     LM_Reversed,
   ];
-  let pureSince = 52;
+  let pureSince = 60;
 }
 def OMP_Scan : Directive<[Spelling<"scan">]> {
   let allowedOnceClauses = [
@@ -1207,6 +1220,7 @@ def OMP_Simd : Directive<[Spelling<"simd">]> {
   ];
   let association = AS_LoopNest;
   let category = CA_Executable;
+  let pureSince = 45;
 }
 def OMP_Single : Directive<[Spelling<"single">]> {
   let allowedClauses = [
@@ -1427,6 +1441,7 @@ def OMP_Teams : Directive<[Spelling<"teams">]> {
   let category = CA_Executable;
 }
 def OMP_ThreadPrivate : Directive<[Spelling<"threadprivate">]> {
+  let pureSince = 50;
   let association = AS_None;
   let category = CA_Declarative;
 }
@@ -1461,7 +1476,7 @@ def OMP_Stripe : Directive<[Spelling<"stripe">]> {
     LM_Grid,
     LM_Offsets,
   ];
-  let pureSince = 52;
+  let pureSince = 60;
 }
 def OMP_Split : Directive<[Spelling<"split">]> {
   let allowedClauses = [
@@ -1478,7 +1493,7 @@ def OMP_Split : Directive<[Spelling<"split">]> {
   let allowedLoopModifiers = [
     LM_Split,
   ];
-  let pureSince = 52;
+  let pureSince = 60;
 }
 def OMP_Unknown : Directive<[Spelling<"unknown">]> {
   let isDefault = true;



More information about the flang-commits mailing list